Commit ef7089c1b9cf196b2da85e8bdca9a6c67ff11300

Authored by YunaiV
1 parent fb2fbbff

完成 druid ad filter 组件

梳理 druid 的配置
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java deleted
1 -package com.ruoyi.common.annotation;  
2 -  
3 -import java.lang.annotation.Documented;  
4 -import java.lang.annotation.ElementType;  
5 -import java.lang.annotation.Inherited;  
6 -import java.lang.annotation.Retention;  
7 -import java.lang.annotation.RetentionPolicy;  
8 -import java.lang.annotation.Target;  
9 -  
10 -import com.ruoyi.common.enums.DataSourceType;  
11 -  
12 -/**  
13 - * 自定义多数据源切换注解  
14 - * <p>  
15 - * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准  
16 - *  
17 - * @author ruoyi  
18 - */  
19 -@Target({ElementType.METHOD, ElementType.TYPE})  
20 -@Retention(RetentionPolicy.RUNTIME)  
21 -@Documented  
22 -@Inherited  
23 -public @interface DataSource {  
24 - /**  
25 - * 切换数据源名称  
26 - */  
27 - public DataSourceType value() default DataSourceType.MASTER;  
28 -}  
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSourceAspect.java deleted
1 -package com.ruoyi.framework.aspectj;  
2 -  
3 -import java.util.Objects;  
4 -  
5 -import org.aspectj.lang.ProceedingJoinPoint;  
6 -import org.aspectj.lang.annotation.Around;  
7 -import org.aspectj.lang.annotation.Aspect;  
8 -import org.aspectj.lang.annotation.Pointcut;  
9 -import org.aspectj.lang.reflect.MethodSignature;  
10 -import org.slf4j.Logger;  
11 -import org.slf4j.LoggerFactory;  
12 -import org.springframework.core.annotation.AnnotationUtils;  
13 -import org.springframework.core.annotation.Order;  
14 -import org.springframework.stereotype.Component;  
15 -import com.ruoyi.common.annotation.DataSource;  
16 -import com.ruoyi.common.utils.StringUtils;  
17 -import com.ruoyi.framework.datasource.DynamicDataSourceContextHolder;  
18 -  
19 -/**  
20 - * 多数据源处理  
21 - *  
22 - * @author ruoyi  
23 - */  
24 -@Aspect  
25 -@Order(1)  
26 -@Component  
27 -public class DataSourceAspect {  
28 - protected Logger logger = LoggerFactory.getLogger(getClass());  
29 -  
30 - @Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)"  
31 - + "|| @within(com.ruoyi.common.annotation.DataSource)")  
32 - public void dsPointCut() {  
33 -  
34 - }  
35 -  
36 - @Around("dsPointCut()")  
37 - public Object around(ProceedingJoinPoint point) throws Throwable {  
38 - DataSource dataSource = getDataSource(point);  
39 -  
40 - if (StringUtils.isNotNull(dataSource)) {  
41 - DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());  
42 - }  
43 -  
44 - try {  
45 - return point.proceed();  
46 - } finally {  
47 - // 销毁数据源 在执行方法之后  
48 - DynamicDataSourceContextHolder.clearDataSourceType();  
49 - }  
50 - }  
51 -  
52 - /**  
53 - * 获取需要切换的数据源  
54 - */  
55 - public DataSource getDataSource(ProceedingJoinPoint point) {  
56 - MethodSignature signature = (MethodSignature) point.getSignature();  
57 - DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);  
58 - if (Objects.nonNull(dataSource)) {  
59 - return dataSource;  
60 - }  
61 -  
62 - return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);  
63 - }  
64 -}  
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSourceType.java deleted
1 -package com.ruoyi.common.enums;  
2 -  
3 -/**  
4 - * 数据源  
5 - *  
6 - * @author ruoyi  
7 - */  
8 -public enum DataSourceType  
9 -{  
10 - /**  
11 - * 主库  
12 - */  
13 - MASTER,  
14 -  
15 - /**  
16 - * 从库  
17 - */  
18 - SLAVE  
19 -}  
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DynamicDataSource.java deleted
1 -package com.ruoyi.framework.datasource;  
2 -  
3 -import java.util.Map;  
4 -import javax.sql.DataSource;  
5 -  
6 -import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;  
7 -  
8 -/**  
9 - * 动态数据源  
10 - *  
11 - * @author ruoyi  
12 - */  
13 -public class DynamicDataSource extends AbstractRoutingDataSource {  
14 - public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {  
15 - super.setDefaultTargetDataSource(defaultTargetDataSource);  
16 - super.setTargetDataSources(targetDataSources);  
17 - super.afterPropertiesSet();  
18 - }  
19 -  
20 - @Override  
21 - protected Object determineCurrentLookupKey() {  
22 - return DynamicDataSourceContextHolder.getDataSourceType();  
23 - }  
24 -}  
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DynamicDataSourceContextHolder.java deleted
1 -package com.ruoyi.framework.datasource;  
2 -  
3 -import org.slf4j.Logger;  
4 -import org.slf4j.LoggerFactory;  
5 -  
6 -/**  
7 - * 数据源切换处理  
8 - *  
9 - * @author ruoyi  
10 - */  
11 -public class DynamicDataSourceContextHolder {  
12 - public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);  
13 -  
14 - /**  
15 - * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,  
16 - * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。  
17 - */  
18 - private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();  
19 -  
20 - /**  
21 - * 设置数据源的变量  
22 - */  
23 - public static void setDataSourceType(String dsType) {  
24 - log.info("切换到{}数据源", dsType);  
25 - CONTEXT_HOLDER.set(dsType);  
26 - }  
27 -  
28 - /**  
29 - * 获得数据源的变量  
30 - */  
31 - public static String getDataSourceType() {  
32 - return CONTEXT_HOLDER.get();  
33 - }  
34 -  
35 - /**  
36 - * 清空数据源变量  
37 - */  
38 - public static void clearDataSourceType() {  
39 - CONTEXT_HOLDER.remove();  
40 - }  
41 -}  
ruoyi-common/src/main/java/com/ruoyi/common/config/DruidConfig.java deleted
1 -package com.ruoyi.framework.config;  
2 -  
3 -import java.io.IOException;  
4 -import java.util.HashMap;  
5 -import java.util.Map;  
6 -import javax.servlet.Filter;  
7 -import javax.servlet.FilterChain;  
8 -import javax.servlet.ServletException;  
9 -import javax.servlet.ServletRequest;  
10 -import javax.servlet.ServletResponse;  
11 -import javax.sql.DataSource;  
12 -  
13 -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;  
14 -import org.springframework.boot.context.properties.ConfigurationProperties;  
15 -import org.springframework.boot.web.servlet.FilterRegistrationBean;  
16 -import org.springframework.context.annotation.Bean;  
17 -import org.springframework.context.annotation.Configuration;  
18 -import org.springframework.context.annotation.Primary;  
19 -import com.alibaba.druid.pool.DruidDataSource;  
20 -import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;  
21 -import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;  
22 -import com.alibaba.druid.util.Utils;  
23 -import com.ruoyi.common.enums.DataSourceType;  
24 -import com.ruoyi.common.utils.spring.SpringUtils;  
25 -import com.ruoyi.framework.config.properties.DruidProperties;  
26 -import com.ruoyi.framework.datasource.DynamicDataSource;  
27 -  
28 -/**  
29 - * druid 配置多数据源  
30 - *  
31 - * @author ruoyi  
32 - */  
33 -@Configuration  
34 -public class DruidConfig {  
35 - @Bean  
36 - @ConfigurationProperties("spring.datasource.druid.master")  
37 - public DataSource masterDataSource(DruidProperties druidProperties) {  
38 - DruidDataSource dataSource = DruidDataSourceBuilder.create().build();  
39 - return druidProperties.dataSource(dataSource);  
40 - }  
41 -  
42 - @Bean  
43 - @ConfigurationProperties("spring.datasource.druid.slave")  
44 - @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")  
45 - public DataSource slaveDataSource(DruidProperties druidProperties) {  
46 - DruidDataSource dataSource = DruidDataSourceBuilder.create().build();  
47 - return druidProperties.dataSource(dataSource);  
48 - }  
49 -  
50 - @Bean(name = "dynamicDataSource")  
51 - @Primary  
52 - public DynamicDataSource dataSource(DataSource masterDataSource) {  
53 - Map<Object, Object> targetDataSources = new HashMap<>();  
54 - targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);  
55 - setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");  
56 - return new DynamicDataSource(masterDataSource, targetDataSources);  
57 - }  
58 -  
59 - /**  
60 - * 设置数据源  
61 - *  
62 - * @param targetDataSources 备选数据源集合  
63 - * @param sourceName 数据源名称  
64 - * @param beanName bean名称  
65 - */  
66 - public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName) {  
67 - try {  
68 - DataSource dataSource = SpringUtils.getBean(beanName);  
69 - targetDataSources.put(sourceName, dataSource);  
70 - } catch (Exception e) {  
71 - }  
72 - }  
73 -  
74 - /**  
75 - * 去除监控页面底部的广告  
76 - */  
77 - @SuppressWarnings({"rawtypes", "unchecked"})  
78 - @Bean  
79 - @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")  
80 - public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) {  
81 - // 获取web监控页面的参数  
82 - DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();  
83 - // 提取common.js的配置路径  
84 - String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";  
85 - String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");  
86 - final String filePath = "support/http/resources/js/common.js";  
87 - // 创建filter进行过滤  
88 - Filter filter = new Filter() {  
89 - @Override  
90 - public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {  
91 - }  
92 -  
93 - @Override  
94 - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)  
95 - throws IOException, ServletException {  
96 - chain.doFilter(request, response);  
97 - // 重置缓冲区,响应头不会被重置  
98 - response.resetBuffer();  
99 - // 获取common.js  
100 - String text = Utils.readFromResource(filePath);  
101 - // 正则替换banner, 除去底部的广告信息  
102 - text = text.replaceAll("<a.*?banner\"></a><br/>", "");  
103 - text = text.replaceAll("powered.*?shrek.wang</a>", "");  
104 - response.getWriter().write(text);  
105 - }  
106 -  
107 - @Override  
108 - public void destroy() {  
109 - }  
110 - };  
111 - FilterRegistrationBean registrationBean = new FilterRegistrationBean();  
112 - registrationBean.setFilter(filter);  
113 - registrationBean.addUrlPatterns(commonJsPattern);  
114 - return registrationBean;  
115 - }  
116 -}  
ruoyi-common/src/main/resources/application-druid.yml deleted
1 -# 数据源配置  
2 -spring:  
3 - datasource:  
4 - type: com.alibaba.druid.pool.DruidDataSource  
5 - driverClassName: com.mysql.cj.jdbc.Driver  
6 - druid:  
7 - # 主库数据源  
8 - master:  
9 - url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8  
10 - username: root  
11 - password: password  
12 - # 从库数据源  
13 - slave:  
14 - # 从数据源开关/默认关闭  
15 - enabled: false  
16 - url:  
17 - username:  
18 - password:  
19 - # 初始连接数  
20 - initialSize: 5  
21 - # 最小连接池数量  
22 - minIdle: 10  
23 - # 最大连接池数量  
24 - maxActive: 20  
25 - # 配置获取连接等待超时的时间  
26 - maxWait: 60000  
27 - # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒  
28 - timeBetweenEvictionRunsMillis: 60000  
29 - # 配置一个连接在池中最小生存的时间,单位是毫秒  
30 - minEvictableIdleTimeMillis: 300000  
31 - # 配置一个连接在池中最大生存的时间,单位是毫秒  
32 - maxEvictableIdleTimeMillis: 900000  
33 - # 配置检测连接是否有效  
34 - validationQuery: SELECT 1 FROM DUAL  
35 - testWhileIdle: true  
36 - testOnBorrow: false  
37 - testOnReturn: false  
src/main/java/cn/iocoder/dashboard/framework/datasource/config/DataSourceConfiguration.java
1 package cn.iocoder.dashboard.framework.datasource.config; 1 package cn.iocoder.dashboard.framework.datasource.config;
2 2
  3 +import cn.iocoder.dashboard.framework.datasource.core.filter.DruidAdRemoveFilter;
  4 +import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
  5 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  6 +import org.springframework.boot.web.servlet.FilterRegistrationBean;
  7 +import org.springframework.context.annotation.Bean;
