阜宁网站制作费用,南昌门户网站,网页升级紧急通知自觉离开更新,什么网站做兼职最好前言
工作中写的一段代码#xff0c;备个份#xff0c;以后兴许能直接用 功能描述#xff1a;如果前端传入了排序规则#xff0c;则优先按传入的字段进行排序#xff0c;SQL原有的排序规则追加到末尾 注#xff1a;我们项目里的分页查询#xff0c;是基于XML的SQL执行的…前言
工作中写的一段代码备个份以后兴许能直接用 功能描述如果前端传入了排序规则则优先按传入的字段进行排序SQL原有的排序规则追加到末尾 注我们项目里的分页查询是基于XML的SQL执行的没有直接使用mybatis-plus的 IPage
正文
定义拦截器 import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.jetbrains.annotations.Nullable;import java.sql.Connection;
import java.util.List;/*** 添加自定义排序规则* 如果前端传入了排序规则则优先按传入的字段进行排序SQL原有的排序规则追加到末尾* 这个SQL的处理方式【不是基于】字符串拼接底层的SQL执行是基于 com.mysql.cj.jdbc.ClientPreparedStatement.execute,* PreparedStatement 是防SQL注入的强行做SQL注入会抛语法错误的异常 - syntax exception* author weiheng* date 2024-01-23**/
Slf4j
public class MybatisPageOrderSqlInterceptor extends JsqlParserSupport implements InnerInterceptor {/** 排序方式 - 升序 */private static final String SORT_ASC asc;Overridepublic void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {if (log.isDebugEnabled()) {log.info( 自定义排序拦截 StatementHandler[{}], sh);log.info( 自定义排序拦截 connection[{}], connection);log.info( 自定义排序拦截 transactionTimeout[{}], transactionTimeout);}PluginUtils.MPStatementHandler mpSh PluginUtils.mpStatementHandler(sh);MappedStatement ms mpSh.mappedStatement();SqlCommandType sct ms.getSqlCommandType();if (sct ! SqlCommandType.SELECT) {// 不是查询操作则直接跳过不做任何操作return;} PluginUtils.MPStatementHandler mpSh PluginUtils.mpStatementHandler(sh);PluginUtils.MPBoundSql mpBs mpSh.mPBoundSql();// 取分页查询的入参 PageDTOPageDTO pageDto getPageDTO(mpSh);if (pageDto null || CollUtil.isEmpty(pageDto.getOrderColumns())) {// 不是自定义分页查询不做处理return;}mpBs.sql(parserMulti(mpBs.sql(), pageDto));}Overrideprotected void processSelect(Select select, int index, String sql, Object obj) {PageDTO dto;if (obj instanceof PageDTO) {dto (PageDTO) obj;} else {// 如果不是分页查询则不做处理return;}// 1. 解析SQLPlainSelect plainSelect (PlainSelect) select.getSelectBody();ListOrderByElement originOrderList plainSelect.getOrderByElements();ListOrderByElement clonedOriginOrder null;if (CollUtil.isNotEmpty(originOrderList)) {// 创建副本然后删除原有排序规则clonedOriginOrder BeanUtil.copyToList(originOrderList, OrderByElement.class);originOrderList.clear();}// 2. 向 plainSelect 中添加自定义排序规则addCustomizeSortColumns(dto, plainSelect);// 3. 添加SQL的原始排序规则 - 追加到末尾if (CollUtil.isNotEmpty(clonedOriginOrder)) {plainSelect.addOrderByElements(clonedOriginOrder);}if (log.isDebugEnabled()) {log.info( 自定义排序拦截 plainSelect[{}], plainSelect);}}/*** 添加自定义排序规则** param dto SQL查询入参* param plainSelect 明文* author weiheng**/private void addCustomizeSortColumns(PageDTO dto, PlainSelect plainSelect) {ListOrderColumnDTO orderColumns dto.getOrderColumns();for (OrderColumnDTO c : orderColumns) {// 构建新的排序规则OrderByElement orderByElement new OrderByElement();// 设置排序 - 不传值则默认asc升序orderByElement.setAsc(SORT_ASC.equalsIgnoreCase(c.getSort()));// 设置排序字段orderByElement.setExpression(new Column(c.getOrderColumn()));// 重新封装条件 - 优先按自定义进行排序plainSelect.addOrderByElements(orderByElement);}}/*** 分页查询入参获取* 大概搜了下没有到3个入参的如果有请将 PageDTO 放到第1或第2的位置* param mpSh 处理对象* return 分页查询入参* author weiheng**/Nullableprivate PageDTO getPageDTO(PluginUtils.MPStatementHandler mpSh) {PageDTO pageDto null;Object obj mpSh.parameterHandler().getParameterObject();try {Object param ((MapperMethod.ParamMap?) obj).get(param1);if (param instanceof PageDTO) {pageDto (PageDTO) param;} else {param ((MapperMethod.ParamMap?) obj).get(param2);if (param instanceof PageDTO) {pageDto (PageDTO) param;}}} catch (Exception e) {// 没有从SQL中获取到对应的参数没有param1或param2不走自定义分页逻辑}return pageDto;}}添加插件 - 添加自定义的拦截器 import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** mybatis配置* author Heng.Wei* date 2022-05-11**/
Configuration
public class MybatisPlusConfig {Beanpublic MybatisPlusInterceptor paginationInterceptor() {MybatisPlusInterceptor interceptor new MybatisPlusInterceptor();// 乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());// 分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));// 添加防止全表更新与删除插件interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());// 深度分页插件interceptor.addInnerInterceptor(new MybatisHighPageInterceptor());// 添加自定义排序interceptor.addInnerInterceptor(new MybatisPageOrderSqlInterceptor());return interceptor;}
}代码很简单不多做废话了自测OK
补充 从上图可以看到这里会 for 循环调用所有拦截器的 beforePrepare 方法 然后再通过 invocation.proceed 反射调用 StatementHandler 接口的 prepare 方法 可以从图中看到接口实现是 PreparedStatementHandler 类的 instantiateStatement 方法 通过 PreparedStatementHandler 执行SQL操作 PS: 很意外昨晚发的帖子基本纯代码也没什么描述和备注第二天早上看展现量9、阅读199、新增粉丝2、收藏6、点赞3 感觉这个东西喜欢看的同学还比较多所以又稍微【补充】了一下内容