diff --git a/springboot/fastbee-admin/src/main/java/com/fastbee/FastBeeApplication.java b/springboot/fastbee-admin/src/main/java/com/fastbee/FastBeeApplication.java index 945d7de5..ed86ee4d 100644 --- a/springboot/fastbee-admin/src/main/java/com/fastbee/FastBeeApplication.java +++ b/springboot/fastbee-admin/src/main/java/com/fastbee/FastBeeApplication.java @@ -2,14 +2,13 @@ package com.fastbee; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; /** * 启动程序 * * @author ruoyi */ -@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) +@SpringBootApplication public class FastBeeApplication { public static void main(String[] args) diff --git a/springboot/fastbee-admin/src/main/resources/application-dev.yml b/springboot/fastbee-admin/src/main/resources/application-dev.yml index 48ae7628..1f64bf16 100644 --- a/springboot/fastbee-admin/src/main/resources/application-dev.yml +++ b/springboot/fastbee-admin/src/main/resources/application-dev.yml @@ -1,57 +1,50 @@ # 数据源配置 spring: datasource: - type: com.alibaba.druid.pool.DruidDataSource - driverClassName: com.mysql.cj.jdbc.Driver - druid: - # 主库数据源 - master: - url: jdbc:mysql://localhost/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 - username: root - password: 123456 - # 从库数据源 - slave: - enabled: false # 从数据源开关/默认关闭 - url: - username: - password: - initialSize: 5 # 初始连接数 - minIdle: 10 # 最小连接池数量 - maxActive: 20 # 最大连接池数量 - maxWait: 60000 # 配置获取连接等待超时的时间 - timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 - minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒 - maxEvictableIdleTimeMillis: 900000 # 配置一个连接在池中最大生存的时间,单位是毫秒 - validationQuery: SELECT 1 FROM DUAL # 配置检测连接是否有效 - testWhileIdle: true - testOnBorrow: false - testOnReturn: false - webStatFilter: - enabled: true - statViewServlet: - enabled: true - # 设置白名单,不填则允许所有访问 - allow: - url-pattern: /druid/* - # 控制台管理用户名和密码 - login-username: fastbee - login-password: fastbee - filter: - stat: - enabled: true - # 慢SQL记录 - log-slow-sql: true - slow-sql-millis: 1000 - merge-sql: true - wall: - config: - multi-statement-allow: true + dynamic: + druid: + initial-size: 5 + min-idle: 10 + max-wait: 60000 + max-active: 20 + timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒 + maxEvictableIdleTimeMillis: 900000 # 配置一个连接在池中最大生存的时间,单位是毫秒 + validation-query: 'SELECT 1' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + datasource: + master: + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + username: root + password: fastbee + druid: + filters: stat,wall + stat: + # 慢SQL记录 + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + none-base-statement-allow: true + # slave: + # type: com.alibaba.druid.pool.DruidDataSource + # driver-class-name: com.mysql.cj.jdbc.Driver + # url: jdbc:mysql://localhost:3306/fastbee1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + # username: root + # password: fastbee + + + # redis 配置 redis: host: localhost # 地址 port: 6379 # 端口,默认为6379 - database: 1 # 数据库索引 - password: 123456 # 密码 + database: 15 # 数据库索引 + password: fastbee # 密码 timeout: 10s # 连接超时时间 lettuce: pool: diff --git a/springboot/fastbee-admin/src/main/resources/application-prod.yml b/springboot/fastbee-admin/src/main/resources/application-prod.yml index 19b302e4..4223593e 100644 --- a/springboot/fastbee-admin/src/main/resources/application-prod.yml +++ b/springboot/fastbee-admin/src/main/resources/application-prod.yml @@ -1,52 +1,42 @@ # 数据源配置 spring: datasource: - type: com.alibaba.druid.pool.DruidDataSource - driverClassName: com.mysql.cj.jdbc.Driver - druid: - # 主库数据源 - master: - url: jdbc:mysql://177.7.0.11/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 - username: root - password: fastbee - # 从库数据源 - slave: - enabled: false # 从数据源开关/默认关闭 - url: - username: - password: + dynamic: + druid: + initial-size: 5 + min-idle: 10 + max-wait: 60000 + max-active: 20 + timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒 + maxEvictableIdleTimeMillis: 900000 # 配置一个连接在池中最大生存的时间,单位是毫秒 + validation-query: 'SELECT 1' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + datasource: + master: + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://177.7.0.11/fastbee?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + username: root + password: fastbee + druid: + filters: stat,wall + stat: + # 慢SQL记录 + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + none-base-statement-allow: true + # slave: + # type: com.alibaba.druid.pool.DruidDataSource + # driver-class-name: com.mysql.cj.jdbc.Driver + # url: jdbc:mysql://localhost:3306/fastbee1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + # username: root + # password: fastbee - initialSize: 5 # 初始连接数 - minIdle: 10 # 最小连接池数量 - maxActive: 20 # 最大连接池数量 - maxWait: 60000 # 配置获取连接等待超时的时间 - timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 - minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒 - maxEvictableIdleTimeMillis: 900000 # 配置一个连接在池中最大生存的时间,单位是毫秒 - validationQuery: SELECT 1 FROM DUAL # 配置检测连接是否有效 - testWhileIdle: true - testOnBorrow: false - testOnReturn: false - webStatFilter: - enabled: true - statViewServlet: - enabled: true - # 设置白名单,不填则允许所有访问 - allow: - url-pattern: /druid/* - # 控制台管理用户名和密码 - login-username: fastbee - login-password: fastbee - filter: - stat: - enabled: true - # 慢SQL记录 - log-slow-sql: true - slow-sql-millis: 1000 - merge-sql: true - wall: - config: - multi-statement-allow: true # redis 配置 redis: host: 177.7.0.10 # 地址 diff --git a/springboot/fastbee-admin/src/main/resources/application.yml b/springboot/fastbee-admin/src/main/resources/application.yml index 8989a4ee..fb1ffa68 100644 --- a/springboot/fastbee-admin/src/main/resources/application.yml +++ b/springboot/fastbee-admin/src/main/resources/application.yml @@ -55,6 +55,20 @@ spring: max-size: 200 # 最大连接数 queue-capacity: 3000 # 最大容量 keep-alive: 60 + datasource: + druid: + webStatFilter: + enabled: true + stat-view-servlet: + enabled: true + allow: + url-pattern: /druid/* + loginUsername: fastbee + loginPassword: fastbee + dynamic: + primary: master + strict: false + lazy: true #集群配置 cluster: diff --git a/springboot/fastbee-admin/src/main/resources/mybatis/mybatis-config.xml b/springboot/fastbee-admin/src/main/resources/mybatis/mybatis-config.xml index ac47c038..6c0fb192 100644 --- a/springboot/fastbee-admin/src/main/resources/mybatis/mybatis-config.xml +++ b/springboot/fastbee-admin/src/main/resources/mybatis/mybatis-config.xml @@ -14,7 +14,9 @@ PUBLIC "-//mybatis.org//DTD Config 3.0//EN" - + + + - + diff --git a/springboot/fastbee-framework/pom.xml b/springboot/fastbee-framework/pom.xml index b628b4e8..f9f2734e 100644 --- a/springboot/fastbee-framework/pom.xml +++ b/springboot/fastbee-framework/pom.xml @@ -16,6 +16,10 @@ + + com.fastbee + fastbee-common + diff --git a/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/ApplicationConfig.java b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/ApplicationConfig.java index 3157801a..be28f9a1 100644 --- a/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/ApplicationConfig.java +++ b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/ApplicationConfig.java @@ -1,7 +1,6 @@ package com.fastbee.framework.config; import java.util.TimeZone; -import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -15,8 +14,6 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration // 表示通过aop框架暴露该代理对象,AopContext能够访问 @EnableAspectJAutoProxy(exposeProxy = true) -// 指定要扫描的Mapper类的包的路径 -@MapperScan("com.fastbee.**.mapper") public class ApplicationConfig { /** diff --git a/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/DataSourceConfig.java b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/DataSourceConfig.java new file mode 100644 index 00000000..96e84b83 --- /dev/null +++ b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/DataSourceConfig.java @@ -0,0 +1,61 @@ +package com.fastbee.framework.config; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; +import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider; +import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +@Configuration +public class DataSourceConfig { + private final DynamicDataSourceProperties properties; + private final DefaultDataSourceCreator dataSourceCreator; + + + public DataSourceConfig(DynamicDataSourceProperties properties, + DefaultDataSourceCreator dataSourceCreator) { + this.properties = properties; + this.dataSourceCreator = dataSourceCreator; + + } + + + @Bean + public DynamicDataSourceProvider dynamicDataSourceProvider() { + return new AbstractDataSourceProvider(dataSourceCreator) { + @Override + public Map loadDataSources() { + Map dataSourceMap = new HashMap<>(); + return dataSourceMap; + } + }; + } + + @Primary + @Bean + public DataSource dataSource(List providers) { + DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(providers); + dataSource.setPrimary(properties.getPrimary()); + dataSource.setStrict(properties.getStrict()); + dataSource.setStrategy(properties.getStrategy()); + dataSource.setP6spy(properties.getP6spy()); + dataSource.setSeata(properties.getSeata()); + return dataSource; + } + + + @Bean + public DataSourceTransactionManager transactionManager(DataSource dataSource) { + return new DataSourceTransactionManager(dataSource); + } +} diff --git a/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/DruidConfig.java b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/DruidConfig.java index d5ffc7d0..367e693f 100644 --- a/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/DruidConfig.java +++ b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/DruidConfig.java @@ -1,86 +1,23 @@ package com.fastbee.framework.config; -import com.alibaba.druid.pool.DruidDataSource; -import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; import com.alibaba.druid.util.Utils; -import com.fastbee.common.enums.DataSourceType; -import com.fastbee.common.utils.spring.SpringUtils; -import com.fastbee.framework.config.properties.DruidProperties; -import com.fastbee.framework.datasource.DynamicDataSource; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; import javax.servlet.*; -import javax.sql.DataSource; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -/** - * druid 配置多数据源 - * - * @author ruoyi - */ @Configuration -public class DruidConfig -{ - @Bean - @ConfigurationProperties("spring.datasource.druid.master") - public DataSource masterDataSource(DruidProperties druidProperties) - { - DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); - return druidProperties.dataSource(dataSource); - } - - @Bean - @ConfigurationProperties("spring.datasource.druid.slave") - @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") - public DataSource slaveDataSource(DruidProperties druidProperties) - { - DruidDataSource dataSource = DruidDataSourceBuilder.create().build(); - return druidProperties.dataSource(dataSource); - } - - @Bean(name = "dynamicDataSource") - @Primary - public DynamicDataSource dataSource(DataSource masterDataSource) - { - Map targetDataSources = new HashMap<>(); - targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource); - setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource"); - return new DynamicDataSource(masterDataSource, targetDataSources); - } - - /** - * 设置数据源 - * - * @param targetDataSources 备选数据源集合 - * @param sourceName 数据源名称 - * @param beanName bean名称 - */ - public void setDataSource(Map targetDataSources, String sourceName, String beanName) - { - try - { - DataSource dataSource = SpringUtils.getBean(beanName); - targetDataSources.put(sourceName, dataSource); - } - catch (Exception e) - { - } - } - +public class DruidConfig { /** * 去除监控页面底部的广告 */ @SuppressWarnings({ "rawtypes", "unchecked" }) @Bean - @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true") + @ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true") public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) { // 获取web监控页面的参数 diff --git a/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/MyBatisConfig.java b/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/MyBatisConfig.java deleted file mode 100644 index a1c902a6..00000000 --- a/springboot/fastbee-framework/src/main/java/com/fastbee/framework/config/MyBatisConfig.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.fastbee.framework.config; - -import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS; -import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; -import com.fastbee.common.utils.StringUtils; -import org.apache.ibatis.io.VFS; -import org.apache.ibatis.session.SqlSessionFactory; -import org.mybatis.spring.SqlSessionTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.core.env.Environment; -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.core.type.classreading.CachingMetadataReaderFactory; -import org.springframework.core.type.classreading.MetadataReader; -import org.springframework.core.type.classreading.MetadataReaderFactory; -import org.springframework.jdbc.datasource.DataSourceTransactionManager; -import org.springframework.util.ClassUtils; - -import javax.sql.DataSource; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; - -/** - * Mybatis支持*匹配扫描包 - * - * @author ruoyi - */ -@Configuration -public class MyBatisConfig -{ - @Autowired - private Environment env; - - static final String DEFAULT_RESOURCE_PATTERN = "**/*.class"; - - public static String setTypeAliasesPackage(String typeAliasesPackage) - { - ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver(); - MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver); - List allResult = new ArrayList(); - try - { - for (String aliasesPackage : typeAliasesPackage.split(",")) - { - List result = new ArrayList(); - aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX - + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN; - Resource[] resources = resolver.getResources(aliasesPackage); - if (resources != null && resources.length > 0) - { - MetadataReader metadataReader = null; - for (Resource resource : resources) - { - if (resource.isReadable()) - { - metadataReader = metadataReaderFactory.getMetadataReader(resource); - try - { - result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName()); - } - catch (ClassNotFoundException e) - { - e.printStackTrace(); - } - } - } - } - if (result.size() > 0) - { - HashSet hashResult = new HashSet(result); - allResult.addAll(hashResult); - } - } - if (allResult.size() > 0) - { - typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0])); - } - else - { - throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包"); - } - } - catch (IOException e) - { - e.printStackTrace(); - } - return typeAliasesPackage; - } - - public Resource[] resolveMapperLocations(String[] mapperLocations) - { - ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); - List resources = new ArrayList(); - 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} + com.baomidou mybatis-plus-generator