Spring系列——MybatisPlus
2021-03-23 10:25
标签:截取 pos update mave group 注入 escape ssim evel 以前是Mybatis XML配套的方式去写,而MybaitsPlus是Mybatis的增强版,抛去了XML文件内容。后者虽然减少了很多繁琐的SQL内容编写,但是同样的,对于复杂的SQL场景,类似流似的SQL生成还是没有XML写法直观。 插件是方便自定义额外功能,比如分页、模糊查询处理特殊字符。我们在编写插件时,除了需要让插件类实现 Interceptor 接口外,还需要通过注解标注 该插件的拦截点。所谓拦截点指的是插件所能拦截的方法,MyBatis 所允许拦截的方法如下: 5.1 原理 (1)配置加载插件 com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration:加载任何实现org.apache.ibatis.plugin.Interceptor的自定义插件类。 (2)Executor org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource com.baomidou.mybatisplus.core.MybatisConfiguration#newExecutor org.apache.ibatis.plugin.InterceptorChain#pluginAll ?案例插件? ?org.apache.ibatis.plugin.Plugin#wrap ?org.apache.ibatis.plugin.Plugin#invoke (3)StatementHandler com.baomidou.mybatisplus.core.executor.MybatisSimpleExecutor#doQuery org.apache.ibatis.session.Configuration#newStatementHandler (4)ParameterHandler org.apache.ibatis.executor.statement.BaseStatementHandler#BaseStatementHandler org.apache.ibatis.session.Configuration#newParameterHandler (5)ResultHandler org.apache.ibatis.session.Configuration#newResultSetHandler 4.2 实战 (1)分页插件 (2)模糊查询处理特殊字符 Q:Mybatis如何做到防SQL注入? A:? Mybatis 使用 #{?} 时,会进行sql的预编译(select from t_user where a = ?);使用${?}时,不会进行sql的预编译(select from t_user where a = 1),这样的话,会有sql注入的风险。经测试,sql注入无法注入两条sql语句,会报错。只能注入类似(select * from t_user where a = 1 or 1 = 1), 注入的变量为 “‘1’ or 1 = 1”; Q:除了配置的方式,QueryWrap可以通过打断点的方式查看组装的SQL吗? A:不能 Q:数据库时间戳接收用Date还是LocalDateTime接收好? Q:在继承BaseMapper Q:Mybatis-plus selectOne函数如何限制返回一条数据? 本文到这里就结束了,感谢看到最后的朋友,都看到最后了,点个赞再走啊,如有不对之处还请多多指正。 Spring系列——MybatisPlus 标签:截取 pos update mave group 注入 escape ssim evel 原文地址:https://blog.51cto.com/14969174/25426872. 特性
3. Mybatis层次结构
4. Maven依赖
5. 插件机制
public MybatisPlusAutoConfiguration(MybatisPlusProperties properties,
ObjectProvider
> configurationCustomizersProvider,
ObjectProvider
> mybatisPlusPropertiesCustomizerProvider,
ApplicationContext applicationContext) {
this.properties = properties;
this.interceptors = interceptorsProvider.getIfAvailable();
this.typeHandlers = typeHandlersProvider.getIfAvailable();
this.languageDrivers = languageDriversProvider.getIfAvailable();
this.resourceLoader = resourceLoader;
this.databaseIdProvider = databaseIdProvider.getIfAvailable();
this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
this.mybatisPlusPropertiesCustomizers = mybatisPlusPropertiesCustomizerProvider.getIfAvailable();
this.applicationContext = applicationContext;
}
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
// ...
if (!ObjectUtils.isEmpty(this.interceptors)) {
factory.setPlugins(this.interceptors);
}
// ...
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// ...
// 创建Executor
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
}
catch (Exception e) {...}
finally {...}
}
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
if (useDeprecatedExecutor) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new MybatisBatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new MybatisReuseExecutor(this, transaction);
} else {
executor = new MybatisSimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new MybatisCachingExecutor(executor);
}
// 植入插件
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
return super.newExecutor(transaction, executorType);
}
public Object pluginAll(Object target) {
// 遍历拦截器
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
public static Object wrap(Object target, Interceptor interceptor) {
// 获取@Intercepts注解的信息,每一个@Signature注解圈定一个方法
Map
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Set
public
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
// 植入插件
statementHandler = (StatementHandler)
interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// ...
// 创建ParameterHandler
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
// 创建ResultSetHandler
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
// 植入插件
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
// 植入插件
resultSetHandler = (ResultSetHandler)
interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
@Bean
public PaginationInnerInterceptor paginationInnerInterceptor() {
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
paginationInnerInterceptor.setDbType(DbType.MYSQL);
return paginationInnerInterceptor;
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(ObjectProvider
> innerInterceptorProviders) {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
List
@Bean
public FuzzyQueryInterceptor fuzzyQueryInterceptor() {
return new FuzzyQueryInterceptor();
}
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import priv.whh.std.boot.mybatis.plus.util.EscapeUtil;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
/**
* 模糊查询拦截器方法,处理模糊查询中包含特殊字符(_、%、\)
*
*/
@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 FuzzyQueryInterceptor implements Interceptor {
private static final String LIKE = " like ";
private static final String QUESTION_MARK = "?";
private static final String LIKE_WITH_QUESTION_MARK = " like ?";
private static final String UNDERLINE = "_";
private static final String PERCENT = "%";
private static final String EW = "ew";
private static final String EW_PARAM_NAME_VALUE_PAIRS = "ew.paramNameValuePairs.";
private static final String DOUBLE_SLASH = "\\";
private static final String DOUBLE_SLASH_WITH_SPOT = "\\.";
private static final String DOUBLE_SLASH_WITH_QUESTION_MARK = "\\?";
@Override
public Object intercept(Invocation invocation) throws InvocationTargetException, IllegalAccessException {
// 拦截sql
Object[] args = invocation.getArgs();
MappedStatement statement = (MappedStatement) args[0];
Object parameterObject = args[1];
BoundSql boundSql = statement.getBoundSql(parameterObject);
String sql = boundSql.getSql();
// 处理特殊字符
Object param = modifyLikeSql(sql, parameterObject, boundSql);
args[1] = param;
// 返回
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
@SuppressWarnings("unchecked")
public static Object modifyLikeSql(String sql, Object parameterObject, BoundSql boundSql) {
boolean paramJudge = parameterObject instanceof HashMap || parameterObject instanceof String;
if (!paramJudge) {
return parameterObject;
}
if (!sql.toLowerCase().contains(LIKE) || !sql.toLowerCase().contains(QUESTION_MARK)) {
return parameterObject;
}
// 获取关键字的个数(去重)
String[] strList = sql.split(DOUBLE_SLASH_WITH_QUESTION_MARK);
Set
6.?缓存机制
7. 会话机制
9. 配置
10. FAQ
11. 结尾