Mybatis在做数据库查询更新操作时,是否有遇到过字段前后出现空格的的情况;如果有,你是怎么处理的?是一个个trim()还是如何处理,接下来我将谈谈我的做法:使用拦截器注解@Intercepts告别字符串前后空格。
Exceutor
Excutor
是Mybatis的最核心的接口之一。其中,SqlSession接口中的功能就是基于Excutor来完成的。我们所需要的拦截的,也是这个接口所定义的CRUD操作方法:query
。
package org.apache.ibatis.executor;
import java.sql.SQLException;
import java.util.List;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.transaction.Transaction;
/**
* Mybatis执行器
*
* @author Clinton Begin
*/
public interface Executor {
/**
* 默认的结果处理器,默认为空,主要是在查询的时候用于处理查询结果
*/
ResultHandler NO_RESULT_HANDLER = null;
/**
* 实现对数据表的insert/update/delete操作
* @param ms
* @param parameter
* @return
* @throws SQLException
*/
int update(MappedStatement ms, Object parameter) throws SQLException;
/**
* 查询,回调处理查询结果,带分页
* @param ms
* @param parameter
* @param rowBounds
* @param resultHandler
* @param cacheKey
* @param boundSql
* @param <E>
* @return
* @throws SQLException
*/
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
/**
* 查询,回调处理查询结果
* @param ms
* @param parameter
* @param rowBounds
* @param resultHandler
* @param <E>
* @return
* @throws SQLException
*/
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
/**
* 查询,返回游标类型
* @param ms
* @param parameter
* @param rowBounds
* @param <E>
* @return
* @throws SQLException
*/
<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
/**
* 批量处理sql语句
* @return
* @throws SQLException
*/
List<BatchResult> flushStatements() throws SQLException;
/**
* 提交事务
* @param required
* @throws SQLException
*/
void commit(boolean required) throws SQLException;
/**
* 回滚事务
* @param required
* @throws SQLException
*/
void rollback(boolean required) throws SQLException;
/**
* 创建缓存中使用的CacheKey,即缓存中使用的key
* @param ms
* @param parameterObject
* @param rowBounds
* @param boundSql
* @return
*/
CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
/**
* 根据对应的key,查找是否存在缓存
* @param ms
* @param key
* @return
*/
boolean isCached(MappedStatement ms, CacheKey key);
/**
* 清理一级缓存
*/
void clearLocalCache();
/**
* 延迟加载一级缓存中的数据
* @param ms
* @param resultObject
* @param property
* @param key
* @param targetType
*/
void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
/**
* 获取事务对象
* @return
*/
Transaction getTransaction();
/**
* 关闭Executor对象
* @param forceRollback
*/
void close(boolean forceRollback);
/**
* 检查Exceutor对象是否关闭
* @return
*/
boolean isClosed();
/**
* 设置包装类
* @param executor
*/
void setExecutorWrapper(Executor executor);
}
拦截器
@Intercepts用于表明当前的对象是一个Interceptor
@Signature则表明要拦截的接口、方法以及对应的参数类型
package com.bly.crm.server.config;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bly.crm.generic.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;
import java.util.*;
/**
* @Author: Cpz
* @Description: 去除数据库查询返回结果集中字符串出现前后空格的情况
* eg: (1) " 文艺 " => " 文艺 ".trim() => "文艺"
* (2) " " => " ".trim() => null
* @Date: 2021/5/24 10:36
* @Version: 1.0
*/
@Slf4j
@Component
@Intercepts({
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
})
public class MybatisInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 获取查询返回类型
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
Class<?> resultType = resultMaps.get(0).getType();
// 获取查询结果并做空判断
Object proceed = invocation.proceed();
JSONArray jsonArray = JSON.parseArray(JSON.toJSONString(proceed));
if (jsonArray.isEmpty()) {
return proceed;
}
// 返回结果不为空则开始去除字符串前后空格
for (int i = 0, l = jsonArray.size(); i < l; i++) {
Object o = jsonArray.get(i);
if (o instanceof JSONObject) {
JSONObject jsonObject = (JSONObject) o;
for (String key : jsonObject.keySet()) {
Object value = jsonObject.get(key);
if (value instanceof String) {
jsonObject.put(key, StringUtils.trim2null(String.valueOf(value)));
}
}
o = jsonObject;
}else if (o instanceof String){
o = StringUtils.trim2null(String.valueOf(o));
}
jsonArray.set(i, o);
}
// 还原本来对象并返回
return JSON.parseArray(jsonArray.toJSONString(), resultType);
}
}
配置拦截器插件
private final MybatisInterceptor mybatisInterceptor;
/**
* 配置mybatis分页插件和自定义拦截器
* @param bean
*/
private void setSqlSessionFactoryPlugins(MybatisSqlSessionFactoryBean bean) {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(paginationInterceptor);
bean.setPlugins(mybatisPlusInterceptor, mybatisInterceptor);
}
拓展
在接口传参的时候,也可能出现类似的情况,可以通过拦截mybatis的update方法实现空格去除,这里就不过多赘述。
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
网友评论