使用mybatis拦截器对mysql中的Geometry进行处理

当谈到在MySQL中处理Geometry数据时,MyBatis拦截器是一个非常有用的工具。 Geometry类型在空间数据库中广泛使用,它允许存储和操作各种地理和几何数据。 在本博客中,我们将探讨如何使用MyBatis拦截器来处理MySQL中的Geometry数据。

首先,让我们了解一下MyBatis拦截器的基本概念。 拦截器是MyBatis提供的一种机制,用于在执行SQL语句之前或之后进行干预和处理。 通过使用拦截器,我们可以在执行SQL语句之前或之后对其进行修改、增强或拦截。

在处理MySQL中的Geometry数据时,我们可能会遇到一些常见的需求,例如计算两个几何对象之间的距离、获取几何对象的边界框或进行空间查询。 MyBatis拦截器可以帮助我们在执行SQL语句之前或之后对这些操作进行自定义处理。

要使用MyBatis拦截器处理MySQL中的Geometry数据,我们需要以下步骤:

  1. 创建一个实现了MyBatis的Interceptor接口的拦截器类。 拦截器类需要实现intercept方法,在该方法中可以自定义处理逻辑。 在这个方法中,我们可以获取SQL语句、参数和结果,并对它们进行修改或拦截。
@Documented
@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Geometry {
}
@Data
public class geoInfo Serializable {

    private Long id;

    private String name;

    /**
     * 空间位置信息
     */
    @Geometry
    private String fenceGis;

}
package com.ruoyi.framework.security.interceptor;

import com.baomidou.mybatisplus.annotation.TableField;
import com.ych.common.annotation.Geometry;
import com.ych.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.RowBounds;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.*;


@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
@Slf4j
public class MybatisGeometryInterceptor implements Interceptor {

