Mybatis TypeHandler 解析转换 MySQL Geometry

5 篇文章 0 订阅

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]}}
]
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值