现在开发服务器的时候,SpringBoot3.x + MybatisPlus + Druid 多数据源配置基本上是标准配置了。本Druid数据源也支持多数据源配置,但是MyBatis Plus团队也提供了一个多数据源的管理组件,他们重写了部分功能,所以在配置上与原生的Druid配置有些不一样。
添加maven依赖
<!-- 阿里数据库连接池 -->
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-3-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.22</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.5</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId>
<version>3.5.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- 动态数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>4.2.0</version>
</dependency>
Mybatis Plus的多数据源自动装配的类是:

它的配置类中也Import了阿里地的Druid配置

因为同时存在了两个数据源的实现,所以在启动的时候,需要把阿里的数据源装配类去掉

配置
# 数据源配置
spring:
data:
redis:
host: 192.168.3.102
port: 6379
password: 123456
datasource:
druid:
filter:
stat:
enabled: true
# 开启druid的sql统计及监控,注意这里配置的时候idea不会提示,估计是因为是去掉阿里数据源的问题
stat-view-servlet:
enabled: true
url-pattern: /druid/*
# 控制台管理用户名和密码,记得生产环境的时候,此接口最好是在安全的环境中访问
login-username: admin
login-password: 123456
reset-enable: false
allow: 192.168.3.25,127.0.0.1 # 允许访问的ip白名单
web-stat-filter:
enabled: true
url-pattern: /*
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
dynamic:
primary: master
lazy: false
datasource:
# 主库数据源
master:
url: jdbc:mysql://192.168.3.102:3306/ciyan_mmo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: 123456
# 从库数据源
# slave:
# url:
# username:
# password:
druid:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置连接超时时间
connectTimeout: 30000
# 配置网络超时时间
socketTimeout: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
filters: stat,wall
启动服务后,就可以访问了:http://127.0.0.1:9901/druid/login.html
端口是启动的web服务的端口

如查你访问的login.html时,显示的是一个空白页面,说明服务器没有reponse返回,这个有可能是你自己写的过滤器导致把response的响应内容重写或过滤掉了。例如使用了ContentCachingResponseWrapper,但是在最后响应的时候没有copyBodyToResponse,正确的应该这样写:
package cn.jw.starter.web.core.filters;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;
import cn.hutool.extra.spring.SpringUtil;
import cn.jw.starter.web.core.properties.JwWebProperties;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/**
* 缓存请求消息的filter,
*
* @author 王广帅
* @since 2024/4/3 20:31
*/
public class CacheRequestBodyFilter extends OncePerRequestFilter {
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
String uri = request.getRequestURI();
// 静态资源都不要走这个过滤
if (uri.endsWith(".html") || uri.endsWith(".js") || uri.endsWith(".css") || uri.endsWith(".ico")) {
return true;
}
JwWebProperties jwWebProperties = SpringUtil.getBean(JwWebProperties.class);
if (jwWebProperties.getIgnoreCacheBodyUriList().contains(uri)) {
return true;
}
return super.shouldNotFilter(request);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
logger.debug("先走一步");
if (request.getContentLength() > 0 && !(request instanceof ContentCachingRequestWrapper)) {
request = new ContentCachingRequestWrapper(request);
request.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
}
if (!(response instanceof ContentCachingResponseWrapper)) {
response = new ContentCachingResponseWrapper(response);
response.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
}
filterChain.doFilter(request, response);
updateResponse(response);
}
/**
* 更新响应(不操作这一步,会导致接口响应空白)
*
* @param response
* 响应对象
* @throws IOException
* /
*/
private void updateResponse(HttpServletResponse response) throws IOException {
ContentCachingResponseWrapper responseWrapper =
WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
if (responseWrapper != null) {
Objects.requireNonNull(responseWrapper).copyBodyToResponse();
}
}
}
之前我就是这样,把updateReponse写到HandlerInterceptor的实现类中了,但是HandlerInterceptor只是拦截Controller里面的操作,像Druid 的监控信息请求的是Servlet,不会走HandlerInterceptor。