积分等级CRUD列表和表单
Group:com.atguigu
Artifact:srb
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.3.4.RELEASEversion>
parent>
<properties>
<java.version>1.8java.version>
<spring-cloud-alibaba.version>2.2.2.RELEASEspring-cloud-alibaba.version>
<spring-cloud.version>Hoxton.SR8spring-cloud.version>
<mybatis-plus.version>3.4.1mybatis-plus.version>
<velocity.version>2.0velocity.version>
<swagger.version>2.9.2swagger.version>
<swagger-bootstrap-ui.version>1.9.2swagger-bootstrap-ui.version>
<commons-lang3.version>3.9commons-lang3.version>
<commons-fileupload.version>1.3.1commons-fileupload.version>
<commons-io.version>2.6commons-io.version>
<alibaba.easyexcel.version>2.1.1alibaba.easyexcel.version>
<apache.xmlbeans.version>3.1.0apache.xmlbeans.version>
<fastjson.version>1.2.28fastjson.version>
<gson.version>2.8.2gson.version>
<json.version>20170516json.version>
<aliyun-java-sdk-core.version>4.3.3aliyun-java-sdk-core.version>
<aliyun-sdk-oss.version>3.10.2aliyun-sdk-oss.version>
<jodatime.version>2.10.1jodatime.version>
<jwt.version>0.7.0jwt.version>
<httpclient.version>4.5.1httpclient.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>${spring-cloud-alibaba.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>${mybatis-plus.version}version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>${mybatis-plus.version}version>
dependency>
<dependency>
<groupId>org.apache.velocitygroupId>
<artifactId>velocity-engine-coreartifactId>
<version>${velocity.version}version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>${swagger.version}version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>${swagger.version}version>
dependency>
<dependency>
<groupId>com.github.xiaoymingroupId>
<artifactId>swagger-bootstrap-uiartifactId>
<version>${swagger-bootstrap-ui.version}version>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>${commons-lang3.version}version>
dependency>
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>${commons-fileupload.version}version>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>${commons-io.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>easyexcelartifactId>
<version>${alibaba.easyexcel.version}version>
dependency>
<dependency>
<groupId>org.apache.xmlbeansgroupId>
<artifactId>xmlbeansartifactId>
<version>${apache.xmlbeans.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>${fastjson.version}version>
dependency>
<dependency>
<groupId>org.jsongroupId>
<artifactId>jsonartifactId>
<version>${json.version}version>
dependency>
<dependency>
<groupId>com.google.code.gsongroupId>
<artifactId>gsonartifactId>
<version>${gson.version}version>
dependency>
<dependency>
<groupId>com.aliyungroupId>
<artifactId>aliyun-java-sdk-coreartifactId>
<version>${aliyun-java-sdk-core.version}version>
dependency>
<dependency>
<groupId>com.aliyun.ossgroupId>
<artifactId>aliyun-sdk-ossartifactId>
<version>${aliyun-sdk-oss.version}version>
dependency>
<dependency>
<groupId>joda-timegroupId>
<artifactId>joda-timeartifactId>
<version>${jodatime.version}version>
dependency>
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>${jwt.version}version>
dependency>
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<version>${httpclient.version}version>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
在srb下创建普通maven模块
Group:com.atguigu
Artifact:guigu-common
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
dependencies>
在srb下创建普通maven模块
Group:com.atguigu
Artifact:service-base
注意:依赖guigu-common
<dependencies>
<dependency>
<groupId>com.atguigugroupId>
<artifactId>guigu-commonartifactId>
<version>0.0.1-SNAPSHOTversion>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
dependency>
dependencies>
在srb下创建普通maven模块
Group:com.atguigu
Artifact:service-core
注意:依赖service-base
<dependencies>
<dependency>
<groupId>com.atguigugroupId>
<artifactId>service-baseartifactId>
<version>0.0.1-SNAPSHOTversion>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
dependency>
<dependency>
<groupId>org.apache.velocitygroupId>
<artifactId>velocity-engine-coreartifactId>
dependency>
dependencies>
创建数据库srb_core
并执行sql脚本初始化数据结构和数据
在test目录中创建测试用例,并执行
package com.atguigu.srb.core;
public class CodeGenerator {
@Test
public void genCode() {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("Helen");
gc.setOpen(false); //生成后是否打开资源管理器
gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setIdType(IdType.AUTO); //主键策略
gc.setSwagger2(true);//开启Swagger2模式
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/srb_core?serverTimezone=GMT%2B8&characterEncoding=utf-8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setParent("com.atguigu.srb.core");
pc.setEntity("pojo.entity"); //此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok
strategy.setLogicDeleteFieldName("is_deleted");//逻辑删除字段名
strategy.setEntityBooleanColumnRemoveIsPrefix(true);//去掉布尔值的is_前缀(确保tinyint(1))
strategy.setRestControllerStyle(true); //restful api风格控制器
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}
server:
port: 8110 # 服务端口
spring:
profiles:
active: dev # 环境设置
application:
name: service-core # 服务名
datasource: # mysql数据库连接
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/srb_core?serverTimezone=GMT%2B8&characterEncoding=utf-8
username: root
password: 123456
mybatis-plus: #mybatis
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath:com/atguigu/srb/core/mapper/xml/*.xml
在service-core中创建config包,创建MybatisPlusConfig类
package com.atguigu.srb.core.config;
@Configuration
@MapperScan("com.atguigu.srb.core.mapper")
@EnableTransactionManagement //事务处理
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//分页
return interceptor;
}
}
注意:扫描com.atguigu.srb
package com.atguigu.srb.core;
@SpringBootApplication
@ComponentScan({"com.atguigu.srb"})
public class ServiceCoreApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceCoreApplication.class, args);
}
}
查看控制台8110端口是否成功启动
在controller中添加admin包,添加AdminIntegralGradeController类
package com.atguigu.srb.core.controller.admin;
@CrossOrigin
@RestController
@RequestMapping("/admin/core/integralGrade")
public class AdminIntegralGradeController {
@Resource
private IntegralGradeService integralGradeService;
@GetMapping("/list")
public List<IntegralGrade> listAll(){
return integralGradeService.list();
}
}
重启服务,访问: http://localhost:8110/admin/core/integralGrade/list 查看结果json数据
AdminIntegralGradeController添加removeById方法
@DeleteMapping("/remove/{id}")
public boolean removeById(@PathVariable Long id){
return integralGradeService.removeById(id);
}
在service-base中创建Swagger2Config
package com.atguigu.srb.base.config;
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket adminApiConfig(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("adminApi")
.apiInfo(adminApiInfo())
.select()
//只显示admin路径下的页面
.paths(Predicates.and(PathSelectors.regex("/admin/.*")))
.build();
}
private ApiInfo adminApiInfo(){
return new ApiInfoBuilder()
.title("尚融宝后台管理系统-API文档")
.description("本文档描述了尚融宝后台管理系统接口")
.version("1.0")
.contact(new Contact("Helen", "http://atguigu.com", "[email protected]"))
.build();
}
}
重启服务器查看接口文档:http://localhost:8110/swagger-ui.html
**实体类注解:**entity的实体类中可以添加一些自定义设置,例如:
@ApiModelProperty(value = "创建时间", example = "2019-01-01 8:00:00")
private LocalDateTime createTime;
@ApiModelProperty(value = "更新时间", example = "2019-01-01 8:00:00")
private LocalDateTime updateTime;
controller注解:
定义在类上
@Api(tags = "积分等级管理")
定义在方法上
@ApiOperation("积分等级列表")
@ApiOperation(value = "根据id删除积分等级", notes = "逻辑删除")
定义在参数上
@ApiParam(value = "数据id", required = true, example = "100")
项目中我们会将响应封装成json返回,一般我们会将所有接口的数据格式统一, 使前端对数据的操作更一致、轻松。
一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。但是一般会包含状态码、返回消息、数据这几部分内容
例如,我们的系统要求返回的基本数据格式如下:
成功:
{
"code": 0,
"message": "成功",
"data": 数据
}
失败:
{
"code": -1,
"message": "失败",
"data": null
}
因此,我们定义统一结果
{
"code": 数字, //业务响应码
"message": 字符串, //返回消息
"data": 对象 //返回数据
}
在guigu-common中创建result包,创建枚举 ResponseEnum
package com.atguigu.common.result;
@Getter
@AllArgsConstructor
@ToString
public enum ResponseEnum {
SUCCESS(0, "成功"),
ERROR(-1, "服务器内部错误"),
;
// 响应状态码
private Integer code;
// 响应信息
private String message;
}
完整的枚举源代码:ResponseEnum.java
package com.atguigu.common.result;
@Data
public class R {
private Integer code;
private String message;
private Map<String, Object> data = new HashMap();
/**
* 构造器私有
*/
private R(){}
/**
* 返回成功
*/
public static R ok(){
R r = new R();
r.setCode(ResponseEnum.SUCCESS.getCode());
r.setMessage(ResponseEnum.SUCCESS.getMessage());
return r;
}
/**
* 返回失败
*/
public static R error(){
R r = new R();
r.setCode(ResponseEnum.ERROR.getCode());
r.setMessage(ResponseEnum.ERROR.getMessage());
return r;
}
/**
* 设置特定结果
*/
public static R setResult(ResponseEnum responseEnum){
R r = new R();
r.setCode(responseEnum.getCode());
r.setMessage(responseEnum.getMessage());
return r;
}
public R message(String message){
this.setMessage(message);
return this;
}
public R code(Integer code){
this.setCode(code);
return this;
}
public R data(String key, Object value){
this.data.put(key, value);
return this;
}
public R data(Map<String, Object> map){
this.setData(map);
return this;
}
}
@ApiOperation("积分等级列表")
@GetMapping("/list")
public R listAll(){
List<IntegralGrade> list = integralGradeService.list();
return R.ok().data("list", list);
}
@ApiOperation(value = "根据id删除积分等级", notes="逻辑删除")
@DeleteMapping("/remove/{id}")
public R removeById(
@ApiParam(value = "数据id", required = true, example = "1")
@PathVariable Long id){
boolean result = integralGradeService.removeById(id);
if(result){
//return R.setResult(ResponseEnum.UPLOAD_ERROR);
return R.ok().message("删除成功");
}else{
return R.error().message("删除失败");
}
}
@ApiOperation("新增积分等级")
@PostMapping("/save")
public R save(
@ApiParam(value = "积分等级对象", required = true)
@RequestBody IntegralGrade integralGrade){
boolean result = integralGradeService.save(integralGrade);
if (result) {
return R.ok().message("保存成功");
} else {
return R.error().message("保存失败");
}
}
@ApiOperation("根据id获取积分等级")
@GetMapping("/get/{id}")
public R getById(
@ApiParam(value = "数据id", required = true, example = "1")
@PathVariable Long id
){
IntegralGrade integralGrade = integralGradeService.getById(id);
if(integralGrade != null){
return R.ok().data("record", integralGrade);
}else{
return R.error().message("数据不存在");
}
}
@ApiOperation("更新积分等级")
@PutMapping("/update")
public R updateById(
@ApiParam(value = "积分等级对象", required = true)
@RequestBody IntegralGrade integralGrade){
boolean result = integralGradeService.updateById(integralGrade);
if(result){
return R.ok().message("修改成功");
}else{
return R.error().message("修改失败");
}
}
屏蔽 IntegralGrade 中的 @TableField注解
@ApiModelProperty(value = "逻辑删除(1:已删除,0:未删除)")
//@TableField("is_deleted")
@TableLogic
private Boolean deleted;
测试列表查询功能,查看结果,发生错误,显示响应失败
目标:我们想让异常结果也显示为统一的返回结果对象,并且统一处理系统的异常信息,那么需要进行统一异常处理。
guigu-common中创建exception包,创建统一异常处理器类UnifiedExceptionHandler
package com.atguigu.common.exception;
@Slf4j
@Component //Spring容易自动管理
@RestControllerAdvice //在controller层添加通知。如果使用@ControllerAdvice,则方法上需要添加@ResponseBody
public class UnifiedExceptionHandler {
/**
* 未定义异常
*/
@ExceptionHandler(value = Exception.class) //当controller中抛出Exception,则捕获
public R handleException(Exception e) {
log.error(e.getMessage(), e);
return R.error();
}
}
添加 “com.atguigu.common”
@SpringBootApplication
@ComponentScan({"com.atguigu.srb", "com.atguigu.common"})
public class ServiceCoreApplication {
返回统一错误结果
如果我们不想显示统一的“服务器内部错误”,需要个性化的显示异常信息,那么需要针对特定的异常做处理
在guigu-common中添加jdbc依赖
org.springframework
spring-jdbc
在 UnifiedExceptionHandler 中添加
/**
* 特定异常
*/
@ExceptionHandler(BadSqlGrammarException.class)
public R handleBadSqlGrammarException(BadSqlGrammarException e){
log.error(e.getMessage(), e);
return R.setResult(ResponseEnum.BAD_SQL_GRAMMAR_ERROR);
}
问题:上面的例子虽然针对特定的异常显示个性化的错误信息,但是你会发现,针对每个不同的异常我们都需要在项目中添加对应的处理方法,并捕获对应的异常对象,可能还要针对这个异常添加额外的依赖。这显然不是最好的方式。
方案:此类异常直接抛出,并且用Exception类捕获就可以了。
@TableField(value = "is_deleted")
目标:使用一个或较少的异常类,可以捕获和显示所有的异常信息。
方案:因此,我们可以创建一个自定义异常类(必须是运行时异常),在程序中抛出这个自定义异常对象,并在统一异常处理器中捕获自定义异常对象
package com.atguigu.common.exception;
@Data
@NoArgsConstructor
public class BusinessException extends RuntimeException {
//状态码
private Integer code;
//错误消息
private String message;
}
完整的源代码:BusinessException.java
UnifiedExceptionHandler类中添加
/**
* 自定义异常
*/
@ExceptionHandler(BusinessException.class)
public R handleBusinessException(BusinessException e){
log.error(e.getMessage(), e);
return R.error().message(e.getMessage()).code(e.getCode());
}
在AdminIntegralGradeController的方法中添加异常处理,业务中需要的位置抛出BusinessException自定义异常。
@ApiOperation("新增积分等级")
@PostMapping("/save")
public R save(
@ApiParam(value = "积分等级对象", required = true)
@RequestBody IntegralGrade integralGrade){
//如果借款额度为空就手动抛出一个自定义的异常!
if(integralGrade.getBorrowAmount() == null){
//BORROW_AMOUNT_NULL_ERROR(-201, "借款额度不能为空"),
throw new BusinessException(ResponseEnum.BORROW_AMOUNT_NULL_ERROR);
}
boolean result = integrationService.save(integralGrade);
if (result) {
return R.ok().message("保存成功");
} else {
return R.error().message("保存失败");
}
}
测试
结果
目标:以优雅的 Assert(断言) 方式来校验业务的异常情况,消除 if else
package com.atguigu.srb.core;
import org.junit.jupiter.api.Test;
import org.springframework.util.Assert;
public class AssertTests {
//if else的用法
@Test
public void test1() {
Object o = null;
if (o == null) {
throw new IllegalArgumentException("用户不存在.");
}
}
//断言的用法:更为简洁
@Test
public void test2() {
// 另一种写法
Object o = null;
Assert.notNull(o, "用户不存在.");
}
}
用断言的方式封装异常的抛出
package com.atguigu.common.exception;
@Slf4j
public abstract class Assert {
/**
* 断言对象不为空
* 如果对象obj为空,则抛出异常
* @param obj 待判断对象
*/
public static void notNull(Object obj, ResponseEnum responseEnum) {
if (obj == null) {
log.info("obj is null...............");
throw new BusinessException(responseEnum);
}
}
}
完整的源代码:Assert.java
在controller中用断言替换if else
Assert.notNull(integralGrade.getBorrowAmount(), ResponseEnum.BORROW_AMOUNT_NULL_ERROR);
对异常按阶段进行分类,大体可以分成:进入Controller前的异常 和 业务层异常,具体可以参考下图:
UnifiedExceptionHandler中添加
/**
* Controller上一层相关异常
*/
@ExceptionHandler({
NoHandlerFoundException.class,
HttpRequestMethodNotSupportedException.class,
HttpMediaTypeNotSupportedException.class,
MissingPathVariableException.class,
MissingServletRequestParameterException.class,
TypeMismatchException.class,
HttpMessageNotReadableException.class,
HttpMessageNotWritableException.class,
MethodArgumentNotValidException.class,
HttpMediaTypeNotAcceptableException.class,
ServletRequestBindingException.class,
ConversionNotSupportedException.class,
MissingServletRequestPartException.class,
AsyncRequestTimeoutException.class
})
public R handleServletException(Exception e) {
log.error(e.getMessage(), e);
//SERVLET_ERROR(-102, "servlet请求异常"),
return R.error().message(ResponseEnum.SERVLET_ERROR.getMessage()).code(ResponseEnum.SERVLET_ERROR.getCode());
}
在save测试用例中输入非法的json参数,则得到下面的结果。我们可以在控制台日志中查看具体的错误原因。前端只需要返回相对简单友好的提示即可。
通过日志查看程序的运行过程,运行信息,异常信息等
日志记录器(Logger)的行为是分等级的。如下表所示:
分为:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF
默认情况下,spring boot从控制台打印出来的日志级别只有INFO及以上级别,可以配置日志级别
# 设置日志级别
logging:
level:
root: ERROR
这种方式能将ERROR级别以及以上级别的日志输出到控制台上,其他级别将不会输出
spring boot内部使用Logback作为日志实现的框架。
先删除前面在application.yml中的日志级别配置
resources 中创建 logback-spring.xml (默认日志文件的名字)
<configuration>
configuration>
将以下日志输出到任意controller的方法中即可,例如list方法中
@ApiOperation("积分等级列表")
@GetMapping("/list")
public R listAll(){
log.info("hi i'm helen");
log.warn("warning!!!");
log.error("it's a error");
List<IntegralGrade> list = integrationService.list();
return R.ok().data("list", list);
}
日志配置的根节点
<configuration>configuration>
是的子节点。
每个logger都关联到logger上下文,默认上下文名称为“default”。但可以使用设置成其他名字,用于区分不同的应用程序。
<contextName>atguiguSrbcontextName>
是的子节点,用来定义变量。
有两个属性,name和value:name的值是变量的名称,value是变量的值。
通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。
<property name="log.path" value="D:/project/finance/srb_log/core" />
<property name="CONSOLE_LOG_PATTERN"
value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) %highlight([%-5level]) %green(%logger) %msg%n"/>
<property name="FILE_LOG_PATTERN"
value="%date{yyyy-MM-dd HH:mm:ss} [%-5level] %thread %file:%line %logger %msg%n" />
<property name="ENCODING"
value="UTF-8" />
是的子节点,是负责写日志的组件
有两个必要属性name和class:name指定appender名称,class指定appender的全限定名
对日志进行格式化
定义日志的具体输出格式
编码方式
控制台日志配置
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}pattern>
<charset>${ENCODING}charset>
encoder>
appender>
**文件日志配置 **
表示日志文件的位置,如果上级目录不存在会自动创建,没有默认值。
默认 true,日志被追加到文件结尾,如果是 false,服务重启后清空现存文件。
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${log.path}/log.logfile>
<append>trueappend>
<encoder>
<pattern>${FILE_LOG_PATTERN}pattern>
<charset>${ENCODING}charset>
encoder>
appender>
可以是的子节点,用来设置某一个包或具体某一个类的日志打印级别、指定
name:用来指定受此logger约束的某一个包或者具体的某一个类
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF。默认继承上级的级别
可以包含零个或多个元素,标识这个appender将会添加到这个logger
<logger name="com.atguigu" level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
logger>
测试日志记录的控制台输出、文件输出、以及日志级别
springProfile
在一个基于Spring boot开发的项目里,常常需要有多套环境的配置:开发,测试以及产品。使用springProfile 可以分别配置开发(dev),测试(test)以及生产(prod)等不同的环境
<springProfile name="dev,test">
<logger name="com.atguigu" level="INFO">
<appender-ref ref="CONSOLE" />
logger>
springProfile>
<springProfile name="prod">
<logger name="com.atguigu" level="ERROR">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
logger>
springProfile>
问题:生产环境下,如果系统长时间运行,那么日志文件会变得越来越大,系统读取和写入日志的时间会越来越慢,严重的情况会耗尽系统内存,导致系统宕机。
解决方案:可以设置滚动日志。
RollingFileAppender是Appender的另一个实现,表示滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将旧日志备份到其他文件
是的子节点,用来定义滚动策略。
TimeBasedRollingPolicy:最常用的滚动策略,根据时间来制定滚动策略。
:包含文件名及转换符, “%d”可以包含指定的时间格式,如:%d{yyyy-MM-dd}。如果直接使用 %d,默认格式是 yyyy-MM-dd。:可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每个月滚动,且是6,则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除。
<appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/log-rolling.logfile>
<encoder>
<pattern>${FILE_LOG_PATTERN}pattern>
<charset>${ENCODING}charset>
encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/info/log-rolling-%d{yyyy-MM-dd}.logfileNamePattern>
<maxHistory>15maxHistory>
rollingPolicy>
appender>
放在的子节点的位置,基于实践策略的触发滚动策略
设置触发滚动条件:单个文件大于100M时生成新的文件
注意:修改日志文件名 此时 ${log.path}/info/log-rolling-%d{yyyy-MM-dd}.%i.log
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>1KBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
<configuration>
<contextName>atguiguSrbcontextName>
<property name="log.path" value="D:/project/test/srb_log/core" />
<property name="CONSOLE_LOG_PATTERN"
value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) %highlight([%-5level]) %green(%logger) %msg%n"/>
<property name="FILE_LOG_PATTERN"
value="%date{yyyy-MM-dd HH:mm:ss} [%-5level] %thread %file:%line %logger %msg%n" />
<property name="ENCODING"
value="UTF-8" />
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}pattern>
<charset>${ENCODING}charset>
encoder>
appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${log.path}/log.logfile>
<append>trueappend>
<encoder>
<pattern>${FILE_LOG_PATTERN}pattern>
<charset>${ENCODING}charset>
encoder>
appender>
<appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/log-rolling.logfile>
<encoder>
<pattern>${FILE_LOG_PATTERN}pattern>
<charset>${ENCODING}charset>
encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/info/log-rolling-%d{yyyy-MM-dd}.%i.logfileNamePattern>
<maxHistory>15maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>1KBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
rollingPolicy>
appender>
<springProfile name="dev,test">
<logger name="com.atguigu" level="INFO">
<appender-ref ref="CONSOLE" />
logger>
springProfile>
<springProfile name="prod">
<logger name="com.atguigu" level="ERROR">
<appender-ref ref="CONSOLE" />
<appender-ref ref="ROLLING_FILE" />
logger>
springProfile>
configuration>
本文章参考B站 尚硅谷《尚融宝》Java微服务分布式金融项目,仅供个人学习使用,部分内容为本人自己见解,与尚硅谷无关。