欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

mybatis几何geometry类型转换

程序员文章站 2022-04-02 17:20:50
...

利用mybatis从postgresql中读取geometry类型字段到实体类中,可以多种接受方式:

1. 直接利用String去接受wkt
2. 利用mybatis在写入实体类时将wkt转换为geometry类型

第一种方式:非常简单粗暴,不过在代码中需要用到geometry类型时,都会写上如下代码:

try {
	......
	JtsUtils.createLineStringByWKT(wkt)
	......
} catch (ParseException) {
	e.printStackTrace();
}

如果代码中存在较多的地方用到几何运算相关的内容,这个在出现很多次。个人认为没有太大必要如此繁琐。当然几何运用的地方较少就当我没有说,直接跳过本文余下内容。

第二种方式:利用mybatis的自定义类型转换的功能,在写入实体时进行统一转换,同时在实体转换为数据库类型是将geometry类型转换为wkt字符串。
废话不多说,直接上代码:

AbstractGeometryTypeHandler.java 几何转换的父类

package com.threestone.common.mybatisTypeHandler;

import com.threestone.utils.JtsUtils;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.WKTReader;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;

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

/**
 * 字符串转为JTS对应的几何类型
 * Created by Friday on 2019/6/19.
 */
@MappedJdbcTypes({JdbcType.OTHER})
public abstract class AbstractGeometryTypeHandler<T extends Geometry> extends BaseTypeHandler<T> {
    /**
     * 把Java类型参数转换为对应的数据库类型
     *
     * @param ps        当前的PreparedStatement对象
     * @param i         当前参数位置
     * @param parameter 当前参数的Java对象
     * @param jdbcType  当前参数的数据库类型
     * @throws SQLException
     */
    public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        String wkt = JtsUtils.toEwkt(parameter);
        ps.setObject(i, wkt);
    }

    /**
     * 获取数据结果集时把数据库类型转换为对应的Java类型
     *
     * @param rs         当前的结果集
     * @param columnName 当前的字段名称
     * @return 转换后的Java对象
     * @throws SQLException
     */
    public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String wkt = (String) rs.getObject(columnName);
        return (T) getGeometryFromWkt(wkt);
    }

    /**
     * 通过字段位置获取字段数据时把数据库类型转换为对应的Java类型
     *
     * @param rs          当前的结果集
     * @param columnIndex 当前字段的位置
     * @return 转换后的Java对象
     * @throws SQLException
     */
    public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String wkt = (String) rs.getObject(columnIndex);
        return (T) getGeometryFromWkt(wkt);
    }

    /**
     * 调用存储过程后把数据库类型的数据转换为对应的Java类型
     *
     * @param cs          当前的CallableStatement执行后的CallableStatement
     * @param columnIndex 当前输出参数的位置
     * @return
     * @throws SQLException
     */
    public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String wkt = (String) cs.getObject(columnIndex);
        return (T) getGeometryFromWkt(wkt);
    }

    // 从WKT中获取几何
    private Geometry getGeometryFromWkt(String wkt) {
        WKTReader reader = new WKTReader();
        Geometry geometry = null;
        try {
            geometry = reader.read(wkt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (geometry == null) {
            return null;
        }
        return geometry;
    }
}

LineStringTypeHandler.java 几何转换的直线类

package com.threestone.common.mybatisTypeHandler;

import com.vividsolutions.jts.geom.LineString;
import org.apache.ibatis.type.MappedTypes;

/**
 * WKT转为LineString
 * Created by Friday on 2019/6/19.
 */
@MappedTypes(LineString.class)
public class LineStringTypeHandler extends AbstractGeometryTypeHandler<LineString>{
}

PointTypeHandler.java 几何转换的点类

package com.threestone.common.mybatisTypeHandler;

import com.vividsolutions.jts.geom.Point;
import org.apache.ibatis.type.MappedTypes;

/**
 * WKT转为Point
 * Created by Friday on 2019/6/19.
 */
@MappedTypes(Point.class)
public class PointTypeHandler extends AbstractGeometryTypeHandler<Point> {
}

其他几何类型polygon等也是如此继承即可。

JtsUtils.java 工具类

    // 将几何类型转换为wkt字符串
    public static String toEwkt(Geometry geom) {
        if (geom == null) {
            return null;
        }
        String type = geom.getGeometryType().toUpperCase();
        switch (type) {
            case "POINT": {
                Coordinate coor = geom.getCoordinate();
                return "POINT(" + formatCoordinate(coor) + ")";
            }
            case "MULTIPOINT": {
                return coordinateToEwkt("MULTIPOINT(", geom.getCoordinates(), ")");
            }
            case "LINESTRING": {
                return coordinateToEwkt("LINESTRING(", geom.getCoordinates(), ")");
            }
            case "POLYGON": {
                return coordinateToEwkt("POLYGON((", geom.getCoordinates(), "))");
            }
            case "MULTILINESTRING": {
                StringBuffer sb = new StringBuffer();
                sb.append("MULTILINESTRING(");
                sb.append(multiGeometryFormat(geom));
                sb.append(")");
                return sb.toString();
            }
            case "MULTIPOLYGON": {
                StringBuffer sb = new StringBuffer();
                sb.append("MULTIPOLYGON(");
                sb.append(multiGeometryFormat(geom));
                sb.append(")");
                return sb.toString();
            }
            case "GEOMETRYCOLLECTION": {
                StringBuffer sb = new StringBuffer();
                int num = geom.getNumGeometries();
                sb.append("GEOMETRYCOLLECTION(");
                for (int j = 0; j < num; j++) {
                    Geometry element = geom.getGeometryN(j);
                    String subType = element.getGeometryType().toUpperCase();
                    if ("POINT".equals(subType)) {
                        sb.append("POINT(" + formatCoordinate(element.getCoordinate()) + ")");
                    } else if ("LINESTRING".equals(subType)) {
                        sb.append(coordinateToEwkt("LINESTRING(", element.getCoordinates(), ")"));
                    } else if ("POLYGON".equals(subType)) {
                        sb.append(coordinateToEwkt("POLYGON((", element.getCoordinates(), "))"));
                    }
                    if (j < num - 1) {
                        sb.append(",");
                    }
                }
                sb.append(")");
                return sb.toString();
            }
        }
        return null;
    }

    private static String formatCoordinate(Coordinate coordinate) {
        if (Double.isNaN(coordinate.z)) {
            coordinate.z = 0;
        }
        return df.format(coordinate.x) + " " + df.format(coordinate.y) + " " + (coordinate.z != 0 ? df.format(coordinate.z) : "0");
    }

    public static String coordinateToEwkt(String prefix, Coordinate[] coordinates, String suffix) {
        StringBuffer sb = new StringBuffer();
        sb.append(prefix);
        boolean append = false;
        for (Coordinate coordinate : coordinates) {
            if (append) {
                sb.append(",");
            }
            sb.append(formatCoordinate(coordinate));
            append = true;
        }
        sb.append(suffix);
        return sb.toString();
    }

接下来就需要对xml进行改写

<resultMap id="ResultMap" type="com.threestone.model.link">
    ......
	<result column="geom" property="geom"  typeHandler="com.threestone.common.mybatisTypeHandler.LineStringTypeHandler"/>
</resultMap>

<sql id="queryColumn">
	st_asewkt("geom") as "geom"
</sql>

<insert id="insertLinks" parameterType="java.util.List">
	insert into link(
    	<include refid="baseColumn" />
    )
    values
    <foreach item="item" collection="list" separator=",">
    	(
	       <choose>
	           <when test="item.geom != null">
	                ST_GEOMFROMTEXT(#{item.geom, typeHandler=com.threestone.common.mybatisTypeHandler.LineStringTypeHandler})
	           </when>
	           <otherwise>
	               NULL
	           </otherwise>
	      </choose>
        )
	</foreach>
</insert>

xml中需要注意我们的数据读取还是读取的wkt字符串,只是在mybatis写入实体时进行了转换。
同时需要注意数据写入数据库时,此时实体类中的geom字段为几何类型,但是mybatis它不认识,这样也需要对其进行标注,告诉mybatis这个字段是geometry类型需要用到我们定义的转换器进行转换。

ST_GEOMFROMTEXT(#{item.geom, typeHandler=com.threestone.common.mybatisTypeHandler.LineStringTypeHandler})

到此大功告成,如有什么不对的地方欢迎指正。

相关标签: gis java mybatis