mybatis-plus拦截器、字段填充器、类型处理器、表名替换、SqlInjector(联合主键处理)

mybatis-plus是一个优秀的ORM框架,除了提供一些常规的功能,还提供了一些高级功能,比如拦截器、字段填充器、类型处理器、表名替换、SqlInjector(联合主键处理)等,这些功能都可以方便我们进行业务开发,以下是详细讲解:

Mybatis-plus拦截器

Mybatis-plus提供了拦截器机制,使得我们可以对Sql语句进行拦截和修改,甚至可以在sql语句执行前后进行处理,这样可以实现一些高级功能,比如动态表名、分表、数据权限等。

接下来是一个通过Mybatis-plus拦截器实现动态表名的示例:

public class DynamicTableNameInterceptor implements Interceptor {

    /**
     * 根据规则构造新表名
     * @param name 原始表名
     * @param parameter sql执行参数
     * @param mapper sql执行Mapper对象
     * @return 返回新表名
     */
    @Override
    public String changeTableName(String name, Object parameter, MapperMethod mapper) {
        // 从执行参数中获取参数值
        Long userId = (Long) ReflectionUtils.invokeGetter(parameter, "userId");
        // 构造新表名
        String tableName = "user" + userId % 10;
        return tableName;
    }

    /**
     * 拦截器逻辑实现
     * @param invocation 拦截器调用方法
     * @return 返回执行结果
     * @throws Throwable 抛出异常
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取MappedStatement对象
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        // 获取sql参数
        Object parameter = invocation.getArgs()[1];
        // 获取MapperMethod对象
        MapperMethod mapper = (MapperMethod) invocation.getArgs()[2];
        // 获取原始表名
        String name = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1);
        // 获取新表名
        String tableName = changeTableName(name, parameter, mapper);
        // 替换表名
        SqlSource sqlSource = mappedStatement.getSqlSource();
        String sql = sqlSource.getBoundSql(parameter).getSql();
        sql = sql.replaceAll(name, tableName);
        BoundSql newBoundSql = new BoundSql(mappedStatement.getConfiguration(), sql, sqlSource.getBoundSql(parameter).getParameterMappings(), parameter);
        MappedStatement.Builder builder = new MappedStatement.Builder(mappedStatement.getConfiguration(), mappedStatement.getId(), new BoundSqlSqlSource(newBoundSql), mappedStatement.getSqlCommandType());
        builder.resource(mappedStatement.getResource());
        builder.fetchSize(mappedStatement.getFetchSize());
        builder.statementType(mappedStatement.getStatementType());
        builder.timeout(mappedStatement.getTimeout());
        builder.parameterMap(mappedStatement.getParameterMap());
        builder.resultMaps(mappedStatement.getResultMaps());
        builder.cache(mappedStatement.getCache());
        builder.flushCacheRequired(mappedStatement.isFlushCacheRequired());
        builder.useCache(mappedStatement.isUseCache());
        MappedStatement newMappedStatement = builder.build();
        invocation.getArgs()[0] = newMappedStatement;
        // 执行sql语句
        return invocation.proceed();
    }

    private static class BoundSqlSqlSource implements SqlSource {

        BoundSql boundSql;

        public BoundSqlSqlSource(BoundSql boundSql) {
            this.boundSql = boundSql;
        }

        @Override
        public BoundSql getBoundSql(Object parameterObject) {
            return boundSql;
        }
    }
}

Mybatis-plus字段填充器

Mybatis-plus提供了字段填充器,使得我们可以在插入或更新数据时自动填充某些字段,比如创建人、创建时间、更新人、更新时间等。

接下来是一个通过Mybatis-plus字段填充器实现创建时间和更新时间字段自动填充的示例:

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    /**
     * 插入数据时填充创建时间和更新时间
     * @param metaObject MyMetaObjectHandler对象
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        // 填充创建时间
        setValue("createTime", LocalDateTime.now(), metaObject);
        // 填充更新时间
        setValue("updateTime", LocalDateTime.now(), metaObject);
    }

    /**
     * 更新数据时填充更新时间
     * @param metaObject MyMetaObjectHandler对象
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        // 填充更新时间
        setValue("updateTime", LocalDateTime.now(), metaObject);
    }

    /**
     * 设置字段值
     * @param fieldName 字段名称
     * @param value 字段值
     * @param metaObject MyMetaObjectHandler对象
     */
    private void setValue(String fieldName, Object value, MetaObject metaObject) {
        if (metaObject.hasSetter(fieldName)) {
            metaObject.setValue(fieldName, value);
        }
    }
}

