在我们工作中想要实现将空间点位信息存储到数据库时,一般使用以下语句实现

INSERT INTO `test-point` ( point,text ) VALUES ( st_GeomFromText ( 'POINT(1 1)' ),'第1个点');
update `test-point` set point=st_PointFromText('POINT(5 5)') where id =10;

但是这样每次都要去编写新增与编辑的sql语句非常麻烦,体现不出mybatisplus的便捷性,所以可以增加GeometryTypeHandler在mybatisplus生成新增编辑语句时将st_GeomFromText ()函数拼接到sql语句上,更加方便快捷

一.准备工作

首先项目添加依赖:

<dependency>
    <groupId>org.locationtech.jts</groupId>
    <artifactId>jts-core</artifactId>
    <version>${jts-core.version}</version>
</dependency>

在项目中加入GeometryTypeHandler

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.PrecisionModel;
import org.locationtech.jts.io.*;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 空间数据类型处理器
 *
 * 参考:{@link https://blog.csdn.net/mcband/article/details/132099924}
 */

@MappedTypes({String.class})
@MappedJdbcTypes({JdbcType.OTHER})
@Slf4j
public class GeometryTypeHandler extends BaseTypeHandler<String> {


    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException {
        try{
            //String转Geometry
            Geometry geo = new WKTReader(new GeometryFactory(new PrecisionModel())).read(s);
            // Geometry转WKB
            byte[] geometryBytes = new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN, false).write(geo);
            // 设置SRID为mysql默认的 0
            byte[] wkb = new byte[geometryBytes.length+4];
            wkb[0] = wkb[1] = wkb[2] = wkb[3] = 0;
            System.arraycopy(geometryBytes, 0, wkb, 4, geometryBytes.length);
            preparedStatement.setBytes(i,wkb);
        }catch (ParseException e){
            log.error("坐标转换异常:【{}】",e.getMessage(),e);
        }
    }

    @Override
    public String getNullableResult(ResultSet resultSet, String s){
        try(InputStream inputStream = resultSet.getBinaryStream(s)){
            Geometry geo = getGeometryFromInputStream(inputStream);
            if(geo != null){
                return geo.toString();
            }
        }catch(Exception e){
            log.error("坐标转换异常:【{}】",e.getMessage(),e);
        }
        return null;
    }

    @Override
    public String getNullableResult(ResultSet resultSet, int i){
        try(InputStream inputStream = resultSet.getBinaryStream(i)){
            Geometry geo = getGeometryFromInputStream(inputStream);
            if(geo != null){
                return geo.toString();
            }
        }catch(Exception e){
            log.error("坐标转换异常:【{}】",e.getMessage(),e);
        }
        return null;
    }

    @Override
    public String getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return "";
    }
    /**
     * 流 转 geometry
     * */
    private  Geometry getGeometryFromInputStream(InputStream inputStream) throws Exception {

        Geometry dbGeometry = null;

        if (inputStream != null) {
            // 二进制流转成字节数组
            byte[] buffer = new byte[255];

            int bytesRead;
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                baos.write(buffer, 0, bytesRead);
            }
            // 得到字节数组
            byte[] geometryAsBytes = baos.toByteArray();
            // 字节数组小于5 异常
            if (geometryAsBytes.length < 5) {
                throw new RuntimeException("坐标异常");
            }

            //字节数组前4个字节表示srid 去掉
            byte[] sridBytes = new byte[4];
            System.arraycopy(geometryAsBytes, 0, sridBytes, 0, 4);
            boolean bigEndian = (geometryAsBytes[4] == 0x00);
            // 解析srid
            int srid = 0;
            if (bigEndian) {
                for (byte sridByte : sridBytes) {
                    srid = (srid << 8) + (sridByte & 0xff);
                }
            } else {
                for (int i = 0; i < sridBytes.length; i++) {
                    srid += (sridBytes[i] & 0xff) << (8 * i);
                }
            }

            WKBReader wkbReader = new WKBReader();
            // WKBReader 把字节数组转成geometry对象。
            byte[] wkb = new byte[geometryAsBytes.length - 4];
            System.arraycopy(geometryAsBytes, 4, wkb, 0, wkb.length);
            dbGeometry = wkbReader.read(wkb);
            dbGeometry.setSRID(srid);
        }
        return dbGeometry;
    }
}

二.使用

找到相对应的空间数据属性字段,加上下面的注解:

@TableField(typeHandler = GeometryTypeHandler.class)

这样的话正常传入字段内容point(1 2),在新增和编辑时mybatisplus就会自动拼接st_GeomFromText (),实现空间点位数据的录入和编辑了.

原文链接:https://blog.csdn.net/mcband/article/details/132099924