本文主要介绍 Spring Boot 开发过程使用到的一些组件,帮助开发人员快速搭建基础开发框架。
1. 配置日志相关
1.1 日志级别 Level
日志的行为等级分为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL
Log4j 建议只使用四个级别,优先级从高到低依次是:ERROR、WARN、INFO、DEBUG。
1.2 配置示例
1. 配置 application.yml,指定 logback.xml 的详细地址。
logging:
config: classpath:logback-config.xml
2. 配置 logback-config.xml,在配置文件中指定日志的打印级别,日志文件的存储路径等日志相关信息。
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds"
debug="false">
<property name="log.path" value="/project/logs/" />
<!--输出到控制台 -->
<appender name="console"
class="ch.qos.logback.core.ConsoleAppender">
<!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level>
</filter> -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!--输出到文件 -->
<appender name="file"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}${log.file}</file>
<!-- <rollingPolicy -->
<!-- class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> -->
<!-- <fileNamePattern>${log.path}deepev.%d{yyyy-MM-dd_HH-mm}.log -->
<!-- </fileNamePattern> -->
<!-- <maxHistory>30</maxHistory> -->
<!-- <totalSizeCap>1GB</totalSizeCap> -->
<!-- </rollingPolicy> -->
<!-- 滚动策略 日期+大小 策略 -->
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}deepev.%d{yyyy-MM-dd}.log-%i.zip</fileNamePattern>
<!-- 单个日志大小 -->
<maxFileSize>30MB</maxFileSize>
<!-- 日志保存周期 -->
<maxHistory>30</maxHistory>
<!-- 总大小 -->
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="warn">
<appender-ref ref="console" />
<appender-ref ref="file" />
</root>
<!-- 指定业务包-->
<logger name="com.**" level="INFO" additivity="false">
<appender-ref ref="console" />
<appender-ref ref="file" />
</logger>
</configuration>
1.3 配置示例详解
根据上边的 logback-config.xml 文件,对 Logback 的相关配置进行详细讲解。
1. 根节点<configuration> 有三个属性,scan、scanPeriod 和 debug。
- scan 值为 true 或 false,用于监控配置文件,如果文件发生改变后,将会被重新加载,此属性默认为 true。
- scanPeriod 是时间间隔,是用来设置监测配置文件是否有修改,默认的时间单位是毫秒,只有 scan 设置为 true 时,此属性才会生效。
- debug 此属性值为 true 或者 false,用于控制是否打印出 Logback 内部日志信息,设置为 true 时,可以通过 Logback 的内部日志,实时查看 Logback 运行状态。默认值为 false。
2. <appender> 节点是负责写日志的组件,有两个必须的属性,分别是 name 和 class,name 用于指定 appender 组件的名称,class 是 appender 组件的策略。
这里介绍一下 appender 的常用的组件:
-
ConsoleAppender 控制台组件,该组件是把日志输出到控制台上。上边示例中的
name=“console”
的组件就是这种策略。console 组件中的 <encoder> 部分是用来格式化日志格式的。 -
FileAppender 文件组件,该组件是把日志输出到文档中去。
-
<file>info.log</file>
:指定日志被写入的文件的地址,该地址可以是相对目录,也可以是绝对目录。指定的目录如果不存在的话,会自动创建。 -
<append>true</append>
:文件的写入类型,true 的话新生成的日志会追加到文件的结尾,如果为 false,则清空现有的文件。默认值为 true。
-
- RollingFileAppender 滚动记录文件组件,该组件与 FileAppender 相比,增加了 rollingPolicy 属性,是对日志滚动处理时,指定对文件复制和重命名时的滚动的策略。
常用策略有三种:
- ch.qos.logback.core.rolling.TimeBasedRollingPolicy:根据时间来制定滚动策略。
- ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy:查看当前日志文件的大小,当超过指定大小时,会告知 RollingFileAppender,触发当前日志文件滚动。
- ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy: 根据日期和大小同时确定滚动策略。
3. <logger> 节点:用来设置某一个包或具体的某一个类的日志打印级别、以及指定<appender>。在 logger 节点下可以包含零个或多个<appender-ref> 元素,ref 值用于标识 appender 的 name,并添加到这个 logger 中。上面的示例中,添加了两个 appender-ref,分别指定 file。
4. <root>节点,它是根 logger,是所有 logger 的上级,只有一个 level 的属性,用于指定日志等级。
2. 集成 Swagger,生成接口文档
Swagger 2
Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。
2.1 添加依赖
这里我添加了两个 UI,springfox-swagger-ui 是官方提供的,swagger-bootstrap-ui 是第三方封装的,我平时更习惯使用第三方 UI。
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.1</version>
</dependency>
2.2 application.yml 中添加开关
Swagger 只能在开发环境使用,部署生产环境时要关闭,为了方便管理,在配置文件中添加开关。
swagger:
enable: true
2.3 编写 Swagger 配置类
在该配置类中,可以配置 API 文档中的显示信息,通过全局配置,可以为所有的 API 接口添加通用条件。
下面的示例中为所有的接口添加 token 公共配置的方法。
package com.**.**.conf;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Value("${swagger.enable}")
private boolean enableSwagger;
@Bean
public Docket docket(){
List<Parameter> params = getParam();
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).enable(enableSwagger).select()
//当前包路径
.apis(RequestHandlerSelectors.basePackage("com.reach.usercenter"))
.paths(PathSelectors.any())
.build()
// .securitySchemes(security()).securityContexts(securityContexts()); //添加全局 token
.globalOperationParameters(params);//在每一个接口上添加 token
}
private List<Parameter> getParam(){
ParameterBuilder ticketPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<Parameter>();
ticketPar.name("Authorization").description("user ticket")//Token 以及 Authorization 为自定义的参数,session 保存的名字是哪个就可以写成那个
.modelRef(new ModelRef("string")).parameterType("header")
.required(true).build(); //header 中的 ticket 参数非必填,传空也可以
pars.add(ticketPar.build()); //根据每个方法名也知道当前方法在设置什么参数
return pars;
}
private List<SecurityContext> securityContexts() {
List<SecurityContext> securityContexts=new ArrayList<>();
securityContexts.add(
SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex("^(?!auth).*$"))
.build());
return securityContexts;
}
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
List<SecurityReference> securityReferences=new ArrayList<>();
securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
return securityReferences;
}
private List<ApiKey> security() {
ApiKey key = new ApiKey("Authorization", "Authorization ", "header");
List<ApiKey> list = new ArrayList();
list.add(key);
return list;
}
//构建 api 文档的详细信息函数
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("EV DATA RESTful API")
.version("1.0")
.description("API 描述")
.build();
}
}
3. 配置文件敏感信息加密
在开发的服务中,为了安全考虑,有一些信息是必须要进行加密处理的,比如数据库的密码等信息,开发环境和测试环境还好说,但是生产环境必须要保证信息安全。Jasypt 是一个通用的加密库,我们可以使用 Jasypt 对配置文件中的敏感信息进行加密处理。
3.1 添加依赖
<!-- https://mvnrepository.com/artifact/com.github.ulisesbocchio/jasypt-spring-boot-starter -->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
3.2 application.yml 配置
#配置文件项加解密密码,此处是开发环境,实际生产中应该注销,使用启动参数的方式传入
jasypt:
encryptor:
password: testtest
spring:
datasource:
url: jdbc:......
username: root
password: ENC(0RVCs2UAXrb8cWsMk8tJuE6XXMuKZxAHRJ1yP9dA4jdY1MU1jKJumLyVUiF0yvuD)
......
3.3 Jasypt 使用测试
通过上边的配置以后,我们就完成了对数据库密码的加密工作,Spring Boot 已经可以正常启动了。更为详细的配置可以参考一下网站:
下边是 Jasypt 的测试例子,实现对信息的加密和解密处理。
package com.**;
import org.jasypt.encryption.StringEncryptor;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class UserEncryptorTest {
@Autowired
private StringEncryptor stringEncryptor;
//加密
@Test
public void encrypt() {
System.out.println("testtest 的密文为:"+ stringEncryptor.encrypt("testtest"));
}
//解密
@Test
public void decrypt() {
System.out.println("解密结果为:"+stringEncryptor.decrypt("+VZcKfSsRgHuXnosbV55R8elvOHMEoThfgKX+ujJDp0pzMeZLZLK3yrcFWPn2iiO"));
}
}
//输出结果
//testtest 的密文为:+VZcKfSsRgHuXnosbV55R8elvOHMEoThfgKX+ujJDp0pzMeZLZLK3yrcFWPn2iiO
//解密结果为:testtest
4. 数据源配置
这里使用 MySQL 数据库,使用 JDBC 和 JPA 操作数据库。
4.1 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>