package com.skyversation.poiaddr.service; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.skyversation.poiaddr.addquery.AddressQueryEngine; import com.skyversation.poiaddr.addquery.Constant; import com.skyversation.poiaddr.bean.*; import com.skyversation.poiaddr.config.DbConnection; import com.skyversation.poiaddr.service.impl.TAddressCallbackRepository; import com.skyversation.poiaddr.service.impl.YyszAddressRepository; import com.skyversation.poiaddr.util.ShanghaiAddressSplitUtil; import com.skyversation.poiaddr.util.SplitAddress; import com.skyversation.poiaddr.util.tasks.ScheduledTasks; import org.geotools.geojson.geom.GeometryJSON; import org.geotools.geometry.jts.JTSFactoryFinder; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.MultiPolygon; import org.locationtech.jts.io.ParseException; import org.locationtech.jts.io.WKTReader; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.io.*; import java.util.*; @Service public class AreaService { private static AreaService instance; @Resource private YyszAddressRepository yyszAddressRepository; @Resource private TAddressCallbackRepository tAddressCallbackRepository; public static AreaService getInstance() { if (instance == null) { return new AreaService(); } return instance; } @Value("${app.area}") private String area; @Value("${app.town}") private String town; @Value("${app.db.search_table_name}") private String searchTableName; @Value("${app.db.pgi_table}") private String pgi_table; @Value("${app.db.gr_table}") private String gr_table; @Value("${app.db.rp_table}") private String rp_table; WKTReader reader = new WKTReader(JTSFactoryFinder.getGeometryFactory()); public List shAllAdministrativeDivisionPolygonList = new ArrayList<>(); public List shAllToensPolygonList = new ArrayList<>(); public List shAllResidentialCommitteeList = new ArrayList<>(); public List wgPolygonList = new ArrayList<>(); public List wgwPolygonList = new ArrayList<>(); public List zhwgPolygonList = new ArrayList<>(); @PostConstruct public void initGeoData() { System.out.println("<<<<<<<<------AreaService>initGeoData------>>>>>>>>>"); instance = this; Thread thread3 = new Thread(this::initPolygons); thread3.start(); try { thread3.join(); } catch (InterruptedException e) { e.printStackTrace(); } // TODO 初始化配置文件变量 Constant.setTowns(town.split(",")); Constant.setArea(area); Constant.setSearchTableName(searchTableName); Constant.setGrTable(gr_table); Constant.setPgiTable(pgi_table); Constant.setRpTable(rp_table); System.out.println("<<<<<<<<------根据配置文件为AREA赋值:" + Constant.getArea()); System.out.println("<<<<<<<<------当前AMAP_CITY_CODE:" + Constant.getAMAP_CITY_CODE()); System.out.println("<<<<<<<<------结果总表:" + Constant.getGrTable()); System.out.println("<<<<<<<<------中间表:" + Constant.getPgiTable()); System.out.println("<<<<<<<<------回匹表:" + Constant.getRpTable()); // TODO 网络连通性测试,可以请求一下测试的市中心地址 try { System.out.println("电脑最大线程数:" + Runtime.getRuntime().availableProcessors()); System.out.println("<<<<<<<<------开始网络连通性测试"); long startTime = System.currentTimeMillis(); List addrs = new ArrayList<>(); addrs.add("上海市松江区乐都路339号"); AddressResult addressResult = AddressQueryEngine.getInstance().commonSearchByName(addrs); long endTime = System.currentTimeMillis(); System.out.println(">>>>>>>>------网络连通性测试完成!用时" + (endTime - startTime) / 1000 + "秒!结果:" + addressResult); } catch (Exception e) { System.err.println(">>>>>>>>------网络连通性测试结果:" + e); } // 查询callback表中最大的id和添加到callBackAllErrorAddrs列表中 try { List tAddressCallbacks = tAddressCallbackRepository.findAll(); if (tAddressCallbacks.size() > 0) { for (TAddressCallback tAddressCallback : tAddressCallbacks) { ScheduledTasks.callBackAllErrorAddrs.add(tAddressCallback.getSearchAddress()); } } } catch (Exception e) { e.printStackTrace(); } } public void initPolygons() { List> lis = new ArrayList<>(); lis.add(shAllAdministrativeDivisionPolygonList); lis.add(shAllToensPolygonList); lis.add(shAllResidentialCommitteeList); lis.add(wgPolygonList); lis.add(wgwPolygonList); lis.add(zhwgPolygonList); String[] path = new String[]{"geojson/上海市_区县边界.geojson", "geojson/上海市_乡镇边界.geojson", "geojson/上海市_村居边界.geojson", "geojson/责任网格-wgs84.geojson", "geojson/青浦区微网格-wgs84.geojson", "geojson/青浦区综合网格.geojson"}; for (int j = 0; j < path.length; j++) { BufferedReader reader = null; try { // 创建 ClassPathResource 对象,指定静态文件的路径 ClassPathResource resource = new ClassPathResource(path[j]); // 获取文件的输入流 reader = new BufferedReader(new InputStreamReader(resource.getInputStream())); String line; StringBuilder sb = new StringBuilder(); while ((line = reader.readLine()) != null) { sb.append(line).append("\r\n"); } reader.close(); JSONObject json = JSONObject.parseObject(sb.toString()); JSONArray featrues = json.getJSONArray("features"); for (int i = 0; i < featrues.size(); i++) { JSONObject properties = featrues.getJSONObject(i).getJSONObject("properties"); JSONObject geoJson = new JSONObject(); geoJson.put("type", "MultiPolygon"); geoJson.put("coordinates", featrues.getJSONObject(i).getJSONObject("geometry").getJSONArray("coordinates")); GeometryJSON geometryJSON = new GeometryJSON(); MultiPolygon multiPolygon = geometryJSON.readMultiPolygon(geoJson.toJSONString()); GeoJsonBean geoJsonBean = new GeoJsonBean(); geoJsonBean.setProperties(properties); geoJsonBean.setMultiPolygon(multiPolygon); lis.get(j).add(geoJsonBean); } } catch (IOException e) { e.printStackTrace(); System.out.println("<<<<<<<<------run geo data error------>>>>>>>>>"); } } System.out.println("<<<<<<<<------run geo data complete------>>>>>>>>>"); } public void putAllDmdzData(String addr, YyskDmdzAddressStandardization item) { if (StringUtils.hasText(addr)) { if (addr.contains("号")) { addr = addr.substring(0, addr.indexOf("号")); } if (addr.contains("弄")) { addr = addr.substring(0, addr.indexOf("弄")); } if (!ScheduledTasks.allDmdzData.containsKey(addr)) { List datas = new ArrayList<>(); datas.add(item); ScheduledTasks.allDmdzData.put(addr, datas); } else if (ScheduledTasks.allDmdzData.get(addr).size() < 20) { ScheduledTasks.allDmdzData.get(addr).add(item); } } } /** * 缓存地址库数据 */ public void getAllDmdzAddressDatas() { long startTime = System.currentTimeMillis(); // 先查询到所有数据 getDmdzDataByPage(0, 10000); System.out.println("ScheduledTasks.allDmdzData初始化完成,有" + ScheduledTasks.allDmdzData.size() + "条记录保存到缓存中,用时" + (System.currentTimeMillis() - startTime) / 1000 + "秒"); } /** * JPA的形式加载所有地址信息到缓存 * * @param maxOid * @param pageSize */ @Transactional(readOnly = true) public void getDmdzDataByPage(int maxOid, int pageSize) { System.out.println("maxOid:" + maxOid + "pageSize:" + pageSize); long sTime = System.currentTimeMillis(); List dataList = yyszAddressRepository.getAllByOidPage(maxOid, pageSize); System.out.println("当前OID" + maxOid + "查询完成,用时:" + (System.currentTimeMillis() - sTime) + "毫秒!"); // TODO 经测试发现一次性读全表,内存根本吃不消 for (YyskDmdzAddressStandardization item : dataList) { if (item.getAddress() != null && StringUtils.hasText(item.getAddress())) { SplitAddress splitAddress = ShanghaiAddressSplitUtil.splitBestAddress(item.getAddress()); putAllDmdzData(splitAddress.getAddr(), item); if(item.getSourceaddress() != null&& StringUtils.hasText(item.getSourceaddress())){ SplitAddress splitAddress2 = ShanghaiAddressSplitUtil.splitBestAddress(item.getSourceaddress()); if(!splitAddress.getAddr().equals(splitAddress2.getAddr())){ putAllDmdzData(splitAddress2.getAddr(), item); } } }else if (item.getSourceaddress() != null && StringUtils.hasText(item.getSourceaddress())) { SplitAddress splitAddress = ShanghaiAddressSplitUtil.splitBestAddress(item.getSourceaddress()); putAllDmdzData(splitAddress.getAddr(), item); } if (item.getOid() > maxOid) { maxOid = item.getOid(); } } System.out.println("当前OID" + maxOid + "缓存处理完成,ScheduledTasks.allDmdzData.size():" + ScheduledTasks.allDmdzData.size() + ",用时:" + (System.currentTimeMillis() - sTime) / 1000 + "秒!"); if (dataList.size() > 0) { getDmdzDataByPage(maxOid, pageSize); } else { System.out.println("分页查询结束"); } } public void selectLimitData(int page, int pageSize) { Map loginfoMap = new HashMap<>(); loginfoMap.put("page", page); loginfoMap.put("pageSize", pageSize); try { long startTime = System.currentTimeMillis(); loginfoMap.put("startTime", startTime); System.out.println("数据库查询page:" + page + ",pageSize:" + pageSize + "完成,用时:" + (System.currentTimeMillis() - startTime) / 1000 + "秒!"); // TODO 要使用JDBC的方式去查询待处理表的数据,然后有个sql需要执行一下,筛选出结果表中不存在的数据,然后进行下一步处理。 } catch (Exception e) { e.printStackTrace(); loginfoMap.put("endTime", System.currentTimeMillis()); loginfoMap.put("message", "异常页码:" + page + ",error:" + e); } finally { ScheduledTasks.logInfos.add(loginfoMap); } } /** * 批量插入数据到callback表 */ public void callBackAddrs() { // TOOD jpa try { List tAddressCallbacks = tAddressCallbackRepository.saveAll(ScheduledTasks.callBackDatas); if (tAddressCallbacks.size() > 0) { ScheduledTasks.callBackDatas.clear(); System.out.println("数据回流成功"); } } catch (Exception e) { e.printStackTrace(); System.out.println("数据回流异常:" + e); } // TODO sql /*StringBuilder sql = new StringBuilder("insert into t_address_callback (id,create_time,address,name,provice_name,city_name,town_name,community_name,status,process_status,is_new) values "); for (String addr : ScheduledTasks.callBackAddrs) { SplitAddress splitAddress = ShanghaiAddressSplitUtil.splitBestAddress(addr); ScheduledTasks.callBackMaxId++; sql.append("(").append(ScheduledTasks.callBackMaxId).append(1).append(",'").append(ScheduledTasks.getCurrentDateTime()).append("','").append(addr).append("','").append(splitAddress.getAddr()).append("','").append(splitAddress.getProvince()).append("','").append(splitAddress.getCity()).append("','").append(splitAddress.getStreet()).append("','").append(splitAddress.getCommunity()).append("',").append(0).append(",").append(0).append(",").append(1).append(") ,"); } try { DbConnection.getInstance().updateSql(sql.substring(0, sql.toString().length() - 2)); ScheduledTasks.callBackAddrs.clear(); System.out.println("数据回流成功"); } catch (Exception e) { e.printStackTrace(); System.out.println("数据回流异常:" + e); }*/ } /** * 是否写入callBack表判断 * * @param addrStr */ public void callBackErrorAddr(String addrStr) { System.out.println("尝试回流无结果数据:" + addrStr); SplitAddress splitAddress = ShanghaiAddressSplitUtil.splitBestAddress(addrStr); if (splitAddress.getStatus() == 3 || splitAddress.getStatus() == -1) { System.out.println("拒绝回流,检测到非地址"); return; } else { // 查询回流列表中是否存在 if (!ScheduledTasks.callBackAllErrorAddrs.contains(addrStr)) { TAddressCallback tAddressCallback = new TAddressCallback(); tAddressCallback.setSearchAddress(addrStr); ScheduledTasks.callBackDatas.add(tAddressCallback); ScheduledTasks.callBackAllErrorAddrs.add(addrStr); System.out.println("回流成功,等待进一检查处理"); } else { System.out.println("回流列表中已存在该数据!"); } } } /** * 数据库查询 尝试给出推荐结果 * * @param splitAddress * @return */ /*public List
getRecommendAddress(SplitAddress splitAddress) { if (splitAddress.getCity() == null) { splitAddress.setCity(""); } if (splitAddress.getDistrict() == null) { splitAddress.setDistrict(""); } if (splitAddress.getStreet() == null) { splitAddress.setStreet(""); } if (splitAddress.getCommunity() == null) { splitAddress.setCommunity(""); } String sql = "select * from " + Constant.getSearchTableName() + " WHERE city like '%" + splitAddress.getCity() + "%' " + "and county like '%" + splitAddress.getDistrict() + "%' and town like '%" + splitAddress.getStreet() + "%' " + "and community like '%" + splitAddress.getCommunity() + "%' order by updatetime desc LIMIT 20"; try { return odsToAddr(DbConnection.getInstance().runSqlStr(sql)); } catch (Exception e) { return null; } }*/ // 进行数据库查询 /*public List
getAddressPoisByAddr(SplitAddress splitAddress) { if (splitAddress.getAddr().contains("号")) { splitAddress.setSearchAddr(splitAddress.getAddr().substring(0, splitAddress.getAddr().lastIndexOf("号"))); } if (splitAddress.getAddr().contains("弄")) { splitAddress.setSearchAddr(splitAddress.getAddr().substring(0, splitAddress.getAddr().lastIndexOf("弄"))); } if (splitAddress.getSearchAddr() == null) { splitAddress.setSearchAddr(splitAddress.getAddr()); } List
list = null; if (StringUtils.hasText(splitAddress.getDistrict())) { String sql = "select * from " + Constant.getSearchTableName() + " WHERE county like '%" + splitAddress.getDistrict() + "%' " + "and (sourceaddress like '%" + splitAddress.getSearchAddr() + "%' or address like '%" + splitAddress.getSearchAddr() + "%') order by updatetime desc LIMIT 20"; try { list = odsToAddr(DbConnection.getInstance().runSqlStr(sql)); } catch (Exception e) { list = null; } } if (list == null) { String sql = "select * from " + Constant.getSearchTableName() + " WHERE sourceaddress like '%" + splitAddress.getSearchAddr() + "%' or address like '%" + splitAddress.getSearchAddr() + "%' order by updatetime desc LIMIT 20"; try { list = odsToAddr(DbConnection.getInstance().runSqlStr(sql)); } catch (Exception e) { list = null; } } return list; }*/ /** * 根据地址关键字查询数据库结果 * * @return */ /*public List
getAddressPoiOnlyDB(String addr) { try { return odsToAddr(DbConnection.getInstance().runSqlStr("select * from " + Constant.getSearchTableName() + " WHERE sourceaddress LIKE '%" + addr + "%' or address LIKE '%" + addr + "%' order by updatetime desc LIMIT 20")); } catch (Exception e) { e.printStackTrace(); } return null; }*/ public List getAddressPoisByAddr(SplitAddress splitAddress) { if (splitAddress.getAddr().contains("号")) { splitAddress.setSearchAddr(splitAddress.getAddr().substring(0, splitAddress.getAddr().indexOf("号"))); } if (splitAddress.getAddr().contains("弄")) { splitAddress.setSearchAddr(splitAddress.getAddr().substring(0, splitAddress.getAddr().indexOf("弄"))); } if (splitAddress.getSearchAddr() == null) { splitAddress.setSearchAddr(splitAddress.getAddr()); } List list = new ArrayList<>(); if (StringUtils.hasText(splitAddress.getDistrict())) { // TODO 数据库查询逻辑调整为内存处理的方式 List dmdzList = new ArrayList<>(); if (ScheduledTasks.allDmdzData.containsKey(splitAddress.getSearchAddr())) { dmdzList = ScheduledTasks.allDmdzData.get(splitAddress.getSearchAddr()); } else { for (String key : ScheduledTasks.allDmdzData.keySet()) { if (splitAddress.getSearchAddr().contains(key)) { dmdzList = ScheduledTasks.allDmdzData.get(key); } } } for (YyskDmdzAddressStandardization item : dmdzList) { if (item.getCounty().contains(splitAddress.getDistrict())) { if (list.size() < 20) { list.add(item); } else { break; } } } // TODO 数据库查询的方式 // list = yyszAddressRepository.getAddressPoisByAddrAQX(splitAddress.getDistrict(), splitAddress.getSearchAddr()); } if (list.size() == 0) { list = getAddressPoiOnlyDB(splitAddress.getSearchAddr()); } return list; } public List getAddressPoiOnlyDB(String addr) { // TODO 数据库查询逻辑调整为内存处理的方式 List returnDatas = new ArrayList<>(); if (ScheduledTasks.allDmdzData.containsKey(addr)) { returnDatas = ScheduledTasks.allDmdzData.get(addr); } else { for (String key : ScheduledTasks.allDmdzData.keySet()) { if (key.contains(addr)) { returnDatas = ScheduledTasks.allDmdzData.get(key); } } if (returnDatas == null || returnDatas.size() == 0) { SplitAddress splitAddress = ShanghaiAddressSplitUtil.splitBestAddress(addr); if (splitAddress.getAddr() != null && splitAddress.getAddr().length() > 0 && StringUtils.hasText(splitAddress.getAddr())) for (String key : ScheduledTasks.allDmdzData.keySet()) { if (key.contains(splitAddress.getAddr())) { returnDatas = ScheduledTasks.allDmdzData.get(key); } } } } return returnDatas; // TODO 数据库查询的方式 // return yyszAddressRepository.getAddressPoisByAddr(addr); } public List getRecommendAddress(SplitAddress splitAddress) { if (splitAddress.getCity() == null) { splitAddress.setCity(""); } if (splitAddress.getDistrict() == null) { splitAddress.setDistrict(""); } if (splitAddress.getStreet() == null) { splitAddress.setStreet(""); } if (splitAddress.getCommunity() == null) { splitAddress.setCommunity(""); } return yyszAddressRepository.getAddressPoisByDivisions(splitAddress.getCity(), splitAddress.getDistrict(), splitAddress.getStreet(), splitAddress.getCommunity()); } public List getCallbackDataByTag(Integer tag) { return tAddressCallbackRepository.getCallbackByTag(tag); } public List updateCallbackData(List datas) { return tAddressCallbackRepository.saveAll(datas); } public List> getUniScDatas() { try { return DbConnection.getInstance().runSqlStr("select * from songjiang_uni_sc_id_v1"); // where real_address is not null and street_town_name is null } catch (Exception e) { e.printStackTrace(); } return null; } public static List
odsToAddr(List> datas) { if (datas == null || datas.size() == 0) { return null; } List
addresses = new ArrayList<>(); for (Map item : datas) { Address address = new Address(); address.setCity(item.get("city") != null ? item.get("city").toString() : ""); address.setCounty(item.get("county") != null ? item.get("county").toString() : ""); address.setTown(item.get("town") != null ? item.get("town").toString() : ""); address.setTown_code(item.get("town_code") != null ? item.get("town_code").toString() : ""); address.setCommunity(item.get("community") != null ? item.get("community").toString() : ""); address.setCommunity_code(item.get("community_code") != null ? item.get("community_code").toString() : ""); address.setGrid_name(item.get("grid_name") != null ? item.get("grid_name").toString() : ""); address.setGrid_code(item.get("grid_code") != null ? item.get("grid_code").toString() : ""); address.setSource(item.get("source") != null ? item.get("source").toString() : ""); address.setSourceaddress(item.get("sourceaddress") != null ? item.get("sourceaddress").toString() : ""); address.setAddress(item.get("address") != null ? item.get("address").toString() : ""); address.setLon(item.get("lon") != null ? Float.valueOf(item.get("lon").toString()) : null); address.setLat(item.get("lat") != null ? Float.valueOf(item.get("lat").toString()) : null); addresses.add(address); } return addresses; } public GeoJsonBean isInadPolygon(double lon, double lat) { try { Geometry point = reader.read("POINT (" + lon + " " + lat + ")"); for (GeoJsonBean bean : shAllAdministrativeDivisionPolygonList) { if (bean.getMultiPolygon().contains(point)) { return bean; } } return null; } catch (ParseException e) { throw new RuntimeException(e); } } public GeoJsonBean isInTownPolygon(double lon, double lat) { try { Geometry point = reader.read("POINT (" + lon + " " + lat + ")"); for (GeoJsonBean bean : shAllToensPolygonList) { if (bean.getMultiPolygon().contains(point)) { return bean; } } return null; } catch (ParseException e) { throw new RuntimeException(e); } } public GeoJsonBean isInResidentialCommitteePolygon(double lon, double lat) { try { Geometry point = reader.read("POINT (" + lon + " " + lat + ")"); for (GeoJsonBean bean : shAllResidentialCommitteeList) { if (bean.getMultiPolygon().contains(point)) { return bean; } } return null; } catch (ParseException e) { throw new RuntimeException(e); } } public GeoJsonBean isInWGPolygon(double lon, double lat) { Geometry point = null; try { point = reader.read("POINT (" + lon + " " + lat + ")"); } catch (ParseException e) { throw new RuntimeException(e); } for (GeoJsonBean bean : wgPolygonList) { try { if (bean.getMultiPolygon().contains(point)) { return bean; } } catch (Exception e) { e.toString(); } } return null; } public GeoJsonBean isInWGWPolygon(double lon, double lat) { Geometry point = null; try { point = reader.read("POINT (" + lon + " " + lat + ")"); } catch (ParseException e) { throw new RuntimeException(e); } for (GeoJsonBean bean : wgwPolygonList) { try { if (bean.getMultiPolygon().contains(point)) { return bean; } } catch (Exception e) { e.toString(); } } return null; } public GeoJsonBean isInZHGWPolygon(double lon, double lat) { Geometry point = null; try { point = reader.read("POINT (" + lon + " " + lat + ")"); } catch (ParseException e) { throw new RuntimeException(e); } for (GeoJsonBean bean : zhwgPolygonList) { try { if (bean.getMultiPolygon().contains(point)) { return bean; } } catch (Exception e) { e.toString(); } } return null; } }