Mybatis-plus类型处理器

Mybatis-plus提供了类型处理器,可以方便地将java类型转换为数据库类型,比如将Java的LocalDateTime类型转换为MYSQL的datetime类型。

接下来是一个通过Mybatis-plus类型处理器将LocalDataTime类型转成long类型的示例:

public class LocalDateTimeTypeHandler extends BaseTypeHandler<LocalDateTime> {

    /**
     * 将LocalDateTime类型转换为long类型保存到数据库中
     * @param preparedStatement PreparedStatement对象
     * @param i 参数下标
     * @param localDateTime LocalDateTime对象
     * @param jdbcType jdbc类型
     * @throws SQLException 执行异常
     */
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, LocalDateTime localDateTime, JdbcType jdbcType) throws SQLException {
        preparedStatement.setLong(i, localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli());
    }

    /**
     * 将long类型转换为LocalDateTime类型返回
     * @param resultSet ResultSet对象
     * @param s 列名
     * @return 返回LocalDateTime对象
     * @throws SQLException 执行异常
     */
    @Override
    public LocalDateTime getNullableResult(ResultSet resultSet, String s) throws SQLException {
        long dateTimeStamp = resultSet.getLong(s);
        if (dateTimeStamp != 0) {
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTimeStamp), ZoneOffset.of("+8"));
        }
        return null;
    }

    /**
     * 将long类型转换为LocalDateTime类型返回
     * @param resultSet ResultSet对象
     * @param i 列的下标
     * @return 返回LocalDateTime对象
     * @throws SQLException 执行异常
     */
    @Override
    public LocalDateTime getNullableResult(ResultSet resultSet, int i) throws SQLException {
        long dateTimeStamp = resultSet.getLong(i);
        if (dateTimeStamp != 0) {
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTimeStamp), ZoneOffset.of("+8"));
        }
        return null;
    }

    /**
     * 将long类型转换为LocalDateTime类型返回
     * @param callableStatement CallableStatement对象
     * @param i 列的下标
     * @return 返回LocalDateTime对象
     * @throws SQLException 执行异常
     */
    @Override
    public LocalDateTime getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        long dateTimeStamp = callableStatement.getLong(i);
        if (dateTimeStamp != 0) {
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(dateTimeStamp), ZoneOffset.of("+8"));
        }
        return null;
    }
}

Mybatis-plus表名替换

表名替换功能可以让我们在查询时将真实表名替换为其他名字,这样可以避免其他应用程序获取到真实的表名。

接下来是一个通过Mybatis-plus表名替换功能将真实表名替换为别名表名的示例:

public class TableNameHandler implements ITableNameHandler {

    /**
     * 替换表名为别名
     * @param tableName 表名
     * @param tablePojo 实体类型
     * @return 返回替换后的表名
     */
    @Override
    public String dynamicTableName(String tableName, Class<?> tablePojo) {
        if (User.class.isAssignableFrom(tablePojo)) {
            tableName = "user_alias";
        } else if (Order.class.isAssignableFrom(tablePojo)) {
            tableName = "order_alias";
        }
        return tableName;
    }
}

Mybatis-plus SqlInjector

SqlInjector实现类可以方便的扩展Mybatis-plus的业务,比如多表关联查询、联合主键处理等。

接下来是一个通过Mybatis-plus SqlInjector实现联合主键处理的示例:

public abstract class AbstractLogicDeleteByIdsWithFill<T> implements ISqlInjector {

    /**
     * 通过ID批量逻辑删除
     * @param tableMeta 逻辑删除表的表元信息
     * @param idList ID列表
     * @return 返回更新记录数
     */
    protected abstract Integer deleteByIdsWithFill(TableInfo tableMeta, Collection<? extends Serializable> idList);

    /**
     * 获取删除标记字段
     * @param tableMeta 表元信息
     * @return 返回逻辑删除字段名称
     */
    protected abstract String getLogicDeleteFieldName(TableInfo tableMeta);

    /**
     * 是否开启了多标签
     * @param globalConfig 全局配置
     * @param idSql 待执行的SQL
     * @return 返回是否开启了多标签
     */
    protected abstract boolean openMultiDelete(GlobalConfig globalConfig, String idSql);

