package com.skyversation.poiaddr.addquery; import com.alibaba.fastjson.JSON; 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.entity.AmapAddressV3; 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.stereotype.Service; 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(); // 数据库查询 for (String addr : addrs) { if (addr.startsWith("中山") && !addr.startsWith("中山街道")) { addr = addr.replace("中山", "中山街道"); } // 优先进行数据库查询 List dbPois = AreaService.getInstance().getAddressPoisByAddr(addr); JSONArray pois = new JSONArray(); if (dbPois != null && dbPois.size() > 0) { System.out.println("数据库查询有结果!!!!"); pois.addAll(dbPois); return new TransfromDataTool().gdV3ResultToResult(addr, pois, false); } } /*for (String addr : addrs) { // 创建请求 addressResult = sj_szxSearchByName(addr, 3); if (addressResult != null) { addressResult.setCode(AddressResultEnum.SZX_SUCCESS); addressResult.setMessage("成功"); return getCjWgWgwByLoc(addressResult); } }*/ // 市中心转发的测绘院地名地址服务 for (String addr : addrs) { // 创建请求 addressResult = szxSearchByName(addr); if (addressResult != null) { addressResult.setCode(AddressResultEnum.SZX_SUCCESS); addressResult.setMessage("成功"); return getCjWgWgwByLoc(addressResult); } } // TODO 如果多次尝试请求市中心地址后,还是请求失败就使用高德地名地址搜索 for (String addr : addrs) { // 创建请求(要返回对应的搜索地址,返回地址,总分,市:cityname,街道:adname,村居:community) addressResult = gdV3SearchByName(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 * @return */ public AddressResult szxSearchByName(String address) { if (!address.startsWith("上海")) { address = "上海市" + address; } if (address.startsWith("中山") && !address.startsWith("中山街道")) { address = address.replace("中山", "中山街道"); } ResponseEntity response = AddressNetTools.getInstance().requestGetOrPost(HttpMethod.GET, Constant.SZX_HLW_URL + address, null, null, 3); if (response == null) { return 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, address); } catch (Exception e) { return AddressTools.getInstance().faildQuery(AddressResultEnum.DATA_FROMAT_FAILD, "格式化失败"); } } /*** * 武大吉奥单条地名搜索 * @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, "格式化失败"); } } public static Map initSigns() { 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", AddressQueryEngine.getSigns(timestamp, appCode, UUid, appSecret)); return headerMap; } public static 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; } /** * 关键字地名地址搜索,专用搜索处理逻辑 * * @param address * @param level * @return */ public AddressResult sj_szxSearchByName(String address, Integer level) { // 鉴权 JSONObject params = new JSONObject(); JSONArray requestJson = new JSONArray(); JSONObject paramObject = new JSONObject(); paramObject.put("name", "query"); paramObject.put("position", "QUERY"); switch (level) { case 3: paramObject.put("value", address); break; case 2: if (address.contains("号")) { paramObject.put("value", address.substring(0, address.lastIndexOf("号") + 1)); } else { level--; return sj_szxSearchByName(address, level); } break; case 1: if (address.contains("弄")) { paramObject.put("value", address.substring(0, address.lastIndexOf("弄") + 1)); } else { paramObject.put("value", address); } break; } if (!address.startsWith("上海")) { paramObject.put("value", "上海市" + paramObject.get("value")); } requestJson.add(paramObject); // 判断是否是关键字版搜索服务 if (Constant.SJ_SZX_SEARCH_BY_NAME.contains("1742459783686")) { JSONObject paramObject2 = new JSONObject(); paramObject2.put("name", "region"); paramObject2.put("position", "QUERY"); paramObject2.put("value", Constant.getAMAP_CITY_CODE()); requestJson.add(paramObject2); JSONObject paramObject3 = new JSONObject(); paramObject3.put("name", "page_size"); paramObject3.put("position", "QUERY"); paramObject3.put("value", "10"); requestJson.add(paramObject3); } params.put("requestJson", requestJson); // 发起请求 ResponseEntity response = AddressNetTools.getInstance().requestGetOrPost(HttpMethod.POST, Constant.SJ_SZX_SEARCH_BY_NAME, params, initSigns(), 5); if (response != null && response.hasBody()) { String body = response.getBody() + ""; if (!StringUtils.hasText(body)) { if (level > 0) { level--; return sj_szxSearchByName(address, level); } return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_NULL, "搜索无结果"); } try { if (body.indexOf("[") != 0) { AddressResult addressResult = TransfromDataTool.szxResultToResult(JSONObject.parseObject(body), address); if (addressResult.getCode().equals(AddressResultEnum.RESULT_NULL) && level > 0) { level--; return sj_szxSearchByName(address, level); } return addressResult; } else { // 将得分最高的结果映射到实体类 return TransfromDataTool.szxResultToResult2(com.skyversation.poiaddr.util.AddressTools.getInstance().findBestMatch(address, JSONArray.parseArray(body), "address")); } } catch (Exception e) { System.err.println("请求地址:" + address + ";返回结果:" + body + ";处理异常:" + e); return AddressTools.getInstance().faildQuery(AddressResultEnum.DATA_FROMAT_FAILD, "格式化失败"); } } else { if (level > 0) { level--; return sj_szxSearchByName(address, level); } 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) { if (address.startsWith("中山") && !address.startsWith("中山街道")) { address = address.replace("中山", "中山街道"); } JSONArray pois = new JSONArray(); 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, "搜索无结果"); } 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 new TransfromDataTool().gdV3ResultToResult(address, pois, true); } catch (Exception e) { System.err.println(e); e.printStackTrace(); 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.getAdname().isEmpty() || content.getCityname() == null || content.getCityname().isEmpty() || content.getCommunity() == null || content.getCommunity().isEmpty()) && content.getLat() != null && content.getLon() != null) { // 判断是否存在行政区划数据 if (content.getCityname() == null || content.getCityname().isEmpty()) { GeoJsonBean adBean = areaService.isInadPolygon(content.getLon(), content.getLat()); content.setAdJson(adBean == null ? new JSONObject() : adBean.getProperties()); } // 判断是否存在街镇数据 if (content.getAdname() == null || content.getAdname().isEmpty()) { GeoJsonBean townBean = areaService.isInTownPolygon(content.getLon(), content.getLat()); content.setTownJson(townBean == null ? new JSONObject() : townBean.getProperties()); } // 判断是否存在村居数据 if (content.getCommunity() == null || content.getCommunity().isEmpty()) { GeoJsonBean cjBean = areaService.isInResidentialCommitteePolygon(content.getLon(), content.getLat()); content.setCjJson(cjBean == null ? new JSONObject() : cjBean.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 townReplace_ct(String address) { address = address.replaceAll(" ", ""); // 替换市 address = address.replaceAll("上海市", ""); String[] towns = Constant.getTowns(); for (String town : towns) { if (address.contains(town)) { address = address.substring(address.indexOf(town) + town.length()); } } // TODO 强行去除居委 if (address.contains("居委会")) { address = address.substring(address.indexOf("居委会") + 3); } if (address.contains("委员会")) { address = address.substring(address.indexOf("委员会") + 3); } return address; } public static String townReplaceAll(String address) { address = townReplace_ct(address); return address.replaceAll("小区", "0").replaceAll("号", "0").replaceAll("弄", "0").replaceAll("室", "0").replaceAll("户", "0").replaceAll("单元", "0").replaceAll("幢", "0"); } /** * 数字和文字分词返回List> * * @param input * @return */ public static List> tokenizeString(String 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; } }