3 import org.springframework.context.annotation.Configuration; 8 import org.springframework.context.annotation.Configuration;
4 import org.springframework.transaction.annotation.EnableTransactionManagement; 9 import org.springframework.transaction.annotation.EnableTransactionManagement;
5 10
6 /** 11 /**
7 - * 数据库匹配类 12 + * 数据库配置类
  13 + *
  14 + * @author 芋道源码
8 */ 15 */
9 @Configuration 16 @Configuration
10 @EnableTransactionManagement(proxyTargetClass = true) // 启动事务管理 17 @EnableTransactionManagement(proxyTargetClass = true) // 启动事务管理
11 public class DataSourceConfiguration { 18 public class DataSourceConfiguration {
  19 +
  20 + /**
  21 + * 创建 DruidAdRemoveFilter 过滤器,过滤 common.js 的广告
  22 + */
  23 + @Bean
  24 + @ConditionalOnProperty(name = "spring.datasource.druid.web-stat-filter.enabled", havingValue = "true")
  25 + public FilterRegistrationBean<DruidAdRemoveFilter> druidAdRemoveFilterFilter(DruidStatProperties properties) {
  26 + // 获取 druid web 监控页面的参数
  27 + DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
  28 + // 提取 common.js 的配置路径
  29 + String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
  30 + String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
  31 + // 创建 DruidAdRemoveFilter Bean
  32 + FilterRegistrationBean<DruidAdRemoveFilter> registrationBean = new FilterRegistrationBean<>();
  33 + registrationBean.setFilter(new DruidAdRemoveFilter());
  34 + registrationBean.addUrlPatterns(commonJsPattern);
  35 + return registrationBean;
  36 + }
  37 +
12 } 38 }
src/main/java/cn/iocoder/dashboard/framework/datasource/enums/DatasourceMark.java renamed to src/main/java/cn/iocoder/dashboard/framework/datasource/core/enums/DatasourceMark.java
1 -package cn.iocoder.dashboard.framework.datasource.enums;  
2 -  
3 -/**  
4 - * 对应于多数据源中不同数据源配置  
5 - *  
6 - * 在方法上使用注解{@code @DS(DatasourceMark.slave)}可以指定slave数据源,默认是master数据源  
7 - */  
8 -public interface DatasourceMark {  
9 - String master = "master";  
10 - String slave = "slave";  
11 -} 1 +package cn.iocoder.dashboard.framework.datasource.core.enums;
  2 +
  3 +/**
  4 + * 对应于多数据源中不同数据源配置
  5 + *
  6 + * 在方法上使用注解{@code @DS(DatasourceMark.slave)}可以指定slave数据源,默认是master数据源
  7 + */
  8 +public interface DatasourceMark {
  9 +
  10 + String MASTER = "master";
  11 +
  12 + String SLAVE = "slave";
  13 +
  14 +}