    /**
     * 获取被逻辑删除的记录数
     * @param metaObject 元对象,可以获取到Mybatis-plus的参数对象
     * @return 返回记录数
     */
    protected abstract String getDeleteCount(MetaObject metaObject);


    @Override
    public void injectSqlRunner(SqlRunner sqlRunner) {
        GlobalConfig globalConfig = GlobalConfigUtils.getGlobalConfig(sqlRunner.getSqlSessionFactory());
        MetaObject metaObject = sqlRunner.getSqlObject().getMetaObject();
        TableInfo tableInfo = MetaUtils.getTableInfo(metaObject);
        String logicDeleteField = getLogicDeleteFieldName(tableInfo);
        // 获取所有ID
        List<Serializable> idList = getIdList(metaObject, tableInfo);
        if (idList.isEmpty()) {
            return;
        }
        // 更新被逻辑删除的记录数
        metaObject.setValue("deleteCount", getDeleteCount(metaObject));
        // 生成SQL
        String deleteSql = SqlHelper.logicDeleteSql(tableInfo, globalConfig.getLogicDeleteValue(logicDeleteField), globalConfig.getLogicNotDeleteValue(logicDeleteField), SqlHelper.getTableStructure(metaObject), idList);
        logger.debug("logic-delete-sql: {}", deleteSql);
        // 是否开启了多标签
        if (openMultiDelete(globalConfig, deleteSql)) {
            AtomicInteger results = new AtomicInteger(0);
            String[] idArray = idList.stream().map((id) -> "'" + id + "'").toArray(String[]::new);
            int batchSize = SqlExecutorConstants.BATCH_SIZE;
            for (int i = 0; i < idArray.length; i += batchSize) {
                StringBuilder sb = new StringBuilder(batchSize * 7);
                sb.append(deleteSql).append(" AND id IN (");
                for (int j = i; j < i + batchSize && j < idArray.length; j++) {
                    sb.append(idArray[j]).append(",");
                }
                sb.setCharAt(sb.length() - 1, ')');
                String batchSql = sb.toString();
                logger.debug("logic-delete-sql: {}", batchSql);
                results.addAndGet(sqlRunner.execute(batchSql));
            }
            metaObject.setValue("result", results.get());
        } else {
            // 执行SQL
            int result = deleteByIdsWithFill(tableInfo, idList);
            metaObject.setValue("result", result);
        }
    }

    /**
     * 获取ID列表
     * @param metaObject 元对象,可以获取到Mybatis-plus的参数对象
     * @param tableInfo 表元信息
     * @return 返回所有ID
     */
    protected List<Serializable> getIdList(MetaObject metaObject, TableInfo tableInfo) {
        String idPropertyName = tableInfo.getKeyProperty();
        Object idPropertyValue = metaObject.getValue(idPropertyName);
        if (idPropertyValue == null) {
            return Collections.emptyList();
        } else if (idPropertyValue instanceof Collection) {
            return (List<Serializable>) ((Collection) idPropertyValue).stream().map((id) -> (Serializable) id).collect(Collectors.toList());
        }
        return Collections.singletonList((Serializable) idPropertyValue);
    }

}

public class LogicDeleteByIdsWithFill extends AbstractLogicDeleteByIdsWithFill<User> {

    /**
     * 通过ID批量逻辑删除
     * @param tableMeta 逻辑删除表的表元信息
     * @param idList ID列表
     * @return 返回更新记录数
     */
    @Override
    protected Integer deleteByIdsWithFill(TableInfo tableMeta, Collection<? extends Serializable> idList) {
        // 自定义业务逻辑
        return null;
    }

    /**
     * 获取删除标记字段
     * @param tableMeta 表元信息
     * @return 返回逻辑删除字段名称
     */
    @Override
    protected String getLogicDeleteFieldName(TableInfo tableMeta) {
        return "deleteFlag";
    }

    /**
     * 是否开启了多标签
     * @param globalConfig 全局配置
     * @param idSql 待执行的SQL
     * @return 返回是否开启了多标签
     */
    @Override
    protected boolean openMultiDelete(GlobalConfig globalConfig, String idSql) {
        return false;
    }