    private final Integer SRID = 4326;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) realTarget(invocation.getTarget());
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
        List<ResultMap> resultMaps = mappedStatement.getResultMaps();
        ResultMap map = resultMaps.get(0);
        Class<?> className = map.getType();

        if (isApplicableResultMap(resultMaps)) {
            if (SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
                return handleSelect(invocation, statementHandler, metaObject, boundSql, resultMaps, map, className);
            } else if (SqlCommandType.INSERT.equals(mappedStatement.getSqlCommandType())) {
                return handleInsert(invocation, statementHandler, metaObject, boundSql, className);
            } else if (SqlCommandType.UPDATE.equals(mappedStatement.getSqlCommandType())) {
                return handleUpdate(invocation, statementHandler, metaObject, boundSql, className);
            }
        }
        return invocation.proceed();
    }

    private Object handleSelect(Invocation invocation, StatementHandler statementHandler, MetaObject metaObject, BoundSql boundSql, List<ResultMap> resultMaps, ResultMap map, Class<?> className) throws Throwable {
        StringBuilder sb = new StringBuilder();
        sb.append(SqlCommandType.SELECT.name());
        String originalSql = boundSql.getSql();
        String reSql = originalSql.replace(SqlCommandType.SELECT.name(), "");
        int from = reSql.toUpperCase(Locale.getDefault()).indexOf("FROM");
        // 获取字段属性
        List<Field> allField = getAllField(className);
        for (Field field : allField) {
            field.setAccessible(true);
            String filedName = StringUtils.toUnderScoreCase(field.getName());
            if ("serial_version_uid".equalsIgnoreCase(filedName) || "serialVersionUID".equalsIgnoreCase(filedName)) {
                continue;
            }
            // 判断字段上是否有@Geometry注解
            if (field.isAnnotationPresent(Geometry.class)) {
                sb.append("ST_ASTEXT(").append(filedName).append(") AS ").append(filedName).append(",");
            } else {
                // 判断字段上是否有@TableField注解
                if (field.isAnnotationPresent(TableField.class)) {
                    // 获取@TableField注解
                    TableField tableField = field.getAnnotation(TableField.class);
                    // exit为true就添加
                    if (!tableField.exist()) {
                        continue;
                    } else {
                        sb.append(" ").append(filedName).append(",");
                    }
                } else {
                    sb.append(" ").append(filedName).append(",");
                }
            }
        }
        sb.deleteCharAt(sb.length() - 1);
        String lastSql = reSql.substring(from);
        sb.append(" " + lastSql);
        metaObject.setValue("delegate.boundSql.sql", sb.toString());
        metaObject.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET);
        metaObject.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);
        return invocation.proceed();
    }

    private Object handleInsert(Invocation invocation, StatementHandler statementHandler, MetaObject metaObject, BoundSql boundSql, Class<?> className) throws Throwable {
        Object paramObj = boundSql.getParameterObject();
        Field[] fields;
        if (paramObj instanceof HashMap) {
            fields = ((HashMap) paramObj).get("et").getClass().getDeclaredFields();
        } else {
            fields = getAllField(paramObj.getClass()).toArray(new Field[0]);
        }
        String originalSql = boundSql.getSql();
        originalSql = originalSql.toUpperCase();

        int start = originalSql.indexOf("(");
        int end = originalSql.indexOf(")");
        String paramNames = originalSql.substring(start + 1, end);
        String substring = originalSql.substring(0, originalSql.indexOf("VALUES"));
        StringBuilder sb = new StringBuilder();
        sb.append(substring).append(" ").append("VALUES ").append("( ");

        String[] split = paramNames.split(",");
        for (String paramName : split) {
            for (Field field : fields) {
                if (field.getName().trim().equalsIgnoreCase(StringUtils.underlineToHump(paramName.trim()))) {
                    // 判断字段上是否有@Geometry注解
                    if (field.isAnnotationPresent(Geometry.class)) {
                        sb.append("ST_GEOMFROMTEXT(").append("? ").append(",").append(SRID).append(",").append("'axis-order=long-lat'").append(")").append(",");
                    } else {
                        sb.append("?").append(",");
                    }
                }
            }
        }
        sb.deleteCharAt(sb.length() - 1).append(" )");
        metaObject.setValue("delegate.boundSql.sql", sb.toString());
        return invocation.proceed();
    }

    private Object handleUpdate(Invocation invocation, StatementHandler statementHandler, MetaObject metaObject, BoundSql boundSql, Class<?> className) throws Throwable {
        Object paramObj = boundSql.getParameterObject();
        Field[] fields;
        if (paramObj instanceof HashMap) {
            fields = ((HashMap) paramObj).get("et").getClass().getDeclaredFields();
        } else {
            fields = getAllField(paramObj.getClass()).toArray(new Field[0]);
        }
        String originalSql = boundSql.getSql();
        originalSql = originalSql.toUpperCase();

        int start = originalSql.indexOf("SET");
        int end = originalSql.indexOf("WHERE");
        StringBuilder sb = new StringBuilder();
        sb.append(originalSql, 0, start + 4);
        String params = originalSql.substring(start + 4, end);
        String after = params.replace("=", "").replace("?", "");

        String[] split = after.split(",");
        for (String paramName : split) {
            for (Field field : fields) {
                if (field.getName().trim().equalsIgnoreCase(StringUtils.underlineToHump(paramName.trim()))) {
                    sb.append(paramName).append("=");
                    // 判断字段上是否有@Geometry注解
                    if (field.isAnnotationPresent(Geometry.class)) {
                        sb.append("ST_GEOMFROMTEXT(").append("? ").append(",").append(SRID).append(",").append("'axis-order=long-lat'").append(")").append(",");
                    } else {
                        sb.append("?").append(",");
                    }
                }
            }
        }
        sb.deleteCharAt(sb.length() - 1).append(originalSql.substring(end));
        metaObject.setValue("delegate.boundSql.sql", sb.toString());
        return invocation.proceed();
    }

    private boolean isApplicableResultMap(List<ResultMap> resultMaps) {
        String resultMapId = resultMaps.get(0).getId();
        return resultMapId.contains("TbFence") || resultMapId.contains("TbHarbor") || resultMapId.contains("TbShip");
    }

    private Object realTarget(Object target) {
        if (Proxy.isProxyClass(target.getClass())) {
            MetaObject metaObject = SystemMetaObject.forObject(target);
            return realTarget(metaObject.getValue("h.target"));
        }
        return target;
    }

    /**
     * 获取本类及父类所有字段
     * @param className
     * @return
     */
    private ArrayList<Field> getAllField(Class<?> className) {
        ArrayList<Field> allField = new ArrayList<>();
        while (className != null && className != Object.class) {
            // 获取所有字段,包括私有字段
            Field[] fields = className.getDeclaredFields();
            Collections.addAll(allField, fields);
            // 获取父类的 Class 对象
            className = className.getSuperclass();
        }
        return allField;
    }

    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }

}

  1. 在MyBatis配置文件中配置拦截器。 在配置文件中,我们需要将拦截器类添加到MyBatis的拦截器链中。 这样,当执行SQL语句时,拦截器就会被调用,并进行自定义的Geometry处理操作。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 全局参数 -->
    <settings>
        <!-- 使全局的映射器启用或禁用缓存 -->
        <setting name="cacheEnabled"             value="true"   />
        <!-- 允许JDBC 支持自动生成主键 -->
        <setting name="useGeneratedKeys"         value="true"   />
        <!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 -->
        <setting name="defaultExecutorType"      value="SIMPLE" />
		<!-- 指定 MyBatis 所用日志的具体实现 -->
        <setting name="logImpl"                  value="SLF4J"  />
        <!-- 使用驼峰命名法转换字段 -->
		<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
	</settings>

    <plugins>
        <plugin interceptor="你的包名.MybatisGeometryInterceptor"/>
    </plugins>
	
