Mybatis TypeHandler 解析转换 MySQL Geometry

MySQL数据中存储Geometry类,存的是WKB格式,前4位是SRID值,所以在解析MySQL的Geometry类数据时,需要处理掉前4位二进制数,再后续的byte[]数组转为java Geometry类

MySQL插入Geometry类型数据,直接插入WKB和WKT,MySQL是不识别的,会报错 com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Cannot get geometry object from data you send to the GEOMETRY field

MySQL 插入 Geometry类型数据,需要用到 ST_GeomFromText函数, 例如 insert into User(geom) values (ST_GeomFromText('POINT (1 2)'))

方式一

import lombok.SneakyThrows;

import org.apache.ibatis.type.BaseTypeHandler;

import org.apache.ibatis.type.JdbcType;

import org.locationtech.jts.geom.Geometry;

import org.locationtech.jts.geom.GeometryFactory;

import org.locationtech.jts.geom.PrecisionModel;

import org.locationtech.jts.io.InputStreamInStream;

import org.locationtech.jts.io.WKBReader;


import java.io.ByteArrayInputStream;

import java.nio.ByteBuffer;

import java.sql.*;



public class MysqlGeometryTypeHandler extends BaseTypeHandler<Geometry> {

    @Override

    public void setNonNullParameter(PreparedStatement ps, int i, Geometry parameter, JdbcType jdbcType) throws SQLException {

        Connection conn = ps.getConnection();


        String wkt = parameter.toText();

        String sql = "SELECT ST_GeomFromText(?)";


        try (PreparedStatement stmt = conn.prepareStatement(sql)) {

            stmt.setString(1, wkt);

            ResultSet rs = stmt.executeQuery();


            if (rs.next()) {

                Object obj = rs.getObject(1);

                ps.setObject(i, obj);

            } else {

                throw new SQLException("Failed to convert Geometry to database type");

            }

        }

    }


    @Override

    public Geometry getNullableResult(ResultSet rs, String columnName) throws SQLException {

        final Object object = rs.getObject(columnName);

        return getGeometry(object);

    }


    @SneakyThrows

    private Geometry getGeometry(Object object) {

        ByteArrayInputStream inputStream = new ByteArrayInputStream((byte[]) object);

        byte[] sridBytes = new byte[4];

        inputStream.read(sridBytes);

        int srid = ByteBuffer.wrap(sridBytes).getInt();

        WKBReader wkbReader = new WKBReader(new GeometryFactory(new PrecisionModel(), srid));

        return wkbReader.read(new InputStreamInStream(inputStream));

    }


    @Override

    public Geometry getNullableResult(ResultSet rs, int columnIndex) throws SQLException {

        final Object object = rs.getObject(columnIndex);

        return getGeometry(object);

    }


    @Override

    public Geometry getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {

        final Object object = cs.getObject(columnIndex);

        return getGeometry(object);

    }

}

 

  <resultMap id="BaseResultMap" type="cn.x.mybatis.po.UserPO">

    <id column="id" jdbcType="INTEGER" property="id" />

    <result column="username" jdbcType="VARCHAR" property="username" />

    <result column="password" jdbcType="VARCHAR" property="password" />

    <result column="nickname" jdbcType="VARCHAR" property="nickname" />

    <result column="name" jdbcType="VARCHAR" property="name" />

    <result column="age" jdbcType="VARCHAR" property="age" />

    <result column="phone" jdbcType="VARCHAR" property="phone" />

    <result column="addr" jdbcType="INTEGER" property="addr" />

    <result column="geom" jdbcType="OTHER" property="geom" typeHandler="cn.x.gis.mybatis.MysqlGeometryTypeHandler"/>

  </resultMap>


  <insert id="insertSelective" parameterType="cn.x.mybatis.po.UserPO">

    insert into sys_user2

    <trim prefix="(" suffix=")" suffixOverrides=",">

      <if test="id != null">

        id,

      </if>

      <if test="username != null">

        username,

      </if>

      <if test="password != null">

        password,

      </if>

      <if test="geom != null">

        geom,

      </if>

    </trim>

    <trim prefix="values (" suffix=")" suffixOverrides=",">

      <if test="id != null">

        #{id,jdbcType=INTEGER},

      </if>

      <if test="username != null">

        #{username,jdbcType=VARCHAR},

      </if>

      <if test="password != null">

        #{password,jdbcType=VARCHAR},

      </if>

      <if test="geom != null">

        #{geom,jdbcType=OTHER,typeHandler=cn.x.gis.mybatis.MysqlGeometryTypeHandler},

      </if>

    </trim>

  </insert>

 

    @Test

    public void test() throws IOException {

        String resource = "mybatis-config.xml";

        InputStream inputStream = Resources.getResourceAsStream(resource);

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);


        try (SqlSession session = sqlSessionFactory.openSession()) {

            UserMapper mapper = session.getMapper(UserMapper.class);

            mapper.insertSelective(new UserPO() {{

                setUsername("test" + System.currentTimeMillis());

                setPassword("123456");

                setGeom(GeomUtils.createPoint(12, 12));

            }});

            session.commit();


            List<UserPO> user = mapper.getUser();

            System.out.println(GisJacksonUtils.toJson(user));

        }

    }

 

