geotools请参考:geotools实现插入,更新,查询

包结构


采用技术:

dom4j,ThreadPoolTaskExecutor线程池,RestTemplate,guava retry,wfs协议,ogc协议,btoa加密,策略模式

通过geoserver来修改postgresql地理数据库,这样就不需要每次更新数据后,人为手动更新geoserver了

相关配置

相关maven

这里只贴了关键的maven

<repositories><repository><id>osgeo</id><name>osgeo Repository</name><url>https://repo.osgeo.org/repository/release/</url><snapshots><enabled>false</enabled></snapshots></repository><repository><id>aliyun</id><name>aliyun Repository</name><url>https://maven.aliyun.com/repository/public</url><snapshots><enabled>false</enabled></snapshots></repository>
</repositories><dependencies><dependency><groupId>org.geotools</groupId><artifactId>gt-main</artifactId><version>25.2</version></dependency><!-- https://mvnrepository.com/artifact/org.geotools/gt-shapefile --><dependency><groupId>org.geotools</groupId><artifactId>gt-shapefile</artifactId><version>25.2</version></dependency><!-- https://mvnrepository.com/artifact/org.geotools.jdbc/gt-jdbc-postgis --><dependency><groupId>org.geotools.jdbc</groupId><artifactId>gt-jdbc-postgis</artifactId><version>25.2</version></dependency><dependency><groupId>org.geotools</groupId><artifactId>gt-epsg-hsql</artifactId><version>25.2</version></dependency><dependency><groupId>it.geosolutions</groupId><artifactId>geoserver-manager</artifactId><version>1.7.0</version></dependency><!--重试机制--><dependency><groupId>com.github.rholder</groupId><artifactId>guava-retrying</artifactId><version>2.0.0</version></dependency><!-- json --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.75</version></dependency><!-- Lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- dom4j --><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version></dependency>
</dependencies>

retry

import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.concurrent.TimeUnit;/*** @author qinlei* @description todo* @date 2021/10/26 9:55*/
@Configuration
public class RetryConfig {@Beanpublic Retryer<Boolean> instance(){Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()//返回false也需要重试.retryIfResult(Predicates.equalTo(false))//抛出runtime异常,checked异常时都会重试,但是抛出error不会重试.retryIfException()//重试策略.withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS))//尝试次数.withStopStrategy(StopStrategies.stopAfterAttempt(3)).build();return retryer;}
}

restTemplate

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;/**
* 优雅的http请求方式RestTemplate
* @Return:
*/
@Configuration
public class RestTemplateConfig {@Beanpublic RestTemplate restTemplate(ClientHttpRequestFactory factory) {return new RestTemplate(factory);}@Beanpublic ClientHttpRequestFactory simpleClientHttpRequestFactory() {SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();factory.setReadTimeout(5000);//msfactory.setConnectTimeout(15000);//msreturn factory;}
}

ThreadPoolExecutor配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;/*** @author qinlei* @description 线程池配置* @date 2021/4/14 11:35*/
@Configuration
public class ThreadsPoolsConfig {@Beanpublic void initThreadPool(){ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//配置核心线程数executor.setCorePoolSize(1);//配置最大线程数executor.setMaxPoolSize(20);//配置队列大小executor.setQueueCapacity(100);//配置线程池中的线程的名称前缀executor.setThreadNamePrefix("async-service-");//线程空闲后的最大存活时间executor.setKeepAliveSeconds(10);executor.setAllowCoreThreadTimeOut(true);// rejection-policy:当pool已经达到max size的时候,如何处理新任务// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//执行初始化executor.initialize();}
}

util

btoa加密

import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** @author qinlei* @description todo* @date 2021/10/21 16:03*/
public class BtoaEncode {//btoa加密方法public static String base64hash = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";/*str:要匹配的数据reg:正则匹配的规则*/public static boolean isMatcher(String str,String reg){//编译成一个正则表达式模式Pattern pattern = Pattern.compile(reg);//匹配模式Matcher matcher = pattern.matcher(str);if(matcher.matches()){return true;}return false;}public static String botaEncodePassword(String pwd){if(pwd==null||isMatcher(pwd,"([^\\u0000-\\u00ff])")){throw new Error("INVALID_CHARACTER_ERR");}int i = 0,prev=0,ascii,mod=0;StringBuilder result = new StringBuilder();while (i<pwd.length()){ascii = pwd.charAt(i);mod = i%3;switch (mod){//第一个6位只需要让8位二进制右移两位case 0:result.append(base64hash.charAt(ascii>>2));break;//第二个6位=第一个8位的后两位+第二个八位的前四位case 1:result.append(base64hash.charAt((prev&3)<<4|(ascii>>4)));break;//第三个6位=第二个8位的后四位+第三个8位的前两位//第四个6位 = 第三个8位的后6位case 2:result.append(base64hash.charAt((prev & 0x0f)<<2|(ascii>>6)));result.append(base64hash.charAt(ascii&0x3f));break;}prev = ascii;i++;}//循环结束后看mod, 为0 证明需补3个6位,第一个为最后一个8位的最后两位后面补4个0。另外两个6位对应的是异常的“=”;// mod为1,证明还需补两个6位,一个是最后一个8位的后4位补两个0,另一个对应异常的“=”if(mod == 0){result.append(base64hash.charAt((prev&3)<<4));result.append("==");}else if(mod == 1){result.append(base64hash.charAt((prev&0x0f)<<2));result.append("=");}return result.toString();}
}

xml转换相关工具类

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;import java.util.List;/*** @author qinlei* @description todo* @date 2021/10/21 23:21*/
public class XMLUtils {/*** 将xml转换为JSON对象** @param xml*            xml字符串* @return* @throws Exception*/public static JSONObject xmltoJson(String xml) throws Exception {JSONObject jsonObject = new JSONObject();Document document = DocumentHelper.parseText(xml);// 获取根节点元素对象Element root = document.getRootElement();iterateNodes(root, jsonObject);return jsonObject;}/*** 遍历元素** @param node*            元素* @param json*            将元素遍历完成之后放的JSON对象*/@SuppressWarnings("unchecked")public static void iterateNodes(Element node, JSONObject json) {// 获取当前元素的名称String nodeName = node.getName();// 判断已遍历的JSON中是否已经有了该元素的名称if (json.containsKey(nodeName)) {// 该元素在同级下有多个Object Object = json.get(nodeName);JSONArray array = null;if (Object instanceof JSONArray) {array = (JSONArray) Object;} else {array = new JSONArray();array.add(Object);}// 获取该元素下所有子元素List<Element> listElement = node.elements();if (listElement.isEmpty()) {// 该元素无子元素,获取元素的值String nodeValue = node.getTextTrim();array.add(nodeValue);json.put(nodeName, array);return;}// 有子元素JSONObject newJson = new JSONObject();// 遍历所有子元素for (Element e : listElement) {// 递归iterateNodes(e, newJson);}array.add(newJson);json.put(nodeName, array);return;}// 该元素同级下第一次遍历// 获取该元素下所有子元素List<Element> listElement = node.elements();if (listElement.isEmpty()) {// 该元素无子元素,获取元素的值String nodeValue = node.getTextTrim();json.put(nodeName, nodeValue);return;}// 有子节点,新建一个JSONObject来存储该节点下子节点的值JSONObject object = new JSONObject();// 遍历所有一级子节点for (Element e : listElement) {// 递归iterateNodes(e, object);}json.put(nodeName, object);return;}
}

wfs-t 核心操作

WFSTXmlGenerate

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jeecg.modules.wfs.exception.GeoXmlQlException;import java.util.List;
import java.util.Map;/*** @author qinlei* @description todo* @date 2021/10/21 16:44*/
public abstract class WFSTXmlGenerate {public static final String INSERT_METHOD = "Insert";public static final String UPDATE_METHOD = "Update";public static final String DELETE_METHOD = "Delete";private Document document;public Document getDocument() {return document;}public WFSTXmlGenerate() {document = DocumentHelper.createDocument();Element wfs = document.addElement("wfs:Transaction");wfs.addAttribute("version", "1.0.0");wfs.addAttribute("service", "WFS");wfs.addNamespace("ogc", "http://www.opengis.net/ogc");wfs.addNamespace("wfs", "http://www.opengis.net/wfs");wfs.addNamespace("gml", "http://www.opengis.net/gml");wfs.addNamespace("xsi", "http://www.opengis.net/xsi");wfs.addAttribute("xsi:schemaLocation", "http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd");}/*** 生成xml方法*/public abstract Document createXml(String businessId,String username, String typeName, String wfsPath, Map<String, Object> variables, Map<String, Object> params)throws GeoXmlQlException;/*** 创建k-v的节点** @param property* @param k* @param v geom时,该v为jsonObject* @param workspace 工作空间(geom需要 其余设置为空)*/void createKVNode(Element property, String k, Object v, String workspace) throws GeoXmlQlException {if (StringUtils.isBlank(workspace)) {Element key = property.addElement("wfs:Name");key.setText(k);Element value = property.addElement("wfs:Value");if (v != null)value.setText(v.toString());return;}Element element = property.addElement(workspace + ":" + k);if(v==null)return;JSONObject valueJson = JSON.parseObject(JSONObject.toJSONString(v));String type = valueJson.getString("type");if("general".equals(type) && v!=null){element.setText(valueJson.getString("value"));}else if("MultiLineString".equals(type)){String coordinates = valueJson.getString("coordinates");this.createMultiLineEle(element,type,coordinates);}else if("Point".equals(type)){String coordinates = valueJson.getString("coordinates");this.createPointEle(element,type,coordinates);}else{}}private void createMultiLineEle(Element element,String type,String coordinates){Element multiLineString = createGeomEle(element,type);Element lineStringMember = multiLineString.addElement("gml:lineStringMember");Element LineString = lineStringMember.addElement("gml:LineString");createCoorEle(LineString,coordinates);}private void createPointEle(Element element,String type,String coordinates){Element point = createGeomEle(element,type);createCoorEle(point,coordinates);}private Element createGeomEle(Element element, String type){Element point = element.addElement("gml:" + type);point.addAttribute("srsName", "http://www.opengis.net/gml/srs/epsg.xml#4326");return point;}private void createCoorEle(Element toPoint,String coordinates){Element coor = toPoint.addElement("gml:coordinates");coor.addAttribute("decimal", ".");coor.addAttribute("cs", ",");coor.addAttribute("ts", ";");coor.setText(coordinates);}public void createUpdateNode(Element element, String typeName, Map<String,Object> variables, Map<String,Object> params) throws GeoXmlQlException {Element updateNode = element.addElement("wfs:"+UPDATE_METHOD);updateNode.addAttribute("typeName",typeName);for (Map.Entry<String, Object> entry : variables.entrySet()) {Element property = updateNode.addElement("wfs:Property");this.createKVNode(property,entry.getKey(),entry.getValue(),null);}createFilterNode(updateNode,typeName.split(":")[0],params);}public void createInsertNode(String wfsPath,Element element, String typeName, Map<String,Object> variables) throws GeoXmlQlException {String[] typeSplit = typeName.split(":");String workspace = typeSplit[0];element.addNamespace(workspace,"http://"+workspace);element.addAttribute("xsi:schemaLocation",element.attributeValue("xsi:schemaLocation")+" http://"+workspace+" "+ wfsPath+"/DescribeFeatureType?typename="+typeName);Element insertNode = element.addElement("wfs:"+INSERT_METHOD);Element property = insertNode.addElement(typeName);for (Map.Entry<String, Object> entry : variables.entrySet()) {this.createKVNode(property,entry.getKey(),entry.getValue(),workspace);}
//        createFilterNode(element,workspace,params);}public void createDeleteNode(Element element, String typeName, Map<String, Object> variables, Map<String, Object> params) throws GeoXmlQlException {Element deleteNode = element.addElement("wfs:" + DELETE_METHOD);deleteNode.addAttribute("typeName", typeName);createFilterNode(deleteNode,typeName.split(":")[0], params);}/*** 创建fid过滤器节点* 为了安全性考虑 fids不允许非空 目前只提供id的过滤** @param element* @param params*/void createFilterNode(Element element,String workspace, Map<String, Object> params) throws GeoXmlQlException {if (params == null || params.isEmpty()) {return;}Element filter = element.addElement("ogc:Filter");for (Map.Entry<String, Object> objectEntry : params.entrySet()) {Element property = filter.addElement("ogc:PropertyIsEqualTo");Element nameEle = property.addElement("ogc:PropertyName");nameEle.setText(workspace+":"+objectEntry.getKey());Element literalEle = property.addElement("ogc:Literal");literalEle.setText(objectEntry.getValue() == null ? null : objectEntry.getValue().toString());}}}

插入操作实现类

import org.dom4j.Document;
import java.util.Map;/*** @author qinlei* @description todo* @date 2021/10/21 18:05*/
public class InsertWfsXmlGenerate extends WFSTXmlGenerate{public InsertWfsXmlGenerate() {super();}@Overridepublic Document createXml(String businessId,String updateUser,String typeName,String wfsPath, Map<String, Object> variables, Map<String, Object> params) {createInsertNode(wfsPath,this.getDocument().getRootElement(),typeName,variables);return this.getDocument();}}

修改编辑操作实现类

import org.dom4j.Document;
import org.jeecg.modules.wfs.exception.GeoXmlQlException;import java.util.Map;/*** @author qinlei* @description todo* @date 2021/10/21 18:05*/
public class UpdateWfsXmlGenerate extends WFSTXmlGenerate {public UpdateWfsXmlGenerate() {super();}@Overridepublic Document createXml(String businessId,String updateUser,String typeName,String wfsPath, Map<String, Object> variables, Map<String, Object> params) throws GeoXmlQlException{this.createUpdateNode(this.getDocument().getRootElement(),typeName,variables,params);return this.getDocument();}}

删除操作实现类

import org.dom4j.Document;
import java.util.Map;/*** @author qinlei* @description todo* @date 2021/10/21 18:05*/
class DeleteWfsXmlGenerate extends WFSTXmlGenerate {public DeleteWfsXmlGenerate() {super();}@Overridepublic Document createXml(String businessId, String updateUser, String typeName, String wfsPath, Map<String, Object> variables, Map<String, Object> params) {this.createDeleteNode(this.getDocument().getRootElement(), typeName, variables, params);return this.getDocument();}
}

插入加修改一个事务操作实现类

import org.dom4j.Document;
import org.jeecg.common.util.DateUtils;
import java.util.HashMap;
import java.util.Map;/*** @author qinlei* @description todo* @date 2021/10/25 11:33*/
public class InsertUpdateWfsXmlGenerate extends WFSTXmlGenerate{public InsertUpdateWfsXmlGenerate() {super();}@Overridepublic Document createXml(String businessId,String username,String typeName,String wfsPath, Map<String, Object> variables, Map<String, Object> params) {Map<String, Object> vars = new HashMap<>();vars.put("isvalid","0");vars.put("uploader",username);vars.put("uploadtime",DateUtils.getTimestamp());createUpdateNode(this.getDocument().getRootElement(),typeName,vars,params);createGeneralParams(variables,"isvalid","1");createGeneralParams(variables,"surveyor",username);createGeneralParams(variables,"surveydate", DateUtils.formatDate());createGeneralParams(variables,"index_id",businessId);createInsertNode(wfsPath,this.getDocument().getRootElement(),typeName,variables);return this.getDocument();}private void createGeneralParams(Map<String, Object> variables,String key,Object param){Map<String, Object> map = new HashMap<>();map.put("type","general");map.put("value",param);variables.put(key,map);}
}

异常类

/*** @author qinlei* @description geoserver专用异常类* @date 2021/10/21 17:56*/
public class GeoXmlQlException extends RuntimeException{private static final long serialVersionUID = 1L;public GeoXmlQlException(String message){super(message);}public GeoXmlQlException(Throwable cause){super(cause);}public GeoXmlQlException(String message, Throwable cause){super(message,cause);}
}

GEOTools封装工具

import com.alibaba.fastjson.JSONObject;
import com.github.rholder.retry.RetryException;
import com.github.rholder.retry.Retryer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.geotools.data.*;
import org.geotools.data.postgis.PostgisNGDataStoreFactory;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.feature.AttributeTypeBuilder;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.referencing.CRS;
import org.jeecg.common.util.RestUtil;
import org.jeecg.modules.wfs.exception.GeoXmlQlException;
import org.jeecg.modules.wfs.xmlGenerate.service.InsertUpdateWfsXmlGenerate;
import org.jeecg.modules.wfs.xmlGenerate.util.BtoaEncode;
import org.jeecg.modules.wfs.xmlGenerate.service.WFSTXmlGenerate;
import org.jeecg.modules.wfs.xmlGenerate.util.XMLUtils;
import org.opengis.feature.Feature;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;import java.io.*;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.ExecutionException;@Slf4j
@Service
public class GeoToolsManager {public static final int CREATE = 0;public static final int APPEND = 1;public static final int OVERWRITE = 2;private static CoordinateReferenceSystem crs4490;@Autowiredprivate Retryer<Boolean> retryer;@Autowiredprivate ThreadPoolTaskExecutor taskExecutor;public GeoToolsManager() {try {crs4490 = CRS.decode("EPSG:4490");} catch (FactoryException e) {e.printStackTrace();}}/*** 根据数据库连接参数,获取数据源** @return* @throws IOException*/private DataStore getPostgisDataStore(String host, String port, String user, String password, String database, String schema) throws IOException {Map<String, Object> params = new HashMap<>();params.put("dbtype", "postgis");params.put("host", host);params.put("port", port);params.put("schema", schema);params.put("database", database);params.put("user", user);params.put("passwd", password);params.put(PostgisNGDataStoreFactory.LOOSEBBOX.key, true);/*** 开启下面后测试数据(7000+要素)由原来的19秒加快到13秒*/params.put(PostgisNGDataStoreFactory.PREPARED_STATEMENTS.key, true);System.out.println("连接数据库");return DataStoreFinder.getDataStore(params);}public boolean shp2postgis(String shppath, String host, String port, String user, String password, String database, String schema, String tablename, String encode, int option) {// 首先尝试连接数据库DataStore pgDatastore = null;try {pgDatastore = getPostgisDataStore(host, port, user, password, database, schema);} catch (IOException e) {e.printStackTrace();System.err.println("连接数据库失败");return false;}// 尝试读取shpShapefileDataStore shpDataStore = null;try {shpDataStore = createShpDataStore(shppath, encode);} catch (IOException e) {e.printStackTrace();System.err.println("读取shp失败");return false;} catch (FactoryException e) {e.printStackTrace();System.err.println("读取shp失败");return false;}// 写入数据return writePostGIS(pgDatastore, shpDataStore, tablename, option);}/*** 根据shp文件创建数据源** @param shppath* @param encode* @return* @throws IOException* @throws FactoryException*/private ShapefileDataStore createShpDataStore(String shppath, String encode) throws IOException, FactoryException {ShapefileDataStore shapefileDataStore = new ShapefileDataStore(new File(shppath).toURI().toURL());// 根据用户指定的字符集编码设置解析编码shapefileDataStore.setCharset(Charset.forName(encode));// 如果没有指定坐标系,则强制使用4490CoordinateReferenceSystem crs = shapefileDataStore.getSchema().getCoordinateReferenceSystem();if (null == crs) {crs = crs4490;shapefileDataStore.forceSchemaCRS(crs);}// 根据数据源获取数据类型return shapefileDataStore;}/*** 根据数据源获取要素集合的迭代器** @param dataStore* @return* @throws IOException*/private FeatureIterator getIterator(ShapefileDataStore dataStore) throws IOException {// 获取shp数据源FeatureSource featureSource = dataStore.getFeatureSource();FeatureCollection featureCollection = featureSource.getFeatures();return featureCollection.features();}/*** 根据一个shp要素类型创建一个新的要素类型** @param tablename* @param shpfeaturetype* @return*/private SimpleFeatureType createPostGISType(String tablename, SimpleFeatureType shpfeaturetype) {SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();// 这些需要设置下默认空间字段,否则不会识别typeBuilder.setDefaultGeometry("geom");// 这里设置一下名称,当shp文件名是大写时需要换成小写typeBuilder.setName(tablename);// 设置坐标系,单独设置没有起到作用CoordinateReferenceSystem crs = shpfeaturetype.getCoordinateReferenceSystem();typeBuilder.setCRS(crs);// 新创建一个属性描述集合List<AttributeDescriptor> attributeDescriptors = new ArrayList<>();for (AttributeDescriptor attributeDescriptor : shpfeaturetype.getAttributeDescriptors()) {//属性构造器AttributeTypeBuilder build = new AttributeTypeBuilder();build.init(attributeDescriptor.getType());build.setNillable(true);//获取字段名,改为小写String name = StringUtils.isNotEmpty(attributeDescriptor.getLocalName()) ? attributeDescriptor.getLocalName().toLowerCase() : attributeDescriptor.getLocalName();if (attributeDescriptor instanceof GeometryDescriptor) {//修改空间字段名name = "geom";}//设置字段名build.setName(name);//创建新的属性类AttributeDescriptor descriptor = build.buildDescriptor(name, attributeDescriptor.getType());attributeDescriptors.add(descriptor);}typeBuilder.addAll(attributeDescriptors);return typeBuilder.buildFeatureType();}/*** 将shp数据源写入postgis数据源** @param pgDatastore* @param shpDataStore* @param tablename* @param option* @return* @throws IOException*/private boolean writePostGIS(DataStore pgDatastore, ShapefileDataStore shpDataStore, String tablename, int option) {SimpleFeatureType shpfeaturetype = null;try {shpfeaturetype = shpDataStore.getSchema();} catch (IOException e) {e.printStackTrace();System.err.println("shp读取失败");return false;}// 原shp数据源的迭代器FeatureIterator iterator = null;try {iterator = getIterator(shpDataStore);} catch (IOException e) {e.printStackTrace();System.err.println("shp读取失败");return false;}// 新建一个postgis要素类型构造器SimpleFeatureType postGISType = this.createPostGISType(tablename, shpfeaturetype);// 新建一个事务Transaction transaction = new DefaultTransaction();// 新建一个要素写对象FeatureWriter<SimpleFeatureType, SimpleFeature> featureWriter = null;try {// 表操作switch (option) {case CREATE:pgDatastore.createSchema(postGISType);System.out.println("postgis创建数据表成功");break;case APPEND:break;case OVERWRITE:pgDatastore.removeSchema(tablename);System.out.println("postgis删除数据表成功");pgDatastore.createSchema(postGISType);System.out.println("postgis创建数据表成功");break;default:System.err.println("非法操作");return false;}// 要素操作featureWriter = pgDatastore.getFeatureWriterAppend(tablename, transaction);System.out.println("开始写入");Date startTime = new Date();// 定义循环用到的变量Feature feature = null;SimpleFeature simpleFeature = null;Collection<Property> properties = null;Property property = null;String pname = null;Object pvalue = null;while (iterator.hasNext()) {feature = iterator.next();simpleFeature = featureWriter.next();properties = feature.getProperties();Iterator<Property> propertyIterator = properties.iterator();while (propertyIterator.hasNext()) {property = propertyIterator.next();pname = property.getName().toString().toLowerCase();if ("the_geom".equals(pname)) {pname = "geom";}// 如果值是空字符串则换成Null,表示无值pvalue = property.getValue();if (null == pvalue || (null != pvalue && StringUtils.isEmpty(property.getValue().toString()))) {pvalue = null;}simpleFeature.setAttribute(pname, pvalue);}featureWriter.write();}// 最后提交事务,可以加快导入速度transaction.commit();Date endTime = new Date();System.out.println("写入结束,共耗时:" + (endTime.getTime() - startTime.getTime()));System.out.println("shp导入postgis成功");return true;} catch (IOException e) {try {transaction.rollback();} catch (IOException ioException) {ioException.printStackTrace();}return false;} finally {try {transaction.close();} catch (IOException e) {e.printStackTrace();}if (null != iterator) {iterator.close();}if (null != featureWriter) {try {featureWriter.close();} catch (IOException e) {e.printStackTrace();}}shpDataStore.dispose();pgDatastore.dispose();}}private HttpHeaders createAuthorHeader(String username, String password) {HttpHeaders headers = RestUtil.getHeaderApplicationJson();headers.add("Authorization", "Basic " + BtoaEncode.botaEncodePassword(username + ":" + password));return headers;}@Value("${geoserver.wfs.error.path}")private String path;private String xmlString = null;/**** @param path 输出的地址* @param content 写入的内容*/private void writeFile2Disk(String path,String content){File file = new File(path);if (!file.getParentFile().exists()) {boolean result = file.getParentFile().mkdirs();}FileOutputStream fos= null;OutputStreamWriter osw= null;BufferedWriter  bw= null;try {fos = new FileOutputStream(file);osw = new OutputStreamWriter(fos, "UTF-8");bw = new BufferedWriter(osw);bw.write(content);} catch (Exception e) {e.printStackTrace();log.error("=====> 写入error xml 失败",e);} finally {//注意关闭的先后顺序,先打开的后关闭,后打开的先关闭try {if(bw!=null){bw.close();}if(osw!=null){osw.close();}if(fos!=null){fos.close();}} catch (IOException e) {e.printStackTrace();log.error("file流关闭失败,",e);}}}/**** @param ip* @param port* @param username* @param password* @param typeName* @param variables 要插入的参数* @param params 要进行修改的数据唯一编号* @return* @throws Exception*/public void insertUpdateByGeoWfs(String businessId,String updateUser,String ip, String port, String username, String password, String typeName, JSONObject variables, Map<String, Object> params){taskExecutor.execute(()->{try {retryer.call(()->{try {this.send2GeoWfs(businessId,updateUser,ip, port, username, password, typeName, variables, params, InsertUpdateWfsXmlGenerate.class);//成功则释放xmlStringthis.xmlString = null;return true;}catch (GeoXmlQlException e){log.error("请求失败,{}",e);return false;}});} catch (ExecutionException e) {e.printStackTrace();this.writeFile2Disk(this.path,this.xmlString);log.error("线程错误",e);} catch (RetryException e) {e.printStackTrace();log.error("重试错误",e);this.writeFile2Disk(this.path,this.xmlString);}});}private JSONObject send2GeoWfs(String businessId,String updateUser,String ip, String port, String username, String password, String typeName, JSONObject variables, Map<String, Object> params, Class<? extends WFSTXmlGenerate> c) throws Exception {HttpHeaders headers = this.createAuthorHeader(username, password);WFSTXmlGenerate generate = c.newInstance();Document document = generate.createXml(businessId,updateUser,typeName, "http://" + ip + ":" + port + "/geoserver/wfs", variables, params);log.info(document.asXML());this.xmlString = document.asXML();ResponseEntity<String> response = RestUtil.request("http://" + ip + ":" + port + "/geoserver/wfs", HttpMethod.POST, headers, null, document.asXML(), String.class);if(response.getStatusCode().is4xxClientError()){throw new GeoXmlQlException("host无法请求!");}if(response.getStatusCode().is5xxServerError()){throw new GeoXmlQlException("系统错误!");}if(response.getStatusCode().is2xxSuccessful() && response.getBody().contains("SUCCESS")){return XMLUtils.xmltoJson(response.getBody());}throw new GeoXmlQlException("请求错误!");}}

对外rest API 接口

import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.utils.GeoToolsManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.*;/*** @author qinlei* @description todo* @date 2021/10/22 10:17*/
@Slf4j
@Api(tags = "wfs-t操作geoserver")
@RestController
@RequestMapping("/wfs")
public class WFSController {@Autowiredprivate GeoToolsManager geoToolsManager;@PutMapping("/{typeName}/{user}/{businessId}")public Result<?> updateGeoserverData(@PathVariable String typeName,@PathVariable String user,@PathVariable String businessId,@RequestBody JSONObject jsonObject) {try {String ip = jsonObject.getString("ip");String port = jsonObject.getString("port");String username = jsonObject.getString("username");String password = jsonObject.getString("password");JSONObject variables = jsonObject.getJSONObject("variables");HashMap<String, Object> params = jsonObject.getObject("params", HashMap.class);geoToolsManager.insertUpdateByGeoWfs(businessId,user,ip,port,username,password,typeName,variables,params);return Result.OK();} catch (Exception e) {log.error("重试失败", e);return Result.error("重试失败");}}
}

接口使用方式

请求方式: put

请求路径url : http://localhost:10000/st-cloud/wfs/tscloud:mixed/qinlei/4563215482120214

请求body

{"ip":"10.0.0.15","port":"9095","username":"admin","password":"bych1234","variables":{"geom":{"type":"Point","coordinates":"108.2326554521,34.1215421254"},"objectid":{"type":"general","value":"11"},"hjd_bh":{"type":"general","value":"test"},"hj_type":{"type":"general","value":"gx"},"hj_reason":{"type":"general","value":"test-reason"}},"params":{"hj_reason":"test-reason2","objectid":"11"}
}

生成的xml

<?xml version="1.0" encoding="UTF-8"?>
<wfs:Transactionxmlns:ogc="http://www.opengis.net/ogc"xmlns:wfs="http://www.opengis.net/wfs"xmlns:gml="http://www.opengis.net/gml"xmlns:xsi="http://www.opengis.net/xsi"xmlns:scloud="http://scloud" version="1.0.0" service="WFS" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd http://scloud http://10.0.0.15:9095/geoserver/wfs/DescribeFeatureType?typename=scloud:mixed"><wfs:Update typeName="scloud:mixed"><wfs:Property><wfs:Name>uploader</wfs:Name><wfs:Value>qinlei</wfs:Value></wfs:Property><wfs:Property><wfs:Name>isvalid</wfs:Name><wfs:Value>0</wfs:Value></wfs:Property><wfs:Property><wfs:Name>uploadtime</wfs:Name><wfs:Value>2021-10-26 11:05:20.48</wfs:Value></wfs:Property><ogc:Filter><ogc:PropertyIsEqualTo><ogc:PropertyName>scloud:hj_reason</ogc:PropertyName><ogc:Literal>test-reason2</ogc:Literal></ogc:PropertyIsEqualTo><ogc:PropertyIsEqualTo><ogc:PropertyName>scloud:objectid</ogc:PropertyName><ogc:Literal>11</ogc:Literal></ogc:PropertyIsEqualTo></ogc:Filter></wfs:Update><wfs:Insert><scloud:mixed><scloud:geom><gml:Point srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"><gml:coordinates decimal="." cs="," ts=";">108.2326554521,34.1215421254</gml:coordinates></gml:Point></scloud:geom><scloud:objectid>11</scloud:objectid><scloud:hjd_bh>test</scloud:hjd_bh><scloud:hj_type>gx</scloud:hj_type><scloud:hj_reason>test-reason</scloud:hj_reason><scloud:isvalid>1</scloud:isvalid><scloud:surveyor>qinlei</scloud:surveyor><scloud:surveydate>2021-10-26</scloud:surveydate><scloud:index_id>4563215482120214</scloud:index_id></scloud:mixed></wfs:Insert>
</wfs:Transaction>

个人正在整理项目中用到的geotools,抽空本人会封装起来。 https://gitee.com/qlanto/geotools-kit

【java】【geoserver】java实现对geoserver图层及数据库的数据增删改相关推荐

