在线教育项目研发之讲师模块业务操作

举报
tea_year 发表于 2025/06/27 09:48:34 2025/06/27
【摘要】 课程目标1)Swagger2介绍2)讲师CRUD操作【重点】3)统一异常处理4)日志处理1、 SpringBoot整合Swagger2在团队开发中,一个好的 API 文档不但可以减少大量的沟通成本,还可以帮助一位新人快速上手业务。传统的做法是由开发人员创建一份 RESTful API 文档来记录所有的接口细节,并在程序员之间代代相传。这种做法存在以下几个问题:第一:API 接口众多,细节复杂...

课程目标

1)Swagger2介绍

2)讲师CRUD操作【重点】

3)统一异常处理

4)日志处理

1、 SpringBoot整合Swagger2

在团队开发中,一个好的 API 文档不但可以减少大量的沟通成本,还可以帮助一位新人快速上手业务。传统的做法是由开发人员创建一份 RESTful API 文档来记录所有的接口细节,并在程序员之间代代相传。

这种做法存在以下几个问题:

第一:API 接口众多,细节复杂,需要考虑不同的HTTP请求类型、HTTP头部信息、HTTP请求内容等,想要高质量的完成这份文档需要耗费大量的精力;


第二:难以维护。随着需求的变更和项目的优化、推进,接口的细节在不断地演     变,接口描述文档也需要同步修订,可是文档和代码处于两个不同的媒介,     除非有严格的管理机制,否则很容易出现文档、接口不一致的情况


Swagger2 的出现就是为了从根本上解决上述问题。它作为一个规范和完整的框架,可以用于生成、描述、调用和可视化 RESTful 风格的 Web 服务:

1.接口文档在线自动生成,文档随接口变动实时更新,节省维护成本

2.支持在线接口测试,不依赖第三方工具


1.1配置Swagger2

parent中已经指定swagger版本,所以再teacher模块中直接引用:

<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>

1.2 创建Swagger2配置文件 

package com.yxzx.ebs.teacher.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;

import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class Swagger2Config {

@Bean
public Docket webApiConfig(){

return new Docket(DocumentationType.SWAGGER_2)
.groupName("webApi")
.apiInfo(webApiInfo())
.select()
.build();

}

private ApiInfo webApiInfo(){

return new ApiInfoBuilder()
.title("优学在线教育-讲师API文档")
.description("本文档描述了讲师服务接口定义")
.version("1.0")
.contact(new Contact("yz", "http://ujiuye.com", "327591159@qq.com"))
.build();
}
}



1.3 重启服务器查看接口

http://localhost:8001/swagger-ui.html


1.4 API模型

MP的代码生成器已经在entity的实体类中生成了模型的定义

@ApiModelProperty(value = "…")


可以添加一些自定义设置,例如:

定义样例数据

@ApiModelProperty(value = "创建时间", example = "2019-01-01 8:00:00")
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;

@ApiModelProperty(value = "更新时间", example = "2019-01-01 8:00:00")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;    

1.5 定义接口说明和参数说明

定义在类上:@Api

定义在方法上:@ApiOperation

定义在参数上:@ApiParam

例如:

@Api(description="讲师管理")
@RestController
@RequestMapping("/teacher")
public class EbsTeacherController {

@Autowired
private EbsTeacherService ebsTeacherService;

@ApiOperation(value = "所有讲师列表")
@GetMapping
private List<EbsTeacher> getTeacherList(){
List<EbsTeacher> list = ebsTeacherService.list(null);
return list;
}

}


2、 讲师逻辑删除

2.1 在Controller中添加删除方法

 @ApiOperation(value = "根据ID删除讲师")
@DeleteMapping("{id}")
public boolean removeById(
@ApiParam(name = "id", value = "讲师ID", required = true)
@PathVariable String id){
return ebsTeacherService.removeById(id);
}


2.2 配置逻辑删除插件

MyBatisPlusConfig 中配置

@Configuration
public class MyBatisPlusConfig {

/**
* 逻辑删除插件
*/
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}


2.3 在EbsTeacher.java文件中

@ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
@TableLogic
@TableField(fill = FieldFill.INSERT, value = "is_delete")
private Boolean isDeleted;


因为在添加之前需要自动填充:FieldFill.INSERT,所以我们需要配置Handler处理;

