从零开始,构建电子地图网站:0_9_web+InitializingBean启动加载本地缓存
我有点忘了当初的宏愿了,所以要回到网站上看看,http://worldmap.harvard.edu/maps/chinaX。
先下载个有道翻译,看下左侧的Overlays,忽然发现除了《中国历史地图集》上有的政区和治所沿革外。还有很多自然地理、农业地理、军事地理,人口变迁、海岸线变迁、黄河变迁的图层,这些数据都没有。
那还是先用现有的数据,参考《中国历史地图集》的索引顺序,以朝代划分图层吧。
商周(春秋战国)、秦、汉(西汉东汉)、晋(三国西晋东晋)、唐、五代十国、宋、元、明、清。
图层展示是用朝代划分的,点击可见覆盖物的时候,弹出infowindow,显示属性。
先看下数据量级,多的话,就分开,不多的话,就全部返给前端。
v6_time_cnty_pts_utf_wgs84这张表对象有10522个。
v6_time_pref_pts_utf_wgs84 这张表对象有5226个。
v6_time_pref_pgn_utf_wgs84这张表对象有3830个。
那么还是按照年代分吧。
商周:<-221
秦:-220~-202
汉:-201~220
晋、三国:221~589
唐、隋:590~907
五代十国:908~960
宋:961~1276
元1277~1368
明1369~1644
清1645~1840
开始对工程进行改造。
一、model
D:\gismap\java\gismap\src\main\java\com\history\gismap\model\GeometryModel.java
首先把model中的类改成GeometryModel,以兼容更多的geometry类型。
package com.history.gismap.model; import com.vividsolutions.jts.geom.Geometry; import lombok.Getter; import lombok.Setter; import lombok.ToString; @Getter @Setter @ToString public class GeometryModel { private Integer gId; private String namePy; private String nameCh; private String nameFt; private String presLoc; private String typePy; private String typeCh; private String levRank; private Integer begYr; private String begRule; private Integer endYr; private String endRule; private String geoSrc; private String compiler; private String gecomplr; private String checker; private String entDate; private String begChgTy; private String endChgTy; private Geometry geometry; }
二、dao
D:\gismap\java\gismap\src\main\java\com\history\gismap\dao\MapDao.java
我们只需要查询,并查询三张表。
把不必要的删掉,补充需要的。
package com.history.gismap.dao; import com.history.gismap.model.GeometryModel; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Service; @Service public interface MapDao { GeometryModel getCntyPoint(@Param("gId") Integer gId); GeometryModel getPrefPoint(@Param("gId") Integer gId); GeometryModel getprefPolygon(@Param("gId") Integer gId); }
三、Mapper
D:\gismap\java\gismap\src\main\resources\mapper\HistoryGISMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.history.gismap.dao.MapDao" > <resultMap id="geometryModelResult" type="com.history.gismap.model.GeometryModel"> <result property="gId" column="gid" jdbcType="BIGINT"/> <result property="namePy" column="name_py" jdbcType="VARCHAR"/> <result property="nameCh" column="name_ch" jdbcType="VARCHAR"/> <result property="nameFt" column="name_ft" jdbcType="VARCHAR"/> <result property="presLoc" column="pres_loc" jdbcType="VARCHAR"/> <result property="typePy" column="type_py" jdbcType="VARCHAR"/> <result property="typeCh" column="type_ch" jdbcType="VARCHAR"/> <result property="levRank" column="lev_rank" jdbcType="VARCHAR"/> <result property="begYr" column="beg_yr" jdbcType="BIGINT"/> <result property="begRule" column="beg_rule" jdbcType="VARCHAR"/> <result property="endYr" column="end_yr" jdbcType="BIGINT"/> <result property="endRule" column="end_rule" jdbcType="VARCHAR"/> <result property="geoSrc" column="geo_src" jdbcType="VARCHAR"/> <result property="compiler" column="compiler" jdbcType="VARCHAR"/> <result property="gecomplr" column="gecomplr" jdbcType="VARCHAR"/> <result property="checker" column="checker" jdbcType="VARCHAR"/> <result property="entDate" column="ent_date" jdbcType="VARCHAR"/> <result property="begChgTy" column="beg_chg_ty" jdbcType="VARCHAR"/> <result property="endChgTy" column="end_chg_ty" jdbcType="VARCHAR"/> <result property="geometry" column="geom" typeHandler="com.history.gismap.mybatis.GeometryTypeHandler"/> </resultMap> <sql id="CNTY_PTS"> v6_time_cnty_pts_utf_wgs84 </sql> <sql id="PREF_PTS"> v6_time_pref_pts_utf_wgs84 </sql> <sql id="PREF_PGN"> v6_time_pref_pgn_utf_wgs84 </sql> <sql id="BASE_COLUMN"> gid,name_py,name_ch,name_ft,pres_loc,type_py,type_ch,lev_rank,beg_yr,beg_rule,end_yr,end_rule,geo_src,compiler,gecomplr,checker,ent_date,beg_chg_ty,end_chg_ty,geom </sql> <select id="getCntyPoint" resultMap="geometryModelResult"> SELECT <include refid="BASE_COLUMN"></include> FROM <include refid="CNTY_PTS"/> WHERE gid=#{gId} LIMIT 1 </select> <select id="getprefPolygon" resultMap="geometryModelResult"> SELECT <include refid="BASE_COLUMN"></include> FROM <include refid="PREF_PGN"/> WHERE gid=#{gId} LIMIT 1 </select> <select id="getPrefPoint" resultMap="geometryModelResult"> SELECT <include refid="BASE_COLUMN"></include> FROM <include refid="PREF_PTS"/> WHERE gid=#{gId} LIMIT 1 </select> </mapper>
四、localcache
直接查库较慢,所以我们把内容存在本地内存中,从内存中访问。
新建一个包:D:\gismap\java\gismap\src\main\java\com\history\gismap\localcache
在包下新建一个类:
D:\gismap\java\gismap\src\main\java\com\history\gismap\localcache\GeometryCache.java
这个类继承了InitializingBean,当程序启动的时候,数据就会加载。
程序中加入了map<>,按照表名区分cntypts、prefpts、prefpgn,每张表,每张表存成一个list,新建一个查询方法getDynastyGeometry,用表名和时间区间查询对象。
package com.history.gismap.localcache;
import com.history.gismap.dao.MapDao;
import com.history.gismap.model.GeometryModel;
import lombok.extern.java.Log;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class GeometryCache implements InitializingBean {
Map<String, List<GeometryModel>> historyGis =new HashMap<>();
@Autowired
private MapDao mapDao;
@Override
public void afterPropertiesSet() throws Exception {
List<GeometryModel> cntyGeometry=new ArrayList<>();
int i=1;
while (mapDao.getCntyPoint(i)!=null){
cntyGeometry.add(mapDao.getCntyPoint(i));
i++;
}
historyGis.put("cntypts",cntyGeometry);
List<GeometryModel> prefPtsGeometry=new ArrayList<>();
i=1;
while (mapDao.getPrefPoint(i)!=null){
prefPtsGeometry.add(mapDao.getCntyPoint(i));
i++;
}
historyGis.put("prefpts",prefPtsGeometry);
List<GeometryModel> prefPgnGeometry=new ArrayList<>();
i=1;
while (mapDao.getprefPolygon(i)!=null){
prefPgnGeometry.add(mapDao.getprefPolygon(i));
i++;
}
historyGis.put("prefpgn",prefPgnGeometry);
}
public List<GeometryModel> getDynastyGeometry(String category,Integer start,Integer end){
List<GeometryModel> result=new ArrayList<>();
for (GeometryModel g:historyGis.get(category)) {
if((g.getBegYr()>=start && g.getBegYr()<=end)||(g.getEndYr()>=start&&g.getEndYr()<=end)){
result.add(g);
}
}
return result;
}
}
五.Service
D:\gismap\java\gismap\src\main\java\com\history\gismap\service\MapService.java
保证结构的规范性,service层还是要写下。
package com.history.gismap.service;
import com.history.gismap.model.GeometryModel;
import java.util.List;
public interface MapService {
List<GeometryModel> getDynastyGeom(String category,Integer start,Integer end);
}
D:\gismap\java\gismap\src\main\java\com\history\gismap\service\impl\MapServiceImpl.java
impl
package com.history.gismap.service.impl;
import com.history.gismap.dao.MapDao;
import com.history.gismap.localcache.GeometryCache;
import com.history.gismap.model.GeometryModel;
import com.history.gismap.service.MapService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class MapServiceImpl implements MapService {
@Autowired
private GeometryCache geometryCache;
@Override
public List<GeometryModel> getDynastyGeom(String category,Integer start,Integer end){
return geometryCache.getDynastyGeometry(category,start,end);
}
}
六、controller
控制层。
D:\gismap\java\gismap\src\main\java\com\history\gismap\controller\MapController.java
用json跟前端交互数据,里面有一个方法geometryToJson,将geometry对象转成json,其实geometry.toString也可以将geometry转成String,但String有长度限制,转成json更安全些。
package com.history.gismap.controller;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.history.gismap.model.GeometryModel;
import com.history.gismap.service.MapService;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller
@RequestMapping(value = "/history")
public class MapController {
@Autowired
private MapService mapService;
@ResponseBody
@GetMapping("/geometry")
public JSONObject getPoint(@RequestParam("category") String category,@RequestParam("start") Integer start,@RequestParam("end") Integer end){
List<GeometryModel> result=mapService.getDynastyGeom(category,start,end);
JSONObject jsonObject=new JSONObject();
jsonObject.put("number",result.size());
JSONArray jsonArray=new JSONArray();
for (GeometryModel g:result) {
JSONObject geom=new JSONObject();
geom.put("gid",g.getGId());
geom.put("namepy",g.getNamePy());
geom.put("namech",g.getNameCh());
geom.put("nameft",g.getNameFt());
geom.put("presloc",g.getPresLoc());
geom.put("typepy",g.getTypePy());
geom.put("typech",g.getTypeCh());
geom.put("levrank",g.getLevRank());
geom.put("begyr",g.getBegYr());
geom.put("begrule",g.getBegRule());
geom.put("endyr",g.getEndYr());
geom.put("endrule",g.getEndRule());
geom.put("geosrc",g.getGeoSrc());
geom.put("compiler",g.getCompiler());
geom.put("gecomplr",g.getGecomplr());
geom.put("checker",g.getChecker());
geom.put("entdate",g.getEntDate());
geom.put("begchgty",g.getBegChgTy());
geom.put("endchgty",g.getEndChgTy());
geom.put("geometry",geometryToJson(g.getGeometry()));
jsonArray.add(geom);
}
jsonObject.put("list",jsonArray);
return jsonObject;
}
private JSONObject geometryToJson(Geometry geometry){
JSONObject jsonObject=new JSONObject();
jsonObject.put("type",geometry.getGeometryType());
JSONArray coorList=new JSONArray();
for (int i=0;i<geometry.getNumGeometries();i++){
JSONArray coors=new JSONArray();
Coordinate[] coordinates=geometry.getGeometryN(i).getCoordinates();
for (Coordinate c:coordinates) {
JSONObject jsonObjectCoor=new JSONObject();
jsonObjectCoor.put("lng",c.x);
jsonObjectCoor.put("lat",c.y);
coors.add(jsonObjectCoor);
}
coorList.add(coors);
}
jsonObject.put("coordinates",coorList);
return jsonObject;
}
}
七、测试:
启动程序。
D:\gismap\java\gismap\src\main\java\com\history\gismap\GismapApplication.java
启动后测试一下。
http://localhost:8080/history/geometry?category=prefpgn&start=-5000&end=-221
localhost:8080/history/geometry?category=prefpts&start=-5000&end=-221
localhost:8080/history/geometry?category=cntypts&start=-5000&end=-221
页面显示都是一坨的,chrome下载个JSONView吧。
按照方法参见:https://www.cnblogs.com/feiyu159/p/8968850.html
https://github.com/gildas-lormeau/JSONView-for-Chrome
安装完JSONView之后,页面长这样,比一坨好看多了。
整个工程已经完成的差不多了。
接着再建立一个分支,上传到git。
https://github.com/yimengyao13/gismap.git
分支:initbean
程序设计体系是数据、后端、前端分离,正常来说,后端要考虑到数据有问题、跟数据库连接有问题的情况是会存在的,而且为了后期维护,需要加上打印log日志、编写文档,不过说实话,日志是能看懂的,但自己的代码、自己写的文档,时间长了,真是一点也看不懂了。
这套程序,还少一些try-catch,log、注释等。