likes
comments
collection
share

Mybatis-plus通过TypeHandler实现wkt字符串类型和数据库GEOMETRY类型自动转换

作者站长头像
站长
· 阅读数 54

步骤一:导入依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.2</version>
</dependency>
<dependency>
    <groupId>net.postgis</groupId>
    <artifactId>postgis-jdbc</artifactId>
    <version>2021.1.0</version>
</dependency>

步骤二:创建handle类

@Component
@MappedJdbcTypes(JdbcType.OTHER)
public class WKTGeoJsonTypeHandler extends BaseTypeHandler<Object> {
    /**
     * 设置参数(用于类型转换操作)
     * @param preparedStatement 
     * @param i
     * @param o
     * @param jdbcType
     * @throws SQLException
     */
    @Override
    public void setParameter(PreparedStatement preparedStatement, int i, Object o, JdbcType jdbcType) throws SQLException {
        //将wkt类型字符串转换为postgis类型PGgeometry用来实现自动入库
        //注意 wkt的类型必须为大写 类如(point 必须为:POINT)
        if(ObjectUtil.isNotNull(o)){
            String wkt=o.toString();
            PGgeometry pGgeometry =new PGgeometry(wkt);
            pGgeometry.getGeometry().setSrid(4528);
            preparedStatement.setObject(i,pGgeometry);
        }
    }

    /**
     * 将结果转为wkt格式
     * @param resultSet 
     * @param columnName
     * @return
     * @throws SQLException
     */
    @Override
    public Object getResult(ResultSet resultSet, String columnName) throws SQLException {
        Object object = Optional.ofNullable(resultSet.getObject(columnName)).orElseGet(Object::new);
        if (object instanceof PGgeometry){
            Geometry geometry = ((PGgeometry) object).getGeometry();
            return geometry.getTypeString()+geometry.getValue();
        }
        return object;
    }

    @Override
    public Object getResult(ResultSet resultSet, int i) throws SQLException {
        return null;
    }

    @Override
    public Object getResult(CallableStatement callableStatement, int i) throws SQLException {
        return null;
    }

    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Object o, JdbcType jdbcType) throws SQLException {

    }

    @Override
    public Object getNullableResult(ResultSet resultSet, String s) throws SQLException {
        return null;
    }

    @Override
    public Object getNullableResult(ResultSet resultSet, int i) throws SQLException {
        return null;
    }

    @Override
    public Object getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return null;
    }


}

步骤三:对字段设置该handle

@Data
@TableName(value = "address")
@Builder
public class Address implements Serializable {
    @TableId(value = "uuid", type = IdType.INPUT)
    private String uuid;

    @TableField(value = "adderss")
    private String adderss;

    @TableField(value = "geom",typeHandler = WKTGeoJsonTypeHandler.class)
    private Object geom;
}

Mybatis-plus通过TypeHandler实现wkt字符串类型和数据库GEOMETRY类型自动转换

步骤四:测试

@Test
void select() throws Exception {
    List<Address> list = addressService.list();
    list.forEach(s-> System.out.println(s.toString()));
}
@Test
public void add() throws SQLException {
    Address test = Address.builder().uuid("1111112").adderss("test").geom("POINT(0 0)").build();
    addressService.save(test);
}

注意:service mapper 通过插件自动生成

其他:XML写法

Mybatis-plus通过TypeHandler实现wkt字符串类型和数据库GEOMETRY类型自动转换

以上就完成了postgis数据自动入库和查询,是不是很秀,该块去尝试吧!!!

Mybatis-plus通过TypeHandler实现wkt字符串类型和数据库GEOMETRY类型自动转换

类型处理器(typeHandlers)

MyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器。

提示 从 3.4.5 开始,MyBatis 默认支持 JSR-310(日期和时间 API) 。