2.4 配置Handler

创建 com.guli.teacher.handler.TeacherMetaObjectHandler.java


@Component
public class TeacherMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("isDelete", 0, metaObject);
this.setFieldValByName("gmtCreate", new Date(), metaObject);
this.setFieldValByName("gmtModified", new Date(), metaObject);
}

@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("gmtModified", new Date(), metaObject);
}
}


2.5 配置application.properties文件

配置指定删除和不删除的状态

# 设置指定删除状态
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0


2.6 讲师逻辑删除测试

使用Swagger-ui.html链接:测试;

显示:

数据库显示:

3、 统一返回结果集

项目中我们会将响应封装成json返回,一般我们会将所有接口的数据格式统一, 使前端(iOS Android, Web)对数据的操作更直观、轻松。

一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。

例如,我们的系统要求返回的基本数据格式如下:

列表:

{

"success": true,

"code": 20000,

"message": "成功",

"data": {

"items": [

{

"memberId": "1",

"mobile": "18911893513",

"createTime": "2018-05-15 01:20:52"

}

]

}

}

分页:

 

{

"success": true,

"code": 20000,

"message": "成功",

"data": {

"total": 17,

"rows": [

{

"memberId": "1",

"mobile": "18911893513",

"createTime": "2018-05-15 01:20:52"

}

]

}

}

没有返回数据:

{

"success": true,

"code": 20000,

"message": "成功",

"data": {“”:””,””:””}

失败:

{

"success": false,

"code": 20001,

"message": "失败",

"data": {}

}

因此,我们定义统一结果

{

"success": 布尔, //响应是否成功

"code": 数字, //响应码

"message": 字符串, //返回消息

"data": HashMap //返回数据,放在键值对中

}


3.1 创建模块yxzx_common

3.1.1 创建模块

yxzx_common项目下初始化一个普通的maven模块

Artifact:yxzx_common

<packaging>jar</packaging>


3.1.2 配置 pom.xml

<dependencies>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<!--lombok用来简化实体类:需要安装lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--开发者工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>


3.1.3 建返回码定义类

一个类:定义状态码

public interface ResultCode {
int OK = 20000;//成功
int ERROR = 20001;//失败
}



一个类:定义返回结果对象;

@Data
@ApiModel(value = "全局统一返回结果")
public class Result {

@ApiModelProperty(value = "是否成功")
private boolean success;

@ApiModelProperty(value = "返回码")
private Integer code;

@ApiModelProperty(value = "返回消息")
private String message;

@ApiModelProperty(value = "返回数据")
private Map<String, Object> data = new HashMap<String, Object>();

private Result(){}

public static Result ok(){
Result r = new Result();
r.setSuccess(true);
r.setCode(ResultCode.OK);
r.setMessage("成功");
return r;
}

public static Result error(){
Result r = new Result();
r.setSuccess(false);
r.setCode(ResultCode.ERROR);
r.setMessage("失败");
return r;
}

public Result message(String message){
this.setMessage(message);
return this;
}

public Result code(Integer code){
this.setCode(code);
return this;
}

public Result data(String key, Object value){
this.data.put(key, value);
return this;
}

public Result data(Map<String, Object> map){
this.setData(map);
return this;
}
}


3.2 添加依赖

3.2.1 在yxzx_teacher 模块中添加依赖

dependency>
<groupId>com.yxzx</groupId>
<artifactId>yxzx_common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>



3.2.2 代码重构

@ApiOperation(value = "所有讲师列表")
@GetMapping
private Result getTeacherList(){
List<EbsTeacher> list = ebsTeacherService.list(null);


return Result.ok().data("items",list);
}


@ApiOperation(value = "根据ID删除讲师")
@DeleteMapping("{id}")
public Result removeById(
@ApiParam(name = "id", value = "讲师ID", required = true)
@PathVariable String id){
boolean flag = ebsTeacherService.removeById(id);
if(flag){
return Result.ok();
}else{
return Result.error();
}

}


4、 分页和条件查询

4.1 MyBatisPlusConfig中配置分页插件

 /**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}


4.2 分页Controller方法

接口文档数据

EbsTeacherController中添加分页方法

 @ApiOperation(value = "分页讲师列表")
@GetMapping("{page}/{limit}")
public Result pageList(
@ApiParam(name = "page", value = "当前页码", required = true)
@PathVariable Long page,

@ApiParam(name = "limit", value = "每页记录数", required = true)
@PathVariable Long limit){
//创建分页提交对象
Page<EbsTeacher> pageParam = new Page<>(page, limit);
//执行分页
ebsTeacherService.page(pageParam, null);
//获取分页结果
List<EbsTeacher> records = pageParam.getRecords();

long total = pageParam.getTotal();

return Result.ok().data("total", total).data("rows", records);
}



4.3 Swagger中测试

4.4 条件查询

根据讲师名称name,讲师头衔level、讲师入驻时间gmt_create(时间段)查询

4.4.1 创建查询对象

创建com.yxzx.ebs.teacher.entity.query包,创建TeacherQuery.java查询对象

 

@ApiModel(value = "EbsTeacher查询对象", description = "讲师查询对象封装")
@Data
public class EbsTeacherQuery implements Serializable {

private static final long serialVersionUID = 1L;

@ApiModelProperty(value = "教师名称,模糊查询")
private String name;

@ApiModelProperty(value = "头衔 1高级讲师 2首席讲师")
private Integer level;

@ApiModelProperty(value = "查询开始时间", example = "2019-01-01 10:10:10")
private String begin;//注意,这里使用的是String类型,前端传过来的数据无需进行类型转换

@ApiModelProperty(value = "查询结束时间", example = "2019-12-01 10:10:10")
private String end;
}


4.4.2 service

接口EbsTeacherService

public interface EbsTeacherService extends IService<EbsTeacher> {

/**
* 根据多个条件查询讲师列表
* @param pageParam
* @param teacherQuery
*/
void pageQuery(Page<EbsTeacher> pageParam, EbsTeacherQuery teacherQuery);

}