src/main/java/cn/iocoder/dashboard/framework/datasource/core/filter/DruidAdRemoveFilter.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.datasource.core.filter;
  2 +
  3 +import com.alibaba.druid.util.Utils;
  4 +import org.springframework.web.filter.OncePerRequestFilter;
  5 +
  6 +import javax.servlet.FilterChain;
  7 +import javax.servlet.ServletException;
  8 +import javax.servlet.http.HttpServletRequest;
  9 +import javax.servlet.http.HttpServletResponse;
  10 +import java.io.IOException;
  11 +
  12 +/**
  13 + * Druid 底部广告过滤器
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +public class DruidAdRemoveFilter extends OncePerRequestFilter {
  18 +
  19 + /**
  20 + * common.js 的路径
  21 + */
  22 + private static final String COMMON_JS_ILE_PATH = "support/http/resources/js/common.js";
  23 +
  24 + @Override
  25 + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
  26 + throws ServletException, IOException {
  27 + chain.doFilter(request, response);
  28 + // 重置缓冲区,响应头不会被重置
  29 + response.resetBuffer();
  30 + // 获取 common.js
  31 + String text = Utils.readFromResource(COMMON_JS_ILE_PATH);
  32 + // 正则替换 banner, 除去底部的广告信息
  33 + text = text.replaceAll("<a.*?banner\"></a><br/>", "");
  34 + text = text.replaceAll("powered.*?shrek.wang</a>", "");
  35 + response.getWriter().write(text);
  36 + }
  37 +
  38 +}
