目录
本文以Maven构建SpringBoot项目,并整合Mybatis、Druid和Swagger2,实现Druid监控和在线API文档的功能。
一、添加依赖
pom.xml中依赖包如下所示:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions> <!-- 去掉Spring默认的日志插件 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 热部署 修改classpath下的文件springboot自动重启 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.15</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- api文档 swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.2.2</version>
</dependency>
</dependencies>
二、配置
(一)配置文件
Druid、Mybatis和log4j2能够很好的支持SpringBoot,这里直接在配置文件application.yml中对其进行配置,配置项的描述已经在文件中进行了注释,这里就不多说了,application.yml内容如下:
我们可以看到,使用SpringBoot后,需要进行的配置的确变简单了,这就是“习惯优于配置”为我们带来的便利。
从此以后,再也不用对老板说:别急,我马上就要配置完了!
server:
port: 8088
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/spring-boot-demo?useUnicode=true&characterEncoding=utf8
username: test
password: 43997k7k
# 初始化时建立的连接数
initial-size: 5
# 最大连接数
max-active: 20
# 最小连接数
min-idle: 5
# 获取连接最大等待时间,单位:毫秒
max-wait: 2000
# 是否缓存preparedStatement
pool-prepared-statements: false
# 最大preparedStatement缓存数,当pool-prepared-statements=true时需要大于0
max-pool-prepared-statement-per-connection-size: -1
# 检测连接是否失效的sql
validation-query: SELECT 'x'
# 检测连接是否失效的超时时间,单位:秒
validation-query-timeout: 2
filters: stat,wall,log4j2
# Spring aop监控的包路径
aop-patterns: cn.greedystar.springbootdemo.modules.service.*
filter:
# 监控统计
stat:
enabled: true
db-type: mysql
# 打印慢sql
log-slow-sql: true
# 超过200毫秒即为慢sql
slow-sql-millis: 200
# sql防火墙
wall:
enabled: true
db-type: mysql
# 对认定的攻击sql进行日志输出
log-violation: true
# 对认定的攻击sql抛出异常
throw-exception: true
config:
# 是否允许下述操作
alter-table-allow: false
truncate-allow: false
drop-table-allow: false
update-where-none-check: true
# metadata会暴露数据的表结构
metadata-allow: false
# 日志
log4j2:
enabled: true
# log4j2仅记录druid的sql执行日志
statement-log-enabled: false
connection-log-enabled: false
result-set-log-enabled: false
statement-executable-sql-log-enable: true
# 数据库连接池监控统计插件
web-stat-filter:
enabled: true
url-pattern: /*
# 过滤掉如下请求
exclusions: '*.gif,*.png,*.jpg,*.html,*.js,*.css,*.ico,/druid/*'
# 数据库连接池监控页面插件
stat-view-servlet:
enabled: true
url-pattern: '/druid/*'
reset-enable: true
login-username: admin
login-password: admin
allow:
deny:
# 设置cglib代理模式,防止非接口代理出错
aop:
proxy-target-class: true
# mybatis映射文件路径
mybatis:
mapper-locations: classpath*:mybatis/*Mapper.xml
# 日志配置文件
logging:
config: classpath:log4j2.xml
log4j2配置文件log4j2.xml参考自Druid的官方wiki:Druid中使用log4j2进行日志输出,将日志输出级别改为了INFO,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<!--只接受程序中INFO级别的日志进行处理-->
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="[%d{HH:mm:ss.SSS}] %-5level %class{36} %L %M - %msg%xEx%n"/>
</Console>
<!--处理DEBUG级别的日志,并把该日志放到logs/debug.log文件中-->
<!--打印出DEBUG级别日志,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileDebug" fileName="./logs/debug.log"
filePattern="logs/$${date:yyyy-MM}/debug-%d{yyyy-MM-dd}-%i.log.gz">
<Filters>
<ThresholdFilter level="DEBUG"/>
<ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="500 MB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
<!--处理INFO级别的日志,并把该日志放到logs/info.log文件中-->
<RollingFile name="RollingFileInfo" fileName="./logs/info.log"
filePattern="logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz">
<Filters>
<!--只接受INFO级别的日志,其余的全部拒绝处理-->
<ThresholdFilter level="INFO"/>
<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="500 MB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
<!--处理WARN级别的日志,并把该日志放到logs/warn.log文件中-->
<RollingFile name="RollingFileWarn" fileName="./logs/warn.log"
filePattern="logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz">
<Filters>
<ThresholdFilter level="WARN"/>
<ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="500 MB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
<!--处理error级别的日志,并把该日志放到logs/error.log文件中-->
<RollingFile name="RollingFileError" fileName="./logs/error.log"
filePattern="logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz">
<ThresholdFilter level="ERROR"/>
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %class{36} %L %M - %msg%xEx%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="500 MB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
<!--druid的日志记录追加器-->
<RollingFile name="druidSqlRollingFile" fileName="./logs/druid-sql.log"
filePattern="logs/$${date:yyyy-MM}/api-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] %-5level %L %M - %msg%xEx%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="500 MB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
</appenders>
<loggers>
<root level="INFO">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
<appender-ref ref="RollingFileDebug"/>
</root>
<!--记录druid-sql的记录-->
<logger name="druid.sql.Statement" level="debug" additivity="false">
<appender-ref ref="druidSqlRollingFile"/>
</logger>
<logger name="druid.sql.Statement" level="debug" additivity="false">
<appender-ref ref="druidSqlRollingFile"/>
</logger>
<!--log4j2 自带过滤日志-->
<Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
<Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
<logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
<Logger name="org.crsh.plugin" level="warn" />
<logger name="org.crsh.ssh" level="warn"/>
<Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
<Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
<logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="warn"/>
<logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
<logger name="org.thymeleaf" level="warn"/>
</loggers>
</configuration>
到这里,Druid的配置就算完成了。
Mybatis的配置除了在配置文件中指定Mapper映射文件的路径外,还要告知应用程序扫描Mapper接口,有两种方式可以实现:
其一,在应用程序入口类上加上Mapper接口的扫描@MapperScan,并指定Mapper接口的包路径,如下所示:
@SpringBootApplication
@MapperScan("cn.greedystar.springbootdemo.modules.dao")
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
其二,在Mapper接口类上加上注解@Mapper,如下所示:
@Mapper
public interface UserDao extends BaseDao<User> {
List<User> findUserList(User user);
}
注意:网上很多资料将以上两种配置方式形容为必须一起使用,这种情况下还是要自己多试一试。
至此,Druid和Mybatis的配置工作就完成了。
(二)配置类
这里使用了Spring3.0引入的注解@Configuration,在@Configuration注解的类中可以定义多个由@Bean注解的方法,用于创建Bean,与在配置文件中定义<bean>的效果是一样的,本文中使用@Configuration注解配置Swagger2,如下所示:
@Configuration
@EnableSwagger2
@ComponentScan({"cn.greedystar.springbootdemo.modules.web"})
public class Swagger2Config {
/**
* 创建API应用
* apiInfo() 增加API相关信息
* 通过select()函数返回一个ApiSelectorBuilder实例,指定扫描的包路径来定义要建立API的controller目录。
*
* @return
*/
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("cn.greedystar.springbootdemo.modules.web"))
.paths(PathSelectors.any())
.build();
}
/**
* 创建该API的基本信息(这些基本信息会展现在文档页面中)
* 访问地址:http://项目实际地址/swagger-ui.html
*
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("利用swagger构建api文档")
.description("更多请关注 http://blog.csdn.net/greedystar")
.termsOfServiceUrl("http://blog.csdn.net/greedystar")
.version("1.0")
.build();
}
}
Swagger2的配置中指定了扫描controller的路径,下面我们来看一看controller中如何配置Api文档的数据,在下面这段代码中,我们使用了@ApiOperation和@ApiImplicitParam来配置Api文档的数据,具体如下所示:
@RestController
@RequestMapping(value = "/user/")
public class UserController {
@Autowired
private UserService userService;
@ApiOperation(value = "获取所有用户列表", notes = "获取所有用户列表")
@RequestMapping(value = "list", method = RequestMethod.GET)
public Response getAllUser() {
List<User> userList = userService.findList(new User());
if (userList == null) {
return new Response.Builder().setMessage("no data found").setStatus(404).build();
}
return new Response.Builder().setMessage("OK").setStatus(200).setData(userList).build();
}
@ApiOperation(value = "获取用户详细信息", notes = "根据id来获取用户详细信息")
@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "String", paramType = "path")
@RequestMapping(value = "{id}", method = RequestMethod.GET)
public Response getUserById(@PathVariable String id) {
User user = userService.get(id);
if (user == null) {
return new Response.Builder().setMessage("no data found").setStatus(404).build();
}
return new Response.Builder().setMessage("ok").setStatus(200).setData(user).build();
}
}
至此,Swagger2的简单配置就完成了。
三、测试
(一)Druid监控
在Druid的监控设置中,我们将监控平台的路径设置为/druid/,下面让我们看一看监控平台的样子,访问监控页面需要输入用户名和密码,这是我们先前配置的,进入监控平台后的页面如下:
在顶级导航栏中我们看到Druid监控平台的主要功能,具体的监控功能还需要进一步学习。
需要指出的是,Druid监控平台是基于内存数据的,在我们使用的过程中需要根据需要进行监控数据的持久化。
(二)日志记录
我们在log4j2.xml中配置了日志的记录方式,将日志文件保存在./logs/下,在项目目录下会生成一个logs文件夹,其中按月份组织日志文件,如下所示:
其中druid-sql.log是我们设置的druid sql执行记录,部分内容如下:
[2018-07-12 18:45:18] DEBUG 137 statementLog - {conn-10005, pstmt-20001} executed. SELECT
a.id AS "id",
a.name AS "name"
FROM user a
[2018-07-12 18:46:11] DEBUG 137 statementLog - {conn-10005, pstmt-20000} executed. SELECT
a.id AS "id",
a.name AS "name"
FROM user a
[2018-07-12 18:53:27] DEBUG 137 statementLog - {conn-10005, pstmt-20000} executed. SELECT
a.id AS "id",
a.name AS "name"
FROM user a
[2018-07-12 18:53:58] DEBUG 137 statementLog - {conn-10005, pstmt-20000} executed. SELECT
a.id AS "id",
a.name AS "name"
FROM user a
(三)在线API文档
界面如下图所示:
这里不仅可以查看配置的接口信息,而且可以用于测试接口,我们以/user/list为例进行测试
测试结果如下:
这里的返回结果是进行了封装了统一相应格式,具体的实现请参考源码。
四、总结
SpringBoot为我们提供了简洁的配置方式,可以让开发人员更注重业务的实现。
Druid由阿里开源,是非常优秀的Java数据库连接池,而且具有很强的监控功能,值得我们深入学习。
Swagger2为我们提供了一个简单的在线API文档平台,而且可以进行接口测试,是后端人员的福利工具。
经过一番配置和测试,我们最终完成了SpringBoot整合Mybatis、Druid和Swagger2,搭建了数据源监控、日志记录以及在线Api文档平台,这个项目作为学习的开端,也将会作为以后学习过程中使用的种子项目。
最后,附上源码:https://github.com/GreedyStar/spring-boot-demo
最后的最后,安利一下自己写的一个Java代码生成工具,能够方便的生成Spring、SpringMVC、Mybatis架构下的Java代码,希望能对大家有所帮助,地址:Java代码生成器:Generator