结果:


[

    {"id":1,"username":"test","password":"123","nickname":"nick","name":"张三","age":99,"phone":"18888888888","addr":"最高人民法院","geom":{"type":"Point","coordinates":[1.0,2.0]}},

    {"id":2,"username":"test1689315606183","password":"123456","nickname":"","name":"","age":0,"phone":"","addr":"","geom":{"type":"Point","coordinates":[12.0,12.0]}},

]

方式二

public class MysqlGeometryTypeHandler2 extends BaseTypeHandler<Geometry> {

    @Override

    public void setNonNullParameter(PreparedStatement ps, int i, Geometry parameter, JdbcType jdbcType) throws SQLException {

        ps.setString(i, parameter.toText());

    }


    @Override

    public Geometry getNullableResult(ResultSet rs, String columnName) throws SQLException {

        final Object object = rs.getObject(columnName);

        return getGeometry(object);

    }


    @SneakyThrows

    private Geometry getGeometry(Object object) {

        ByteArrayInputStream inputStream = new ByteArrayInputStream((byte[]) object);

        byte[] sridBytes = new byte[4];

        inputStream.read(sridBytes);

        int srid = ByteBuffer.wrap(sridBytes).getInt();

        WKBReader wkbReader = new WKBReader(new GeometryFactory(new PrecisionModel(), srid));

        return wkbReader.read(new InputStreamInStream(inputStream));

    }


    @Override

    public Geometry getNullableResult(ResultSet rs, int columnIndex) throws SQLException {

        final Object object = rs.getObject(columnIndex);

        return getGeometry(object);

    }


    @Override

    public Geometry getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {

        final Object object = cs.getObject(columnIndex);

        return getGeometry(object);

    }

}

<insert id="insertSelective2" parameterType="cn.cjf.mybatis.po.UserPO">

    insert into sys_user2

    <trim prefix="(" suffix=")" suffixOverrides=",">

      <if test="id != null">

        id,

      </if>

      <if test="username != null">

        username,

      </if>

      <if test="password != null">

        password,

      </if>

      <if test="geom != null">

        geom,

      </if>

    </trim>

    <trim prefix="values (" suffix=")" suffixOverrides=",">

      <if test="id != null">

        #{id,jdbcType=INTEGER},

      </if>

      <if test="username != null">

        #{username,jdbcType=VARCHAR},

      </if>

      <if test="password != null">

        #{password,jdbcType=VARCHAR},

      </if>

      <if test="geom != null">

        ST_GeomFromText(#{geom,jdbcType=OTHER,typeHandler=cn.cjf.gis.mybatis.MysqlGeometryTypeHandler2}),

      </if>

    </trim>

  </insert>

    @Test

    public void test3() throws IOException {

        String resource = "mybatis-config.xml";

        InputStream inputStream = Resources.getResourceAsStream(resource);

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);


        try (SqlSession session = sqlSessionFactory.openSession()) {

            UserMapper mapper = session.getMapper(UserMapper.class);

            mapper.insertSelective2(new UserPO() {{

                setUsername("test" + System.currentTimeMillis());

                setPassword("123456");

                setGeom(GeomUtils.createPoint(12, 12));

            }});

            session.commit();


            List<UserPO> user = mapper.getUser();

            System.out.println(GisJacksonUtils.toJson(user));

        }

    }

结果


[

    {"id":1,"username":"test","password":"123","nickname":"nick","name":"张三","age":99,"phone":"18888888888","addr":"最高人民法院","geom":{"type":"Point","coordinates":[1.0,2.0]}},

    {"id":8,"username":"test1689317869524","password":"123456","nickname":"","name":"","age":0,"phone":"","addr":"","geom":{"type":"Point","coordinates":[12.0,12.0]}}

]

————————————————

版权声明:本文为CSDN博主「qq_35987023」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qq_35987023/article/details/131723981