基于Mybatis-Plus实现Geometry字段在PostGis空间数据库中的使用

Posted 夜郎king

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Mybatis-Plus实现Geometry字段在PostGis空间数据库中的使用相关的知识,希望对你有一定的参考价值。

目录

背景

一、在pom.xml中引入postgis-jdbc相关jar包

二、需要自定义Handler类来扩展字段支持。

三、在数据中创建表,建表语句如下:

四、定义Mybatis-plus实体

五、定义mapper查询器

六、定义service业务类

八、使用pgadmin可以查看到相应的点数据,如下图所示:


背景

        之前的一些个人文章介绍了空间数据库,以及Mybatis-Plus快速操作数据库组件,以及空间数据库PostGis的相关介绍。现在基于在空间数据库中已经定义了一张空间表,需要在应用程序中使用Mybatis-Plus来进行空间数据的查询、插入等常规操作。

        在OGC标准中,通常空间字段是由Geometry类型来表示。而一般编程语言中是没有这种数据类型的。以java为例,怎么操作这些数据,满足业务需求呢?跟着本文一起来学习吧。

今天介绍基于postgis-jdbc的geometry属性的操作。

一、在pom.xml中引入postgis-jdbc相关jar包

<!-- PostgreSql 驱动包 add by wuzuhu on 2022-08-16 -->
<dependency>
    <groupId>net.postgis</groupId>
	<artifactId>postgis-jdbc</artifactId>
	<version>2.5.0</version>
</dependency>

二、需要自定义Handler类来扩展字段支持。

package com.hngtghy.framework.handler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import org.postgis.Geometry;
import org.postgis.PGgeometry;

@MappedTypes(String.class)
public class PgGeometryTypeHandler extends BaseTypeHandler<String> 

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException 
        PGgeometry pGgeometry = new PGgeometry(parameter);
        Geometry geometry = pGgeometry.getGeometry();
        geometry.setSrid(4326);
        ps.setObject(i, pGgeometry);
    

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException 
        String string = rs.getString(columnName);
        return getResult(string);
    

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException 
        String string = rs.getString(columnIndex);
        return getResult(string);
    

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException 
        String string = cs.getString(columnIndex);
        return getResult(string);
    


    private String getResult(String string) throws SQLException 
        PGgeometry pGgeometry = new PGgeometry(string);
        String s = pGgeometry.toString();
        return s.replace("SRID=4326;", "");
    


        注意,在getResult()中关于4326坐标系的定义,可以根据需要进行废弃。这里写上为了统一投影坐标系。

三、在数据中创建表,建表语句如下:

create table biz_point_test(
	id int8 primary key,
	name varchar(100),
	geom geometry(Point,4326)
);

四、定义Mybatis-plus实体

package com.hngtghy.project.extend.student.domain;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.hngtghy.framework.handler.PgGeometryTypeHandler;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@TableName(value ="biz_point_test",autoResultMap = true)
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class PointTest 

	@TableId
	private Long id;
	
	private String name;
	
	@TableField(typeHandler = PgGeometryTypeHandler.class)
	private String geom;
	
	@TableField(exist=false)
	private String geomJson;

       提醒:1、在属性上使用@TableField(typeHandler=xxx)来指定对应的类型转换器。2、需要在实体上定义autoResultMap=true。否则配置不一定生效。

五、定义mapper查询器

package com.hngtghy.project.extend.student.mapper;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hngtghy.project.extend.student.domain.PointTest;

public interface PointTestMapper extends BaseMapper<PointTest>

	static final String FIND_GEOJSON_SQL="<script>"
			+ "select st_asgeojson(geom) as geomJson from biz_point_test "
			+ "where id = #id "
			+ "<if test='null != name'>and p.name like concat('%', #name, '%')</if>"
			+ "</script>";
	@Select(FIND_GEOJSON_SQL)
	PointTest findGeoJsonById(@Param("id")Long id,@Param("name")String name);
	

六、定义service业务类

package com.hngtghy.project.extend.student.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hngtghy.project.extend.student.domain.PointTest;
import com.hngtghy.project.extend.student.mapper.PointTestMapper;
import com.hngtghy.project.extend.student.service.IPointTestService;

@Service
public class PointTestServcieImpl extends ServiceImpl<PointTestMapper, PointTest> implements IPointTestService

	@Autowired
	private PointTestMapper pointMapper;
	
	@Override
	public PointTest selectById(Long id) 
		return pointMapper.selectById(id);
	

	@Override
	public List<PointTest> selectList(PointTest point) 
		QueryWrapper<PointTest> queryWrapper = new QueryWrapper<PointTest>();
		queryWrapper.select("id,name");
        return this.getBaseMapper().selectList(queryWrapper);
	

	@Override
	public int insertPointTest(PointTest point) 
		return pointMapper.insert(point);
	

	@Override
	public int updatePoint(PointTest point) 
		return pointMapper.updateById(point);
	

	@Override
	public PointTest selectGeomById(Long id) 
		QueryWrapper<PointTest> queryWrapper = new QueryWrapper<PointTest>();
		queryWrapper.select("geom","st_asgeojson(geom) as geomJson");
		queryWrapper.eq("id", id);
        return this.getBaseMapper().selectOne(queryWrapper);
	

	@Override
	public PointTest findGeoJsonById(Long id) 
		return pointMapper.findGeoJsonById(id, null);
	


       这里添加了一个数据库不存在的字段geomJson,会将空间属性转变成geojson字段,方便于前台的如leaflet、openlayers、cesium等组件进行展示。所以使用postgis的st_asgeojson(xxx)进行函数转换。