    /**
     * 获取被逻辑删除的记录数
     * @param metaObject 元对象,可以获取到Mybatis-plus的参数对象
     * @return 返回记录数
     */
    @Override
    protected String getDeleteCount(MetaObject metaObject) {
        User user = (User) metaObject.getValue("et");
        return "SELECT COUNT(*) FROM user WHERE deleteFlag=1 AND name='" + user.getName() + "'";
    }
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:mybatis-plus拦截器、字段填充器、类型处理器、表名替换、SqlInjector(联合主键处理) - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • docker安装mysql,设置mysql初始密码

    docker安装mysql,只需要2分钟就可以完成 docker search mysql 拉取mysql镜像(https://hub.docker.com/_/mysql) docker pull mysql:5.7 官网可查看存在的镜像,以及需要的版本号 运行mysql(–name 容器名称  -e MYSQL_ROOT_PASSWORD设置初始密码 …

    MySQL 2023年4月12日
    00
  • SpringBoot整合MyCat实现读写分离的方法

    下面我为你详细讲解如何通过Spring Boot和MyCat实现读写分离。 一、概述 MyCat是一个开源的数据库中间件,提供了多种高性能、高可用性的数据库分片集群方案。MyCat支持读写分离、数据分片、数据分区、集群高可用等多种特性。Spring Boot是一个快速开发、便捷启动的框架,支持自动化配置和快速集成第三方组件。 这里我将介绍如何使用Spring…

    database 2023年5月22日
    00
  • ezSQL PHP数据库操作类库

    ezSQL PHP数据库操作类库是一种为了让开发者更加方便地进行数据库操作而制作出来的类库。其核心原理是利用了PHP的PDO扩展或者MySQLi扩展来实现与数据库的交互,提高了代码的可读性和可维护性。下面就给大家详细介绍一下如何使用ezSQL PHP数据库操作类库进行数据库操作。 安装ezSQL PHP数据库操作类库 ezSQL PHP数据库操作类库的安装非…

    database 2023年5月22日
    00
  • Win2008 server + IIS7 设置身份模拟(ASP.NET impersonation)

    Win2008 server + IIS7 设置身份模拟(ASP.NET impersonation)可以实现以不同的账户来运行ASP.NET应用程序,并且可以使得ASP.NET应用程序获得更高的权限,比如访问受限的资源。以下是详细的设置攻略: 1. 打开“服务器管理器”,点击“角色”->“添加角色”。 2. 选择“Web服务器(IIS)”并安装,注意…

    database 2023年5月21日
    00
  • Java Web开发之信息查询方式总结

    Java Web 开发之信息查询方式总结 为什么需要信息查询方式总结 在 Java Web 开发中,信息查询功能一直都是必不可少的一部分。例如,在一个电商网站中,用户可以通过搜索框输入关键词查找商品;在一个博客网站中,用户可以通过分类、标签、搜索等方式查找文章。因此,掌握信息查询的方式和技巧对于开发人员来说是非常重要的。 信息查询方式包括但不限于 SQL 查…

    database 2023年5月21日
    00
  • 对MySQL几种联合查询的通俗解释

    这是关于MySQL联合查询的通俗解释攻略: 什么是联合查询 联合查询是一种将多个SELECT语句的结果组合为单个结果集的查询方法。它主要用于查询多个表中的数据,并且不需要将这些查询的结果放入同一个表中。联合查询的结果集包含所有查询结果的行,其中每个查询语句的列必须具有相同的数据类型。 联合查询的类型 MySQL支持以下几种联合查询: UNION UNION联…

    database 2023年5月21日
    00
  • 深入学习MySQL表数据操作

    深入学习MySQL表数据操作的完整攻略 1. 理解表数据操作的基本概念 在MySQL中,表数据操作主要包括增加数据、修改数据、删除数据和查询数据。这些操作是通过SQL语句实现的,其中增加数据、修改数据和删除数据属于数据更新操作,查询数据则是数据检索操作。具体的SQL语句包括: 1.1 增加数据 增加数据的SQL语句是INSERT INTO,一般包括插入的表名…

    database 2023年5月21日
    00
  • centOS安装mysql5.7详细教程

    CentOS安装MySQL 5.7详细教程 本教程介绍CentOS系统下安装MySQL 5.7的详细步骤。 环境准备 在开始安装过程前,请确保你的CentOS系统已经安装了epel-release仓库和wget工具,如果没有,请先执行以下命令进行安装: sudo yum -y install epel-release wget 下载MySQL RPM包 访问…

    database 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部