Эх сурвалжийг харах

完成流程图中的调度逻辑
添加调用yysz_address地名搜索服务
添加有结果数据回流
添加无结果数据回流

ximinghao 1 сар өмнө
parent
commit
e1d586de01

+ 203 - 25
src/main/java/com/skyversation/poiaddr/addquery/AddressQueryEngine.java

@@ -6,21 +6,41 @@ 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 java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+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() {
     }
 
@@ -48,14 +68,121 @@ public class AddressQueryEngine {
         if (addrs == null || addrs.size() < 1) {
             return null;
         }
-        AddressResult addressResult = new AddressResult();
-        List<AddressResult.ContentBean> contentBeans = new ArrayList<>();
-        /*try {
+        //先走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<String> 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<String> addrs, AddressLevel level) {
+        try{
+            for (String addr : addrs) {
+                AddressResult.ContentBean contentBean = verificaData(yyszSearchByName(addr), level, addr);
+                if (contentBean != null) {
+                    contentBean.setSearchAddress(addr);
+
+                    List<com.skyversation.poiaddr.bean.AddressResult.ContentBean> 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<String> addrs, AddressLevel level) {
+        try {
             for (String addr : addrs) {
                 AddressResult.ContentBean contentBean = verificaData(wdjaSearchByName(addr), level, addr);
                 if (contentBean != null) {
                     contentBean.setSearchAddress(addr);
+                    List<com.skyversation.poiaddr.bean.AddressResult.ContentBean> contentBeans = new ArrayList<>();
                     contentBeans.add(contentBean);
+                    AddressResult addressResult = new AddressResult();
                     addressResult.setData(contentBeans);
                     addressResult.setCode(AddressResultEnum.WDJA_SUCCESS);
                     addressResult.setMessage("成功");
@@ -64,52 +191,102 @@ public class AddressQueryEngine {
             }
         } catch (Exception e) {
             System.err.println("武大吉奥:日常异常" + e);
-        }*/
-        if (addressResult.getData() == null || addressResult.getData().size() == 0) {
+        }
+        return null;
+    }
+    /**
+     * 四中心多条搜索
+     */
+    private AddressResult szxMultiSearch(List<String> addrs, AddressLevel level) {
+        try {
             for (String addr : addrs) {
                 AddressResult.ContentBean contentBean = verificaData(szxSearchByName(addr), level, addr);
                 if (contentBean != null) {
                     contentBean.setSearchAddress(addr);
+                    List<com.skyversation.poiaddr.bean.AddressResult.ContentBean> contentBeans = new ArrayList<>();
                     contentBeans.add(contentBean);
+                    AddressResult addressResult = new AddressResult();
                     addressResult.setData(contentBeans);
                     addressResult.setCode(AddressResultEnum.SZX_SUCCESS);
                     addressResult.setMessage("成功");
-                    return getCjWgWgwByLoc(addressResult);
+                    return addressResult;
                 }
             }
+        } catch (Exception e) {
+            System.err.println(" 四中心异常" + e);
         }
-        /*if (addressResult.getData() == null || addressResult.getData().size() == 0) {
+        return null;
+    }
+    /**
+     * 高德多条搜索
+     */
+    private AddressResult gdMultiSearch(List<String> addrs, AddressLevel level) {
+        try {
             for (String addr : addrs) {
                 AddressResult.ContentBean contentBean = verificaData(gdSearchByName(addr), level, addr);
                 if (contentBean != null) {
                     contentBean.setSearchAddress(addr);
+                    List<com.skyversation.poiaddr.bean.AddressResult.ContentBean> contentBeans = new ArrayList<>();
                     contentBeans.add(contentBean);
+                    AddressResult addressResult = new AddressResult();
                     addressResult.setData(contentBeans);
                     addressResult.setCode(AddressResultEnum.GD_SUCCESS);
                     addressResult.setMessage("成功");
-                    return getCjWgWgwByLoc(addressResult);
+                    return addressResult;
                 }
             }
-        }*/
-        /*if (addressResult.getData() == null || addressResult.getData().size() == 0) {
+        } catch (Exception e) {
+            System.err.println("高德异常" + e);
+        }
+        return null;
+    }/**
+     * 高德高级多条搜索
+     */
+    private AddressResult gdV3MultiSearch(List<String> addrs, AddressLevel level) {
+        try {
             for (String addr : addrs) {
                 AddressResult.ContentBean contentBean = verificaData(gdV3SearchByName(addr), level, addr);
                 if (contentBean != null) {
                     contentBean.setSearchAddress(addr);
+                    List<com.skyversation.poiaddr.bean.AddressResult.ContentBean> contentBeans = new ArrayList<>();
                     contentBeans.add(contentBean);
+                    AddressResult addressResult = new AddressResult();
                     addressResult.setData(contentBeans);
                     addressResult.setCode(AddressResultEnum.GDV3_SUCCESS);
                     addressResult.setMessage("成功");
-                    return getCjWgWgwByLoc(addressResult);
+                    return addressResult;
                 }
             }
-        }*/
-        addressResult.setCode(AddressResultEnum.RESULT_NULL);
-        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
      */
@@ -143,7 +320,7 @@ public class AddressQueryEngine {
         }
     }
 
-    /***
+    /**
      * 市四中心地名搜索
      * @param address
      * @return
@@ -185,7 +362,7 @@ public class AddressQueryEngine {
         }
     }*/
 
-    /***
+    /**
      * 高德普通地名搜索
      * @param address
      * @return
@@ -209,7 +386,7 @@ public class AddressQueryEngine {
         }
     }
 
-    /***
+    /**
      * 高德高级地名搜索
      * @param address
      * @return
@@ -262,7 +439,8 @@ public class AddressQueryEngine {
     }
 
 
-    /***
+
+    /**
      * 根据搜索地址,赋值村居、网格、微格网信息
      * @param result
      * @return

+ 178 - 0
src/main/java/com/skyversation/poiaddr/addquery/DataCallBack.java

@@ -0,0 +1,178 @@
+package com.skyversation.poiaddr.addquery;
+
+import com.skyversation.poiaddr.bean.AddressResult;
+import com.skyversation.poiaddr.bean.GeoJsonBean;
+import com.skyversation.poiaddr.bean.SplitAddress;
+import com.skyversation.poiaddr.service.AreaService;
+import com.skyversation.poiaddr.util.CoordTransform;
+import com.skyversation.poiaddr.util.CoordTransform2;
+import com.skyversation.poiaddr.util.ShanghaiAddressSplitUtil;
+import com.skyversation.poiaddr.util.jpa.entity.TAddressCallback;
+import com.skyversation.poiaddr.util.jpa.entity.YyszAddressQp;
+import com.skyversation.poiaddr.util.jpa.rep.TAddressCallbackRep;
+import com.skyversation.poiaddr.util.jpa.rep.YyszAddressQpRep;
+import lombok.Getter;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.support.TransactionCallbackWithoutResult;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.annotation.Resource;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@Service
+public class DataCallBack {
+    private DataCallBack(){};
+    @Getter
+    private static final DataCallBack instance = new DataCallBack();
+    private final ExecutorService successES = Executors.newSingleThreadExecutor();
+    private final ExecutorService failES = Executors.newSingleThreadExecutor();
+    @Resource
+    private TAddressCallbackRep tAddressCallbackRep;
+    @Resource
+    private YyszAddressQpRep yyszAddressQpRep;
+    @Resource
+    private ShanghaiAddressSplitUtil shanghaiAddressSplitUtil;
+
+    @Resource
+    private PlatformTransactionManager transactionManager;
+
+    private static final Map<String, String> CHINESE_TO_ARABIC = new HashMap<>();
+    static {
+        CHINESE_TO_ARABIC.put("第一", "01");
+        CHINESE_TO_ARABIC.put("第二", "02");
+        CHINESE_TO_ARABIC.put("第三", "03");
+        CHINESE_TO_ARABIC.put("第四", "04");
+        CHINESE_TO_ARABIC.put("第五", "05");
+        CHINESE_TO_ARABIC.put("第六", "06");
+        CHINESE_TO_ARABIC.put("第七", "07");
+        CHINESE_TO_ARABIC.put("第八", "08");
+        CHINESE_TO_ARABIC.put("第九", "09");
+    }
+
+    public void successDataCallBack(AddressResult addressResult){
+        for (AddressResult.ContentBean bean :addressResult.getData()){
+            successES.execute(() -> {
+                TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
+
+                transactionTemplate.execute(new TransactionCallbackWithoutResult() {
+                    @Override
+                    protected void doInTransactionWithoutResult(TransactionStatus status) {
+                        try {
+                            System.out.println("回流有结果数据:" + bean.getSearchAddress());
+                            YyszAddressQp yyszAddressQp = new YyszAddressQp();
+
+                            yyszAddressQp.setSourceaddress(bean.getSearchAddress());
+                            yyszAddressQp.setId(yyszAddressQpRep.findMaxId().orElse(0) + 1);
+
+                            yyszAddressQp.setLon(bean.getLon());
+                            yyszAddressQp.setLat(bean.getLat());
+
+
+                            SplitAddress splitAddress = ShanghaiAddressSplitUtil.splitBestAddress(bean.getSearchAddress());
+                            yyszAddressQp.setAddress(splitAddress.getAddr());
+
+                            yyszAddressQp.setCity(splitAddress.getCity());
+                            yyszAddressQp.setCounty(splitAddress.getDistrict());
+                            yyszAddressQp.setTown(splitAddress.getStreet());
+                            yyszAddressQp.setCommunity(splitAddress.getCommunity());
+
+                            yyszAddressQp.setCityCode(splitAddress.getCityCode());
+                            yyszAddressQp.setCountyCode(splitAddress.getDistrictCode());
+                            yyszAddressQp.setTownCode(splitAddress.getStreetCode());
+                            yyszAddressQp.setCommunityCode(splitAddress.getCommunityCode());
+
+                            yyszAddressQp.setIsHistory(0);
+                            yyszAddressQp.setSignatureCheckState(0);
+                            yyszAddressQp.setSecurityGrade(0);
+                            yyszAddressQp.setModelType(0);
+                            yyszAddressQp.setIsDelete(0);
+                            yyszAddressQp.setLv(0);
+                            yyszAddressQp.setIsMulti(0);
+                            yyszAddressQp.setRoomOfFloor(0);
+
+                            yyszAddressQp.setSource("标准地址");
+
+                            yyszAddressQp.setUpdatetime(Instant.now());
+                            yyszAddressQp.setCreatetime(Instant.now());
+
+
+                            String regex = "([^0-9]*[路道街])(\\d+[弄号])?(.*)";
+                            Pattern pattern = Pattern.compile(regex);
+                            Matcher matcher = pattern.matcher(splitAddress.getAddr());
+
+                            if (matcher.matches()) {
+                                String road = matcher.group(1);
+                                String alley =  matcher.group(2);
+                                String additionalInfo = matcher.group(3);
+                                yyszAddressQp.setStreet(road);
+                                yyszAddressQp.setDoor(alley);
+                            }
+
+                            if (yyszAddressQp.getLon()!=null&&yyszAddressQp.getLat()!=null){
+                                double[] result = CoordTransform2.getInstance().wgs84_to_shcj(yyszAddressQp.getLon(),yyszAddressQp.getLat());
+                                yyszAddressQp.setX(String.valueOf(result[0]));
+                                yyszAddressQp.setY(String.valueOf(result[1]));
+
+                                GeoJsonBean geoJsonBean = AreaService.getInstance().isInGridPolygon(yyszAddressQp.getLon(),yyszAddressQp.getLat());
+                                if (geoJsonBean!=null){
+                                    yyszAddressQp.setCounty(geoJsonBean.getProperties().getString("所属区县"));
+                                    yyszAddressQp.setTown(geoJsonBean.getProperties().getString("所属街道"));
+                                    yyszAddressQp.setGridName(geoJsonBean.getProperties().getString("网格名称"));
+
+                                    if (yyszAddressQp.getGridName()!=null&&yyszAddressQp.getTownCode()!=null&&!yyszAddressQp.getTownCode().isEmpty()){
+                                        for (String key:CHINESE_TO_ARABIC.keySet()){
+                                            if (yyszAddressQp.getGridName().startsWith(key)){
+                                                yyszAddressQp.setGridCode(yyszAddressQp.getTownCode()+CHINESE_TO_ARABIC.get(key));
+                                                break;
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+
+
+                            yyszAddressQpRep.save(yyszAddressQp);
+                            if (yyszAddressQp.getLon()!=null&&yyszAddressQp.getLat()!=null){
+                                yyszAddressQpRep.updateLocation(yyszAddressQp.getId(), String.format("POINT(%f %f)", yyszAddressQp.getLon(), yyszAddressQp.getLat()));
+                            }
+                            } catch (Exception e) {
+                            status.setRollbackOnly();
+                            e.printStackTrace();
+                        }
+                    }
+                });
+            });
+        }
+
+    }
+    public void failDataCallBack(List<String> addr){
+        for (String addrStr:addr){
+            failES.execute(()->{
+                System.out.println("尝试回流无结果数据:"+addrStr);
+                SplitAddress splitAddress = ShanghaiAddressSplitUtil.splitBestAddress(addrStr);
+                if (splitAddress.getStatus()==3||splitAddress.getStatus()==-1){
+                    System.out.println("拒绝回流,检测到非地址");
+                    return;
+                }
+                int id = tAddressCallbackRep.findMaxId().orElse(0)+1;
+                TAddressCallback tAddressCallback = new TAddressCallback(id, LocalDate.now(),addrStr, splitAddress.getAddr(),
+                        splitAddress.getProvince(),splitAddress.getCity(),splitAddress.getStreet(), splitAddress.getCommunity(),
+                        (short) 0);
+                tAddressCallbackRep.save(tAddressCallback);
+                System.out.println("回流成功,等待进一检查处理");
+            });
+        }
+
+    }
+}

+ 31 - 0
src/main/java/com/skyversation/poiaddr/addquery/TransfromDataTool.java

@@ -167,4 +167,35 @@ public class TransfromDataTool {
         return result;
     }
 
+    public static AddressResult yyszResultToResult(JSONObject json){
+        if(json==null){return null;}
+        AddressResult result = new AddressResult();
+        JSONArray array = json.getJSONObject("content").getJSONArray("data");
+        if (array == null || array.isEmpty()) {
+            result.setCode(AddressResultEnum.RESULT_NULL);
+            return result;
+        }
+        for (int i = 0; i < array.size(); i++) {
+            JSONObject jsonObject = array.getJSONObject(i);
+            AddressResult.ContentBean content = new AddressResult.ContentBean();
+            content.setPname(jsonObject.getString("pname"));
+            content.setCityname(jsonObject.getString("cityname"));
+            content.setAdname(jsonObject.getString("adname"));
+            content.setCommunity(jsonObject.getString("community"));
+            content.setCommunityCode(jsonObject.getString("communityCode"));
+            content.setType(jsonObject.getString("type"));
+            content.setAddress(jsonObject.getString("address"));
+            content.setDistance(jsonObject.getString("distance"));
+            content.setName(jsonObject.getString("name"));
+            content.setLocation(jsonObject.getString("location"));
+            content.setLon(jsonObject.getDouble("lon"));
+            content.setLat(jsonObject.getDouble("lat"));
+            if (result.getData() == null) {
+                result.setData(new ArrayList<>());
+            }
+            result.getData().add(content);
+        }
+        result.setCode(AddressResultEnum.YYSZ_SUCCESS);
+        return result;
+    }
 }

+ 70 - 0
src/main/java/com/skyversation/poiaddr/bean/SplitAddress.java

@@ -0,0 +1,70 @@
+package com.skyversation.poiaddr.bean;
+
+import lombok.Data;
+
+/**
+ * 分割后的数据
+ * @see SplitAddress#status
+ * @see com/skyversation/poiaddr.util.ShanghaiAddressSplitUtil
+ */
+@Data
+public class SplitAddress implements Comparable<SplitAddress>{
+    private String fullAddress;
+    private String sourceAddress;
+    /**
+     * 0->正常<br/>
+     * 1->未分离区一下地址(不代表数据不可用,有可能是源地址中不存在任何行政区划)<br/>
+     * 2->外省数据<br/>
+     * 3->非地址(检查到源地址非正常地址,例如网址)<br/>
+     * 4->无法确认是否为外省
+     */
+    private int status=-1;
+    private String addr = "";
+    private String province = "";
+    private String city = "";
+    private String district = "";
+    private String street = "";
+    private String community="";
+    private String cityCode = "";
+    private String districtCode = "";
+    private String streetCode = "";
+    private String communityCode="";
+    public boolean isSuccess(){
+        switch (status){
+            case 0: case 1: case 4:{
+                return true;
+            }
+            case 2: case 3: default:{
+                return false;
+            }
+        }
+    }
+    @Override
+    public String toString() {
+        return "AddressInfo{" +
+                "sourceAddress='" + sourceAddress + '\'' +
+                "fullAddress='" + fullAddress + '\'' +
+                ", status=" + status +
+                ", addr='" + addr + '\'' +
+                ", province='" + province + '\'' +
+                ", city='" + city + '\'' +
+                ", district='" + district + '\'' +
+                ", street='" + street + '\'' +
+                ", community='" + community + '\'' +
+                '}';
+    }
+    private int point(){
+        int output=0;
+        if (status==0||status==1)output+=1000;
+        if (status==4)output+=800;
+        if (district.isEmpty())output-=100;
+        if (street.isEmpty())output-=100;
+        if (community.isEmpty())output-=100;
+        return  output;
+
+    }
+    @Override
+    public int compareTo(SplitAddress o)throws NullPointerException {
+        return this.point()-o.point();
+    }
+}

+ 7 - 2
src/main/java/com/skyversation/poiaddr/controller/PoiAddressController.java

@@ -38,6 +38,9 @@ public class PoiAddressController {
     @Resource
     private TestDataServiceImpl testDataService;
 
+    @Resource
+    private AddressQueryEngine addressQueryEngine;
+
     //    地址查询
     @GetMapping(value = "/selectAddressInfo/{address}")
     public Object selectAddressInfo(@PathVariable("address") String address) {
@@ -101,7 +104,9 @@ public class PoiAddressController {
      * @return Object
      */
     @RequestMapping(value = "/nameQueryTaskInterface", produces = MediaType.MULTIPART_FORM_DATA_VALUE)
-    public Object GeoCoordinate(HttpServletResponse response, @RequestHeader(value = "token") String token, @RequestParam(name = "file") MultipartFile file,
+    public Object GeoCoordinate(HttpServletResponse response,
+                                @RequestHeader(value = "token") String token,
+                                @RequestParam(name = "file") MultipartFile file,
                                 @RequestParam(name = "addrColNames") String addrColNames,
                                 @RequestParam(name = "inCoordinate", required = false) String inCoordinate,
                                 @RequestParam(name = "latLonColName", required = false) String latLonColName,
@@ -243,7 +248,7 @@ public class PoiAddressController {
                             addrList.add(fileDataDto.getAddr2());
                         }
                         if (addrList.size() > 0) {
-                            AddressResult addressResult = AddressQueryEngine.getInstance().commonSearchByName(addrList, AddressLevel.values()[fileDataDto.getMatchingLevel() - 1]);
+                            AddressResult addressResult = addressQueryEngine.commonSearchByName(addrList, AddressLevel.values()[fileDataDto.getMatchingLevel() - 1]);
                             if (addressResult != null) {
                                 if (addressResult.getData() == null || addressResult.getData().size() < 1) {
                                     fileDataDto.getProperties().put("所属街道", null);

+ 25 - 2
src/main/java/com/skyversation/poiaddr/service/AreaService.java

@@ -22,6 +22,7 @@ import org.springframework.core.io.ClassPathResource;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
 import java.io.*;
 import java.util.ArrayList;
 import java.util.List;
@@ -29,6 +30,9 @@ import java.util.List;
 @Service
 public class AreaService {
 
+    @Resource
+    private AddressQueryEngine addressQueryEngine;
+
     private static AreaService instance;
 
     public static AreaService getInstance() {
@@ -54,6 +58,7 @@ public class AreaService {
     List<MultiPolygon> zrwlMulPolygonList = new ArrayList<>();
 
     public List<GeoJsonBean> cjPolygonList = new ArrayList<>();
+    public List<GeoJsonBean> zhGridPolygonList = new ArrayList<>();
     public List<GeoJsonBean> wGridPolygonList = new ArrayList<>();
     public List<GeoJsonBean> gridPolygonList = new ArrayList<>();
     public List<GeoJsonBean> shAllAdministrativeDivisionPolygonList = new ArrayList<>();
@@ -99,7 +104,7 @@ public class AreaService {
             System.out.println("<<<<<<<<------开始网络连通性测试");
             List<String> addrs = new ArrayList<>();
             addrs.add("上海市青浦区馨浦苑西区2号楼1201");
-            AddressResult addressResult = AddressQueryEngine.getInstance().commonSearchByName(addrs, AddressLevel.values()[0]);
+            AddressResult addressResult = AddressQueryEngine.getInstance().commonSearchByNameForTest(addrs, AddressLevel.values()[0]);
             System.out.println("<<<<<<<<------网络连通性测试结果:" + addressResult);
         } catch (Exception e) {
             System.err.println("<<<<<<<<------网络连通性测试结果:" + e);
@@ -122,10 +127,11 @@ public class AreaService {
         }
         lis.add(shAllAdministrativeDivisionPolygonList);
         lis.add(shAllToensPolygonList);
+        lis.add(zhGridPolygonList);
         String[] path;
         if ("青浦".equals(area)) {
             path = new String[]{"geojson/qp_cunju.geojson", "geojson/青浦区微网格-wgs84.geojson",
-                    "geojson/责任网格-wgs84.geojson", "geojson/sh_all_administrative_division.geojson", "geojson/sh_all_towns.geojson"};
+                    "geojson/责任网格-wgs84.geojson", "geojson/sh_all_administrative_division.geojson", "geojson/sh_all_towns.geojson","geojson/青浦区综合网格.geojson"};
         } else {
             path = new String[]{"geojson/sh_all_administrative_division.geojson", "geojson/sh_all_towns.geojson"};
         }
@@ -187,6 +193,8 @@ public class AreaService {
                         geoJsonBean.setProperties(properties);
                     } else if (path[j].contains("sh_all")) {
                         geoJsonBean.setProperties(properties);
+                    } else if (path[j].contains("青浦区综合网格")) {
+                        geoJsonBean.setProperties(properties);
                     }
                     geoJsonBean.setMultiPolygon(multiPolygon);
                     lis.get(j).add(geoJsonBean);
@@ -252,6 +260,21 @@ public class AreaService {
         }
         return null;
     }
+    public GeoJsonBean isInZhGridPolygon(double lon, double lat) {
+        Geometry point = null;
+        try {
+            point = reader.read("POINT (" + lon + " " + lat + ")");
+        } catch (ParseException e) {
+            throw new RuntimeException(e);
+        }
+
+        for (GeoJsonBean bean : zhGridPolygonList) {
+            if (bean.getMultiPolygon().contains(point)) {
+                return bean;
+            }
+        }
+        return null;
+    }
 
     public GeoJsonBean isInadPolygon(double lon, double lat) {
         Geometry point = null;

+ 292 - 0
src/main/java/com/skyversation/poiaddr/util/AddressSplitUtil.java

@@ -0,0 +1,292 @@
+package com.skyversation.poiaddr.util;
+
+import java.io.InputStream;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+public class AddressSplitUtil {
+    /**省级行政单位简称->全称映射表
+     * 只读,请勿修改
+     * */
+    public static final Map<String,String> LEVEL_1_NAME_MAP;
+    /**市级行政单位简称->全称映射表
+     * 只读,请勿修改
+     * */
+    public static final Map<String,String> LEVEL_2_NAME_MAP;
+    /**县级行政单位简称->全称映射表
+     * 只读,请勿修改
+     * */
+    public static final Map<String,String> LEVEL_3_NAME_MAP;
+    /**省市县三级行政单位简称树
+     * 只读,请勿修改
+     * */
+    public static final Map<String,Map<String,Set<String>>> SIMPLE_NAME_TREE;
+    private static final Map<String,Set<String>> All_CITY_IN_TREE;
+
+    private static final Pattern LEVEL_1_SUFFIX_PATTERN = Pattern.compile("^(?:维吾尔|((?:(?!省|市|自治区).)*?族))?(?:省|市|自治区)");
+
+    private static final Pattern LEVEL_2_SUFFIX_PATTERN = Pattern.compile("^(?:市|自治州|地区|盟)");
+
+    private static final Pattern LEVEL_3_SUFFIX_PATTERN = Pattern.compile("^(?:县|自治县|市|区|旗|自治旗|林区|特区)");
+
+    public static final Pattern ROAD_SUFFIX_PATTERN = Pattern.compile("^(?:旅游区|[东南西北中一二三四五六七八九十公大小支新老]{0,2}(?:大街|路|环路|大道|街|菜市场|马路|村))");
+
+    static {
+        Map<String,String> level1NameMap = new HashMap<>();
+        Map<String,String> level2NameMap = new HashMap<>();
+        Map<String,String> level3NameMap = new HashMap<>();
+        Map<String,Map<String,Set<String>>> simpleNameTree = new HashMap<>();
+        String file = "全国省市县记录.xlsx";
+        InputStream is = AddressSplitUtil.class.getResourceAsStream(file);
+        if (is==null) is= AddressSplitUtil.class.getResourceAsStream("/"+file);
+        if (is==null) throw new RuntimeException("无法找到"+file);
+        try {
+            List<Map<String, Object>> list = ExcelReaderUtils.readExcel(is);
+            for (Map<String,Object> row : list) {
+                Object level1Name = row.get("省份");
+                Object level1SimpleName = row.get("省份简称");
+                Object level2Name = row.get("地级市");
+                Object level2SimpleName = row.get("地级市简称");
+                Object level3Name = row.get("县级市");
+                Object level3SimpleName = row.get("县级市简称");
+                if (level1SimpleName != null && level1Name!=null) {
+                    level1NameMap.put(level1SimpleName.toString(), level1Name.toString());
+                }
+                if (level2SimpleName != null && level2Name!=null) {
+                    level2NameMap.put(level2SimpleName.toString(), level2Name.toString());
+                }
+                if (level3SimpleName != null && level3Name!=null) {
+                    level3NameMap.put(level3SimpleName.toString(), level3Name.toString());
+                }
+                if (level1SimpleName!=null){
+                    if (!simpleNameTree.containsKey(level1SimpleName.toString())){
+                        simpleNameTree.put(level1SimpleName.toString(),new HashMap<>());
+                    }
+                    Map<String, Set<String>> level2Map = simpleNameTree.get(level1SimpleName.toString());
+                    if (level2SimpleName!=null){
+                        if(!level2Map.containsKey(level2SimpleName.toString())){
+                            level2Map.put(level2SimpleName.toString(),new HashSet<>());
+                        }
+                        if (level3SimpleName!=null){
+                            level2Map.get(level2SimpleName.toString()).add(level3SimpleName.toString());
+                        }
+                    }
+                }
+            }
+            LEVEL_1_NAME_MAP = Collections.unmodifiableMap(level1NameMap);
+            LEVEL_2_NAME_MAP = Collections.unmodifiableMap(level2NameMap);
+            LEVEL_3_NAME_MAP = Collections.unmodifiableMap(level3NameMap);
+            Map<String,Map<String,Set<String>>> simpleNameTree_= new HashMap<>();
+            for (String key : simpleNameTree.keySet()){
+                simpleNameTree_.put(key , Collections.unmodifiableMap(simpleNameTree.get(key)));
+            }
+            SIMPLE_NAME_TREE= Collections.unmodifiableMap(simpleNameTree_);
+            All_CITY_IN_TREE= Collections.unmodifiableMap(SIMPLE_NAME_TREE.values().stream()
+                    .flatMap(map -> map.entrySet().stream())
+                    .collect(Collectors.toMap(
+                            Map.Entry::getKey,
+                            Map.Entry::getValue,
+                            (oldValue, newValue) -> newValue
+                    ))
+            );
+
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static class SplittingAddress {
+        int province = -1;
+        int city = -1;
+        int county = -1;
+        Map<Integer,String> provinceInChoose = new HashMap<>();
+        Map<Integer,String> cityInChoose = new HashMap<>();
+        Map<Integer,String> countyInChoose = new HashMap<>();
+        String sourceAddress ;
+        SplittingAddress(String sourceAddress){
+            this.sourceAddress=sourceAddress;
+        }
+        String[] toStringList(){
+            String[] output = new String[4];
+            output[0]=((province!=-1)?LEVEL_1_NAME_MAP.get(provinceInChoose.get(province)):"");
+            output[1]=((city!=-1)?LEVEL_2_NAME_MAP.get(cityInChoose.get(city)):"");
+            output[2]=((county!=-1)?LEVEL_3_NAME_MAP.get(countyInChoose.get(county)):"");
+            return  output;
+        }
+        String getOtherAddress(){
+            int max = Math.max(province,Math.max(county,city));
+            String maxName = "";
+            if(max==-1){
+                return sourceAddress;
+            }
+            if (province==max){
+                maxName=provinceInChoose.get(province);
+            }
+            if (city==max){
+                maxName=cityInChoose.get(city);
+            }
+            if (county==max){
+                maxName=countyInChoose.get(county);
+            }
+            String sub = sourceAddress.substring(max+maxName.length());
+            Matcher m = LEVEL_1_SUFFIX_PATTERN.matcher(sub);
+            if (m.find()){
+                sub = sub.substring(m.end());
+            }
+            m = LEVEL_2_SUFFIX_PATTERN.matcher(sub);
+            if (m.find()){
+                sub = sub.substring(m.end());
+            }
+            m = LEVEL_3_SUFFIX_PATTERN.matcher(sub);
+            if (m.find()){
+                sub = sub.substring(m.end());
+            }
+            return sub;
+        }
+        void findProvince(){
+            Map<Integer,String> results = contain(this.sourceAddress,SIMPLE_NAME_TREE.keySet());
+            for (int index : results.keySet()){
+                String name = results.get(index);
+                String sub = this.sourceAddress.substring(index+name.length());
+                //去除南京路,北京大道型选手
+                if (ROAD_SUFFIX_PATTERN.matcher(sub).find()){
+                    continue;
+                }
+                provinceInChoose.put(index,name);
+                //匹配到后缀时直接当做第一选择
+                if (LEVEL_1_SUFFIX_PATTERN.matcher(sub).find()){
+                    province = index;
+                }
+            }
+            //仅有一个选择时当成一选
+            if (provinceInChoose.size()==1){
+                province = (int)provinceInChoose.keySet().toArray()[0];
+            }
+        }
+        void findCity(){
+            Map<Integer,String> results =null;
+            //首先尝试在一选下匹配
+            if (province!=-1){
+                results  = contain(this.sourceAddress,SIMPLE_NAME_TREE.get(provinceInChoose.
+                        get(province)).keySet());
+            }
+            //一选不存在或匹配无结果,直接搜全国
+            if (results==null||results.isEmpty()){
+                results = contain(this.sourceAddress,LEVEL_2_NAME_MAP.keySet());
+            }
+
+            Iterator<Integer> iterator = results.keySet().iterator();
+            while (iterator.hasNext()) {
+                int key = iterator.next();
+                String name = results.get(key);
+                if (key > 0 && name.equals("南县") &&"滦辉甘桦灌苍阜屏定全沂莒汝衡南郁平宁思广洛商南".indexOf(sourceAddress.charAt(key - 1)) != -1) {
+                    iterator.remove();
+                }
+
+            }
+            for (int index : results.keySet()){
+                String name = results.get(index);
+                String sub = this.sourceAddress.substring(index+name.length());
+                //去除南京路,北京大道型选手
+                if (ROAD_SUFFIX_PATTERN.matcher(sub).find()){
+                    continue;
+                }
+                cityInChoose.put(index,name);
+                //匹配到后缀时直接当做第一选择
+                if (LEVEL_2_SUFFIX_PATTERN.matcher(sub).find()){
+                    city = index;
+                }
+            }
+
+            //仅有一个选择时当成一选
+            if (cityInChoose.size()==1){
+                city = (int)cityInChoose.keySet().toArray()[0];
+            }
+        }
+        void findCounty(){
+            Map<Integer,String> results = null;
+            //尝试一选
+            if (city!=-1){
+                results=contain(sourceAddress,All_CITY_IN_TREE.get(cityInChoose.get(city)));
+            }
+            //一选不存在或匹配无结果,先搜全省
+            if ((results == null || results.isEmpty()) && province != -1) {
+                results = contain(sourceAddress, SIMPLE_NAME_TREE.get(provinceInChoose.get(province)).values().stream().
+                        flatMap(Set::stream).collect(Collectors.toSet()));
+            }
+            //最后全国
+            if (results == null || results.isEmpty()) {
+                results = contain(sourceAddress, LEVEL_3_NAME_MAP.keySet());
+            }
+            for (int index : results.keySet()) {
+                String name = results.get(index);
+                String sub = this.sourceAddress.substring(index + name.length());
+                //去除南京路,北京大道型选手
+                if (ROAD_SUFFIX_PATTERN.matcher(sub).find()) {
+                    continue;
+                }
+                countyInChoose.put(index, name);
+                //匹配到后缀时直接当做第一选择
+                if (LEVEL_3_SUFFIX_PATTERN.matcher(sub).find()) {
+                    county = index;
+                }
+            }
+            //仅有一个选择时当成一选
+            if (countyInChoose.size()==1){
+                county = (int)countyInChoose.keySet().toArray()[0];
+            }
+        }
+    }
+    /**
+     * 检查字符串含有哪些字符,输出这些匹配字符的位置和字符的map
+     * @param s 被检查字符串
+     * @param nameList 检查范围
+     */
+    private static Map<Integer,String> contain(String s,Iterable<String> nameList){
+        Map<Integer,String> output = new HashMap<Integer,String>();
+        for (String name:nameList){
+            if (name.isEmpty())continue;
+            int index = -1;
+            while ((index = s.indexOf(name, index + 1)) != -1){
+                output.put(index,name);
+            }
+        }
+        return output;
+    }
+
+    /**
+     * 分离地址字符串,请优先使用shanghaiAddressSplitUtil,此类只分词到县<br/>
+     * 注意,当输入的地址错误时不会自动修正,未找到的级会被空置<br/>
+     * 例如输入"北京青浦区盈港路515号1061室" ,输出[北京市,北京市,青浦区,盈港路515号1061室]<br/>
+     * 输入"安徽怀宁县黄墩镇老埂村双闸组" ,输出[安徽省,怀宁县,黄墩镇,盈港路515号1061室]<br/>
+     * @return 结果为[省级,城级,县级,余下的部分],分离失败则返回null<br/>
+     * @see ShanghaiAddressSplitUtil
+     */
+    public static String[] splitAddress(String address){
+        SplittingAddress a = new SplittingAddress(address.replaceAll("\\s+",""));
+        a.findProvince();
+        a.findCity();
+        a.findCounty();
+        String[] output = a.toStringList();
+        output[3]=(a.getOtherAddress());
+        return output;
+
+    }
+    //测试用
+    public static void main(String[] args) {
+        System.out.println(Arrays.toString(splitAddress("安徽省安徽省颍上县垂岗乡陶嘴村东道场31号")));
+        System.out.println(Arrays.toString(splitAddress("荣乐西路1058弄32号501室")));
+        System.out.println(Arrays.toString(splitAddress("泗泾镇新家园路30弄21号402室")));
+        System.out.println(Arrays.toString(splitAddress("山东省山东省单县莱河镇宋楼行政村霍井村041号")));
+        System.out.println(Arrays.toString(splitAddress("安徽省五河县安徽省五河县朱顶乡胡庄村447号")));
+        System.out.println(Arrays.toString(splitAddress("九亭镇九亭大街506弄22号101室")));
+        System.out.println(Arrays.toString(splitAddress("陕西省宝鸡市凤翔区陕西省凤翔区尹家务乡槐中村5组024号")));
+        System.out.println(Arrays.toString(splitAddress("江苏省海门市江苏省海门市正余镇王灶河村十三组36号")));
+        System.out.println(Arrays.toString(splitAddress("泗泾镇古楼公路519弄1号1102室")));
+        System.out.println(Arrays.toString(splitAddress("奉贤县奉城镇奉粮路115号")));
+        System.out.println(Arrays.toString(splitAddress("上海市奉贤区南桥镇沪杭支路24号14幢165室")));
+        System.out.println(Arrays.toString(splitAddress("浦东新区周浦镇年家浜路10、12号1层")));
+    }
+}

+ 30 - 5
src/main/java/com/skyversation/poiaddr/util/ExcelReaderUtils.java

@@ -4,16 +4,12 @@ import com.skyversation.poiaddr.addquery.Constant;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.ss.usermodel.*;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
+import java.io.*;
 import java.util.*;
 
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 
-import java.io.FileOutputStream;
-
 /**
  * xlsx文档解析并输出内容为List<Map<String,String>>
  * 大文件分割
@@ -97,6 +93,35 @@ public class ExcelReaderUtils {
         return resultList;
     }
 
+    public static List<Map<String, Object>> readExcel(InputStream is) throws Exception {
+        List<Map<String, Object>> resultList = new ArrayList<>();
+        // 创建工作簿对象,用于代表整个Excel文件
+        Workbook workbook = WorkbookFactory.create(is);
+        // 这里我们默认读取第一个工作表,如果需要读取指定名称或者索引的工作表可以进行相应修改
+        Sheet sheet = workbook.getSheetAt(0);
+        // 获取表头行
+        Row headerRow = sheet.getRow(0);
+        int headerSize = headerRow.getLastCellNum();
+
+        // 遍历数据行(从第二行开始,第一行是表头)
+        for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
+            Row currentRow = sheet.getRow(rowIndex);
+            Map<String, Object> rowMap = new HashMap<>();
+            for (int cellIndex = 0; cellIndex < headerSize; cellIndex++) {
+                Cell headerCell = headerRow.getCell(cellIndex);
+                Cell currentCell = currentRow.getCell(cellIndex);
+                String headerValue = getCellValue(headerCell).toString();
+                Object currentValue = getCellValue(currentCell);
+                rowMap.put(headerValue, currentValue);
+            }
+            resultList.add(rowMap);
+        }
+
+        workbook.close();
+        is.close();
+        return resultList;
+    }
+
 
     public static List<Map<String, Object>> readExcel(File file) throws IOException {
         List<Map<String, Object>> resultList = new ArrayList<>();

+ 466 - 0
src/main/java/com/skyversation/poiaddr/util/ShanghaiAddressSplitUtil.java

@@ -0,0 +1,466 @@
+package com.skyversation.poiaddr.util;
+
+import com.skyversation.poiaddr.bean.SplitAddress;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.io.InputStream;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+@Service
+public class ShanghaiAddressSplitUtil {
+    @AllArgsConstructor
+    static class threeLevelAddress{
+        String district;
+        String street;
+        String community;
+        String districtFullName;
+        String streetFullName;
+        String communityFullName;
+        String districtCode;
+        String streetCode;
+        String communityCode;
+
+    }
+    private static Map<String,List<threeLevelAddress>> All_STREET_IN_SHANGHAI;
+    private static Map<String,List<threeLevelAddress>> All_COMMUNITY_IN_SHANGHAI;
+    private static Map<String,List<String>> DISTRICT_TO_STREET_MAP;
+    private static Map<String,List<String>> STREET_TO_COMMUNITY_MAP;
+    private static Map<String,List<String>> DISTRICT_TO_COMMUNITY_MAP;
+
+    private static final Pattern LEVEL_1_SUFFIX_PATTERN = Pattern.compile("^(?:区|新区)");
+
+    private static final Pattern LEVEL_2_SUFFIX_PATTERN = Pattern.compile("^(?:街道|路街道|镇|乡|新镇)");
+
+    private static final Pattern LEVEL_3_SUFFIX_PATTERN = Pattern.compile("^(?:居委会|管委会居委会|管委会|社区|社区居委会|居民委员会|居民区|居委|村|村委会|园区|苑|安居办|居|工作站|会)");
+
+    private static final Pattern ROAD_SUFFIX_PATTERN = AddressSplitUtil.ROAD_SUFFIX_PATTERN;
+
+    private static final Pattern UN_ADDRESS_PATTERN = Pattern.compile("http");
+
+    private static final Pattern OVER_SPLIT=Pattern.compile("^(?:[0123456789-\\-一二三四五六七八九十大A-za-z]{0,4}[街队组栋号站弄]|(?:车站|工业区|市场|农贸市场)(?![东南西北中一二三四五六七八九十公大小支新老环]路)|[A-za-z]?[0123456789-\\-])");
+
+    private static final Pattern MULTI_ADDRESS = Pattern.compile("(?<=[0-9])[号弄]?[、—/\\\\-][0-9]+(?=[号弄])");
+    @PostConstruct
+    private void init(){
+        System.out.println("开始初始化分词器");
+        Map<String,threeLevelAddress> districtMap= new HashMap<>();
+        Map<String,List<threeLevelAddress>> streetMap= new HashMap<>();
+        Map<String,List<threeLevelAddress>> communityMap= new HashMap<>();
+        Map<String,List<String>> districtToStreetMap=new HashMap<>();
+        Map<String,List<String>> streetToCommunityMap=new HashMap<>();
+
+        String file = "上海市县乡记录.xlsx";
+        InputStream is = ShanghaiAddressSplitUtil.class.getResourceAsStream(file);
+        if (is==null) is= ShanghaiAddressSplitUtil.class.getResourceAsStream("/"+file);
+        if (is==null) throw new RuntimeException("无法找到"+file);
+        try {
+            for (Map<String, Object> row : ExcelReaderUtils.readExcel(is)) {
+                String district = Optional.ofNullable(row.get("县级市简称")).map(Object::toString).orElse("");
+                String street = Optional.ofNullable(row.get("街道简称")).map(Object::toString).orElse("");
+                String community = Optional.ofNullable(row.get("居委")).map(Object::toString).orElse("");
+                String districtFullName = Optional.ofNullable(row.get("县级市")).map(Object::toString).orElse("");
+                String streetFullName = Optional.ofNullable(row.get("街道")).map(Object::toString).orElse("");
+                String communityFullName = Optional.ofNullable(row.get("居委")).map(Object::toString).orElse("");
+                String districtCode = Optional.ofNullable(row.get("县级市编码")).map(Object::toString).orElse("");
+                String streetCode = Optional.ofNullable(row.get("街道编码")).map(Object::toString).orElse("");
+                String communityCode = Optional.ofNullable(row.get("居委编码")).map(Object::toString).orElse("");
+                initData(district, street, community, districtFullName, streetFullName, communityFullName,districtCode, streetCode, communityCode, districtMap, streetMap, communityMap, districtToStreetMap, streetToCommunityMap);
+            }
+            //自贸区
+            initData("浦东",  "试验区","", "浦东新区", "自由贸易试验区","","310115","","",  districtMap, streetMap, communityMap, districtToStreetMap, streetToCommunityMap);
+            //松江镇特别处理
+            initData("松江",  "松江","", "松江区", "","","310117","","",  districtMap, streetMap, communityMap, districtToStreetMap, streetToCommunityMap);
+            //金山工业区
+            initData("金山",  "金山工业区","", "金山区", "金山工业区","","310116","","",  districtMap, streetMap, communityMap, districtToStreetMap, streetToCommunityMap);
+
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        All_STREET_IN_SHANGHAI = Collections.unmodifiableMap(streetMap);
+        All_COMMUNITY_IN_SHANGHAI = Collections.unmodifiableMap(communityMap);
+        DISTRICT_TO_STREET_MAP=Collections.unmodifiableMap(districtToStreetMap);
+        STREET_TO_COMMUNITY_MAP=Collections.unmodifiableMap(streetToCommunityMap);
+        DISTRICT_TO_COMMUNITY_MAP=Collections.unmodifiableMap(DISTRICT_TO_STREET_MAP.entrySet().stream()
+                .collect(Collectors.toMap(
+                        Map.Entry::getKey,
+                        entry -> entry.getValue().stream()
+                                .flatMap(street -> STREET_TO_COMMUNITY_MAP.getOrDefault(street, Collections.emptyList()).stream())
+                                .collect(Collectors.toList())
+                )));
+        System.out.println("分词器初始化完成");
+    }
+
+    private static void initData(String district, String street, String community, String districtFullName, String streetFullName, String communityFullName,String districtCode, String streetCode, String communityCode, Map<String, threeLevelAddress> districtMap, Map<String, List<threeLevelAddress>> streetMap, Map<String, List<threeLevelAddress>> communityMap, Map<String, List<String>> districtToStreetMap, Map<String, List<String>> streetToCommunityMap) {
+        threeLevelAddress add = new threeLevelAddress(district, street, community, districtFullName, streetFullName, communityFullName, districtCode ,streetCode, communityCode);
+        districtMap.put(district,add);
+        if (!streetMap.containsKey(street)) streetMap.put(street,new ArrayList<>());
+        streetMap.get(street).add(add);
+        if (!communityMap.containsKey(community)) communityMap.put(community,new ArrayList<>());
+        communityMap.get(community).add(add);
+        if (!districtToStreetMap.containsKey(district)) districtToStreetMap.put(district,new ArrayList<>());
+        districtToStreetMap.get(district).add(street);
+        if (!streetToCommunityMap.containsKey(street)) streetToCommunityMap.put(street,new ArrayList<>());
+        streetToCommunityMap.get(street).add(community);
+    }
+
+    private static class splittingAddress{
+        SplitAddress splitAddress;
+
+        int street=-1;
+        int community=-1;
+
+        Map<Integer,String> streetMap =new HashMap<>();
+        Map<Integer,String> communityMap=new HashMap<>();
+        threeLevelAddress threeLevelAddress;
+
+        String targetString;
+
+        void findStreet(){
+            Map<Integer,String> results =null;
+            int completeMatchIndex=-1;
+            //首先尝试在一选下匹配
+            if (splitAddress.getDistrict()!=null){
+                results  = contain(this.targetString,DISTRICT_TO_STREET_MAP.get(splitAddress.getDistrict()),0);
+                completeMatchIndex = washResult(this.targetString,results,LEVEL_2_SUFFIX_PATTERN,LEVEL_3_SUFFIX_PATTERN,LEVEL_1_SUFFIX_PATTERN);
+            }
+            //一选不存在或匹配无结果,直接搜全国
+            if (results==null||results.isEmpty()){
+                results = contain(this.targetString,All_STREET_IN_SHANGHAI.keySet(),0);
+                if (completeMatchIndex==-1)completeMatchIndex = washResult(this.targetString,results,LEVEL_2_SUFFIX_PATTERN,LEVEL_3_SUFFIX_PATTERN,LEVEL_1_SUFFIX_PATTERN);
+
+            }
+
+            streetMap.putAll(results);
+            street=completeMatchIndex;
+            //仅有一个选择时当成一选
+            if (streetMap.size()==1){
+                street = (int)streetMap.keySet().toArray()[0];
+            }
+
+        }
+
+        void findCommunity(){
+            Map<Integer,String> results = null;
+            int completeMatchCommunity=-1;
+            String sub=targetString;
+            //尝试一选
+            if (street!=-1){
+                sub = targetString.substring(street+streetMap.get(street).length());
+                Matcher m = LEVEL_2_SUFFIX_PATTERN.matcher(sub);
+                if (m.find()){
+                    sub=sub.substring(m.end());
+                }
+                results= contain(sub,STREET_TO_COMMUNITY_MAP.get(streetMap.get(street)),targetString.length()-sub.length());
+                completeMatchCommunity=washResult(targetString,results,LEVEL_3_SUFFIX_PATTERN,LEVEL_1_SUFFIX_PATTERN,LEVEL_2_SUFFIX_PATTERN);
+
+            }
+            //一选不存在或匹配无结果,先搜全区
+            if ((results == null || results.isEmpty()) && splitAddress.getDistrict()!=null) {
+                results = contain(sub, DISTRICT_TO_COMMUNITY_MAP.get(splitAddress.getDistrict()),targetString.length()-sub.length());
+                if (completeMatchCommunity==-1)completeMatchCommunity=washResult(targetString,results,LEVEL_3_SUFFIX_PATTERN,LEVEL_1_SUFFIX_PATTERN,LEVEL_2_SUFFIX_PATTERN);
+            }
+            //最后全市
+            if (results == null || results.isEmpty()) {
+                results = contain(sub, All_COMMUNITY_IN_SHANGHAI.keySet(),targetString.length()-sub.length());
+                if (completeMatchCommunity==-1)completeMatchCommunity=washResult(targetString,results,LEVEL_3_SUFFIX_PATTERN,LEVEL_1_SUFFIX_PATTERN,LEVEL_2_SUFFIX_PATTERN);
+            }
+            Iterator<Integer> iterator = results.keySet().iterator();
+            while (iterator.hasNext()) {
+                int key = iterator.next();
+                String name = results.get(key);
+                if (key > 0 && name.equals("江镇") && targetString.charAt(key - 1) == '松') {
+                    iterator.remove();
+                }
+            }
+            communityMap.putAll(results);
+            //仅有一个选择时当成一选
+            if (communityMap.size()==1){
+                int index = (int)communityMap.keySet().toArray()[0];
+                if (street!=index)community=index;
+            }
+
+        }
+
+        void matchThreeLevelAdd(){
+            int handingPoint=0;
+            threeLevelAddress handingTLA=new threeLevelAddress("","","","","","","","","");
+            for (String communityName: new HashSet<>(communityMap.values())){
+                if (communityName.isEmpty())continue;
+                for(threeLevelAddress t:All_COMMUNITY_IN_SHANGHAI.get(communityName)){
+                    int point = checkTLA(t);
+                    if (point==221){
+                        threeLevelAddress=t;
+                        return;
+                    }else if (point>handingPoint){
+                        handingPoint=point;
+                        handingTLA=t;
+                    }
+                }
+            }
+            for (String streetName:new HashSet<>(streetMap.values())){
+                if (streetName.isEmpty())continue;
+                for(threeLevelAddress t:All_STREET_IN_SHANGHAI.get(streetName)){
+                    int point = checkTLA(t);
+                    if (point==2111){
+                        threeLevelAddress=t;
+                        return;
+                    }else if (point>handingPoint){
+                        handingPoint=point;
+                        handingTLA=t;
+                    }
+                }
+            }
+            threeLevelAddress = handingTLA;
+        }
+        int checkTLA(threeLevelAddress t){
+            int output=0;
+            if (t.district.equals(splitAddress.getDistrict()))output+=1;
+            if (streetMap.containsValue(t.street))output+=10;
+            if (street!=-1&&streetMap.get(street).equals(t.street))output+=1000;
+            if (communityMap.containsValue(t.community))output+=100;
+            if (community!=-1&&communityMap.get(community).equals(t.community))output+=1000;
+            if (community!=-1&&Pattern.matches(".*\\d$",communityMap.get(community)))output-=1000;
+            return output;
+        }
+        void guessFirstMatch(){
+            //先街道
+            if (!streetMap.isEmpty()&&street==-1) {
+                for (int i :streetMap.keySet()){
+                    if (streetMap.get(i).equals(threeLevelAddress.street)&&(i<street||street==-1)) {
+                        street=i;
+                    }
+                }
+            }
+            //再居委
+            if (community==-1&& !communityMap.isEmpty()){
+                for (int i :communityMap.keySet()){
+                    if (communityMap.get(i).equals(threeLevelAddress.community)&&street!=i&&(i<community||community==-1)){
+                        community=i;
+                    }
+                }
+
+            }
+
+        }
+    }
+    static int washResult(String sourceAddress, Map<Integer, String> result, Pattern should, Pattern... never){
+        Map<Integer,String> output=new HashMap<>();
+        int outputInt = -1;
+        for (int index : result.keySet()) {
+            String name = result.get(index);
+            String sub =sourceAddress.substring(index + name.length());
+            //匹配到后缀时直接保留
+            if (should.matcher(sub).find()) {
+                outputInt=index;
+            } else {
+                //去除南京路,北京大道型选手
+                if (ROAD_SUFFIX_PATTERN.matcher(sub).find()) {
+                    continue;
+                }
+                boolean skip =false;
+                for (Pattern p :never){
+                    if (p.matcher(sub).find())skip=true;
+                }
+                if (skip) continue;
+            }
+            output.put(index,name);
+        }
+        result.clear();
+        result.putAll(output);
+        return outputInt;
+    }
+
+    /**
+     * 检查字符串含有哪些字符,输出这些匹配字符的位置和字符的map
+     * @param s 被检查字符串
+     * @param nameList 检查范围
+     */
+    private static Map<Integer,String> contain(String s,Iterable<String> nameList,int offset){
+        Map<Integer,String> output = new HashMap<>();
+        if (nameList==null){
+            return output;
+        }
+        for (String name:nameList){
+            if (name.isEmpty())continue;
+            int index = -1;
+            while ((index = s.indexOf(name, index + 1)) != -1){
+                output.put(index+offset,name);
+            }
+        }
+        return output;
+    }
+    private static SplitAddress split(String sourceAddress){
+        //事前准备
+        String beautyAddress = sourceAddress.replaceAll("[\\s]+","");
+
+        SplitAddress splitAddress = new SplitAddress();
+        splitAddress.setFullAddress(sourceAddress);
+
+
+        splittingAddress splittingAddress = new splittingAddress();
+        splittingAddress.splitAddress=splitAddress;
+
+
+        String[] result = AddressSplitUtil.splitAddress(beautyAddress);
+
+
+        splitAddress.setProvince(result[0]);
+        splitAddress.setCity(result[1]);
+        splitAddress.setDistrict(result[2]);
+        //检查是否在外省,未找到省市或者在省市中找到上海,或者找到上海的区都算作省内
+        Map<Integer, String> districtContainResult = contain(beautyAddress, DISTRICT_TO_COMMUNITY_MAP.keySet(), 0);
+        washResult(beautyAddress, districtContainResult,LEVEL_1_SUFFIX_PATTERN);
+        if (!((result[0].isEmpty()|| result[0].equals("上海市")) && (result[1].isEmpty()  || result[1].equals("上海市")||
+                !districtContainResult.isEmpty()))) {
+            splitAddress.setStatus(2);
+            splitAddress.setAddr(result[3]);
+            return splitAddress;
+        }
+        splitAddress.setProvince("上海市");
+        splitAddress.setCity("上海市");
+        splitAddress.setCityCode("3101");
+        splittingAddress.targetString = beautyAddress;
+        //开始省内分词
+        splittingAddress.findStreet();
+        splittingAddress.findCommunity();
+        splittingAddress.matchThreeLevelAdd();
+        splittingAddress.guessFirstMatch();
+
+
+        if (splittingAddress.street!=-1||splittingAddress.community!=-1){
+            splitAddress.setStreet(splittingAddress.threeLevelAddress.streetFullName);
+            splitAddress.setStreetCode(splittingAddress.threeLevelAddress.streetCode);
+
+        }
+        if (splittingAddress.community!=-1){
+            splitAddress.setCommunity(splittingAddress.threeLevelAddress.communityFullName);
+            splitAddress.setCommunityCode(splittingAddress.threeLevelAddress.communityCode);
+
+        }
+        splitAddress.setDistrict(splittingAddress.threeLevelAddress.districtFullName);
+        splitAddress.setDistrictCode(splittingAddress.threeLevelAddress.districtCode);
+
+
+        //检查是否能够分离
+        if(splittingAddress.community==-1&&splittingAddress.street==-1){
+            //检查是否是非地址
+            if (UN_ADDRESS_PATTERN.matcher(splitAddress.getFullAddress()).find()){
+                splitAddress.setStatus(3);
+                return splitAddress;
+            }
+            splitAddress.setDistrict(result[2]);
+            splitAddress.setAddr(result[3]);
+
+            splitAddress.setStatus(1);
+            if (result[0].isEmpty()&&result[1].isEmpty()&&districtContainResult.isEmpty())splitAddress.setStatus(4);
+            return splitAddress;
+        }
+        //尝试分离
+        if (splittingAddress.street> splittingAddress.community){
+            String sub = beautyAddress.substring(splittingAddress.street+splittingAddress.streetMap.get(splittingAddress.street).length());
+            Matcher m = LEVEL_2_SUFFIX_PATTERN.matcher(sub);
+            if (m.find()){
+                sub = sub.substring(m.end());
+            }
+            splitAddress.setAddr(sub);
+        }else {
+            String sub = beautyAddress.substring(
+                    splittingAddress.community+
+                            splittingAddress.communityMap.
+                                    get(splittingAddress.community).length());
+            Matcher m = LEVEL_3_SUFFIX_PATTERN.matcher(sub);
+            if (m.find()){
+                sub = sub.substring(m.end());
+            }
+            splitAddress.setAddr(sub);
+        }
+        splitAddress.setStatus(0);
+        if (result[0].isEmpty()&&result[1].isEmpty()&&districtContainResult.isEmpty())splitAddress.setStatus(4);
+        if (splitAddress.getStreet().equals("自由贸易试验区"))splitAddress.setStatus(0);
+        return splitAddress;
+    }
+
+    private static SplitAddress beautyResult(SplitAddress splitAddress){
+        //检查过度分割
+        if (splitAddress.getAddr().isEmpty() ||OVER_SPLIT.matcher(splitAddress.getAddr()).find()){
+            if (splitAddress.getCommunity().isEmpty()){
+                if (splitAddress.getStreet().isEmpty()){
+                    if (splitAddress.getDistrict().isEmpty()){
+                        splitAddress.setAddr("上海市"+splitAddress.getAddr());
+                    }else {
+                        splitAddress.setAddr(splitAddress.getDistrict()+splitAddress.getAddr());
+                    }
+                }else {
+                    splitAddress.setAddr(splitAddress.getStreet()+splitAddress.getAddr());
+                }
+            }else {
+                splitAddress.setAddr(splitAddress.getCommunity()+splitAddress.getAddr());
+            }
+        }
+        //检查多号,多弄
+        splitAddress.setAddr(splitAddress.getAddr().replaceAll(String.valueOf(MULTI_ADDRESS),""));
+
+        return splitAddress;
+    }
+    /**
+     * 工具入口,返回所有数据
+     * @param sourceAddress 任意形式的地址,请注意,上海市外的地址仅分词到县,上海市内分词到居委
+     */
+    public static List<SplitAddress> splitAddresses(String sourceAddress){
+        Matcher matcher = Pattern.compile("\\(([^()]*|\\([^()]*\\))*\\)|\\[([^\\[\\]]*|\\[[^\\[\\]]*])*]|(([^()]*|([^()]*))*)").matcher(sourceAddress);
+        List<SplitAddress> addressList =new ArrayList<>();
+        String beautyString = sourceAddress.replaceAll("\\(([^()]*|\\([^()]*\\))*\\)|\\[([^\\[\\]]*|\\[[^\\[\\]]*])*]|(([^()]*|([^()]*))*)","");
+        StringBuilder sb = new StringBuilder();
+        for (char c : beautyString.toCharArray()) {
+            // 检查是否为全角数字
+            if (c >= '0' && c <= '9') {
+                // 转换为半角数字
+                sb.append((char) (c - '0' + '0'));
+            } else if (c=='\uE5CE'){
+                // 奇妙的乱码,跳过
+            }else {
+                // 保持原字符
+                sb.append(c);
+            }
+        }
+        beautyString = sb.toString();
+        addressList.add(beautyResult(split(beautyString)));
+        while (matcher.find()){
+            String address=matcher.group();
+            if (address.length()<=2)continue;
+            addressList.addAll(splitAddresses(address.substring(1,address.length()-1)));
+        }
+        for (SplitAddress s :addressList)s.setSourceAddress(sourceAddress);
+        return addressList;
+    }
+
+    /**
+     * 工具入口,仅返回最优
+     * @param sourceAddress 任意形式的地址,请注意,上海市外的地址仅分词到县,上海市内分词到居委
+     */
+    public static SplitAddress splitBestAddress(String sourceAddress){
+        return splitAddresses(sourceAddress).stream().max(SplitAddress::compareTo).orElse(new SplitAddress());
+    }
+    public static void main(String[] args) throws Exception {
+//        List<SplitAddress> result = new ArrayList<>();
+//        for (Map<String,Object> row:ExcelReaderUtils.readExcel("C:\\Users\\dxh\\IdeaProjects\\address_poi_yysz_server\\src\\main\\resources\\yysk_dmdz_address_standardization_200000_36.xlsx")){
+//            result.add(splitAddresses(row.get("address").toString()).stream().max(SplitAddress::compareTo).orElse(new SplitAddress()));
+//            System.out.println("正在处理:"+row.get("address"));
+//        };
+//        ExcelReaderUtils.writeSplitAddressExcel(result,"C:\\\\Users\\\\dxh\\\\IdeaProjects\\\\address_poi_yysz_server\\\\src\\\\main\\\\resources\\\\result.xlsx");
+//        System.out.println("完成");
+        new ShanghaiAddressSplitUtil().init();
+        System.out.println(splitBestAddress("新胜路88、98号3号厂房"));
+        System.out.println(splitBestAddress("新胜路88-98号3号厂房"));
+        System.out.println(splitBestAddress("新胜路、98号3号厂房"));
+        System.out.println(splitBestAddress("新胜路88\\98号3号厂房"));
+        System.out.println(splitBestAddress("新胜路18、28号3号厂房"));
+        System.out.println(splitBestAddress("新胜路28号3号厂房"));
+        System.out.println(splitBestAddress("88、98号3号厂房"));
+    }
+}

+ 49 - 0
src/main/java/com/skyversation/poiaddr/util/jpa/entity/TAddressCallback.java

@@ -0,0 +1,49 @@
+package com.skyversation.poiaddr.util.jpa.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.time.LocalDate;
+
+@Getter
+@Setter
+@Entity
+@Table(name = "t_address_callback")
+@AllArgsConstructor
+@NoArgsConstructor
+public class TAddressCallback{
+    @Id
+    @Column(name = "id", nullable = false)
+    private Integer id;
+
+    @Column(name = "create_time")
+    private LocalDate createTime;
+
+    @Column(name = "address")
+    private String address;
+
+    @Column(name = "name")
+    private String name;
+
+    @Column(name = "provice_name")
+    private String proviceName;
+
+    @Column(name = "city_name")
+    private String cityName;
+
+    @Column(name = "town_name")
+    private String townName;
+
+    @Column(name = "community_name")
+    private String communityName;
+
+    @Column(name = "status")
+    private Short status;
+
+}

+ 220 - 0
src/main/java/com/skyversation/poiaddr/util/jpa/entity/YyszAddressQp.java

@@ -0,0 +1,220 @@
+package com.skyversation.poiaddr.util.jpa.entity;
+
+import com.skyversation.poiaddr.util.jpa.rep.YyszAddressQpRep;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.hibernate.annotations.Formula;
+import org.hibernate.annotations.Type;
+
+import javax.persistence.*;
+import java.sql.SQLException;
+import java.time.Instant;
+
+@Getter
+@Setter
+@Entity
+@Table(name = "yysz_address_qp")
+@AllArgsConstructor
+@NoArgsConstructor
+public class YyszAddressQp {
+    @Id
+    @Column(name = "oid", nullable = false)
+    private Integer id;
+
+    @Column(name = "code")
+    private String code;
+
+    @Column(name = "sourceaddress", length = 500)
+    private String sourceaddress;
+
+    @Column(name = "city")
+    private String city;
+
+    @Column(name = "county")
+    private String county;
+
+    @Column(name = "town")
+    private String town;
+
+    @Column(name = "community")
+    private String community;
+
+    @Column(name = "village")
+    private String village;
+
+    @Column(name = "squad")
+    private String squad;
+
+    @Column(name = "szone")
+    private String szone;
+
+    @Column(name = "street")
+    private String street;
+
+    @Column(name = "door")
+    private String door;
+
+    @Column(name = "resregion")
+    private String resregion;
+
+    @Column(name = "building")
+    private String building;
+
+    @Column(name = "building_num")
+    private String buildingNum;
+
+    @Column(name = "unit")
+    private String unit;
+
+    @Column(name = "floor")
+    private String floor;
+
+    @Column(name = "room")
+    private String room;
+
+    @Column(name = "unique_code")
+    private String uniqueCode;
+
+    @Column(name = "room_of_floor")
+    private Integer roomOfFloor;
+
+    @Column(name = "source")
+    private String source;
+
+    @Column(name = "lon")
+    private Double lon;
+
+    @Column(name = "lat")
+    private Double lat;
+
+    @Column(name = "shape")
+    private String shape;
+
+    @Column(name = "belong_building")
+    private String belongBuilding;
+
+    @Column(name = "address_type")
+    private Integer addressType;
+
+    @Column(name = "lv")
+    private Integer lv;
+
+    @Column(name = "is_delete")
+    private Integer isDelete;
+
+    @Column(name = "is_multi")
+    private Integer isMulti;
+
+    @Column(name = "createtime")
+    private Instant createtime;
+
+    @Column(name = "updatetime")
+    private Instant updatetime;
+
+    @Column(name = "alt")
+    private Double alt;
+
+    @Column(name = "model_type")
+    private Integer modelType;
+
+    @Column(name = "full_place")
+    private String fullPlace;
+
+    @Column(name = "security_grade")
+    private Integer securityGrade;
+
+    @Column(name = "city_code")
+    private String cityCode;
+
+    @Column(name = "county_code")
+    private String countyCode;
+
+    @Column(name = "town_code")
+    private String townCode;
+
+    @Column(name = "community_code")
+    private String communityCode;
+
+    @Column(name = "grid_name")
+    private String gridName;
+
+    @Column(name = "grid_code")
+    private String gridCode;
+
+    @Column(name = "data_type", length = 50)
+    private String dataType;
+
+    @Column(name = "mphid", length = 100)
+    private String mphid;
+
+    @Column(name = "address_code", length = 100)
+    private String addressCode;
+
+    @Column(name = "systemid", length = 100)
+    private String systemid;
+
+    @Column(name = "type", length = 10)
+    private String type;
+
+    @Column(name = "x")
+    private String x;
+
+    @Column(name = "y")
+    private String y;
+
+    @Column(name = "label", length = 50)
+    private String label;
+
+    @Column(name = "addr_tag")
+    private String addrTag;
+
+    @Column(name = "multiple_unique")
+    private String multipleUnique;
+
+    @Column(name = "standardize_task_id")
+    private String standardizeTaskId;
+
+    @Column(name = "dlhh")
+    private String dlhh;
+
+    @Column(name = "signature_data")
+    @Type(type = "org.hibernate.type.TextType")
+    private String signatureData;
+
+    @Column(name = "signature_check_state")
+    private Integer signatureCheckState;
+
+    @Column(name = "signature_time")
+    private Instant signatureTime;
+
+    @Column(name = "signature_check_time")
+    private Instant signatureCheckTime;
+
+    @Column(name = "is_history")
+    private Integer isHistory;
+
+    @Column(name = "ylmc")
+    private String ylmc;
+
+    @Column(name = "ylbm", length = 50)
+    private String ylbm;
+
+    @Column(name = "address")
+    private String address;
+
+    @Column(name = "ybdd", length = 50)
+    private String ybdd;
+
+    @Formula("ST_AsText(geom)")
+    @Transient
+    private String location;
+
+    @Column(name = "tydz_jc", length = 50)
+    private String tydzJc;
+    @PostPersist
+    @PostUpdate
+    public void setGeomFromWkt() throws SQLException {
+    }
+}

+ 12 - 0
src/main/java/com/skyversation/poiaddr/util/jpa/rep/TAddressCallbackRep.java

@@ -0,0 +1,12 @@
+package com.skyversation.poiaddr.util.jpa.rep;
+
+import com.skyversation.poiaddr.util.jpa.entity.TAddressCallback;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.Optional;
+
+public interface TAddressCallbackRep extends JpaRepository<TAddressCallback,Integer> {
+    @Query(value = "SELECT MAX(e.id) FROM t_address_callback e", nativeQuery = true)
+    Optional<Integer> findMaxId();
+}

+ 17 - 0
src/main/java/com/skyversation/poiaddr/util/jpa/rep/YyszAddressQpRep.java

@@ -0,0 +1,17 @@
+package com.skyversation.poiaddr.util.jpa.rep;
+
+import com.skyversation.poiaddr.util.jpa.entity.YyszAddressQp;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import java.util.Optional;
+
+public interface YyszAddressQpRep extends JpaRepository<YyszAddressQp, Integer> {
+    @Query(value = "SELECT MAX(e.oid) FROM yysz_address_qp e", nativeQuery = true)
+    Optional<Integer> findMaxId();
+    @Query(value = "UPDATE yysz_address_qp e SET location = ST_GeomFromText(:wkt) WHERE oid = :id", nativeQuery = true)
+    @Modifying
+    void updateLocation(@Param("id") int id, @Param("wkt") String wkt);
+}

+ 2 - 1
src/main/java/com/skyversation/poiaddr/util/status/AddressResultEnum.java

@@ -9,6 +9,7 @@ public enum AddressResultEnum {
     WDJA_SUCCESS,// 武大吉奥成功
     SZX_SUCCESS,// 市四中心成功
     GD_SUCCESS,// 高德成功
-    GDV3_SUCCESS;// 高德v3成功
+    GDV3_SUCCESS,// 高德v3成功
+    YYSZ_SUCCESS,//yysz_address成功
 
 }

+ 14 - 8
src/main/resources/application.properties

@@ -4,10 +4,10 @@ spring.application.name=poiAddr
 spring.servlet.multipart.max-file-size=300MB
 spring.servlet.multipart.max-request-size=300MB
 # \u6570\u636E\u5E93\u914D\u7F6E\uFF08\u672C\u5730\u8C03\u8BD5\u73AF\u5883\uFF09
-spring.datasource.url=jdbc:mysql://127.0.0.1:3306/songjiang?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
-spring.datasource.username=root
-spring.datasource.password=root
-spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/postgres?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
+spring.datasource.username=postgres
+spring.datasource.password=417512
+spring.datasource.driver-class-name=org.postgresql.Driver
 # \u6570\u636E\u5E93\u8FDE\u63A5\u4FE1\u606F\uFF08\u5F00\u53D1\u73AF\u5883\uFF09
 #spring.datasource.url=jdbc:transwarp2://172.30.75.126:31768/dws
 #spring.datasource.username=dev_sjbdc_kjyy
@@ -24,8 +24,14 @@ spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
 spring.jpa.hibernate.ddl-auto=update
 spring.jpa.show-sql=false
 # \u677E\u6C5F\u8857\u9547
-app.area=\u677E\u6C5F
-app.town=\u5CB3\u9633\u8857\u9053\u3001\u6C38\u4E30\u8857\u9053\u3001\u65B9\u677E\u8857\u9053\u3001\u4E2D\u5C71\u8857\u9053\u3001\u5E7F\u5BCC\u6797\u8857\u9053\u3001\u4E5D\u91CC\u4EAD\u8857\u9053\u3001\u6CD7\u6CFE\u9547\u3001\u4F58\u5C71\u9547\u3001\u8F66\u58A9\u9547\u3001\u65B0\u6865\u9547\u3001\u6D1E\u6CFE\u9547\u3001\u4E5D\u4EAD\u9547\u3001\u6CD6\u6E2F\u9547\u3001\u77F3\u6E56\u8361\u9547\u3001\u65B0\u6D5C\u9547\u3001\u53F6\u69AD\u9547\u3001\u5C0F\u6606\u5C71\u9547
+#app.area=\u677E\u6C5F
+#app.town=\u5CB3\u9633\u8857\u9053\u3001\u6C38\u4E30\u8857\u9053\u3001\u65B9\u677E\u8857\u9053\u3001\u4E2D\u5C71\u8857\u9053\u3001\u5E7F\u5BCC\u6797\u8857\u9053\u3001\u4E5D\u91CC\u4EAD\u8857\u9053\u3001\u6CD7\u6CFE\u9547\u3001\u4F58\u5C71\u9547\u3001\u8F66\u58A9\u9547\u3001\u65B0\u6865\u9547\u3001\u6D1E\u6CFE\u9547\u3001\u4E5D\u4EAD\u9547\u3001\u6CD6\u6E2F\u9547\u3001\u77F3\u6E56\u8361\u9547\u3001\u65B0\u6D5C\u9547\u3001\u53F6\u69AD\u9547\u3001\u5C0F\u6606\u5C71\u9547
 # \u9752\u6D66\u8857\u9547
-#app.area=\u9752\u6D66
-#app.town2=\u6731\u5BB6\u89D2\u9547\u3001\u8D75\u5DF7\u9547\u3001\u5F90\u6CFE\u9547\u3001\u534E\u65B0\u9547\u3001\u91CD\u56FA\u9547\u3001\u767D\u9E64\u9547\u3001\u7EC3\u5858\u9547\u3001\u91D1\u6CFD\u9547\u3001\u590F\u9633\u8857\u9053\u3001\u76C8\u6D66\u8857\u9053\u3001\u9999\u82B1\u6865\u8857\u9053
+app.area=\u9752\u6D66
+app.town=\u6731\u5BB6\u89D2\u9547\u3001\u8D75\u5DF7\u9547\u3001\u5F90\u6CFE\u9547\u3001\u534E\u65B0\u9547\u3001\u91CD\u56FA\u9547\u3001\u767D\u9E64\u9547\u3001\u7EC3\u5858\u9547\u3001\u91D1\u6CFD\u9547\u3001\u590F\u9633\u8857\u9053\u3001\u76C8\u6D66\u8857\u9053\u3001\u9999\u82B1\u6865\u8857\u9053
+
+app.net-type=${NET_TYPE:internet}
+app.yysz-address-service=http://localhost:10012/poi
+#
+#logging.level.org.hibernate=DEBUG
+#logging.level.org.springframework=DEBUG

BIN
src/main/resources/上海市县乡记录.xlsx


BIN
src/main/resources/全国省市县记录.xlsx