类型处理器Java 类型JDBC 类型
BooleanTypeHandlerjava.lang.Booleanboolean数据库兼容的 BOOLEAN
ByteTypeHandlerjava.lang.Bytebyte数据库兼容的 NUMERIC 或 BYTE
ShortTypeHandlerjava.lang.Shortshort数据库兼容的 NUMERIC 或 SMALLINT
IntegerTypeHandlerjava.lang.Integerint数据库兼容的 NUMERIC 或 INTEGER
LongTypeHandlerjava.lang.Longlong数据库兼容的 NUMERIC 或 BIGINT
FloatTypeHandlerjava.lang.Floatfloat数据库兼容的 NUMERIC 或 FLOAT
DoubleTypeHandlerjava.lang.Doubledouble数据库兼容的 NUMERIC 或 DOUBLE
BigDecimalTypeHandlerjava.math.BigDecimal数据库兼容的 NUMERIC 或 DECIMAL
StringTypeHandlerjava.lang.StringCHARVARCHAR
ClobReaderTypeHandlerjava.io.Reader-
ClobTypeHandlerjava.lang.StringCLOBLONGVARCHAR
NStringTypeHandlerjava.lang.StringNVARCHARNCHAR
NClobTypeHandlerjava.lang.StringNCLOB
BlobInputStreamTypeHandlerjava.io.InputStream-
ByteArrayTypeHandlerbyte[]数据库兼容的字节流类型
BlobTypeHandlerbyte[]BLOBLONGVARBINARY
DateTypeHandlerjava.util.DateTIMESTAMP
DateOnlyTypeHandlerjava.util.DateDATE
TimeOnlyTypeHandlerjava.util.DateTIME
SqlTimestampTypeHandlerjava.sql.TimestampTIMESTAMP
SqlDateTypeHandlerjava.sql.DateDATE
SqlTimeTypeHandlerjava.sql.TimeTIME
ObjectTypeHandlerAnyOTHER 或未指定类型
EnumTypeHandlerEnumeration TypeVARCHAR 或任何兼容的字符串类型,用来存储枚举的名称(而不是索引序数值)
EnumOrdinalTypeHandlerEnumeration Type任何兼容的 NUMERIC 或 DOUBLE 类型,用来存储枚举的序数值(而不是名称)。
SqlxmlTypeHandlerjava.lang.StringSQLXML
InstantTypeHandlerjava.time.InstantTIMESTAMP
LocalDateTimeTypeHandlerjava.time.LocalDateTimeTIMESTAMP
LocalDateTypeHandlerjava.time.LocalDateDATE
LocalTimeTypeHandlerjava.time.LocalTimeTIME
OffsetDateTimeTypeHandlerjava.time.OffsetDateTimeTIMESTAMP
OffsetTimeTypeHandlerjava.time.OffsetTimeTIME
ZonedDateTimeTypeHandlerjava.time.ZonedDateTimeTIMESTAMP
YearTypeHandlerjava.time.YearINTEGER
MonthTypeHandlerjava.time.MonthINTEGER
YearMonthTypeHandlerjava.time.YearMonthVARCHAR 或 LONGVARCHAR
JapaneseDateTypeHandlerjava.time.chrono.JapaneseDateDATE

你可以重写已有的类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。 具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 并且可以(可选地)将它映射到一个 JDBC 类型。比如:

// ExampleTypeHandler.java
@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler<String> {

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

  @Override
  public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
    return rs.getString(columnName);
  }

  @Override
  public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    return rs.getString(columnIndex);
  }

  @Override
  public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    return cs.getString(columnIndex);
  }
}
<!-- mybatis-config.xml -->
<typeHandlers>
  <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>

使用上述的类型处理器将会覆盖已有的处理 Java String 类型的属性以及 VARCHAR 类型的参数和结果的类型处理器。 要注意 MyBatis 不会通过检测数据库元信息来决定使用哪种类型,所以你必须在参数和结果映射中指明字段是 VARCHAR 类型, 以使其能够绑定到正确的类型处理器上。这是因为 MyBatis 直到语句被执行时才清楚数据类型。

通过类型处理器的泛型,MyBatis 可以得知该类型处理器处理的 Java 类型,不过这种行为可以通过两种方法改变:

  • 在类型处理器的配置元素(typeHandler 元素)上增加一个 javaType 属性(比如:javaType="String");
  • 在类型处理器的类上增加一个 @MappedTypes 注解指定与其关联的 Java 类型列表。 如果在 javaType 属性中也同时指定,则注解上的配置将被忽略。

可以通过两种方式来指定关联的 JDBC 类型:

  • 在类型处理器的配置元素上增加一个 jdbcType 属性(比如:jdbcType="VARCHAR");
  • 在类型处理器的类上增加一个 @MappedJdbcTypes 注解指定与其关联的 JDBC 类型列表。 如果在 jdbcType 属性中也同时指定,则注解上的配置将被忽略。

当在 ResultMap 中决定使用哪种类型处理器时,此时 Java 类型是已知的(从结果类型中获得),但是 JDBC 类型是未知的。 因此 Mybatis 使用 javaType=[Java 类型], jdbcType=null 的组合来选择一个类型处理器。 这意味着使用 @MappedJdbcTypes 注解可以限制类型处理器的作用范围,并且可以确保,除非显式地设置,否则类型处理器在 ResultMap 中将不会生效。 如果希望能在 ResultMap 中隐式地使用类型处理器,那么设置 @MappedJdbcTypes 注解的 includeNullJdbcType=true 即可。 然而从 Mybatis 3.4.0 开始,如果某个 Java 类型只有一个注册的类型处理器,即使没有设置 includeNullJdbcType=true,那么这个类型处理器也会是 ResultMap 使用 Java 类型时的默认处理器。

最后,可以让 MyBatis 帮你查找类型处理器:

<!-- mybatis-config.xml -->
<typeHandlers>
  <package name="org.mybatis.example"/>
</typeHandlers>

注意在使用自动发现功能的时候,只能通过注解方式来指定 JDBC 的类型。

你可以创建能够处理多个类的泛型类型处理器。为了使用泛型类型处理器, 需要增加一个接受该类的 class 作为参数的构造器,这样 MyBatis 会在构造一个类型处理器实例的时候传入一个具体的类。

//GenericTypeHandler.java
public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E> {

  private Class<E> type;

  public GenericTypeHandler(Class<E> type) {
    if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
    this.type = type;
  }
  ...
转载自:https://juejin.cn/post/7168760625190371364
评论
请登录