上一节已经搭建好了项目结构,连接好了数据库,可以通过url进行简单的增删改查操作。这节主要是针对geometry几何对象的增删改查,这个就需要mybatis自定义类型了!
我们的数据有几何类型:点和面。
1
| SELECT geom FROM v6_time_cnty_pts_utf_wgs84 LIMIT 1
|
查询的结果geom是geohash编码的:0101000020E6100000A165DD3F16C55B4089963C9E96814340
1
| sql:SELECT st_astext(geom) FROM v6_time_cnty_pts_utf_wgs84 LIMIT 1
|
查询结果是WKT格式的:
POINT(111.079483 39.012409)
- WKT和geohash都是空间数据的存储格式,但是WKT比geohash编码更直观;在mybatis中,直接查geometry对象,返回的是字符类型的geohash,但是交互的时候,我们不能返一串geohash码。对于后端来说,我们应该直接操作geometry类,给前端提供json数组
1 引入依赖
Jts是空间处理jar包,功能很全很强大,这个jar包的maven依赖,我们之前已经在pom中引用了,再加一个解析json的jar包。
1 2 3 4 5 6 7
| <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency>
|
2 增加mybatis自定义类
新建一个mybatis
包==》新建一个GeometryTypeHandler.java
类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| @MappedTypes(Geometry.class) public class GeometryTypeHandler extends BaseTypeHandler<Geometry> {
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Geometry geometry, JdbcType jdbcType) throws SQLException { PGobject pGobject=new PGobject(); pGobject.setValue(geometry.toString()); pGobject.setType("geometry"); preparedStatement.setObject(i,pGobject); }
public Geometry getNullableResult(ResultSet resultSet, String columnName) throws SQLException { PGobject pGgeometry= (PGobject) resultSet.getObject(columnName); if(pGgeometry==null){ return null; }else{ WKBReader wkbReader=new WKBReader(); try { return wkbReader.read(WKBReader.hexToBytes(pGgeometry.getValue())); } catch (ParseException e) { e.printStackTrace(); return null; } } }
public Geometry getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException { PGobject pGgeometry= (PGobject) resultSet.getObject(columnIndex); if(pGgeometry==null){ return null; }else{ WKBReader wkbReader=new WKBReader(); try { return wkbReader.read(WKBReader.hexToBytes(pGgeometry.getValue())); } catch (ParseException e) { e.printStackTrace(); return null; } } }
public Geometry getNullableResult(CallableStatement callableStatement, int i) throws SQLException { PGobject pGgeometry= (PGobject) callableStatement.getObject(i); if(pGgeometry==null){ return null; }else{ WKBReader wkbReader=new WKBReader(); try { return wkbReader.read(WKBReader.hexToBytes(pGgeometry.getValue())); } catch (ParseException e) { e.printStackTrace(); return null; } } } }
|
3 修改model类
添加一个geometry
属性
1 2 3 4 5 6 7 8
| @Getter @Setter @ToString public class PointModel { private Integer gId; private String nameCh; private Geometry geometry; }
|
4 修改mapper
主要是加上typeHandler="com.history.gismap.mybatis.GeometryTypeHandler"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//http://mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.history.gismap.dao.MapDao" > <resultMap id="pointModelResult" type="com.history.gismap.model.PointModel"> <result property="gId" column="gid" jdbcType="BIGINT"/> <result property="nameCh" column="name_ch" jdbcType="VARCHAR"/> <result property="geometry" column="geom" typeHandler="com.history.gismap.mybatis.GeometryTypeHandler"/> </resultMap> <sql id="BASE_TABLE"> v6_time_cnty_pts_utf_wgs84 </sql> <sql id="BASE_COLUMN"> gid,name_ch,geom </sql> <select id="getCntyPoint" resultMap="pointModelResult"> SELECT <include refid="BASE_COLUMN"></include> FROM <include refid="BASE_TABLE"/> WHERE gid=#{gId} </select> <insert id="insertCntyPoint" parameterType="com.history.gismap.model.PointModel"> INSERT INTO <include refid="BASE_TABLE"/> <trim prefix="(" suffix=")" suffixOverrides=","> <if test="gId != null"> gid, </if> <if test="nameCh != null"> name_ch, </if> <if test="geometry != null"> geom, </if> </trim> <trim prefix="VALUES(" suffix=")" suffixOverrides=","> <if test="gId != null"> #{gId, jdbcType=BIGINT}, </if> <if test="nameCh != null"> #{nameCh, jdbcType=VARCHAR}, </if> <if test="geometry != null"> #{geometry,typeHandler=com.history.gismap.mybatis.GeometryTypeHandler} </if> </trim> </insert> <update id="updateCntyPoint" parameterType="com.history.gismap.model.PointModel"> UPDATE <include refid="BASE_TABLE"/> SET name_ch=#{nameCh}, geom=#{geometry,typeHandler=com.history.gismap.mybatis.GeometryTypeHandler} WHERE gid=#{gId} </update> <delete id="deleteCntyPoint" parameterType="com.history.gismap.model.PointModel"> DELETE FROM <include refid="BASE_TABLE"/> WHERE gid=#{gId} </delete> </mapper>
|
5 修改controller
为了便于前端读写,我们要把geometry对象转化成geojson。这个改动比较大,查询返回结果、增加入参、修改入参都改成了json格式,WKTReader用来读取WKT文本,mybatis自定义引擎中引入的WKBReader是用来读geohash文本的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| @Controller @RequestMapping(value = "/history") public class MapController { @Autowired private MapService mapService; @ResponseBody @GetMapping("/pointmodel") public JSONObject getPoint(@RequestParam("gid") Integer gId){ PointModel pointModel=mapService.getCntyPointByGid(gId).get(0); JSONObject jsonObject=new JSONObject(); jsonObject.put("gid",pointModel.getGId()); jsonObject.put("namech",pointModel.getNameCh()); JSONObject geometry=new JSONObject(); geometry.put("type",pointModel.getGeometry().getGeometryType()); JSONArray coordinateArray=new JSONArray(); Coordinate[] coordinates=pointModel.getGeometry().getCoordinates(); JSONObject coor=new JSONObject(); coor.put("longitude",coordinates[0].x); coor.put("latitude",coordinates[0].y); coordinateArray.add(coor); geometry.put("coordinate",coordinateArray); jsonObject.put("geometry",geometry); return jsonObject; } @ResponseBody @PostMapping("/add") public int addPoint(@RequestBody JSONObject request){ PointModel pointModel=new PointModel(); pointModel.setGId((Integer) JSONPath.eval(request,"$.gId")); pointModel.setNameCh((String) JSONPath.eval(request,"$.nameCh")); String pointStr= (String) JSONPath.eval(request,"$.point"); GeometryFactory geometryFactory = new GeometryFactory(); WKTReader reader = new WKTReader( geometryFactory ); try { Geometry point = (Point) reader.read(pointStr); pointModel.setGeometry(point); } catch (ParseException e) { e.printStackTrace(); } return mapService.addCntyPoint(pointModel); } @ResponseBody @PostMapping("/modify") public int update(@RequestBody JSONObject request){ PointModel pointModel=new PointModel(); pointModel.setGId((Integer) JSONPath.eval(request,"$.gId")); pointModel.setNameCh((String) JSONPath.eval(request,"$.nameCh")); String pointStr= (String) JSONPath.eval(request,"$.point"); GeometryFactory geometryFactory = new GeometryFactory(); WKTReader reader = new WKTReader( geometryFactory ); try { Geometry point = (Point) reader.read(pointStr); pointModel.setGeometry(point); } catch (ParseException e) { e.printStackTrace(); } return mapService.modifyCntyPoint(pointModel); } @ResponseBody @GetMapping("/remove") public int removetPoint(@RequestParam("gid") Integer gId){ return mapService.removeCntyPoint(gId); } }
|
dao层、service层都没有需要修改的地方
6 测试
使用postman和postwoman都可以
查询
GET请求:http://localhost:8080/history/pointmodel?gid=1
增加
POST请求:http://localhost:8080/history/add
修改
POST请求:http://localhost:8080/history/modify
删除
POST请求:http://localhost:8080/history/remove?gid=14357
7 不太懂的代码Tips
mybatis包下的GeometryTypeHandler类的作用:
对于一般的数据类型(如string等),我们不用关注定义的数据是如何映射到MySQL中的char类型的,因为mybatis已经为我们做好了这件事;But,mybatis没有做空间几何数据(点线面)的映射处理,所以我们需要自定义一个类型处理器TypeHandler来做这一层映射,实现特殊对象与sql字段的映射关系!
WKT,是一种文本标记语言,用于表示矢量几何对象(点、线、多边形、TIN<不规则三角网>、多面体)、空间参照系统及空间参照系统之间的转换;可以通过几何集合的方式来表示不同维度的几何对象,几何物体的坐标可以是2D(x,y),3D(x,y,z),4D(x,y,z,m),加上一个属于线性参照系统的m值。
报错
报错1
1
| Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported
|
先是在postwoman中直接POST请求http://localhost:8080/history/add
和请求http://localhost:8080/history/add?gid=14357&nameCh=test&point(109.221,80.287)
都报如上的错误!一直就以为是json数据传输和接收有问题,也没找到解决办法。
想着有可能也会是这个postwoman平台的问题,接着下载了postman软件,当输入上述同样的请求后,报了如下的错误:
1
| Required request body is missing: public int com.cc.controller.MapController.addPoint(com.alibaba.fastjson.JSONObject)]
|
即请求的主题内容不存在,这个接口的请求方式是post,是需要从前端提交到后端的,请求的body应该以json的形式写到raw里面
在postwoman中也可以提交,之前一直想的是就在url中提交应该就可以了,以前也是在url中提交的,but,你的代码里面并没有把id/nameCh这些东西写到你提交的url之中
【这个问题困扰了我大概三四天了,最后发现问题出在哪儿的时候,真的想骂自己一句蠢笨如猪!!!归根结底还是自己还有很多专业基础知识缺乏,还是菜鸡!!!编程还是没入门吧~】
参考链接:Required request body is missing 错误解决_IBLiplus的博客-CSDN博客
报错2
1
| template might not exist or might not be accessible by any of the configured Template Resolvers\r\n\
|
在Controller中缺少@ResponseBody
注解
参考链接:(38条消息) 错误:template might not exist or might not be accessible by any of the configured Template Resolvers_群鸿的博客-CSDN博客