实现EbsTeacherServiceImpl

/**
* 根据多个条件查询讲师列表
*
* @param pageParam
* @param teacherQuery
*/
@Override
public void pageQuery(Page<EbsTeacher> pageParam, EbsTeacherQuery teacherQuery) {
QueryWrapper<EbsTeacher> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByAsc("sort");

if (teacherQuery == null){
baseMapper.selectPage(pageParam, queryWrapper);
return;
}

String name = teacherQuery.getName();
Integer level = teacherQuery.getLevel();
String begin = teacherQuery.getBegin();
String end = teacherQuery.getEnd();

if (!StringUtils.isEmpty(name)) {
queryWrapper.like("name", name);
}

if (!StringUtils.isEmpty(level) ) {
queryWrapper.eq("level", level);
}

if (!StringUtils.isEmpty(begin)) {
queryWrapper.ge("gmt_create", begin);
}

if (!StringUtils.isEmpty(end)) {
queryWrapper.le("gmt_create", end);
}

baseMapper.selectPage(pageParam, queryWrapper);
}


 


4.4.3 controller

EbsTeacherController中修改 pageList方法:

增加参数EbsTeacherQuery ebsTeacherQuery,非必选

@ApiOperation(value = "分页讲师列表")
@GetMapping("{page}/{limit}")
public Result pageList(
@ApiParam(name = "page", value = "当前页码", required = true)
@PathVariable Long page,

@ApiParam(name = "limit", value = "每页记录数", required = true)
@PathVariable Long limit,
@ApiParam(name = "teacherQuery", value = "查询对象", required = false)
EbsTeacherQuery ebsTeacherQuery){
//创建分页提交对象
Page<EbsTeacher> pageParam = new Page<>(page, limit);
//执行分页
ebsTeacherService.pageQuery(pageParam, ebsTeacherQuery);
//获取分页结果
List<EbsTeacher> records = pageParam.getRecords();

long total = pageParam.getTotal();

return Result.ok().data("total", total).data("rows", records);
}


4.4.4 Swagger中测试

5、 讲师新增和修改

5.1 新增

在Controller中编写代码

@ApiOperation(value = "新增讲师")
@PostMapping
public Result save(
@ApiParam(name = "teacher", value = "讲师对象", required = true)
@RequestBody EbsTeacher teacher){

ebsTeacherService.save(teacher);
return Result.ok();
}



5.2 根据id查询


