修复druid的sql监控和sql防火墙,并暂时关闭分布式事务

This commit is contained in:
Dftre 2025-01-09 23:42:54 +08:00
parent 827eb90e89
commit 50d9199f53
6 changed files with 96 additions and 10 deletions

View File

@ -15,6 +15,8 @@ spring:
# url: jdbc:postgresql://127.0.0.1/ry # url: jdbc:postgresql://127.0.0.1/ry
# username: postgres # username: postgres
# password: 123456 # password: 123456
# filters: stat,wall
# connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 从库数据源 # 从库数据源
# SLAVE: # SLAVE:
# url: jdbc:mysql://127.0.0.1/ruoyi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 # url: jdbc:mysql://127.0.0.1/ruoyi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
@ -44,16 +46,26 @@ spring:
testWhileIdle: true testWhileIdle: true
testOnBorrow: false testOnBorrow: false
testOnReturn: false testOnReturn: false
# 配置监控统计拦截的filters
filters: stat,wall
# 通过connectProperties属性来打开mergeSql功能慢SQL记录
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
webStatFilter: webStatFilter:
enabled: true enabled: true
url-pattern: /*
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
sessionStatEnable: true
statViewServlet: statViewServlet:
enabled: true enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/* url-pattern: /druid/*
# 控制台管理用户名和密码 allow: 127.0.0.1
deny: ""
reset-enable: false
login-username: ruoyi login-username: ruoyi
login-password: 123456 login-password: 123456
filter: filter:
stat: stat:
enabled: true enabled: true
@ -62,10 +74,14 @@ spring:
slow-sql-millis: 1000 slow-sql-millis: 1000
merge-sql: true merge-sql: true
wall: wall:
enabled: true
config: config:
multi-statement-allow: true multi-statement-allow: true
select-allow: true
stat-view-servlet:
enabled: true
# 是否开启分布式事务如不开启请删除atomikos插件否则atomikos相关驱动虽不生效但仍会启动 # 是否开启分布式事务如不开启请删除atomikos插件否则atomikos相关驱动虽不生效但仍会启动
atomikos: atomikos:
enabled: true enabled: false

View File

@ -125,7 +125,7 @@ public class DataScopeAspect {
sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId())); sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
} else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) { } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) {
sqlString.append(StringUtils.format( sqlString.append(StringUtils.format(
" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or array_position(string_to_array(ancestors , ','), CAST( {} AS TEXT)) IS NOT NULL )",
deptAlias, user.getDeptId(), user.getDeptId())); deptAlias, user.getDeptId(), user.getDeptId()));
} else if (DATA_SCOPE_SELF.equals(dataScope)) { } else if (DATA_SCOPE_SELF.equals(dataScope)) {
if (StringUtils.isNotBlank(userAlias)) { if (StringUtils.isNotBlank(userAlias)) {

View File

@ -9,11 +9,14 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties; import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties;
import com.alibaba.druid.support.jakarta.StatViewServlet;
import com.alibaba.druid.support.jakarta.WebStatFilter;
import com.alibaba.druid.util.Utils; import com.alibaba.druid.util.Utils;
import jakarta.annotation.PreDestroy; import jakarta.annotation.PreDestroy;
@ -81,6 +84,29 @@ public class DruidConfig {
return registrationBean; return registrationBean;
} }
@Bean
@ConditionalOnProperty(name = "spring.datasource.druid.webStatFilter.enabled", havingValue = "true")
public FilterRegistrationBean webStatFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
filterRegistrationBean.addInitParameter("sessionStatEnable", "true");
return filterRegistrationBean;
}
@Bean
@ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
public ServletRegistrationBean statViewServlet(DruidStatProperties properties) {
DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
servletRegistrationBean.addInitParameter("loginUsername", config.getLoginUsername());
servletRegistrationBean.addInitParameter("loginPassword", config.getLoginPassword());
servletRegistrationBean.addInitParameter("allow", config.getAllow());
servletRegistrationBean.addInitParameter("deny", config.getDeny());
servletRegistrationBean.addInitParameter("resetEnable", String.valueOf(config.getResetEnable()));
return servletRegistrationBean;
}
public List<DruidDataSource> getDruidDataSources() { public List<DruidDataSource> getDruidDataSources() {
return druidDataSources; return druidDataSources;
} }

View File

@ -1,5 +1,6 @@
package com.ruoyi.framework.config; package com.ruoyi.framework.config;
import java.util.ArrayList;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@ -18,6 +19,8 @@ public class DynamicDataSourceProperties {
private Map<String, DataSourceProperties> datasource; private Map<String, DataSourceProperties> datasource;
private String primary; private String primary;
public Properties build(DataSourceProperties dataSourceProperties) { public Properties build(DataSourceProperties dataSourceProperties) {
Properties prop = new Properties(); Properties prop = new Properties();
DruidProperties druidProperties = SpringUtils.getBean(DruidProperties.class); DruidProperties druidProperties = SpringUtils.getBean(DruidProperties.class);
@ -28,13 +31,18 @@ public class DynamicDataSourceProperties {
prop.setProperty("minIdle", String.valueOf(druidProperties.getMinIdle())); prop.setProperty("minIdle", String.valueOf(druidProperties.getMinIdle()));
prop.setProperty("maxActive", String.valueOf(druidProperties.getMaxActive())); prop.setProperty("maxActive", String.valueOf(druidProperties.getMaxActive()));
prop.setProperty("maxWait", String.valueOf(druidProperties.getMaxWait())); prop.setProperty("maxWait", String.valueOf(druidProperties.getMaxWait()));
prop.setProperty("timeBetweenEvictionRunsMillis", String.valueOf(druidProperties.getTimeBetweenEvictionRunsMillis())); prop.setProperty("timeBetweenEvictionRunsMillis",
String.valueOf(druidProperties.getTimeBetweenEvictionRunsMillis()));
prop.setProperty("minEvictableIdleTimeMillis", String.valueOf(druidProperties.getMinEvictableIdleTimeMillis())); prop.setProperty("minEvictableIdleTimeMillis", String.valueOf(druidProperties.getMinEvictableIdleTimeMillis()));
prop.setProperty("maxEvictableIdleTimeMillis", String.valueOf(druidProperties.getMaxEvictableIdleTimeMillis())); prop.setProperty("maxEvictableIdleTimeMillis", String.valueOf(druidProperties.getMaxEvictableIdleTimeMillis()));
prop.setProperty("validationQuery", druidProperties.getValidationQuery()); prop.setProperty("validationQuery", druidProperties.getValidationQuery());
prop.setProperty("testWhileIdle", String.valueOf(druidProperties.isTestWhileIdle())); prop.setProperty("testWhileIdle", String.valueOf(druidProperties.isTestWhileIdle()));
prop.setProperty("testOnBorrow", String.valueOf(druidProperties.isTestOnBorrow())); prop.setProperty("testOnBorrow", String.valueOf(druidProperties.isTestOnBorrow()));
prop.setProperty("testOnReturn", String.valueOf(druidProperties.isTestOnReturn())); prop.setProperty("testOnReturn", String.valueOf(druidProperties.isTestOnReturn()));
// 添加过滤器配置
prop.setProperty("filters", "stat,wall");
prop.setProperty("connectionProperties", "druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000");
prop.setProperty("proxyFilters", ""); // 确保不会覆盖默认的过滤器
return prop; return prop;
} }
@ -76,6 +84,30 @@ public class DynamicDataSourceProperties {
if (prop.getProperty("testOnReturn") != null) { if (prop.getProperty("testOnReturn") != null) {
dataSource.setTestOnReturn(Boolean.parseBoolean(prop.getProperty("testOnReturn"))); dataSource.setTestOnReturn(Boolean.parseBoolean(prop.getProperty("testOnReturn")));
} }
// 添加监控配置
if (prop.getProperty("filters") != null) {
try {
dataSource.setFilters(prop.getProperty("filters"));
} catch (Exception e) {
e.printStackTrace();
}
}
if (prop.getProperty("connectionProperties") != null) {
dataSource.setConnectionProperties(prop.getProperty("connectionProperties"));
}
// 确保过滤器配置生效
try {
if (prop.getProperty("filters") != null) {
dataSource.setFilters(prop.getProperty("filters"));
}
if (prop.getProperty("connectionProperties") != null) {
dataSource.setConnectionProperties(prop.getProperty("connectionProperties"));
}
// 启用防火墙功能
dataSource.setProxyFilters(new ArrayList<>());
} catch (Exception e) {
throw new RuntimeException("配置Druid过滤器失败", e);
}
} }
public Map<String, DataSourceProperties> getDatasource() { public Map<String, DataSourceProperties> getDatasource() {

View File

@ -7,7 +7,8 @@ import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.alibaba.druid.pool.xa.DruidXADataSource; import com.alibaba.druid.pool.DruidDataSource;
// import com.alibaba.druid.pool.xa.DruidXADataSource;
import com.ruoyi.common.service.datasource.CreateDataSource; import com.ruoyi.common.service.datasource.CreateDataSource;
import com.ruoyi.framework.config.DruidConfig; import com.ruoyi.framework.config.DruidConfig;
import com.ruoyi.framework.config.DynamicDataSourceProperties; import com.ruoyi.framework.config.DynamicDataSourceProperties;
@ -22,10 +23,21 @@ public class DataSourceCreate implements CreateDataSource {
private DruidConfig druidConfig; private DruidConfig druidConfig;
public DataSource createDataSource(String name, Properties prop) { public DataSource createDataSource(String name, Properties prop) {
DruidXADataSource dataSource = new DruidXADataSource(); DruidDataSource dataSource = new DruidDataSource();
druidConfig.getDruidDataSources().add(dataSource); druidConfig.getDruidDataSources().add(dataSource);
// 设置基础属性
dataSource.setConnectProperties(prop); dataSource.setConnectProperties(prop);
properties.setProperties(dataSource, prop); properties.setProperties(dataSource, prop);
// 确保监控和防火墙功能开启
try {
dataSource.setFilters("stat,wall");
dataSource.init();
} catch (Exception e) {
throw new RuntimeException("初始化数据源失败", e);
}
return dataSource; return dataSource;
} }
} }

View File

@ -63,10 +63,10 @@
</dependency> </dependency>
<!-- atomikos--> <!-- atomikos-->
<dependency> <!-- <dependency>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-atomikos</artifactId> <artifactId>ruoyi-atomikos</artifactId>
</dependency> </dependency> -->
</dependencies> </dependencies>
</project> </project>