package com.skyversation.poiaddr.addquery; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.skyversation.poiaddr.bean.AddressResult; import com.skyversation.poiaddr.bean.GeoJsonBean; import com.skyversation.poiaddr.bean.WDToken; import com.skyversation.poiaddr.service.AreaService; import com.skyversation.poiaddr.util.ExcelReaderUtils; import com.skyversation.poiaddr.util.net.AddressNetTools; import com.skyversation.poiaddr.util.status.AddressLevel; import com.skyversation.poiaddr.util.status.AddressResultEnum; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.io.IOException; import java.util.*; import static com.skyversation.poiaddr.addquery.TransfromDataTool.yyszResultToResult; @Service public class AddressQueryEngine { private static AddressQueryEngine instance = new AddressQueryEngine(); @Value("${app.net-type}") private String netType=null; @Value("${app.yysz-address-service}") private String yyszAddressService=null; @Resource private DataCallBack dataCallBack; @PostConstruct public void init(){ if (netType == null) { netType = "internet"; System.out.println("spring环境未初始化,使用默认网络环境"+netType); } else { // netType = netTypeInProp.getNetType(); System.out.println("通过配置文件获取当前网络环境为:" + netType); } } private AddressQueryEngine() { } public synchronized static AddressQueryEngine getInstance() { if (instance == null) { instance = new AddressQueryEngine(); } return instance; } private WDToken wdToken = null; /*** * 单条地名搜索通用方法,搜索顺序 1. 武大吉奥; 2. 市四中心; 3. 高德搜索; 4. 高德高级搜索; * @param addrs * @param level 搜索等级: * 1. 搜索到结果就返回第一个; * 2. 搜索到结果去除行政区划后,存在包含关系,则使用; * 3. 搜索到结果,数字进行分词,数字匹配则使用; * 4. 搜索到结果,数字与文本均匹配,则使用; * 5. 结果与基准数据完全一致,则使用。 * @return */ public AddressResult commonSearchByName(List addrs, AddressLevel level) { if (addrs == null || addrs.size() < 1) { return null; } //先走yysz_address AddressResult yyszAddressResult =null; yyszAddressResult = yyszMultiSearch(addrs, level ); if (yyszAddressResult != null) return yyszAddressResult; if (!Objects.equals(netType, "internet")) { //武大 if (Objects.equals(netType, "qingpu")) { AddressResult wdAddressResult = wdMultiSearch(addrs, level); if (wdAddressResult != null) { dataCallBack.successDataCallBack(wdAddressResult); return wdAddressResult; } } //四中心 AddressResult szxAddressResult = szxMultiSearch(addrs, level); if (szxAddressResult != null) { dataCallBack.successDataCallBack(szxAddressResult); return szxAddressResult; } }else { //高德 AddressResult gdAddressResult = gdMultiSearch(addrs, level); if (gdAddressResult != null) { dataCallBack.successDataCallBack(gdAddressResult); return gdAddressResult; } //高德高级 AddressResult gdV3AddressResult = gdV3MultiSearch(addrs, level); if (gdV3AddressResult != null) { dataCallBack.successDataCallBack(gdV3AddressResult); return gdV3AddressResult; } } //失败 AddressResult addressResult =new AddressResult(); dataCallBack.failDataCallBack(addrs); addressResult.setCode(AddressResultEnum.RESULT_NULL); addressResult.setMessage("失败"); return addressResult; } public AddressResult commonSearchByNameForTest(List addrs, AddressLevel level) { if (addrs == null || addrs.size() < 1) { return null; } if (!Objects.equals(netType, "internet")) { //武大 if (Objects.equals(netType, "qingpu")) { AddressResult wdAddressResult = wdMultiSearch(addrs, level); if (wdAddressResult != null) { return wdAddressResult; } } //四中心 AddressResult szxAddressResult = szxMultiSearch(addrs, level); if (szxAddressResult != null) { return szxAddressResult; } }else { //高德 AddressResult gdAddressResult = gdMultiSearch(addrs, level); if (gdAddressResult != null) { return gdAddressResult; } //高德高级 AddressResult gdV3AddressResult = gdV3MultiSearch(addrs, level); if (gdV3AddressResult != null) { return gdV3AddressResult; } } //失败 AddressResult addressResult =new AddressResult(); addressResult.setCode(AddressResultEnum.RESULT_NULL); addressResult.setMessage("失败"); return addressResult; } //多条搜索 /** * yysz_address多条搜索 */ private AddressResult yyszMultiSearch(List addrs, AddressLevel level) { try{ for (String addr : addrs) { AddressResult.ContentBean contentBean = verificaData(yyszSearchByName(addr), level, addr); if (contentBean != null) { contentBean.setSearchAddress(addr); List contentBeans = new ArrayList<>(); contentBeans.add(contentBean); AddressResult addressResult = new AddressResult(); addressResult.setData(contentBeans); addressResult.setCode(AddressResultEnum.YYSZ_SUCCESS); addressResult.setMessage("成功"); return addressResult; } } }catch (Exception e){ throw new RuntimeException("yysz_address服务异常"); } return null; } /** * 武大多条搜索 */ private AddressResult wdMultiSearch(List addrs, AddressLevel level) { try { for (String addr : addrs) { AddressResult.ContentBean contentBean = verificaData(wdjaSearchByName(addr), level, addr); if (contentBean != null) { contentBean.setSearchAddress(addr); List contentBeans = new ArrayList<>(); contentBeans.add(contentBean); AddressResult addressResult = new AddressResult(); addressResult.setData(contentBeans); addressResult.setCode(AddressResultEnum.WDJA_SUCCESS); addressResult.setMessage("成功"); return addressResult; } } } catch (Exception e) { System.err.println("武大吉奥:日常异常" + e); } return null; } /** * 四中心多条搜索 */ private AddressResult szxMultiSearch(List addrs, AddressLevel level) { try { for (String addr : addrs) { AddressResult.ContentBean contentBean = verificaData(szxSearchByName(addr), level, addr); if (contentBean != null) { contentBean.setSearchAddress(addr); List contentBeans = new ArrayList<>(); contentBeans.add(contentBean); AddressResult addressResult = new AddressResult(); addressResult.setData(contentBeans); addressResult.setCode(AddressResultEnum.SZX_SUCCESS); addressResult.setMessage("成功"); return addressResult; } } } catch (Exception e) { System.err.println(" 四中心异常" + e); } return null; } /** * 高德多条搜索 */ private AddressResult gdMultiSearch(List addrs, AddressLevel level) { try { for (String addr : addrs) { AddressResult.ContentBean contentBean = verificaData(gdSearchByName(addr), level, addr); if (contentBean != null) { contentBean.setSearchAddress(addr); List contentBeans = new ArrayList<>(); contentBeans.add(contentBean); AddressResult addressResult = new AddressResult(); addressResult.setData(contentBeans); addressResult.setCode(AddressResultEnum.GD_SUCCESS); addressResult.setMessage("成功"); return addressResult; } } } catch (Exception e) { System.err.println("高德异常" + e); } return null; }/** * 高德高级多条搜索 */ private AddressResult gdV3MultiSearch(List addrs, AddressLevel level) { try { for (String addr : addrs) { AddressResult.ContentBean contentBean = verificaData(gdV3SearchByName(addr), level, addr); if (contentBean != null) { contentBean.setSearchAddress(addr); List contentBeans = new ArrayList<>(); contentBeans.add(contentBean); AddressResult addressResult = new AddressResult(); addressResult.setData(contentBeans); addressResult.setCode(AddressResultEnum.GDV3_SUCCESS); addressResult.setMessage("成功"); return addressResult; } } } catch (Exception e) { System.err.println("高德高级异常" + e); } return null; } //单搜索 /** * yysz_address地名搜索 */ public AddressResult yyszSearchByName(String address){ ResponseEntity response = AddressNetTools.getInstance().requestGet(yyszAddressService+"/search/searchByName?address="+address, null, null, 10); if (response != null) { String body = response.getBody() + ""; if (!StringUtils.hasText(body)) return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_NULL, "搜索无结果"); try { AddressResult addressResult = yyszResultToResult(JSONObject.parseObject(body)); if (addressResult==null)System.out.println("yysz_address地址[" + address + "]未查询到数据!"); return addressResult; } catch (Exception e) { System.err.println(e); return AddressTools.getInstance().faildQuery(AddressResultEnum.DATA_FROMAT_FAILD, "格式化失败"); } } else { System.out.println("yysz_address地址[" + address + "]未查询到数据!"); return null; } } /** * 武大吉奥单条地名搜索 * @param address */ public AddressResult wdjaSearchByName(String address) { System.out.println("<<<<<<<<<<----------开始武大吉奥地名地址搜索------------>>>>>>>>>>>>>"); if (wdToken == null || System.currentTimeMillis() - wdToken.getTime() > 36000000) { wdToken = AddressTools.getInstance().getWDToken(Constant.WD_USER_NAME, Constant.WD_USER_PWD); if (wdToken == null) { return null; } wdToken.setTime(System.currentTimeMillis()); } if (wdToken == null) return AddressTools.getInstance().faildQuery(AddressResultEnum.NO_TOKEN, "token获取失败"); String token = wdToken.getToken(); String url = Constant.GET_ADDRESS_MEG_URL + "?token=" + token + "&addr=" + address; String body = null; try { body = AddressNetTools.getInstance().wdSendGetRequest(url); } catch (Exception e) { e.toString(); } if (body == null || body.equals("null") || !StringUtils.hasText(body)) return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_NULL, "搜索无结果"); try { JSONObject json = JSONObject.parseObject(body); return TransfromDataTool.wdResultToResult(json); } catch (Exception e) { return AddressTools.getInstance().faildQuery(AddressResultEnum.DATA_FROMAT_FAILD, "格式化失败"); } } /** * 市四中心地名搜索 * @param address * @return */ public AddressResult szxSearchByName(String address) { ResponseEntity response = AddressNetTools.getInstance().requestGet(Constant.SZX_URL + "®ion=" + Constant.getAMAP_CITY_CODE() + "&query=" + address, null, null, 10); if (response != null) { String body = response.getBody() + ""; if (!StringUtils.hasText(body)) return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_NULL, "搜索无结果"); try { return TransfromDataTool.szxResultToResult(JSONObject.parseObject(body)); } catch (Exception e) { System.err.println(e); return AddressTools.getInstance().faildQuery(AddressResultEnum.DATA_FROMAT_FAILD, "格式化失败"); } } else { System.out.println("地址[" + address + "]未查询到数据!"); return null; } } /*public AddressResult v4SearchByName(String address) { ResponseEntity response = AddressNetTools.getInstance().requestGet(Constant.V4_URL + address, null, null); if (response != null) { String body = response.getBody() + ""; if (!StringUtils.hasText(body)) return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_NULL, "搜索无结果"); try { JSONObject json = JSONObject.parseObject(body); return TransfromDataTool.szxResultToResult(json); } catch (Exception e) { System.err.println(e); return AddressTools.getInstance().faildQuery(AddressResultEnum.DATA_FROMAT_FAILD, "格式化失败"); } } else { System.out.println("地址" + address + "未查询到数据!"); return null; } }*/ /** * 高德普通地名搜索 * @param address * @return */ public AddressResult gdSearchByName(String address) { String geoUrl = Constant.AMAP_GEO_URL + "?key=" + Constant.AMAP_KEY + "&address=" + address + "&city=" + Constant.getAMAP_CITY_CODE() + "&output=JSON"; ResponseEntity response = AddressNetTools.getInstance().requestGet(geoUrl, null, null, 0); if (response != null && response.getBody() != null) { String body = response.getBody() + ""; if (!StringUtils.hasText(body)) return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_NULL, "搜索无结果"); try { JSONObject json = JSONObject.parseObject(body); return TransfromDataTool.gdResultToResult(json); } catch (Exception e) { System.err.println(e); return AddressTools.getInstance().faildQuery(AddressResultEnum.DATA_FROMAT_FAILD, "格式化失败"); } } else { return null; } } /** * 高德高级地名搜索 * @param address * @return */ public AddressResult gdV3SearchByName(String address) { String geoUrl = Constant.AMAP_SEARCH_NAME_V3 + "?key=" + Constant.AMAP_KEY + "&types=" + Constant.AMAP_SEARCH_TYPES + "&keywords=" + address + "&city=" + Constant.getAMAP_CITY_CODE() + "&offset=20"; ResponseEntity responseEntity = AddressNetTools.getInstance().requestGet(geoUrl, null, null, 0); if (responseEntity.hasBody()) { String body = responseEntity.getBody() + ""; if (!StringUtils.hasText(body)) { return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_NULL, "搜索无结果"); } JSONArray pois = new JSONArray(); JSONObject json = JSONObject.parseObject(body); if (json.containsKey("pois")) { pois.addAll(json.getJSONArray("pois")); } if (json.containsKey("count")) { int count = Integer.parseInt(json.get("count") + ""); if (count > 20) { for (int i = 2; i < (count % 20 + 1); i++) { geoUrl = Constant.AMAP_SEARCH_NAME_V3 + "?key=" + Constant.AMAP_KEY + "&types=" + Constant.AMAP_SEARCH_TYPES + "&keywords=" + address + "&city=" + Constant.getAMAP_CITY_CODE() + "&offset=20&page=" + i; ResponseEntity responseEntity2 = AddressNetTools.getInstance().requestGet(geoUrl, null, null, 0); if (responseEntity2.hasBody()) { body = responseEntity2.getBody() + ""; } if (!StringUtils.hasText(body)) { return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_AGAIN_NULL, "多次搜索无结果"); } JSONObject json2 = JSONObject.parseObject(body); if (json2.containsKey(pois)) { pois.addAll(JSONObject.parseObject(body).getJSONArray("pois")); } } } } try { return TransfromDataTool.gdV3ResultToResult(pois); } catch (Exception e) { System.err.println(e); return AddressTools.getInstance().faildQuery(AddressResultEnum.DATA_FROMAT_FAILD, "格式化失败"); } } else { return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_AGAIN_NULL, "高德V3分页查询无结果"); } } /** * 根据搜索地址,赋值村居、网格、微格网信息 * @param result * @return */ public AddressResult getCjWgWgwByLoc(AddressResult result) { if (result == null || result.getData() == null || result.getData().size() < 1) { return result; } else { AreaService areaService = AreaService.getInstance(); for (AddressResult.ContentBean content : result.getData()) { if (content.getLat() != null && content.getLon() != null) { // TODO 松江的话只跑行政区划和街镇 /*GeoJsonBean cjBean = areaService.isInCJPolygon(content.getLon(), content.getLat()); content.setCjJson(cjBean == null ? new JSONObject() : cjBean.getProperties()); GeoJsonBean gridBean = areaService.isInGridPolygon(content.getLon(), content.getLat()); content.setWgwJson(gridBean == null ? new JSONObject() : gridBean.getProperties()); GeoJsonBean wgridBean = areaService.isInWGridPolygon(content.getLon(), content.getLat()); content.setWgwJson(wgridBean == null ? new JSONObject() : wgridBean.getProperties());*/ GeoJsonBean adBean = areaService.isInadPolygon(content.getLon(), content.getLat()); content.setAdJson(adBean == null ? new JSONObject() : adBean.getProperties()); GeoJsonBean townBean = areaService.isInTownPolygon(content.getLon(), content.getLat()); content.setTownJson(townBean == null ? new JSONObject() : townBean.getProperties()); } } return result; } } // public static boolean isNotEmptyOrBlank(String str) { return str != null && !str.trim().isEmpty(); } /** * 1. 搜索到结果就返回第一个; * 2. 搜索到结果去除行政区划后,存在包含关系,则使用; * 3. 搜索到结果,数字进行分词,数字匹配则使用; * 4. 搜索到结果,数字与文本均匹配,则使用; * 5. 结果与基准数据完全一致,则使用。 * * @param result * @param level * @return */ public AddressResult.ContentBean verificaData(AddressResult result, AddressLevel level, String addr) { switch (level) { case LEVEL_1: { if (result != null && result.getData() != null && result.getData().size() > 0) { return result.getData().get(0); } else { return null; } } // 2. 搜索到结果去除行政区划后,存在包含关系,则使用; case LEVEL_CONTAINS_2: { if (result != null && result.getData() != null && result.getData().size() > 0) { List contentBean = result.getData(); for (AddressResult.ContentBean contentBean1 : contentBean) { if (contentBean1.getAddress() != null) { String address = townReplaceAll(addressReplaceAll(contentBean1.getAddress())); String address2 = townReplaceAll(addressReplaceAll(addr)); if (isNotEmptyOrBlank(address) && address.contains(address2)) { return contentBean1; } } } } else { return null; } } // 3. 搜索到结果,数字进行分词,数字匹配则使用; case LEVLE_NUMBER_3: { if (result != null && result.getData() != null && result.getData().size() > 0) { List contentBean = result.getData(); for (AddressResult.ContentBean contentBean1 : contentBean) { if (contentBean1.getAddress() != null) { Set address = tokenizeString(contentBean1.getAddress()).get(1); if (address != null && address.size() > 1) { Set address2 = tokenizeString(addr).get(1); int addressSize = address.size(); for (String addr2 : address2) { if (address.contains(addr2)) { addressSize--; if (addressSize == 0) { return contentBean1; } } } } } } } else { return null; } } // 4. 搜索到结果,数字与文本均匹配,则使用; case LEVEL_NUMBER_TEXT_4: { if (result != null && result.getData() != null && result.getData().size() > 0) { List contentBean = result.getData(); for (AddressResult.ContentBean contentBean1 : contentBean) { if (contentBean1.getAddress() != null) { Set addressString = tokenizeString(contentBean1.getAddress()).get(0); Set addressNumber = tokenizeString(contentBean1.getAddress()).get(1); Set address2String = tokenizeString(addr).get(0); Set address2Number = tokenizeString(addr).get(1); if (addressString != null && addressString.size() > 1) { int addressStrSize = addressString.size(); for (String addr2str : address2String) { if (addressString.contains(addr2str)) { addressStrSize--; if (addressStrSize == 0) { int addressNumSize = addressNumber.size(); for (String addr2Num : address2Number) { if (addressNumber.contains(addr2Num)) { addressNumSize--; if (addressNumSize == 0) { return contentBean1; } } } } } } } } } } else { return null; } } // 结果与基准数据完全一致,则使用。 case LEVEL_TOTAL_CONTAINS_5: { if (result != null && result.getData() != null && result.getData().size() > 0) { List contentBean = result.getData(); for (AddressResult.ContentBean contentBean1 : contentBean) { if (contentBean1.getAddress() != null) { String address = addressReplaceAll(contentBean1.getAddress()); String address2 = addressReplaceAll(addr); if (isNotEmptyOrBlank(address) && address.equals(address2)) { return contentBean1; } } } } else { return null; } } default: { return null; } } } public static String addressReplaceAll(String address) { return address.replaceAll("上海市", "").replaceAll(Constant.getArea() + "区", "").replaceAll("-", "").replaceAll("_", "").replaceAll("/", "").replaceAll(" ", "").replaceAll(",", "").replaceAll("\\.", "").replaceAll(",", "").replaceAll("。", "").replaceAll("\\+", "").replaceAll("\\*", ""); } public static String townReplaceAll(String address) { String[] towns = Constant.getTowns(); for (String town : towns) { address = address.replaceAll(town, ""); } return address.replaceAll("号", "0").replaceAll("弄", "0").replaceAll("室", "0").replaceAll("户", "0").replaceAll("单元", "0").replaceAll("幢", "0"); } /** * 数字和文字分词返回List> * * @param input * @return */ public static List> tokenizeString(String input) { input = townReplaceAll(input); // 初始化两个集合,一个用于存储非数字字符串,一个用于存储数字字符串 Set nonNumberSet = new HashSet<>(); Set numberSet = new HashSet<>(); StringBuilder currentToken = new StringBuilder(); for (int i = 0; i < input.length(); i++) { char c = input.charAt(i); if (Character.isDigit(c)) { // 如果当前字符是数字 if (currentToken.length() > 0 && !Character.isDigit(currentToken.charAt(0))) { // 如果之前的 token 是非数字,将其添加到非数字集合中 nonNumberSet.add(currentToken.toString()); currentToken.setLength(0); } currentToken.append(c); } else { // 如果当前字符不是数字 if (currentToken.length() > 0 && Character.isDigit(currentToken.charAt(0))) { // 如果之前的 token 是数字,将其添加到数字集合中 numberSet.add(currentToken.toString()); currentToken.setLength(0); } if (!Character.isWhitespace(c)) { currentToken.append(c); } } } // 处理最后一个 token if (currentToken.length() > 0) { if (Character.isDigit(currentToken.charAt(0))) { numberSet.add(currentToken.toString()); } else { nonNumberSet.add(currentToken.toString()); } } // 将两个集合添加到列表中 List> result = new ArrayList<>(); result.add(nonNumberSet); result.add(numberSet); return result; } }