GeometryCollection 的类型映射器(TypeHandler)

by emanjusaka from https://www.emanjusaka.top/2024/05/mybatis-typeHandler-geometryCollection 彼岸花开可奈何
本文欢迎分享与聚合,全文转载请留下原文地址。

GeometryCollection 是 GeoJSON 数据模型中的一个类型,用于表示一个几何对象的集合。MySQL8 中支持了 GeometryCollection 类型,在对数据库和实体类进行对象映射时需要我们自己编写类型映射器来完成映射。java 本身不支持 GeometryCollection 类型,我们需要引入第三方包来获得支持。

引入geotools工具包

该依赖在 maven 中央仓库中没有,需要另外配置下仓库

geotools库支持 jdk8 的最高版本是 28.2。

 <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-geojson-core</artifactId>
            <version>28.2</version>
        </dependency>

 <repositories>
        <!-- geotools的远程库 -->
        <repository>
            <id>osgeo</id>
            <name>OSGeo Release Repository</name>
            <url>https://repo.osgeo.org/repository/release/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <releases>
                <enabled>true</enabled>
            </releases>
        </repository>
        <repository>
            <id>osgeo-snapshot</id>
            <name>OSGeo Snapshot Repository</name>
            <url>https://repo.osgeo.org/repository/snapshot/</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
        <!-- geotools的远程库end -->
    </repositories>

实体类

本示例的 mybatis 增加框架使用的是 tkmapper,如果是使用的 MyBatisPlus 注解切换成对应的注解,大同小异。为了演示方便我去除了无关字段,重点关注 GeometryCollection 类型的 areaGeom 字段即可。

package top.emanjusaka.test;

import com.iles.handler.GeometryCollectionTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.locationtech.jts.geom.GeometryCollection;
import tk.mybatis.mapper.annotation.ColumnType;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "car_work_area")
public class CarWorkAreaDO {
    private static final long serialVersionUID = 1L;

    /**
     * 自增 ID
     */
    @Id
    @GeneratedValue(generator = "JDBC")
    private Long id;

    @Column(name = "area_geom")
    @ColumnType(typeHandler = GeometryCollectionTypeHandler.class)
    private GeometryCollection areaGeom;


}

TypeHandler 映射器

大多数支持地理空间数据的数据库系统(如 PostgreSQL/PostGIS、MySQL、SQL Server 等)都支持以 WKT 或 WKB 格式存储和检索 GeometryCollection 类型的数据。具体使用哪种格式取决于应用场景的需求,比如对存储空间的敏感度、数据交换的便捷性以及性能要求等。本文存储的是 WKT 格式。

package top.emanjusaka.handler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.io.WKTWriter;

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

/**
 * @Author emanjusaka
 */
public class GeometryCollectionTypeHandler extends BaseTypeHandler<GeometryCollection> {
    private static final WKTReader wktReader = new WKTReader();

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, GeometryCollection parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter.toText());
    }

    @Override
    public GeometryCollection getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String wkt = rs.getString(columnName);
        try {
            return wkt != null ? (GeometryCollection) wktReader.read(wkt) : null;
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public GeometryCollection getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String wkt = rs.getString(columnIndex);
        try {
            return wkt != null ? (GeometryCollection) wktReader.read(wkt) : null;
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public GeometryCollection getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String wkt = cs.getString(columnIndex);
        try {
            return wkt != null ? (GeometryCollection) wktReader.read(wkt) : null;
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}

mapper 文件

package top.emanjusaka.mapper;

import top.emanjusaka.test.CarWorkAreaDO;
import org.apache.ibatis.annotations.Param;
import tk.mybatis.mapper.common.Mapper;

import java.util.List;


public interface CarWorkAreaMapper extends Mapper<CarWorkAreaDO> {
    /**
     * 插入数据
     *
     * @param carWorkArea
     * @return:
     */
    int insertCustom(CarWorkAreaDO carWorkArea);
}

注意事项:

  • resultMap 中 area_geom 字段注意配置 TypeHandler,否则无法进行映射导致报错
  • 插入的 sql 语句中,area_geom 字段也需要指定 typeHandler,并且需要调用 ST_GeomCollFrom()函数读取数据。
  • 查询时可以调用函数 AsTex()
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="top.emanjusaka.mapper.CarWorkAreaMapper">
    <resultMap type="com.iles.models.car.CarWorkAreaDO" id="carWorkAreaResult">
        <result property="id" column="id"/>
        <result property="areaGeom" column="area_geom" javaType="org.locationtech.jts.geom.GeometryCollection"
                jdbcType="OTHER"
                typeHandler="top.emanjusaka.handler.GeometryCollectionTypeHandler"/>
    </resultMap>


    <insert id="insertCustom" parameterType="com.iles.models.car.CarWorkAreaDO">
        insert into
        car_work_area(id,area_geom)
        values
        (#{id},ST_GeomCollFromText(#{areaGeom,typeHandler=top.emanjusaka.handler.GeometryCollectionTypeHandler}))
    </insert>
</mapper>

在技术的星河中遨游,我们互为引路星辰,共同追逐成长的光芒。愿本文的洞见能触动您的思绪,若有所共鸣,请以点赞之手,轻抚赞同的弦。
原文地址: https://www.emanjusaka.top/2024/05/mybatis-typeHandler-geometryCollection
微信公众号:emanjusaka的编程栈

热门相关:非人类基因统合体   脑洞大爆炸   来自地狱的男人   春秋我为王   独步仙尘