</configuration>

  1. 在拦截器的intercept方法中,我们可以使用MySQL的空间函数或扩展库来处理Geometry数据。 MySQL提供了一系列的空间函数和操作符,用于处理和查询Geometry数据。 通过在拦截器中使用这些函数,我们可以实现各种Geometry处理操作。

例如,我们可以使用MySQL的ST_Distance函数来计算两个几何对象之间的距离。 在拦截器的intercept方法中,我们可以获取SQL语句和参数,判断是否是Geometry操作,然后使用ST_Distance函数计算距离,并将结果返回给应用程序。

另一个例子是使用MySQL的ST_Envelope函数来获取几何对象的边界框。 在拦截器中,我们可以通过解析SQL语句和参数,找到包含ST_Envelope函数的查询,并将其替换为对应的边界框查询。

通过使用MyBatis拦截器,我们可以灵活地处理MySQL中的Geometry数据,实现各种自定义的操作和查询。 拦截器提供了一个强大的机制,允许我们在SQL语句的执行过程中对Geometry数据进行处理和干预。

总结起来,使用MyBatis拦截器对MySQL中的Geometry进行处理是一种强大而灵活的方法。 通过自定义拦截器类和处理逻辑,我们可以在SQL语句执行前后对Geometry数据进行修改、增强或拦截。 这为我们实现各种Geometry操作和查询提供了便利和灵活性。 希望这篇博客对你在处理MySQL中的Geometry数据时有所帮助!

  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot使用Mybatis拦截器,需要进行以下步骤: 1.定义拦截器类,实现Mybatis的Interceptor接口。 ```java @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}) }) public class MyInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { //拦截逻辑 return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { //设置拦截器属性 } } ``` 2.在Spring Boot的配置文件配置拦截器。 ```yaml mybatis: configuration: #配置拦截器 #注意:mybatis下的configuration属性是Mybatis的Configuration对象,不是Spring Boot的配置文件 #使用Mybatis的配置文件时需要使用mybatis.config-location属性 #使用Spring Boot的配置文件时需要使用mybatis.configuration属性 #两者不能同时使用 plugins: - com.example.MyInterceptor ``` 3.在Mybatis的Mapper接口使用@Intercepts注解指定拦截器。 ```java @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}) }) public interface UserMapper { List<User> selectAll(); } ``` 其,@Intercepts注解用于指定拦截器,@Signature注解用于指定拦截的方法。 总的来说,在Spring Boot使用Mybatis拦截器的过程和在其他环境下使用Mybatis拦截器的过程类似,只需要在Spring Boot的配置文件配置拦截器即可。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值