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.net.AddressNetTools; import com.skyversation.poiaddr.util.status.AddressLevel; import com.skyversation.poiaddr.util.status.AddressResultEnum; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; import org.apache.commons.codec.binary.Base64; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.util.*; public class AddressQueryEngine { private static AddressQueryEngine instance = new AddressQueryEngine(); 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 * @return */ public AddressResult commonSearchByName(List addrs) { if (addrs == null || addrs.size() < 1) { return null; } AddressResult addressResult = new AddressResult(); if (addressResult.getData() == null || addressResult.getData().size() == 0) { for (String addr : addrs) { // 创建请求 addressResult = sj_szxSearchByName(addr); if(addressResult != null){ addressResult.setCode(AddressResultEnum.SZX_SUCCESS); addressResult.setMessage("成功"); return getCjWgWgwByLoc(addressResult); } } } addressResult.setCode(AddressResultEnum.RESULT_NULL); addressResult.setMessage("失败"); return addressResult; } /*** * 武大吉奥单条地名搜索 * @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().requestGetOrPost(HttpMethod.GET, 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 String getSigns(String timestamp, String appCode, String UUid, String appSecret) { // 先拼接 String signData = timestamp + appCode + UUid; // 生成sign String sign = ""; try { Mac sha256 = Mac.getInstance("HmacSHA256"); sha256.init(new SecretKeySpec(appSecret.getBytes(), "HmacSHA256")); byte[] result = sha256.doFinal(signData.getBytes()); sign = Base64.encodeBase64String(result); } catch (Exception e) { System.err.println("sign 生成异常:" + e); } return sign; } public AddressResult sj_szxSearchByName(String address) { // 鉴权 Map headerMap = new HashMap<>(); String timestamp = System.currentTimeMillis() + ""; String appCode = "7unv4vbwqxnq4a7m9h"; String UUid = UUID.randomUUID().toString(); String appSecret = "w6tawvf4k3ck4ikij9"; headerMap.put("x-timestamp", timestamp); headerMap.put("x-appcode", appCode); headerMap.put("x-uuid", UUid); // 签名 headerMap.put("x-sign", getSigns(timestamp, appCode, UUid, appSecret)); JSONObject params = new JSONObject(); JSONArray requestJson = new JSONArray(); JSONObject paramObject = new JSONObject(); paramObject.put("name", "query"); paramObject.put("position", "QUERY"); paramObject.put("value", address); requestJson.add(paramObject); params.put("requestJson", requestJson); // 发起请求 ResponseEntity response = AddressNetTools.getInstance().requestGetOrPost(HttpMethod.POST, Constant.SJ_SZX_SEARCH_BY_NAME, params, headerMap, 1); if (response != null) { String body = response.getBody() + ""; if (!StringUtils.hasText(body)) return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_NULL, "搜索无结果"); try { if(body.indexOf("[") != 0){ System.out.println("请求地址:" + address + ";返回结果错误:" + body); return null; }else{ // 匹配得到得分最高的结果 JSONObject res = com.skyversation.poiaddr.util.AddressTools.getInstance().findBestMatch(address,JSONArray.parseArray(body),"address"); // 将得分最高的结果映射到实体类 return TransfromDataTool.szxResultToResult2(res); } } catch (Exception e) { System.err.println("请求地址:" + address + ";返回结果:" + body + ";处理异常:" + 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().requestGetOrPost(HttpMethod.GET, 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().requestGetOrPost(HttpMethod.GET, 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().requestGetOrPost(HttpMethod.GET, 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.getAdname() == null || content.getCityname() == null) && content.getLat() != null && content.getLon() != null) { 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; } }