@ApiOperation(value = "根据ID查询讲师")
@GetMapping("{id}")
public Result getById(
@ApiParam(name = "id", value = "讲师ID", required = true)
@PathVariable String id){

EbsTeacher teacher = ebsTeacherService.getById(id);
return Result.ok().data("item", teacher);
}


5.3 根据id修改

@ApiOperation(value = "根据ID修改讲师")
@PutMapping("{id}")
public Result updateById(
@ApiParam(name = "id", value = "讲师ID", required = true)
@PathVariable String id,

@ApiParam(name = "teacher", value = "讲师对象", required = true)
@RequestBody EbsTeacher teacher){

ebsTeacherService.updateById(teacher);
return Result.ok();
}



6、 统一异常处理

6.1 测试系统对错误的响应

例如输入两个不合法的分页参数


6.2 测试

查看结果


6.3 全局异常处理

我们想让异常结果也统一,并且在集中的地方处理系统的异常信息,那么需要统一异常处理

yxzx_teacher中创建统一异常处理类:

package com.yxzx.ebs.teacher.handler;

import com.yxzx.ebs.common.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;



/**
* 统一异常处理类
*/
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public Result error(Exception e){
e.printStackTrace();
return Result.error().message("执行出现了异常");
}

}



返回统一错误结果

注解说明:

@ControllerAdvice ,很多初学者可能都没有听说过这个注解,实际上,这是一个非常有用的注解,顾名思义,这是一个增强的 Controller。使用这个 Controller ,可以实现三个方面的功能:

全局异常处理

全局数据绑定

全局数据预处理

灵活使用这三个功能,可以帮助我们简化很多工作,需要注意的是,这是 SpringMVC 提供的功能,在 Spring Boot 中可以直接使用.

@ExceptionHandler 注解用来指明异常的处理类型,即如果这里指定为NullpointerException,则数组越界异常就不会进到这个方法中来。


6.4 特定异常配置

 如果是SQL语句的问题;那么需要配置捕获SQL语句的异常:

6.4.1 定义状态码

yxzx_common中添加

package com.yxzx.ebs.common.Exception;

public interface ResultCode {

int SUCCESS=20000;//成功
int ERROR=20001;//统一异常
int SQL_ERROR = 20006;//sql错误

}

 

6.4.2 在Handler中配置捕获指定SQL异常

/**
* 统一异常处理类
*/
@ControllerAdvice
public class GlobalExceptionHandler {

/**
* 统一异常处理器
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Result error(Exception e){
e.printStackTrace();
return Result.error().message("执行出现了异常");
}

/**
* 特定异常处理器
* @param e
* @return
*/
@ExceptionHandler(MySQLSyntaxErrorException.class)
@ResponseBody
public Result error(MySQLSyntaxErrorException e){
e.printStackTrace();

return Result.error().code(ResultCode.SQL_ERROR).message("SQL语法错误");
}

}


6.5 自定义异常

6.5.1 EbsException通用异常类

 在yxzx_common中创建Exception的异常类

注意:需要在ebs启动类添加注解

@SpringBootApplication(scanBasePackages = {"com.yxzx"})

package com.yxzx.ebs.common.Exception;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* 自定义异常处理类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "全局异常")
public class EbsException extends RuntimeException {

@ApiModelProperty(value = "状态码")
private Integer code;
@ApiModelProperty(value = "异常消息")
private String msg;

}



6.5.2 创建捕获自定义异常类

package com.yxzx.ebs.common.Exception;
import com.yxzx.ebs.common.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
*自定义异常捕捉类
*/
@ControllerAdvice
public class GlobalExceptionHandler {


@ExceptionHandler(EbsException.class)
@ResponseBody
public Result error(EbsException e){
e.printStackTrace();
return Result.error().code(e.getCode()).message(e.getMsg());
}

}



6.5.3 测试

在业务中需要的位置抛出EbsException,举例子在查询列表中出错:

@ApiOperation(value = "所有讲师列表")
@GetMapping
private Result getTeacherList(){
//测试自定义异常
try {
int i=1/0;
}catch (Exception e){
throw new EbsException(ResultCode.ERROR,"除零错误!");
}
List<EbsTeacher> list = ebsTeacherService.list(null);
return Result.ok().data("list",list);
}


7、 日志

7.1 配置日志级别

日志记录器(Logger)的行为是分等级的。如下表所示:

分为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL

DEBUG:输出调试信息;指出细粒度信息事件对调试应用程序是非常有帮助的。

INFO: 输出提示信息;消息在粗粒度级别上突出强调应用程序的运行过程。

WARN: 输出警告信息;表明会出现潜在错误的情形。

ERROR:输出错误信息;指出虽然发生错误事件,但仍然不影响系统的继续运行。

FATAL: 输出致命错误;指出每个严重的错误事件将会导致应用程序的退出。

ALL level:打开所有日志记录开关;是最低等级的,用于打开所有日志记录。

OFF level:关闭所有日志记录开关;是最高等级的,用于关闭所有日志记录。

默认情况下,spring boot从控制台打印出来的日志级别只有INFO及以上级别,可以配置日志级别

# 设置日志级别

logging.level.root=WARN

这种方式只能将日志打印在控制台上

7.2 Logback日志

spring boot内部使用Logback作为日志实现的框架。

Logback和log4j非常相似,如果你对log4j很熟悉,那对logback很快就会得心应手。


7.2.1 配置logback日志

删除application.properties中的日志配置

安装idea彩色日志插件:grep-console

resources 中创建 logback-spring.xml 

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->

<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值是变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
<property name="log.path" value="D:/yxzx_log/eds" />

<!-- 彩色日志 -->
<!-- 配置格式变量:CONSOLE_LOG_PATTERN 彩色日志格式 -->
<!-- magenta:洋红 -->
<!-- boldMagenta:粗红-->
<!-- cyan:青色 -->
<!-- white:白色 -->
<!-- magenta:洋红 -->
<property name="CONSOLE_LOG_PATTERN"
value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>


<!--输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<!-- 例如:如果此处配置了INFO级别,则后面其他位置即使配置了DEBUG级别的日志,也不会被输出 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>


<!--输出到文件-->

<!-- 时间滚动输出 level为 INFO 日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_info.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<!-- 时间滚动输出 level为 WARN 日志 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_warn.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>


<!-- 时间滚动输出 level为 ERROR 日志 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_error.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<!--
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。
<logger>仅有一个name属性,
一个可选的level和一个可选的addtivity属性。
name:用来指定受此logger约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
如果未设置此属性,那么当前logger将会继承上级的级别。
-->
<!--
使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
第一种把<root level="INFO">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
第二种就是单独给mapper下目录配置DEBUG模式,代码如下,这样配置sql语句会打印,其他还是正常DEBUG级别:
-->
<!--开发环境:打印控制台-->
<springProfile name="dev">
<!--可以输出项目中的debug日志,包括mybatis的sql日志-->
<logger name="com.guli" level="INFO" />

<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,默认是DEBUG
可以包含零个或多个appender元素。
-->
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
</springProfile>


<!--生产环境:输出到文件-->
<springProfile name="pro">

<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
<appender-ref ref="WARN_FILE" />
</root>
</springProfile>

</configuration>


 


7.3 将错误日志输出到文件

GlobalExceptionHandler.java 中

类上添加注解

@Slf4j

异常输出语句

 

log.error(e.getMessage());

7.4 将日志堆栈信息输出到文件

7.4.1 定义工具类

Yxzx_common下创建util包,创建ExceptionUtil.java工具类

 package com.yxzx.ebs.common;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

public class ExceptionUtil {

public static String getMessage(Exception e) {
StringWriter sw = null;
PrintWriter pw = null;
try {
sw = new StringWriter();
pw = new PrintWriter(sw);
// 将出错的栈信息输出到printWriter
e.printStackTrace(pw);
pw.flush();
sw.flush();
} finally {
if (sw != null) {
try {
sw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (pw != null) {
pw.close();
}
}
return sw.toString();
}

}




7.4.2 调用

在全局异常处理类GlobalExceptionHandler中调用


@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

.....

/**
* 自定义异常处理器
* @param e
* @return
*/
@ExceptionHandler(EbsException.class)
@ResponseBody
public Result error(EbsException e){
e.printStackTrace();

log.error(ExceptionUtil.getMessage(e));
return Result.error().code(e.getCode()).message(e.getMsg());
}

}


 

7.4.3 修改EduException类中

EbsException中创建toString方法

@Override
public String toString() {
return "EduException{" +
"message=" + this.getMsg() +
", code=" + code +
"}";
}

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。