七、相关方法调用

//1、列表查询List<PointTest> pointList = pointService.selectList(null);System.out.println(pointList);
[PointTest(id=1559371184090423297, name=中寨居委会, geom=null, geomJson=null), PointTest(id=2, name=禾滩村, geom=null, geomJson=null), PointTest(id=1559403683801796610, name=中寨居委会, geom=null, geomJson=null)]
//2、插入PointTest point = new PointTest();point.setName("中寨居委会");point.setGeom("POINT(109.262605 27.200669)");//POINT(lng,lat) 经度,纬度pointService.insertPointTest(point);
//3、查询数据 PointTest point = pointService.selectGeomById(1559371184090423297L); PointTest json = pointService.findGeoJsonById(1559371184090423297L);
PointTest(id=null, name=null, geom=POINT(109.262605 27.200669), geomJson="type":"Point","coordinates":[109.262605,27.200669])PointTest(id=null, name=null, geom=null, geomJson="type":"Point","coordinates":[109.262605,27.200669])

八、使用pgadmin可以查看到相应的点数据,如下图所示:

        总结:通过以上步骤可以实现在mybatis-plus中操作geometry空间字段,同时实现查询和插入操作。通过geojson,结合前端可视化组件即可完成矢量数据的空间可视化。希望本文可以帮到你,欢迎交流。

 

基于Spring+SpringMVC+MyBatis-Plus开发书评网(十四)后台管理CRUD业务实现+项目完结

目录

概要

一、 新增图书信息

1.1 引入Json Html解析组件jsoup

1.2 BookServiceImpl

1.3 MBookController

1.4 前端渲染

二、 分页查询

三、 更新图书信息

3.1 BookServiceImpl

3.2 MBookController

3.2.1 selectById

3.2.2 updateBook

四、 删除图书信息

4.1 BookServiceImpl

4.2 MBookController


项目已完结,链接如下:

Maven项目改造为Web项目

Spring和SpringMVC的整合

Spring和MyBatis的整合

MyBatis-Plus的整合

首页-图书分类展示模块

图书分页查询模块采用Ajax动态加载图书信息和实现图书多条件动态查询

图书详情模块开发之获取图书信息并展示

图书详情页-显示评论列表开发

Kaptcha验证码组件配置

用户注册与登录功能实现 + MD5处理用户密码 + 业务逻辑异常类

用户对于某本书的阅读状态的查询与更新功能实现

已登录用户写短评和短评点赞功能的实现

利用Spring-Task自动计算图书评分以及评论人数

后台管理之wangEditor图片上传

概要

后台管理的CRUD业务以及后台的集成,系统基本已经实现,喜欢的小伙伴可以到我的GitHub克隆哟,数据库也有!!!!

后续还会抽时间完善一下,两个部分,一是短评管理(参照后台管理开发);而是数据表系统用户表user,模仿OA系统,重新开发登录功能。

一、 新增图书信息

1.1 引入Json Html解析组件jsoup

<!-- Json Html解析组件jsoup -->
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.12.1</version>
        </dependency>

1.2 BookServiceImpl

/**
     * 新增图书
     * @param book 新图书数据
     * @return 更新后的数据
     */
    @Transactional
    public Book createBook(Book book) 
        bookMapper.insert(book);
        return book;
    

1.3 MBookController

/**
     * 新增图书
     * @param book
     * @return
     */
    @PostMapping("/create")
    @ResponseBody
    public Map createBook(Book book)
        Map result = new HashMap();
        try 
            // 1、 设置默认评价人数和分数
            book.setEvaluationQuantity(0);
            book.setEvaluationScore(0f);

            // 2、 解析图书详情
            // JavaHTML解析器Jsoup,提取需要的数据
            Document doc = Jsoup.parse(book.getDescription());

            // 获取图书详情第一图的元素对象
            Element img = doc.select("img").first();

            // attr获取当前元素的指定值
            String cover = img.attr("src");

            // 来自于description描述的第一幅图
            book.setCover(cover);

            // 3、 保存
            bookService.createBook(book);

            // 返回前端的信息
            result.put("code", "0");
            result.put("msg", "success");
        catch (BussinessException ex)
            ex.printStackTrace();
            result.put("code", ex.getCode());
            result.put("msg", ex.getMsg());
        
        return result;
    

1.4 前端渲染

