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 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 8 import org.springframework.context.annotation.Configuration;
4 9 import org.springframework.transaction.annotation.EnableTransactionManagement;
5 10  
6 11 /**
7   - * 数据库匹配类
  12 + * 数据库配置类
  13 + *
  14 + * @author 芋道源码
8 15 */
9 16 @Configuration
10 17 @EnableTransactionManagement(proxyTargetClass = true) // 启动事务管理
11 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 5  
6 6 spring:
7 7 # 数据源配置项 TODO 监控配置
8   - # 排除默认的自动配置,使用dynamic-datasource-spring-boot-starter配置多数据源,整合druid
9 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 11 datasource:
12   - druid:
  12 + druid: # Druid 【监控】相关的全局配置
13 13 web-stat-filter:
14 14 enabled: true
15 15 stat-view-servlet:
16 16 enabled: true
17   - # 设置白名单,不填则允许所有访问
18   - allow:
  17 + allow: # 设置白名单,不填则允许所有访问
19 18 url-pattern: /druid/*
20   - # 控制台管理用户名和密码
21   - login-username:
  19 + login-username: # 控制台管理用户名和密码
22 20 login-password:
23 21 filter:
24 22 stat:
25 23 enabled: true
26   - # 慢 SQL 记录
27   - log-slow-sql: true
  24 + log-slow-sql: true # 慢 SQL 记录
28 25 slow-sql-millis: 100
29 26 merge-sql: true
30 27 wall:
31 28 config:
32 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 43 primary: master
41 44 datasource:
42 45 master:
... ... @@ -45,17 +48,12 @@ spring:
45 48 driver-class-name: com.mysql.jdbc.Driver
46 49 username: root
47 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 58 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
61 59 redis:
... ...