共计 9756 个字符,预计需要花费 25 分钟才能阅读完成。
一、应用场景:
基于天地图开发时需要远程调用天地图的 js、css 以及各层级瓦片数据,但是在内网环境或者非互联网环境下无法远程访问资源,下面详细介绍本人离线开发的步骤。
二、天地图资源下载
1. 天地图 key 申请
进入天地图网址天地图 API。
点击“控制台”进行账号注册,注册成功后,点击右上角“创建新应用”,得到 Key 名称。
2. 天地图 js、css 资源下载
需要下载的天地图静态资源包括:
tiandituApi.js(http://api.tianditu.gov.cn/api?v=4.0&tk=)
components.js(https://api.tianditu.gov.cn/v4.0/components.js)
military.js(https://api.tianditu.gov.cn/v4.0/military.js)
service.js(https://api.tianditu.gov.cn/v4.0/service.js)
tianditu4.0.css(http://api.tianditu.gov.cn/v4.0/css/tianditu4.0.css)
将四个文件的代码复制到本地。
3. 天地图瓦片数据下载
在天地图官网,点击“地图 API”。
网站最下面有个瓦片数据连接地址。
但是不同的瓦片有不同的下载地址,上两张图中有瓦片的分类,包括:矢量底图、矢量注记、影像底图等等,不同的瓦片图不同的下载地址。
如果根据瓦片地址一个个去下载,工作量巨大,而且各个点位不清晰,无法采用人工方式去下载,我们可以使用 java 代码去统一抓取瓦片数据。
java 抓取瓦片代码:
public class TileDownload {
// 不同的瓦片采用不同的下载地址,一般用的比较多的还是矢量地图
// 矢量(行政)- 等经纬度
public static String vec_c = "http://{server}.tianditu.gov.cn/vec_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}";
// 矢量(行政)- 墨卡托
public static String vec_w = "http://{server}.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}";
// 矢量注记(行政)- 等经纬度
public static String cva_c = "http://{server}.tianditu.gov.cn/cva_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}";
// 矢量注记(行政)- 墨卡托
public static String cva_w = "http://{server}.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}";
// 影像 - 等经纬度
public static String img_c = "http://{server}.tianditu.gov.cn/img_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}";
// 影像 - 墨卡托
public static String img_w = "http://{server}.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}";
// 影像注记 - 等经纬度
public static String cia_c = "http://{server}.tianditu.gov.cn/cia_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}";
// 影像注记 - 墨卡托
public static String cia_w = "http://{server}.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}";
// 地形 - 等经纬度
public static String ter_c = "http://{server}.tianditu.gov.cn/ter_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}";
// 地形 - 墨卡托
public static String ter_w = "http://{server}.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}";
// 地形注记 - 等经纬度
public static String cta_c = "http://{server}.tianditu.gov.cn/cta_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cta&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}";
// 地形注记 - 墨卡托
public static String cta_w = "http://{server}.tianditu.gov.cn/cta_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cta&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk={tk}";
public static String[] servers = {"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"};
public static void main(String[] args){
String basePath = "D:/lianyungangtianditu";// 设置下载的路径
// 这里放你的天地图开发者秘钥,注意天地图 API 访问次数限制
String tk = "1125258295c5d403d7fbf5e096***";
// 将需要下载的图层地址放到一个数组中,不需要下载的可以去掉
String[] urlArr = {vec_c, vec_w, cva_c, cva_w, img_c, img_w, cia_c, cia_w, ter_c, ter_w, cta_c, cta_w};
// 天地图一共有 18 个图层,从 1 -18,越往后,瓦片数据量越大
int minZoom = 1;
int maxZoom = 18;
// 中国的经纬度
//double startLat = 53.58;// 开始纬度(从北到南)//double endLat = 2.7;// 结束纬度(从北到南)//double startLon = 73.2;// 开始经度(从西到东)//double endLon = 135.15;// 结束经度(从西到东)// 江苏连云港的经纬度,这边经纬度可以根据自己需要下载的地市或者省份去百度查询经纬度信息,我这边只下载连云港
double startLat = 35.07;// 开始纬度(从北到南)double endLat = 34.12;// 结束纬度(从北到南)double startLon = 118.24;// 开始经度(从西到东)double endLon = 119.48;// 结束经度(从西到东)ExecutorService exe = Executors.newFixedThreadPool(15);
for(int i=0; i -1){out.write(b, 0, len);
out.flush();}
out.close();
in.close();
loop = false;
} catch (Exception e) {loop = true;}
}
if(loop){System.out.println("下载失败:"+newUrl);
System.exit(0);// 下载失败后停止任务
}
}
}
});
}
}
}
}else{
// 墨卡托
if(startLat> 85.051128){startLat = 85.051128;}
if(endLat -1){out.write(b, 0, len);
out.flush();}
out.close();
in.close();
loop = false;
} catch (Exception e) {loop = true;}
}
if(loop){System.out.println("下载失败:"+newUrl);
System.exit(0);// 下载失败后停止任务
}
}
}
});
}
}
}
}
}
exe.shutdown();
while (true) {
try {Thread.sleep(1000L);
} catch (InterruptedException e) { }
if (exe.isTerminated()) {break;}
}
}
public static InputStream getFileInputStream(String url) throws Exception{
InputStream is = null;
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet request = new HttpGet(url);
request.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
HttpResponse response = httpclient.execute(request);
response.setHeader("Content-Type", "application/octet-stream");
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {HttpEntity entity = response.getEntity();
is = entity.getContent();}
return is;
}
}
下载的时间会特别长,下载后的文件路径如下:
4. 瓦片下载问题汇总
问题一:下载失败
解决:将代码中 tk 变量改成自己申请的 key。
问题二:下载中断
解决:下载中断的原因是 key 的访问次数受限制,个人 key 每天只能访问 1 万次,如果中途下载终端,只需要再次新建应用,采用新应用的 key 进行再次访问,每个账号可以申请五个 key 信息。
问题二:中断后重新下载,又会重头开始下载
解决一:根据下载的瓦片层级,需要手动调整代码,如果需要可以直接问我;
解决二:采用下面的实时加载方法,下面有介绍。
三、Java 后端读取瓦片数据
瓦片数据下载成功后,前端需要访问数据库加载瓦片信息,代码如下:
@GetMapping("getTiles/{LAYER}")
public void getTiles(HttpServletResponse response, @PathVariable("LAYER") String LAYER,
@RequestParam("TILECOL") String TILECOL,
@RequestParam("TILEROW") String TILEROW,
@RequestParam("TILEMATRIX")String TILEMATRIX) throws IOException {
String tilesPath = "D:lianyungangtianditu";
String tk = "e4237d5eefb7b69a4a472fd64f***";
ServletOutputStream out = null;
try {BufferedImage image = ImageIO.read(Files.newInputStream(Paths.get(tilesPath + "/" + LAYER + "/" + TILEMATRIX + "/" + TILEROW + "/" + TILECOL + ".png")));
response.setContentType("image/png");
response.setHeader("Cache-Control", "public");
out = response.getOutputStream();
ImageIO.write(image, "png", out);
} catch (Exception e) {response.setStatus(HttpServletResponse.SC_NOT_FOUND);
} finally {if (out != null) {out.flush();
out.close();}
}
}
代码采用 restful 风格,四个参数分别为:
LAYER:瓦片类型(cva_c、cva_w、vec_c 等)
TILEMATRIX、TILEROW 代表:当前瓦片类型下的文件夹
TILECOL 代表:瓦片号
四、Vue 前端静态资源修改
1. 引入天地图.js
在 vue 的 index.html 中分别引入之前下载的 4 个 js 文件和 css 文件。
2. 修改 tiandituApi.js
天地图 js 文件默认远程访问瓦片数据,需要将远程访问瓦片的方式改成访问本地瓦片。
定义一个本地服务器的变量,将需要访问的瓦片请求链接修改成刚刚我们自己写的后端请求路径。
// 定义一个本地服务器地址变量
window.TMAP_URL = 'http://localhost:8080/tiles';
// 修改 js 中瓦片访问地址,本人只用了天地图的矢量瓦片,所以其他的就不需要修改了
r:function(){return window.TMAP_URL+"/getTiles/vec_c?"},
T:function(){return window.TMAP_URL+"/getTiles/cva_c?"},
t:function(){return window.TMAP_URL+"/getTiles/vec_w?"},
Y:function(){return window.TMAP_URL+"/getTiles/cva_w?"}
以上就是整个方案的修改。
五、瓦片实时加载(有需要再用)
问题:当使用 java 方法进行下载瓦片数据时,受限于 key 的访问次数限制、天地图图层数等原因,尤其是到最后面,图层越高,瓦片数据量越大,会导致下载中断。
解决:可以采用按需加载的方式,在地图进行访问的时候,根据访问的位置,进行实时下载瓦片到本地。代码如下:
@RestController
public class MapController {
/**
*
* @param response
* @param LAYER
* @param TILECOL
* @param TILEROW
* @param TILEMATRIX
* @throws IOException
*/
@GetMapping("getTiles/{LAYER}")
public void getTiles(HttpServletResponse response, @PathVariable("LAYER") String LAYER,
@RequestParam("TILECOL") String TILECOL,
@RequestParam("TILEROW") String TILEROW,
@RequestParam("TILEMATRIX")String TILEMATRIX) throws IOException {
String tilesPath = "D:lianyungangtianditu";
String tk = "e4237d5eefb7b69a4a472fd64f***";
ServletOutputStream out = null;
try {BufferedImage image = ImageIO.read(Files.newInputStream(Paths.get(tilesPath + "/" + LAYER + "/" + TILEMATRIX + "/" + TILEROW + "/" + TILECOL + ".png")));
if(null!=imageGary){image=imageGary;}*/
response.setContentType("image/png");
response.setHeader("Cache-Control", "public");
out = response.getOutputStream();
ImageIO.write(image, "png", out);
} catch (Exception e) {
// 如果没有找到图片,就去下载,然后保存进去
//response.setStatus(HttpServletResponse.SC_NOT_FOUND);
this.saveImg(tilesPath, LAYER, TILEMATRIX, TILEROW, TILECOL, tk);
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
} finally {if (out != null) {out.flush();
out.close();}
}
}
public void saveImg(String path, String layer, String TILEMATRIX, String TILEROW, String TILECOL, String tk){StringBuffer sb = new StringBuffer();
sb.append("http://t0.tianditu.gov.cn/")
.append(layer);
if (layer.equals("cva_w") || layer.equals("cva_c")){sb.append("/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles");
}else {sb.append("/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles");
}
sb.append("&TILEMATRIX=").append(TILEMATRIX)
.append("&TILEROW=").append(TILEROW)
.append("&TILECOL=").append(TILECOL)
.append("&tk=").append(tk);
System.out.println(sb.toString());
String filePath = path + "/" + layer + "/" + TILEMATRIX + "/" + TILEROW + "/" + TILECOL + ".png";
File file = new File(filePath);
if(!file.exists()){if(!file.getParentFile().exists()){file.getParentFile().mkdirs();}
try {InputStream in = getFileInputStream(sb.toString());
OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
byte[] b = new byte[8192];
int len = 0;
while((len = in.read(b)) > -1){out.write(b, 0, len);
out.flush();}
out.close();
in.close();} catch (Exception e) {}}
}
public static InputStream getFileInputStream(String url) throws Exception{
InputStream is = null;
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet request = new HttpGet(url);
request.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
HttpResponse response = httpclient.execute(request);
response.setHeader("Content-Type", "application/octet-stream");
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {HttpEntity entity = response.getEntity();
is = entity.getContent();}
return is;
}
}
原文地址: Java vue 天地图离线开发