leaflet地图上的图层导出为shape文件,要求采用国家2000坐标系
参考资料:
leaflet.js API:https://leafletjs.com/reference-1.6.0.html
WKT、WKB、GeoJSON:https://blog.csdn.net/xcymorningsun/article/details/89848096
选中图层,获取图层的属性:
var arrCoordinates = feature.geometry.coordinates; //保存选中的图层的坐标
var arrProperties = feature.properties; //保存选中的图层的属性
var geometryType = feature.geometry.type; //保存选中的图层的类型
feature.geometry.coordinates获取到的坐标是这样的:[114.509255, 22.759991],要把它转换成x坐标以2开头,y坐标以5开头:[2519488.256,556778.197]。
点击导出(下载)按钮,下载图层为shp文件:
// 导出单个shp文件
function outFeayureshp() {
var coordinates = wktGeometryType(geometryType,arrCoordinates);
var form = $("<form></form>");
form.attr("action", "/map/leafletMap/outShp");
form.attr("method", "post");
form.attr("enctype", "multipart/form-data");
form.append("<input type='input' name='coordinates' value='"+ JSON.stringify(coordinates) + "' />");
form.append("<input type='input' name='arrProperties ' value='"+ JSON.stringify(arrProperties ) + "' />");
form.append("<input type='input' name='geometryType' value='"+geometryType+"' />");
$("body").append(form);
form.submit();
form.remove();
}
//区分图层类型的方法
function wktGeometryType(geometryType,coordinates){
var coordinatesArrs = [];
if(geometryType == "Point"){ //点
var y = coordinates[0];
var x = coordinates[1];
var arr = [];
var arrs = new Array();
arrs = ctarr(x, y);
arr = [ arrs[0], arrs[1] ];
coordinatesArrs = arr;
}else if(geometryType == "LineString"){ //线
for (var i = 0; i < coordinates.length; i++) {
var y = coordinates[i][0];
var x = coordinates[i][1];
var arr = [];
var arrs = new Array();
arrs = ctarr(x, y);
arr = [ arrs[0], arrs[1] ];
coordinatesArrs[i] = arr;
}
}else if (geometryType == "Polygon") { //面
for (var i = 0; i < coordinates.length; i++) {
var py = coordinates[i];
var coor = [];
for (var j = 0; j < py.length; j++) {
var y = py[j][0]; // lng
var x = py[j][1]; // lat
var arr = [];
var arrs = new Array();
arrs = ctarr(x, y);
arr = [ arrs[0], arrs[1] ];
coor[j] = arr;
}
coordinatesArrs[i]=coor;
}
}else if(geometryType == "MultiPolygon"){ //多面体
for (var i = 0; i < coordinates.length; i++) {
var coor = [];
for (var j = 0; j < coordinates[i].length; j++) {
var py = coordinates[i][j];
var coor1 = [];
for (var n = 0; n < py.length; n++) {
var y = py[n][0];
var x = py[n][1];
var arr = [];
var arrs = new Array();
arrs = ctarr(x, y);
arr = [ arrs[0], arrs[1] ];
coor1[n] = arr;
}
coor[j] = coor1;
}
coordinatesArrs[i] = coor;
}
}else if(geometryType == "MultiLineString"){ //线集合
for (var i = 0; i < coordinates.length; i++) {
var py = coordinates[i];
var coor = [];
for (var j = 0; j < py.length; j++) {
var y = py[j][0];
var x = py[j][1];
var arr = [];
var arrs = new Array();
arrs = ctarr(x, y);
arr = [ arrs[0], arrs[1] ];
coor[j] = arr;
}
coordinatesArrs[i] = coor;
}
}else if(geometryType == "MultiPoint"){ //点集合
for (var i = 0; i < coordinates.length; i++) {
var y = coordinates[i][0];
var x = coordinates[i][1];
var arr = [];
var arrs = new Array();
arrs = ctarr(x, y);
arr = [ arrs[0], arrs[1] ];
coordinatesArrs[i] = arr;
}
}
return coordinatesArrs;
}
// 坐标转换等方法,x坐标以2开头,y坐标以5开头
function ctarr(x, y) {
var arr = new Array(x, y);
var acr = L.latLng(arr);
var catLng = crs.project(acr);
var arrs = new Array(catLng.x, catLng.y);
return arrs;
}
controller层的代码:
/**
* 下载shp文件
* */
@RequestMapping(value="outShp", method=RequestMethod.POST)
@ResponseBody
public void outShp(HttpServletRequest request, HttpServletResponse response){
leafletService.outShp(request,response);
}
leafletService中的代码:
/**
* 下载shp文件
* */
public void outShp(HttpServletRequest request, HttpServletResponse response){
try {
JsonMapper jsonMapper = new JsonMapper();
List jsonListY = jsonMapper.fromJson(request.getParameter("coordinates"),List.class);
GeoToolsUtils gu=new GeoToolsUtils();
String downFile = Global.getUserfilesBaseDir("shpfiles","download")+"shapefile.shp"; //未压缩的文件主体
File file = gu.writes(downFile,jsonListY,request.getParameter("arrProperties"),request.getParameter("geometryType"));
String filename = file.getName();
InputStream fis = new BufferedInputStream(new FileInputStream(file));
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
response.reset();
// 先去掉文件名称中的空格,然后转换编码格式为utf-8,保证不出现乱码,这个文件名称用于浏览器的下载框中自动显示的文件名
response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.replaceAll(" ", "").getBytes("utf-8"),"iso8859-1"));
response.addHeader("Content-Length", "" + file.length());
OutputStream os = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
os.write(buffer);// 输出文件
os.flush();
os.close();
file.delete();
}catch (Exception e){
e.printStackTrace();
}
}
GeoToolsUtils 中的代码
public class GeoToolsUtils {
//投影坐标系(国家2000坐标系)
private final static String strWKT = "PROJCS[\"CGCS2000_3_Degree_GK_CM_114E\",GEOGCS[\"GCS_China_Geodetic_Coordinate_System_2000\",DATUM[\"D_China_2000\",SPHEROID[\"CGCS2000\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Gauss_Kruger\"],PARAMETER[\"False_Easting\",500000.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",114.0],PARAMETER[\"Scale_Factor\",1.0],PARAMETER[\"Latitude_Of_Origin\",0.0],UNIT[\"Meter\",1.0]]";
//一个反序列化的类
private final static JsonMapper jsonMapper = new JsonMapper();
/**
* shape文件下载
* @param filepath 下载路径
* @param jsonListY 坐标
* @param jsonListR 属性
* @return
*/
public File writes(String filepath,List<List> jsonListY,String jsonListR,String geometryType) {
try {
JsonNode tree = jsonMapper.readTree(jsonListR);
File file = new File(filepath);
Map<String, Serializable> params = new HashMap<>();
params.put(ShapefileDataStoreFactory.URLP.key, file.toURI().toURL());
ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
Charset charset = Charset.forName("UTF-8");
SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
FeatureWriter<SimpleFeatureType, SimpleFeature> writer = null;
tb.setName("shapefile"); //设置下载的文件名
ds.setCharset(charset); //设置编码
//jsonMapper.fromJson()是反序列化POJO或简单Collection如List<String>的方法
Map<String,String> fromJsonPr = jsonMapper.fromJson(tree.toString(),HashMap.class);
switch (geometryType) {
case "Point":
tb.add("the_geom", Point.class);
break;
case "LineString":
tb.add("the_geom", LineString.class);
break;
case "Polygon":
tb.add("the_geom", Polygon.class);
break;
case "MultiPoint":
tb.add("the_geom", MultiPoint.class);
break;
case "MultiLineString":
tb.add("the_geom", MultiLineString.class);
break;
case "MultiPolygon":
tb.add("the_geom", MultiPolygon.class);
break;
}
for(String key:fromJsonPr.keySet()){
tb.add(key, String.class);
}
ds.createSchema(tb.buildFeatureType());
if (null==writer){
writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
}
SimpleFeature feature = writer.next();
WKTReader reader = new WKTReader( new GeometryFactory() );
wktGeo(feature,reader,geometryType,jsonListY,fromJsonPr);
writer.write();
writer.close();
ds.dispose();
File zips=zipShapeFile(filepath);
file.delete();
return zips;
}catch(Exception e) {
e.printStackTrace();
}
return null;
}
public void wktGeo(SimpleFeature feature,WKTReader reader,String type,List<List> jsonListY,Map<String,String> fromJsonPr) {
/* POINT (30 10)
* LINESTRING (30 10, 10 30, 40 40)
* POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))
* POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10),(20 30, 35 35, 30 20, 20 30))
* MULTIPOINT (10 40, 40 30, 20 20, 30 10)
* MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10))
* MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)),((20 35, 10 30, 10 10, 30 5, 45 20, 20 35),(30 20, 20 15, 20 25, 30 20)))
* MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))
* */
String strp="";
try {
switch (type) {
case "Point":
strp += jsonListY.get(0)+" "+jsonListY.get(1);
Point point = (Point) reader.read("POINT("+strp+")");
feature.setAttribute("the_geom", point);
break;
case "LineString":
for (int i = 0; i < jsonListY.size(); i++) {
strp += jsonListY.get(i).get(0)+" "+jsonListY.get(i).get(1);
if(i != jsonListY.size()-1) strp+=",";
}
LineString lineString = (LineString) reader.read("LINESTRING("+strp+")");
feature.setAttribute("the_geom", lineString);
break;
case "Polygon":
strp="(";
for (int i = 0; i < jsonListY.size(); i++) {
List<List> list = jsonMapper.fromJson(jsonListY.get(i).toString(),List.class);
if (i>0) strp += ",(";
for(int j=0; j<list.size(); j++){
strp += list.get(j).get(0)+" "+list.get(j).get(1);
if(j != list.size()-1) strp+=",";
else strp += ")";
}
}
Polygon polygon = (Polygon) reader.read("POLYGON("+strp+")");
feature.setAttribute("the_geom", polygon);
break;
case "MultiPoint":
for (int i = 0; i < jsonListY.size(); i++) {
strp += jsonListY.get(i).get(0)+" "+jsonListY.get(i).get(1);
if(i != jsonListY.size()-1) strp+=",";
}
MultiPoint multiPoint = (MultiPoint) reader.read("MULTIPOINT("+strp+")");
feature.setAttribute("the_geom", multiPoint);
break;
case "MultiLineString":
strp="(";
for (int i = 0; i < jsonListY.size(); i++) {
List<List> list = jsonMapper.fromJson(jsonListY.get(i).toString(),List.class);
if (i>0) strp += ",(";
for(int j=0; j<list.size(); j++){
strp += list.get(j).get(0)+" "+list.get(j).get(1);
if(j != list.size()-1) strp+=",";
else strp += ")";
}
}
MultiLineString mLineString = (MultiLineString) reader.read("MULTILINESTRING("+strp+")");
feature.setAttribute("the_geom", mLineString);
break;
case "MultiPolygon":
strp="((";
for (int i = 0; i < jsonListY.size(); i++) {
List<List> list = jsonMapper.fromJson(jsonListY.get(i).toString(),List.class);
if (i>0) strp += ",((";
for(int j=0; j<list.size(); j++){
if (j>0) strp += ",(";
List<List> list1 = jsonMapper.fromJson(list.get(j).toString(),List.class);
for (int n = 0; n < list1.size(); n++) {
strp += list1.get(n).get(0)+" "+list1.get(n).get(1);
if(n != list1.size()-1) strp+=",";
else strp += ")";
}
if(j != list.size()-1) strp+=",";
else strp += ")";
}
}
MultiPolygon mPolygon = (MultiPolygon) reader.read("MULTIPOLYGON("+strp+")");
feature.setAttribute("the_geom", mPolygon);
break;
}
for(String key:fromJsonPr.keySet()){
if (fromJsonPr.get(key) != null) {
String str = String.valueOf(fromJsonPr.get(key));
feature.setAttribute(key,str);
}
}
System.out.println(feature.getAttribute("the_geom"));
} catch (Exception e) {
e.printStackTrace();
}
}
public File zipShapeFile(String shpPath){
try{
File shpFile = new File(shpPath);
String shpRoot = shpFile.getParentFile().getPath(),
_shpName = shpFile.getName(),
shpName = _shpName.substring(0, _shpName.lastIndexOf("."));
String zipPath = shpRoot+File.separator+shpName+".zip";
File zipFile = new File(zipPath);
InputStream input = null;
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
// zip的名称为
zipOut.setComment(shpName);
String[] shpFiles = new String[]{
shpRoot+File.separator+shpName+".dbf",
shpRoot+File.separator+shpName+".prj",
shpRoot+File.separator+shpName+".shp",
shpRoot+File.separator+shpName+".shx",
};
for(int i=0;i<shpFiles.length;i++){
//获取后缀名为 prj 的文件
String string = shpFiles[i].substring(shpFiles[i].lastIndexOf(".") + 1);
if ("prj".equals(string)) {
FileWriter fw = new FileWriter(shpRoot+File.separator+shpName+".prj");
fw.write(strWKT);//往.prj文件中写入投影坐标系
fw.flush();
fw.close();
}
File _file = new File(shpFiles[i]);
input = new FileInputStream(_file);
zipOut.putNextEntry(new ZipEntry(_file.getName()));
int temp = 0;
while ((temp = input.read()) != -1) {
zipOut.write(temp);
}
input.close();
}
zipOut.close();
return zipFile;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}