();
- if (mapperLocations != null)
- {
- for (String mapperLocation : mapperLocations)
- {
- try
- {
- Resource[] mappers = resourceResolver.getResources(mapperLocation);
- resources.addAll(Arrays.asList(mappers));
- }
- catch (IOException e)
- {
- // ignore
- }
- }
- }
- return resources.toArray(new Resource[resources.size()]);
- }
-
- /**
- * mybatis 配置
- */
-// @Bean(name = "mysqlSessionFactory")
-// @Primary
-// public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
-// {
-// String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
-// String mapperLocations = env.getProperty("mybatis.mapperLocations");
-// String configLocation = env.getProperty("mybatis.configLocation");
-// typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
-// VFS.addImplClass(SpringBootVFS.class);
-//
-// final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
-// sessionFactory.setDataSource(dataSource);
-// sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
-// sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
-// sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
-// return sessionFactory.getObject();
-// }
-
- /**
- * mybatis-plus 配置:把 SqlSessionFactoryBean 换成 MybatisSqlSessionFactoryBean就行
- * @param dataSource 数据源
- * @return
- */
- @Bean(name = "mysqlSessionFactory")
- @Primary
- public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
- {
- String typeAliasesPackage = env.getProperty("mybatis-plus.typeAliasesPackage");
- String mapperLocations = env.getProperty("mybatis-plus.mapperLocations");
- String configLocation = env.getProperty("mybatis-plus.configLocation");
- typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
- VFS.addImplClass(SpringBootVFS.class);
-
- final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
- sessionFactory.setDataSource(dataSource);
- sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
- sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
- sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
- return sessionFactory.getObject();
- }
-
- @Bean(name = "mysqlTransactionManager")
- @Primary
- public DataSourceTransactionManager mysqlTransactionManager(@Qualifier("dynamicDataSource") DataSource dataSource) {
- return new DataSourceTransactionManager(dataSource);
- }
-
- @Bean(name = "mysqlSqlSessionTemplate")
- @Primary
- public SqlSessionTemplate mysqlSqlSessionTemplate(@Qualifier("mysqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
- return new SqlSessionTemplate(sqlSessionFactory);
- }
-
-}
diff --git a/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/SqlFilterArgumentResolver.java b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/SqlFilterArgumentResolver.java
new file mode 100644
index 00000000..f1acaa53
--- /dev/null
+++ b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/SqlFilterArgumentResolver.java
@@ -0,0 +1,92 @@
+package com.fastbee.framework.config;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.MethodParameter;
+import org.springframework.web.bind.support.WebDataBinderFactory;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.method.support.ModelAndViewContainer;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * 解决Mybatis Plus Order By SQL注入问题
+ * @author admin
+ */
+@Slf4j
+public class SqlFilterArgumentResolver implements HandlerMethodArgumentResolver {
+
+ private final static String[] KEYWORDS = { "master", "truncate", "insert", "select", "delete", "update", "declare",
+ "alter", "drop", "sleep" };
+
+ /**
+ * 判断Controller是否包含page 参数
+ * @param parameter 参数
+ * @return 是否过滤
+ */
+ @Override
+ public boolean supportsParameter(MethodParameter parameter) {
+ return parameter.getParameterType().equals(Page.class);
+ }
+
+ /**
+ * @param parameter 入参集合
+ * @param mavContainer model 和 view
+ * @param webRequest web相关
+ * @param binderFactory 入参解析
+ * @return 检查后新的page对象
+ *
+ * page 只支持查询 GET .如需解析POST获取请求报文体处理
+ */
+ @Override
+ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
+ NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
+
+ HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
+
+ String[] ascs = request.getParameterValues("ascs");
+ String[] descs = request.getParameterValues("descs");
+ String current = request.getParameter("current");
+ String size = request.getParameter("size");
+
+ Page> page = new Page<>();
+ if (StrUtil.isNotBlank(current)) {
+ page.setCurrent(Long.parseLong(current));
+ }
+
+ if (StrUtil.isNotBlank(size)) {
+ page.setSize(Long.parseLong(size));
+ }
+ List orderItemList = new ArrayList<>();
+ Optional.ofNullable(ascs).ifPresent(s -> orderItemList.addAll(
+ Arrays.stream(s).filter(sqlInjectPredicate()).map(OrderItem::asc).collect(Collectors.toList())));
+ Optional.ofNullable(descs).ifPresent(s -> orderItemList.addAll(
+ Arrays.stream(s).filter(sqlInjectPredicate()).map(OrderItem::desc).collect(Collectors.toList())));
+ page.addOrder(orderItemList);
+ return page;
+ }
+
+ /**
+ * 判断用户输入里面有没有关键字
+ * @return Predicate
+ */
+ private Predicate sqlInjectPredicate() {
+ return sql -> {
+ for (String keyword : KEYWORDS) {
+ if (StrUtil.containsIgnoreCase(sql, keyword)) {
+ return false;
+ }
+ }
+ return true;
+ };
+ }
+}
diff --git a/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/properties/DruidProperties.java b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/properties/DruidProperties.java
index 057403ec..594da2c7 100644
--- a/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/properties/DruidProperties.java
+++ b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/properties/DruidProperties.java
@@ -1,50 +1,31 @@
package com.fastbee.framework.config.properties;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.pool.DruidDataSource;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
/**
* druid 配置属性
- *
+ *
* @author ruoyi
*/
+@Data
@Configuration
+@ConfigurationProperties(prefix = "spring.datasource.dynamic.druid")
public class DruidProperties
{
- @Value("${spring.datasource.druid.initialSize}")
- private int initialSize;
-
- @Value("${spring.datasource.druid.minIdle}")
- private int minIdle;
-
- @Value("${spring.datasource.druid.maxActive}")
- private int maxActive;
-
- @Value("${spring.datasource.druid.maxWait}")
- private int maxWait;
-
- @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
- private int timeBetweenEvictionRunsMillis;
-
- @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
- private int minEvictableIdleTimeMillis;
-
- @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}")
- private int maxEvictableIdleTimeMillis;
-
- @Value("${spring.datasource.druid.validationQuery}")
+ private Integer initialSize;
+ private Integer minIdle;
+ private Integer maxActive;
+ private Integer maxWait;
+ private Long timeBetweenEvictionRunsMillis;
+ private Long minEvictableIdleTimeMillis;
+ private Long maxEvictableIdleTimeMillis;
private String validationQuery;
-
- @Value("${spring.datasource.druid.testWhileIdle}")
- private boolean testWhileIdle;
-
- @Value("${spring.datasource.druid.testOnBorrow}")
- private boolean testOnBorrow;
-
- @Value("${spring.datasource.druid.testOnReturn}")
- private boolean testOnReturn;
-
+ private Boolean testWhileIdle;
+ private Boolean testOnBorrow;
+ private Boolean testOnReturn;
public DruidDataSource dataSource(DruidDataSource datasource)
{
/** 配置初始化大小、最小、最大 */
diff --git a/springboot/fastbee-framework/src/main/java/com/fastbee/framework/mybatis/config/AutoPaginationInnerInterceptor.java b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/mybatis/config/AutoPaginationInnerInterceptor.java
new file mode 100644
index 00000000..f98e656b
--- /dev/null
+++ b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/mybatis/config/AutoPaginationInnerInterceptor.java
@@ -0,0 +1,33 @@
+package com.fastbee.framework.mybatis.config;
+
+
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.pagination.DialectFactory;
+import com.baomidou.mybatisplus.extension.plugins.pagination.dialects.IDialect;
+import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
+import org.apache.ibatis.executor.Executor;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+public class AutoPaginationInnerInterceptor extends PaginationInnerInterceptor {
+ @Override
+ protected IDialect findIDialect(Executor executor) {
+ Connection conn = null;
+ try {
+ conn = executor.getTransaction().getConnection();
+ String jdbcUrl = conn.getMetaData().getURL();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ if (this.getDialect() != null) {
+ return this.getDialect();
+ } else if (this.getDbType() != null) {
+ this.setDialect(DialectFactory.getDialect(this.getDbType()));
+ return this.getDialect();
+ } else {
+ return DialectFactory.getDialect(JdbcUtils.getDbType(executor));
+ }
+ }
+
+}
diff --git a/springboot/fastbee-framework/src/main/java/com/fastbee/framework/mybatis/config/MybatisPlusConfig.java b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/mybatis/config/MybatisPlusConfig.java
new file mode 100644
index 00000000..22a08a8e
--- /dev/null
+++ b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/mybatis/config/MybatisPlusConfig.java
@@ -0,0 +1,67 @@
+package com.fastbee.framework.mybatis.config;
+
+import cn.hutool.core.net.NetUtil;
+import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
+import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import com.fastbee.framework.config.SqlFilterArgumentResolver;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import java.util.List;
+
+/**
+ * @author admin
+ */
+@Configuration(proxyBeanMethods = false)
+@MapperScan("com.fastbee.**.mapper")
+public class MybatisPlusConfig implements WebMvcConfigurer {
+
+ /**
+ * SQL 过滤器避免SQL 注入
+ * @param argumentResolvers
+ */
+ @Override
+ public void addArgumentResolvers(List argumentResolvers) {
+ argumentResolvers.add(new SqlFilterArgumentResolver());
+ }
+
+ @Bean
+ public MybatisPlusInterceptor mybatisPlusInterceptor() {
+ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+ interceptor.addInnerInterceptor(paginationInnerInterceptor());
+ return interceptor;
+ }
+
+ /**
+ * 分页插件,自动识别数据库类型
+ */
+ public PaginationInnerInterceptor paginationInnerInterceptor() {
+ PaginationInnerInterceptor paginationInnerInterceptor = new AutoPaginationInnerInterceptor();
+ // 分页合理化
+ paginationInnerInterceptor.setOverflow(true);
+ return paginationInnerInterceptor;
+ }
+
+ /**
+ * 使用网卡信息绑定雪花生成器
+ * 防止集群雪花ID重复
+ */
+ @Bean
+ public IdentifierGenerator idGenerator() {
+ return new DefaultIdentifierGenerator(NetUtil.getLocalhost());
+ }
+ /**
+ * 审计字段自动填充
+ * @return {@link MybatisPlusMetaObjectHandler}
+ */
+ @Bean
+ public MybatisPlusMetaObjectHandler mybatisPlusMetaObjectHandler() {
+ return new MybatisPlusMetaObjectHandler();
+ }
+
+}
diff --git a/springboot/fastbee-framework/src/main/java/com/fastbee/framework/mybatis/config/MybatisPlusMetaObjectHandler.java b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/mybatis/config/MybatisPlusMetaObjectHandler.java
new file mode 100644
index 00000000..a599a9a5
--- /dev/null
+++ b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/mybatis/config/MybatisPlusMetaObjectHandler.java
@@ -0,0 +1,75 @@
+package com.fastbee.framework.mybatis.config;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import com.fastbee.common.core.domain.model.LoginUser;
+import com.fastbee.common.utils.SecurityUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.reflection.MetaObject;
+import org.springframework.util.ClassUtils;
+
+import java.nio.charset.Charset;
+import java.util.Date;
+
+/**
+ * MybatisPlus 自动填充配置
+ *
+ * @author admin
+ */
+@Slf4j
+public class MybatisPlusMetaObjectHandler implements MetaObjectHandler {
+
+ @Override
+ public void insertFill(MetaObject metaObject) {
+ log.debug("mybatisPlus插入填充--------------");
+ Date date = new Date();
+
+ fillValIfNullByName("createTime", date, metaObject, false);
+ fillValIfNullByName("updateTime", date, metaObject, false);
+ fillValIfNullByName("createBy", getUserName(), metaObject, false);
+ fillValIfNullByName("updateBy", getUserName(), metaObject, false);
+ fillValIfNullByName("deleteFlag", "1", metaObject, false);
+ }
+
+ @Override
+ public void updateFill(MetaObject metaObject) {
+ log.debug("mybatisPlus更新填充--------------");
+ fillValIfNullByName("updateTime", new Date(), metaObject, true);
+ fillValIfNullByName("updateBy", getUserName(), metaObject, true);
+ }
+
+ /**
+ * 填充值,先判断是否有手动设置,优先手动设置的值,例如:job必须手动设置
+ * @param fieldName 属性名
+ * @param fieldVal 属性值
+ * @param metaObject MetaObject
+ * @param isCover 是否覆盖原有值,避免更新操作手动入参
+ */
+ private static void fillValIfNullByName(String fieldName, Object fieldVal, MetaObject metaObject, boolean isCover) {
+ // 1. 没有 get 方法
+ if (!metaObject.hasSetter(fieldName)) {
+ return;
+ }
+ // 2. 如果用户有手动设置的值
+ Object userSetValue = metaObject.getValue(fieldName);
+ String setValueStr = StrUtil.str(userSetValue, Charset.defaultCharset());
+ if (StrUtil.isNotBlank(setValueStr) && !isCover) {
+ return;
+ }
+ // 3. field 类型相同时设置
+ Class> getterType = metaObject.getGetterType(fieldName);
+ if (ClassUtils.isAssignableValue(getterType, fieldVal)) {
+ metaObject.setValue(fieldName, fieldVal);
+ }
+ }
+
+ /**
+ * 获取 spring security 当前的用户名
+ * @return 当前用户名
+ */
+ private String getUserName() {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ return loginUser.getUsername();
+ }
+
+}
diff --git a/springboot/pom.xml b/springboot/pom.xml
index f545ec7b..3d063f0f 100644
--- a/springboot/pom.xml
+++ b/springboot/pom.xml
@@ -152,6 +152,7 @@
mybatis-plus-boot-starter
${mybatis-plus.version}