//  显示新增图书对话框
    function showCreate()
        //   弹出"新增图书"对话框
        layui.layer.open(
            id: "dlgBook",
            title: "新增图书",
            type: 1,
            content: $('#dialog').html(),
            area: ['820px', '730px'],
            resize: false
        )
        //  初始化wangEditor
        editor = new wangEditor('#dlgBook #editor');
        //  设置图片上传地址
        editor.customConfig.uploadImgServer = '/management/book/upload';
        //  设置图片上传参数
        editor.customConfig.uploadFileName = 'img';
        //  创建wangEditor
        editor.create();

        //  LayUI表单重新渲染
        layui.form.render();
        //  设置当前表单提交时提交至"create"新增地址
        $("#dlgBook #optype").val("create");

    ;

二、 分页查询

/**
     * 分页查询图书数据
     * @param page
     * @param limit
     * @return
     */
    @GetMapping("/list")
    @ResponseBody
    public Map list(Integer page , Integer limit)
        // 默认查询第一页
        if(page == null)
            page = 1;
        
        // 默认10行
        if(limit == null)
            limit = 10;
        

        // 实现之前首页的分页接口,忽略数据类别和降序,设置为NULL
        IPage<Book> pageObject = bookService.paging(null, null, page, limit);
        // 返回的数据
        Map result = new HashMap();
        result.put("code", "0");
        result.put("msg", "success");
        // 当前页面数据
        result.put("data", pageObject.getRecords());
        // 未分页时记录总数
        result.put("count", pageObject.getTotal());

        return result;
    

三、 更新图书信息

3.1 BookServiceImpl

/**
     * 更新图书
     * @param book 新图书数据
     * @return 更新后的数据
     */
    @Transactional
    public Book updateBook(Book book) 
        bookMapper.updateById(book);
        return book;
    

3.2 MBookController

① 先要获取更新书籍的ID

② 再根据ID进行更新

3.2.1 selectById

/**
     * 获取图书详细信息
     * @param bookId
     * @return
     */
    @GetMapping("/id/id")
    @ResponseBody
    public Map selectById(@PathVariable("id") Long bookId)
        Book book = bookService.selectById(bookId);
        Map result = new HashMap();
        result.put("code", "0");
        result.put("msg", "success");
        result.put("data", book);
        return result;
    

3.2.2 updateBook

/**
     * 更新图书数据
     * @param book
     * @return
     */
    @PostMapping("/update")
    @ResponseBody
    public Map updateBook(Book book)
        Map result = new HashMap();
        try 
            // 创建临时对象,获取原始数据库记录,在这个rawBook上进行更新,以免数据混乱
            Book rawBook = bookService.selectById(book.getBookId());
            // 将前端获取的值录入rawBook(原始的数据),可以理解为重置
            rawBook.setBookName(book.getBookName());
            rawBook.setSubTitle(book.getSubTitle());
            rawBook.setAuthor(book.getAuthor());
            rawBook.setCategoryId(book.getCategoryId());
            rawBook.setDescription(book.getDescription());

            // 更新第一张图片,因为可能变化了
            // 获取图书详情第一图的元素对象
            Document doc = Jsoup.parse(book.getDescription());
            // attr获取当前元素的指定值
            String cover = doc.select("img").first().attr("src");

            rawBook.setCover(cover);

            // 最后再覆盖
            bookService.updateBook(rawBook);

            // 返回前端信息
            result.put("code", "0");
            result.put("msg", "success");
        catch (BussinessException ex)
            ex.printStackTrace();
            result.put("code", ex.getCode());
            result.put("msg", ex.getMsg());
        
        return result;
    

四、 删除图书信息

4.1 BookServiceImpl

 /**
     * 删除图书及相关数据
     * @param bookId 图书编号
     */
    @Transactional
    public void deleteBook(Long bookId) 
        // 1、 删除book表的数据
        bookMapper.deleteById(bookId);

        // 2、 删除阅读状态表的数据
        QueryWrapper<MemberReadState> mrsQueryWrapper = new QueryWrapper<MemberReadState>();
        mrsQueryWrapper.eq("book_id", bookId);
        memberReadStateMapper.delete(mrsQueryWrapper);

        // 3、 删除评论表格的数据
        QueryWrapper<Evaluation> evaluationQueryWrapper = new QueryWrapper<Evaluation>();
        evaluationQueryWrapper.eq("book_id", bookId);
        evaluationMapper.delete(evaluationQueryWrapper);

    

4.2 MBookController

/**
     * 删除图书数据
     * @param bookId
     * @return
     */
    @GetMapping("/delete/id")
    @ResponseBody
    public Map deleteBook(@PathVariable("id") Long bookId)
        Map result = new HashMap();
        try
            bookService.deleteBook(bookId);
            result.put("code", "0");
            result.put("msg", "success");
        catch (BussinessException ex)
            ex.printStackTrace();
            result.put("code", ex.getCode());
            result.put("msg", ex.getMsg());
        
        return result;
    

以上是关于基于Mybatis-Plus实现Geometry字段在PostGis空间数据库中的使用的主要内容,如果未能解决你的问题,请参考以下文章

基于 spring boot + mybatis-plus实现简单的转账业务

基于Spring+SpringMVC+MyBatis-Plus开发书评网(十四)后台管理CRUD业务实现+项目完结

MyBatis-Plus 实现分页的几种写法

乐观锁及mybatis-plus实现

Mybatis-plus:入门

Mybatis-plus