您的位置:首页 > 编程语言 > Java开发

通过Java代码自动发布Geoserver的地图服务WMS

2018-08-12 17:21 716 查看
GeoServer 顾名思义。是一个Server,它是开源的,允许用户查看和编辑地理数据的服务器,它可以比较容易的在用户之间迅速共享空间地理信息。利用Geoserver可以把数据作为maps/images来发布(利用WMS来实现)也可以直接发布实际的数据(利用WFS来实现),它同时也提供了修改,删除和新增的功能(利用WFS-T)。

为什么要使用GeoServer?相比较同类产品ArcServer不是一个开源GIS服务器,所有想在Web地图应用开发中使用ArcServer就需要付费,而且价格比较高(ref:GeoServer与ArcServer对比)。本文将完成用ArcGIS切片好的数据,通过代码自动发布Geoserver 中。如果不清楚手动发布流程和实现的效果,可以看我的另外一篇文章:GeoServer手动发布本地Shapefile地图

一、引入pom依赖

指定远程仓库

<repository>
<id>GeoSolutions</id>
<url>http://maven.geo-solutions.it/</url>
</repository>

加入dependency

<dependency>
<groupId>it.geosolutions</groupId>
<artifactId>geoserver-manager</artifactId>
<version>1.7.0</version>
</dependency>


二、编写发布工具类

import it.geosolutions.geoserver.rest.GeoServerRESTManager;
import it.geosolutions.geoserver.rest.GeoServerRESTPublisher;
import it.geosolutions.geoserver.rest.GeoServerRESTReader;
import org.apache.commons.httpclient.NameValuePair;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ResourceBundle;

public class GeoServerUtil {
public static final String RESTURL;

public static final String RESTUSER;

public static final String RESTPW;

public static final String GS_VERSION;

public static java.net.URL URL;

public static GeoServerRESTManager manager;

public static GeoServerRESTReader reader;

public static GeoServerRESTPublisher publisher;

private static ResourceBundle bundle = ResourceBundle.getBundle("constant");

//初始化用户名密码赋值,发布图集时会进行身份认证
static {
RESTURL = getenv("gsmgr_resturl", "http://localhost:18080/geoserver/");
RESTUSER = getenv("gsmgr_restuser","admin");
RESTPW = getenv("gsmgr_restpw", "geoserver");
GS_VERSION = getenv("gsmgr_version", "2.11.2");
try {
URL = new URL(RESTURL);
manager = new GeoServerRESTManager(URL, RESTUSER, RESTPW);
reader = manager.getReader();
publisher = manager.getPublisher();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}

//获取环境信息
private static String getenv(String envName, String envDefault) {
String env = System.getenv(envName);
String prop = System.getProperty(envName, env);
return prop != null ? prop : envDefault;
}

public  static boolean  publishShpAndReloadStore(String workspace,String zipFilePath,String storeName,String layerName,String styleType,String coordinateSystem) throws  Exception{
//坐标系,判断是否为空
if(ComUtil.isEmpty(coordinateSystem)){
coordinateSystem=GeoServerRESTPublisher.DEFAULT_CRS;
}
//存在相应的工作区
if(!reader.existsWorkspace(workspace)){
publisher.createWorkspace(workspace);
}
boolean published;
if(Constant.AtlasStyleType.ATLAS_STYLE_TYPE_5.equals(styleType)){
published = publisher.publishShp(workspace, storeName, layerName, new File(zipFilePath),coordinateSystem,
new NameValuePair[]{new NameValuePair("charset", "GBK")});
}else{
//读取style文件
String styleFile = bundle.getString("geoServer-dir")+"/"+styleType+".sld";
File file  = new File(styleFile);
String strStyle = "style"+styleType;
//是否已经发布了改style
if(!reader.existsStyle(workspace,strStyle)){
publisher.publishStyleInWorkspace(workspace,file,strStyle);
}
//创建发布类,放入用户名密码和url
GeoServerRESTPublisher geoServerRESTPublisher  =new GeoServerRESTPublisher(RESTURL,RESTUSER,RESTPW);
//工作区      数据存储名称
published =geoServerRESTPublisher.publishShp( workspace,  storeName, new NameValuePair[]{new NameValuePair("charset", "GBK")},
//图层名称               指定用于发布资源的方法
layerName, it.geosolutions.geoserver.rest.GeoServerRESTPublisher.UploadMethod.FILE,
//        zip图集的地址           坐标系         样式
new File(zipFilePath).toURI(),coordinateSystem, strStyle);
}
return published;
}

public static boolean unPublishShpAndReloadStore(String workspace,String storeName){
return publisher.removeLayer(workspace,storeName);
}

}


三、解压zip文件工具类

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;

import java.io.*;
import java.nio.channels.FileChannel;
import java.util.*;

/**
* <p>
* 文件操作类
* </p>
*
* @author liugh
* @since 2018/3/20
*/
public class FileUtils {

private static ResourceBundle bundle = ResourceBundle.getBundle("constant");

//配置文件里获得,根目录地址 /data/test-version
public static String fileUploadPath =bundle.getString("file-upload.dir");

/**
* 判断当前文件是否是zip文件
*
* @param fileName
*            文件名
* @return true 是
*/
public static boolean isZip(String fileName) {
return fileName.toLowerCase().endsWith(Constant.FilePostFix.ZIP_FILE);
}

/**
* 删除目录
* @param fileName
*/
public static void removeDocument(String fileName){
File file=new File(fileName);
if(file.exists() && file.isFile()) {
file.delete();
}
if(file.isDirectory()){
delDir(fileName);
}
if (fileName.lastIndexOf(Constant.FilePostFix.ZIP_FILE) > 0) {
delDir(fileName.substring(0,fileName.lastIndexOf(Constant.FilePostFix.ZIP_FILE))+"/");
}

}

/**
* 获取坐标系
* @param filePath
* @return
*/
public static String getCoordinate(String filePath){
try{
InputStreamReader reader = new InputStreamReader(new FileInputStream(filePath),"UTF-8");
BufferedReader br = new BufferedReader(reader);
String line;
StringBuilder sb  =new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
reader.close();
String str = sb.toString();
String substring = str.substring(str.indexOf("\"") + 1, str.indexOf("\","));
return parseCoordinate(substring);
} catch(IOException e){
e.printStackTrace();
}
return null;
}

private static String parseCoordinate(String  coordinate){
switch (coordinate){
case "Beijing_1954_GK_Zone_21N": return "EPSG:21481";
case "Beijing_1954_GK_Zone_22N": return "EPSG:21482";
case "GCS_Xian_1980": return "EPSG:4610";
case "GCS_WGS_1984": return "EPSG:4326";
default:return null;
}
}

/**
* 检查第一级目录是否有.shp文件
* @param sourcePath
* @return
*/
public static boolean checkZipFile(String sourcePath){
System.setProperty("sun.zip.encoding", System.getProperty("sun.jnu.encoding"));
ZipFile zipFile =null;
try {
File sourceFile = new File(sourcePath);
zipFile = new ZipFile(sourcePath, "gbk");
if ((!sourceFile.exists()) && (sourceFile.length() <= 0)) {
throw new Exception("要解压的文件不存在!");
}
Enumeration<?> e = zipFile.getEntries();
while (e.hasMoreElements()) {
ZipEntry zipEnt = (ZipEntry) e.nextElement();
if (zipEnt.isDirectory()) {
return false;
}
if(zipEnt.getName().endsWith(".shp")){
return true;
}
}

} catch (Exception e) {
e.printStackTrace();
return false;
}finally {
try {
if(null!=zipFile){
zipFile.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}

private static List<String> listFile = new ArrayList<>();

/**
* 将存放在sourceFilePath目录下的源文件,打包成fileName名称的zip文件,并存放到zipFilePath路径下
* (把指定文件夹下的所有文件目录和文件都压缩到指定文件夹下)
* @param sourceFilePath
*            :待压缩的文件路径
* @param zipFilePath
*            :压缩后存放路径
* @param fileName
*            :压缩后文件的名称
* @return
*/
public static boolean fileToZip(String sourceFilePath,String zipFilePath,String fileName)throws  Exception{
boolean flag = false;
FileOutputStream fos =null;
ZipOutputStream zos =null;
BufferedInputStream bis =null;
FileInputStream  fis =null;
BufferedOutputStream bufferedOutputStream =null;
File sourceFile = new File(sourceFilePath);
if(sourceFile.exists() == false){
throw new Exception("待压缩的文件目录:"+sourceFilePath+"不存在.");
}else{
try {
File zipFile = new File(zipFilePath +fileName );
if(zipFile.exists()){
throw new Exception(zipFilePath + "目录下存在名字为:" + fileName +Constant.FilePostFix.ZIP_FILE +"打包文件.");
}else{
File[] sourceFiles = sourceFile.listFiles();
if(null == sourceFiles || sourceFiles.length<1){
throw new Exception("待压缩的文件目录:" + sourceFilePath + "里面不存在文件,无需压缩.");
}else{
fos = new FileOutputStream(zipFile);
bufferedOutputStream = new BufferedOutputStream(fos);
zos = new ZipOutputStream(bufferedOutputStream);
byte[] bufs = new byte[1024*10];
for(int i=0;i<sourceFiles.length;i++){
//创建ZIP实体,并添加进压缩包
ZipEntry zipEntry = new ZipEntry(sourceFiles[i].getName());
zos.putNextEntry(zipEntry);
//读取待压缩的文件并写进压缩包里
fis = new FileInputStream(sourceFiles[i]);
bis = new BufferedInputStream(fis, Constant.BYTE_BUFFER *Constant.BUFFER_MULTIPLE);
int read;
while((read=bis.read(bufs, 0, Constant.BYTE_BUFFER *Constant.BUFFER_MULTIPLE)) != -1){
zos.write(bufs,0,read);
}
fis.close();
bis.close();
}
flag = true;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally{
//关闭流
try {
if (null != bis) {
bis.close();
}
if (null != zos) {
zos.close();
}
if (null != bufferedOutputStream) {
bufferedOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
return flag;
}

public static boolean updateLayerNameByZipFile(String sourcePath,String targetLayerName) {
File file = new File(sourcePath);
if (file.isDirectory()) {
String[] fileList = file.list();
if (!ComUtil.isEmpty(fileList)) {
for (String fileName : fileList) {
File oldName = new File(sourcePath + File.separator + fileName);
File newName = new File(sourcePath + File.separator + targetLayerName + fileName.substring(fileName.lastIndexOf(".")));
if (".xml".equals(fileName.substring(fileName.lastIndexOf(".")))) {
newName = new File(sourcePath + File.separator + targetLayerName + fileName.substring(fileName.lastIndexOf(".shp")));
}
oldName.renameTo(newName);
}
return true;
}
return false;
}
return false;
}

/**
* 保存文件到临时目录
* @param inputStream 文件输入流
* @param fileName 文件名
*/
public static void savePic(InputStream inputStream, String fileName) {
OutputStream os = null;
try {
// 保存到临时文件
// 1K的数据缓冲
byte[] bs = new byte[1024];
// 读取到的数据长度
int len;
// 输出的文件流保存到本地文件
File tempFile = new File(fileUploadPath);
if (!tempFile.exists()) {
tempFile.mkdirs();
}
os = new FileOutputStream(tempFile.getPath() + File.separator + fileName);
// 开始读取
while ((len = inputStream.read(bs)) != -1) {
os.write(bs, 0, len);
}
}catch (Exception e) {
e.printStackTrace();
} finally {
// 完毕,关闭所有链接
try {
os.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

public static String saveFile(InputStream file, int type, String name, String tag) throws Exception {
Date time = new Date();
String fileName = fileName(time, type, name,tag);
File newFile = getNewFile(fileName);
File oldFile = createTemporaryFile(file, name);
copyFile(newFile, new FileInputStream(oldFile));
oldFile.delete();
return fileName;
}

public static File createTemporaryFile(InputStream file, String name) throws Exception {
File temp = new File(name);
OutputStream out = new FileOutputStream(temp);
try {
int byteCount = 0;
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = file.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
byteCount += bytesRead;
}
out.flush();
}
finally {
try {
file.close();
}
catch (IOException ex) {
}
try {
out.close();
}
catch (IOException ex) {
}
}
return temp;
}

private static void copyFile(File newFile, FileInputStream file) throws Exception {
FileOutputStream outFile = new FileOutputStream(newFile);
FileChannel inC = file.getChannel();
FileChannel outC = outFile.getChannel();
int length = 2097152;
while (true) {
if (inC.position() == inC.size()) {
inC.close();
outC.close();
outFile.close();
file.close();
return ;
}
if ((inC.size() - inC.position()) < 20971520) {
length = (int) (inC.size() - inC.position());
}else {
length = 20971520;
}
inC.transferTo(inC.position(), length, outC);
inC.position(inC.position() + length);
}

}

public static File getNewFile(String fileName) throws IOException {
String filePath = bundle.getString("file-upload.dir") + fileName;
File newFile = new File(filePath);
File fileParent = newFile.getParentFile();
if(!fileParent.exists()){
fileParent.mkdirs();
}
if (!newFile.exists()){
newFile.createNewFile();
}
return newFile;
}

/**
* 文件保存路径
* @param time
* @param type
* @param name
* @return
*/
private static String fileName(Date time, int type, String name,String tag) {
StringBuffer str = new StringBuffer();
if (type== Constant.FileType.FILE_IMG) {
str.append(Constant.FileType.FILE_IMG_DIR);
}
if (type==Constant.FileType.FILE_ZIP) {
str.append(Constant.FileType.FILE_ZIP_DIR);
}
if (type==Constant.FileType.FILE_VEDIO) {
str.append(Constant.FileType.FILE_VEDIO_DIR);
}
if (type==Constant.FileType.FILE_APK) {
str.append(Constant.FileType.FILE_APK_DIR);
}
if (type==Constant.FileType.FIVE_OFFICE) {
str.append(Constant.FileType.FIVE_OFFICE_DIR);
}
str.append(DateTimeUtil.formatDateToString(time));
str.append("/");
str.append(DateTimeUtil.currentidDatetime());
if(!ComUtil.isEmpty(tag)) {
str.append(tag);
}
str.append("-"+name);
return str.toString();
}
public static String getFileUrl(String fileDir){
return bundle.getString("file-upload.url") + fileDir;
}

/**
* 删除文件目录
* @param path
*/
private static void delDir(String path){
File dir=new File(path);
if(dir.exists()){
File[] tmp=dir.listFiles();
for(int i=0;i<tmp.length;i++){
if(tmp[i].isDirectory()){
delDir(path+File.separator+tmp[i].getName());
}else{
tmp[i].delete();
}
}
dir.delete();
}
}

/**
* 解压zip格式的压缩文件到指定位置
*
* @param sourcePath
*            压缩文件
* @param targetPath
*            解压目录
* @throws Exception
*/
public static boolean unZipFiles(String sourcePath, String targetPath) throws Exception {
System.setProperty("sun.zip.encoding", System.getProperty("sun.jnu.encoding"));
InputStream is =null;
BufferedInputStream bis =null;
try {
(new File(targetPath)).mkdirs();
File sourceFile = new File(sourcePath);
// 处理中文文件名乱码的问题
ZipFile zipFile = new ZipFile(sourcePath, "UTF-8");
if ((!sourceFile.exists()) && (sourceFile.length() <= 0)) {
throw new Exception("要解压的文件不存在!");
}
String strPath, gbkPath, strtemp;
File tempFile = new File(targetPath);
strPath = tempFile.getAbsolutePath();
Enumeration<?> e = zipFile.getEntries();
while (e.hasMoreElements()) {
ZipEntry zipEnt = (ZipEntry) e.nextElement();
gbkPath = zipEnt.getName();
if (zipEnt.isDirectory()) {
strtemp = strPath + File.separator + gbkPath;
File dir = new File(strtemp);
dir.mkdirs();
continue;
} else {
// 读写文件
is = zipFile.getInputStream((ZipEntry) zipEnt);
bis = new BufferedInputStream(is);
gbkPath = zipEnt.getName();
strtemp = strPath + File.separator + gbkPath;
// 建目录
String strsubdir = gbkPath;
for (int i = 0; i < strsubdir.length(); i++) {
if ("/".equalsIgnoreCase(strsubdir.substring(i, i + 1))) {
String temp = strPath + File.separator + strsubdir.substring(0, i);
File subdir = new File(temp);
if (!subdir.exists()) {
subdir.mkdir();
}
}
}
FileOutputStream fos = new FileOutputStream(strtemp);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int c;
while ((c = bis.read()) != -1) {
bos.write((byte) c);
}
bos.flush();
fos.close();
bos.close();
}
}
zipFile.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}finally {
try {
if (is != null) {
is.close();
}
if (bis != null) {
bis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

public static boolean deleteUploadedFile(String fileName) {
String filePath = bundle.getString("file-upload.dir") + fileName;
File file =  new File(filePath);
if(file.exists()){
if(file.isFile()) {
file.delete();
}else{
removeDocument(fileName);
}
return true;
}else{
return false;
}
}

public static int getFileType(String originalFilename) {
String postFix = originalFilename.split("//.")[originalFilename.split("//.").length-1];
if(Arrays.asList(Constant.FilePostFix.IMAGES).contains(postFix)){
return Constant.FileType.FILE_IMG;
}
if(Arrays.asList(Constant.FilePostFix.ZIP).contains(postFix)){
return Constant.FileType.FILE_ZIP;
}
if(Arrays.asList(Constant.FilePostFix.VIDEO).contains(postFix)){
return Constant.FileType.FILE_VEDIO;
}
if(Arrays.asList(Constant.FilePostFix.APK).contains(postFix)){
return Constant.FileType.FILE_APK;
}
if(Arrays.asList(Constant.FilePostFix.OFFICE).contains(postFix)){
return Constant.FileType.FIVE_OFFICE;
}
return Constant.FileType.FILE_IMG;
}
}


四、可能会遇到的问题

1.坐标系问题(显示位置错乱)。

GeoServer的坐标系要根据ArcGIS切片好的数据的图集坐标系一一对应起来,不然会位置错乱。左边坐标系可以在图集的.prj文件里找到,右边是GeoServer需要的,目前常用的是这几个



2.发布图集报错(表现为点击OpenLayers直接下载了空文件):

可能与style有关,检查编码。我遇到一个大坑,在windows上修改的带中文的.sld文件复制到linux上就会乱码,导致图集报错。

可能与zip文件内容有关(尽量用.zip,rar有低版本问题解决不了)。zip压缩的文件必须是第一级目录就有.shp等文件,不能包含目录



获取url发布地址问题。可以通过读取本地Geoserver所在路径,加上发布的工作区名字,拼接图层的id到url上即可。

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.ResourceBundle;

/**
* <p>
*  xml解析工具类
* </p>
*
* @author liugh
* @since 2018/4/3
*/
public class XmlUtil {

private static String GEO_SERVER_PATH = ResourceBundle.getBundle("constant").getString("geoServer-dir");

private static String BUNDLE_URL = ResourceBundle.getBundle("constant").getString("geoServer-url");

private static String XML_ELEMENT_NAME="latLonBoundingBox";

public static void main(String[] args)throws Exception {
getMapUrl("1522723368940","unitMap");
}

//获取图集发布地址
public static String  getMapUrl(String layerId,String workspace)throws Exception{
File file =new File(GEO_SERVER_PATH+File.separator+workspace);
String[] fileList = file.list();
StringBuilder mapUrl = new StringBuilder();
mapUrl.append(BUNDLE_URL+workspace)
.append("/wms?service=WMS&version=1.1.0&request=GetMap&layers=").append(workspace+":"+layerId).append("&styles=&bbox=");
if(!ComUtil.isEmpty(fileList)){
for (String fileName:fileList) {
if(fileName.equals(layerId)){
String []  coordinates = readXMLDocument(layerId,workspace);
mapUrl.append(coordinates[0]+","+coordinates[2]+","+coordinates[1]+","+coordinates[3]).append("&width=768&height=437&srs=").append(coordinates[4]);
}
}
}else{
return null;
}
return  mapUrl.toString();
}

private static String []  readXMLDocument(String layerId, String workspace){
File file = new File(GEO_SERVER_PATH+File.separator+workspace+
File.separator+layerId+File.separator+layerId+File.separator+"featuretype.xml");
if (!file.exists()) {
try {
throw new IOException("Can't find the path");
} catch (IOException e) {
e.printStackTrace();
}
}
//创建SAXReader对象
SAXReader saxReader = new SAXReader();
Document document;
try {
//读取文件 转换成Document
document = saxReader.read(file);
//获取根节点元素对象  遍历当前节点下的所有节点
for (Iterator iter = document.getRootElement().elementIterator(); iter.hasNext();){
//获取节点
Element e1 = (Element) iter.next();

//如果过节点的名称等于beanName那么继续进入循环读取beanName节点下的所有节点
if(e1.getName().equalsIgnoreCase(XML_ELEMENT_NAME)){
String [] ss = new String[5];
int i =0;
//遍历beanName当前节点下的所有节点
for (Iterator iter1 = e1.elementIterator(); iter1.hasNext();){
Element e2 = (Element) iter1.next();
ss[i]= e2.getStringValue();
i++;
}
return ss;
}
}
} catch (DocumentException e) {
e.printStackTrace();
return null;
}
return null;
}
}


3.过滤属性问题。

当鼠标点击GeoServer发布地图的某个区域,会在下方显示属性。我这里通过Http方式获取到所有值,然后用Jsoup来解析,类似于爬虫的方式。返回属性后可以根据业务屏蔽或展示一些属性值。

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* <p>
*  HTTP请求工具类
* </p>
*
* @author liugh
* @since 2018/3/20
*/
public class HttpLayerPropertyUtil {

/**
* 获取图层所有属性
* @param layerPreviewURL
* @return
*/
public static List<Map<String,String>> getLayerProperty(String layerPreviewURL){
List<Map<String,String>>  retList = new ArrayList();
try {
Document doc = Jsoup.connect(layerPreviewURL).get();
Elements select = doc.select("th");
Elements select1 = doc.select("td");
for (int i = 0; i < select.size(); i++) {
HashMap<String,String> tempMap = new HashMap<>(16);
tempMap.put(cutValue(select.get(i).toString()), cutValue(select1.get(i).toString()));
retList.add(tempMap);
}
return retList;
} catch (IOException e) {
System.out.println("页面获取异常!");
e.printStackTrace();
}
return null;
}

private static String cutValue(String s){
String substring = s.substring(4,s.indexOf("</"));
return substring;
}
}

如果读者还遇到其他问题,或者想要资源,可以在下方评论,我看见就会回复你。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