  1. java调用oracle删除,使用IDEA对Oracle数据库进行简单增删改查操作

    1.1 java中的数据存储技术 在java中,数据库存取技术可分为如下几类: 1.jdbc直接访问数据库 2.jdo(java data object)是java对象持久化的新的规范,也是一个用于存 ...

  2. java用poi实现对word读取和修改操作

    java编程要实现对word的操作没有vb那种编程语言来得容易,得借助一些开源组件,其中就包括jacob.poi等, 而poi应用得最为广泛,对word2003和2007的读和写word操作都十分方便 ...

  3. jaba窗体连接mysql增删改查_知识实现——Java使用jdbc连接MySql数据库,实现增删改查...

    Java使用jdbc连接MySql数据库,实现增删改查 首先,导入MySql连接数据库的jar包,我用的是 mysql连接jar包 DB类,用于获得数据库连接 import java.sql.Driv ...

  4. Java 实现Dbhelper 支持大数据增删改

    引言 在做项目的时候,技术选型很重要,在底层的方法直接影响了我们对大数据访问以及修改的速度,在Java中有很多优秀的ORM框架,比如说:JPA,Hibernate 等等,正如我们所说的,框架有框架的好 ...

  5. cactus java,使用cactus实现对servlet进行单元测试

    使用cactus实现对servlet进行单元测试 步骤如下: [1]创建Web工程ServletTestDemo 在myeclipse中创建Web project,命名为ServletTestDemo ...

  6. 【SpringBoot集成ElasticSearch 02】Java HTTP Rest client for ElasticSearch Jest 客户端集成(配置+增删改查测试源码)【推荐使用】

    1.简介 SpringBoot 项目初始化时就有 NoSQL 选项 Spring Data Elasticsearch(Access+Driver) 此时 pom 文件里引入的依赖是 spring-b ...

  7. java三年工作经验工资_工作三年还是只会增删改查,Java 程序员如何进阶?

    大部分的企业级应用从本质上看,都是在做增删查改,但是有些公司的业务复杂而专业,有些公司应用的在线用户很多,你做的增删查改和别人做的增删查改,可能会有极大的区别,举个例子: 你做一个新闻资讯网站,首页上 ...

  8. 数据库创建、增删改查、java连接数据库

    数据库 1.数据库类型 1.1.MySQL[市面上大多数用的,开源] 1.2.Oracle[付费] 1.3.SQLServer[微软体系下的] 1.4.PGSQL 2.MySQL数据库安装 2.1.解 ...

  9. Java使用iText实现对PDF文件的操作

    iText是著名的开放项目,是用于生成PDF文档的一个java类库.通过iText不仅可以生成PDF或rtf的文档,而且可以将XML.Html文件转化为PDF文件. http://itextpdf.c ...

最新文章

  1. what do we want for advertiesement
  2. RocketMQ的历史发展
  3. MySQL5.7绿色版安装
  4. 爬了知乎200万数据,图说程序员都喜欢去哪儿工作~
  5. Leetcode每日一题:116.populating-next-right-pointers-in-each-node(填充每个节点的下一个右侧节点指针)
  6. deque stack java_一文弄懂java中的Queue家族
  7. 华为方舟编译器 下载 和 LiteOS Studio Setup 2019-04-16.exe SDK下载
  8. 3.Oracle中的函数
  9. 模糊C均值聚类算法---图像分割(python)
  10. Power BI报表常见格式 1 - 报告
  11. 基于GitHub的敏捷学习方法之道与术
  12. Chrome导出扩展程序
  13. 深入理解分布式技术 - 容器化技术
  14. Word秘籍:如何30秒做出精美的Word排版
  15. wampServer 设置
  16. SQL优化(三) 查询条件优化
  17. 2019 xnuca pwn vexx
  18. Codeforces 76A Gift 题解
  19. 【NRF51822】百度手环开源源码分析--存储部分
  20. 120行python代码解锁10000分微信跳一跳

热门文章

  1. TortoiseGit第一次使用
  2. ResNet(残差网络模型)原理解读-包括residual block与BN原理介绍
  3. 搭建自己的Gitlab仓库
  4. WiFi基础学习心得
  5. [学习计划]QSC Q-SYS Level 1 音频处理器
  6. Arduino UNO开发板开箱体验
  7. openGauss 账本数据库函数
  8. ctp java_CTP API 开发之二 :制作CTP java版 API
  9. HDFS Federation联邦
  10. ubuntu升级内核到指定版本