src/main/resources/application-local.yaml
@@ -5,38 +5,41 @@ server: @@ -5,38 +5,41 @@ server:
5 5
6 spring: 6 spring:
7 # 数据源配置项 TODO 监控配置 7 # 数据源配置项 TODO 监控配置
8 - # 排除默认的自动配置,使用dynamic-datasource-spring-boot-starter配置多数据源,整合druid  
9 autoconfigure: 8 autoconfigure:
10 - exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure 9 + exclude:
  10 + - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源
11 datasource: 11 datasource:
12 - druid: 12 + druid: # Druid 【监控】相关的全局配置
13 web-stat-filter: 13 web-stat-filter:
14 enabled: true 14 enabled: true
15 stat-view-servlet: 15 stat-view-servlet:
16 enabled: true 16 enabled: true
17 - # 设置白名单,不填则允许所有访问  
18 - allow: 17 + allow: # 设置白名单,不填则允许所有访问
19 url-pattern: /druid/* 18 url-pattern: /druid/*
20 - # 控制台管理用户名和密码  
21 - login-username: 19 + login-username: # 控制台管理用户名和密码
22 login-password: 20 login-password:
23 filter: 21 filter:
24 stat: 22 stat:
25 enabled: true 23 enabled: true
26 - # 慢 SQL 记录  
27 - log-slow-sql: true 24 + log-slow-sql: true # 慢 SQL 记录
28 slow-sql-millis: 100 25 slow-sql-millis: 100
29 merge-sql: true 26 merge-sql: true
30 wall: 27 wall:
31 config: 28 config:
32 multi-statement-allow: true 29 multi-statement-allow: true
33 - dynamic:  
34 - # druid全局配置 https://dynamic-datasource.com/en/guide/integration/Druid.html#configurate-parameters  
35 -# druid: #The following are the supported global parameters  
36 -# initial-size:  
37 -# max-active:  
38 -# min-idle:  
39 -# max-wait: 30 + dynamic: # 多数据源配置
  31 + druid: # Druid 【连接池】相关的全局配置
  32 + initial-size: 5 # 初始连接数
  33 + min-idle: 10 # 最小连接池数量
  34 + max-active: 20 # 最大连接池数量
  35 + max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒
  36 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒
  37 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒
  38 + max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒
  39 + validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效
  40 + test-while-idle: true
  41 + test-on-borrow: false
  42 + test-on-return: false
40 primary: master 43 primary: master
41 datasource: 44 datasource:
42 master: 45 master:
@@ -45,17 +48,12 @@ spring: @@ -45,17 +48,12 @@ spring:
45 driver-class-name: com.mysql.jdbc.Driver 48 driver-class-name: com.mysql.jdbc.Driver
46 username: root 49 username: root
47 password: 123456 50 password: 123456
48 - # druid 局部配置  
49 -# druid: # The following are independent parameters that can be reset for each db  
50 -# validation-query: select 1 FROM DUAL #such as oracle need this  
51 -# slave:  
52 -# name: ruoyi-vue-pro-slave  
53 -# url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT  
54 -# driver-class-name: com.mysql.jdbc.Driver  
55 -# username: root  
56 -# password: 123456  
57 -  
58 - 51 + slave:
  52 + name: ruoyi-vue-slave
  53 + url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
  54 + driver-class-name: com.mysql.jdbc.Driver
  55 + username: root
  56 + password: 123456
59 57
60 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 58 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
61 redis: 59 redis: