谷粒学苑 —— 2、讲师管理接口开发

目录

1、讲师管理模块配置和生成代码

1.1、配置 application.properties

1.2、创建 MP 代码生成器

2、编写后台管理 api 接口

2.1、编写启动类

2.2、获取所有讲师信息

2.3、编写配置类

2.4、统一返回的 JSON 时间格式

2.5、讲师逻辑删除

2.5.1、配置逻辑删除插件

2.5.2、在对应属性添加 @TableLogic 注解

2.5.3、Controller 方法

3、整合 Swagger

3.1、Swagger2 介绍

3.2、配置 Swagger2

3.2.1、创建 common 模块

3.2.2、在 common 下面创建子模块 service-base

3.2.3、在模块 service-base 中,创建 swagger 的配置类

3.2.4、在模块 service 模块中引入s ervice-base

3.2.5、设置扫描 Swagger 配置类

3.2.6、测试

3.2.7、API 模型

3.2.8、定义接口说明和参数说明

4、统一返回数据格式

4.1、介绍

4.2、创建统一返回结果类

4.2.1、在 common 模块下创建子模块 common_utils

4.2.2、创建接口定义返回码

4.2.3、创建结果类

4.2.4、使用统一返回结果

5、讲师分页功能

5.1、配置分页插件

5.2、Controller 方法

6、带条件分页查询

6.1、创建查询对象的 VO 实体类

6.2、Controller 方法

7、新增讲师

7.1、在实体类添加自动填充注解

7.2、创建自动填充类

7.3、Controller 方法

8、讲师修改

8.1、根据 ID 查询讲师

8.2、根据 ID 修改讲师

9、统一异常处理

9.1、创建统一异常处理器

9.2、处理特定异常

9.3、处理自定义异常

9.3.1、自定义异常类

9.3.2、自定义异常处理器

10、统一日志处理

10.1、配置日志级别

10.2、Logback 日志

10.2.1、配置 Logback 日志

10.2.2、将错误日志输出到文件

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


1、讲师管理模块配置和生成代码

1.1、配置 application.properties

在 service_edu 模块的 resources目录下创建文件 application.properties

# 服务端口
server.port=8001
# 服务名
spring.application.name=service-edu

# 环境设置:dev、test、prod
spring.profiles.active=dev

# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root

#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

1.2、创建 MP 代码生成器

在 test/java 目录下创建包 com.zyj.eduservice,从资料中导入代码生成器:CodeGenerator.java

要修改的地方:

gc.setOutputDir("D:..." + "/src/main/java"); // 建议使用绝对路径
gc.setIdType(IdType.ID_WORKER_STR); //主键策略
数据库连接(注意要加时区)

修改完后运行即可快速生成代码

生成后,在 Mapper 类上加上 @Mapper 注解

2、编写后台管理 api 接口

2.1、编写启动类

创建启动类 EduApplication.java

@SpringBootApplication
public class EduApplication {

    public static void main(String[] args) {
        SpringApplication.run(EduApplication.class, args);
    }

}

2.2、获取所有讲师信息

@RestController
@RequestMapping("/eduservice/teacher")
public class EduTeacherController {

    @Autowired
    private EduTeacherService eduTeacherService;

    /**
     * 获取所有讲师信息
     * @return
     */
    @GetMapping("/findAll")
    public List<EduTeacher> findAll(){
        List<EduTeacher> list = eduTeacherService.list(null);
        return list;
    }

}

2.3、编写配置类

在 eduservice 包下创建 config 包,创建 MyBatisPlusConfig.java

@Configuration
@EnableTransactionManagement
public class EduConfig {
}

2.4、统一返回的 JSON 时间格式

#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8

2.5、讲师逻辑删除

2.5.1、配置逻辑删除插件

mp 版本 ≥ 3.1.1,不需要配置逻辑删除插件,反之需要配置

在 EduConfig 类中添加即可

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

2.5.2、在对应属性添加 @TableLogic 注解

    @TableLogic
    @ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
    private Boolean isDeleted;

2.5.3、Controller 方法

    /**
     * 讲师逻辑删除
     * @param id
     * @return
     */
    @DeleteMapping("/{id}")
    public boolean removeTeacher(@PathVariable("id") String id){
        boolean flag = eduTeacherService.removeById(id);
        return flag;
    }

3、整合 Swagger

3.1、Swagger2 介绍

前后端分离开发模式中,api文档是最好的沟通方式。

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。

  1. 及时性 (接口变更后,能够及时准确地通知相关前后端开发人员)
  2. 规范性 (并且保证接口的规范性,如接口的地址,请求方式,参数及响应格式和错误信息)
  3. 一致性 (接口信息一致,不会出现因开发人员拿到的文档版本不一致,而出现分歧)
  4. 可测性 (直接在接口文档上进行测试,以方便理解业务)

3.2、配置 Swagger2

3.2.1、创建 common 模块

在 guli_parent 下创建 Maven 模块 common

修改 packaging 为 pom,然后引入依赖

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>provided </scope>
        </dependency>

        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <scope>provided </scope>
        </dependency>

        <!--lombok用来简化实体类:需要安装lombok插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided </scope>
        </dependency>

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

        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- spring2.X集成redis所需common-pool2
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.0</version>
        </dependency>-->
    </dependencies>

3.2.2、在 common 下面创建子模块 service-base

正常创建 Maven 模块即可

3.2.3、在模块 service-base 中,创建 swagger 的配置类

在 com.zyj.servicebase.config 下创建 SwaggerConfig 配置类

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket webApiConfig(){

        return new Docket(DocumentationType.SWAGGER_2)  // 类型
                .groupName("webApi")
                .apiInfo(webApiInfo())
                .select()
                .paths(Predicates.not(PathSelectors.regex("/admin/.*"))) // 包含admin的接口不显示
                .paths(Predicates.not(PathSelectors.regex("/error.*")))
                .build();

    }

    private ApiInfo webApiInfo(){

        return new ApiInfoBuilder()
                .title("网站-课程中心API文档")
                .description("本文档描述了课程中心微服务接口定义")
                .version("1.0")
                .contact(new Contact("Helen", "http://atguigu.com", "55317332@qq.com"))
                .build();
    }

}

3.2.4、在模块 service 模块中引入s ervice-base

在 service 模块的 pom.xml 引入

        <dependency>
            <groupId>com.zyj</groupId>
            <artifactId>service-base</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

3.2.5、设置扫描 Swagger 配置类

在service-edu启动类上添加注解 @ComponentScan 设置包扫描规则

@SpringBootApplication
@ComponentScan("com.zyj")
public class EduApplication{}

3.2.6、测试

启动服务,浏览器访问 http://localhost:8001/swagger-ui.html,出现如下界面

3.2.7、API 模型

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

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

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

3.2.8、定义接口说明和参数说明

定义在类上:@Api

定义在方法上:@ApiOperation

定义在参数上:@ApiParam

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

    @Autowired
    private EduTeacherService eduTeacherService;

    /**
     * 获取所有讲师信息
     * @return
     */
    @ApiOperation(value = "获取所有讲师信息")
    @GetMapping("/findAll")
    public List<EduTeacher> findAll(){
        List<EduTeacher> list = eduTeacherService.list(null);
        return list;
    }

    /**
     * 讲师逻辑删除
     * @param id
     * @return
     */
    @ApiOperation(value = "根据ID逻辑删除讲师")
    @DeleteMapping("/{id}")
    public boolean removeTeacher(@ApiParam(name = "id", value = "讲师ID", required = true) @PathVariable("id") String id){
        boolean flag = eduTeacherService.removeById(id);
        return flag;
    }

}

4、统一返回数据格式

4.1、介绍

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

一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。但是一般会包含状态码、返回消息、数据这几部分内容,例如,我们的系统要求返回的基本数据格式如下:

{
  "success": 布尔, //响应是否成功
  "code": 数字, //响应码
  "message": 字符串, //返回消息
  "data": HashMap //返回数据,放在键值对中
}

4.2、创建统一返回结果类

4.2.1、在 common 模块下创建子模块 common_utils

在 common 模块下创建正常 Maven 模块即可

4.2.2、创建接口定义返回码

在 common_utils 下创建包 com.zyj.commonutils,创建接口 ResultCode.java

public interface ResultCode {

    public static Integer SUCCESS = 20000;

    public static Integer ERROR = 20001;
    
}

4.2.3、创建结果类

在 com.zyj.commonutils 下创建类 R.java

@Data
public class R {
    @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 R(){}

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

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

    public R success(Boolean success){
        this.setSuccess(success);
        return this;
    }

    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;
    }
}

4.2.4、使用统一返回结果

① 在 service 模块添加依赖

        <dependency>
            <groupId>com.zyj</groupId>
            <artifactId>common_utils</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

② 修改 Controller 方法的返回对象都是 R

    /**
     * 获取所有讲师信息
     * @return
     */
    @ApiOperation(value = "获取所有讲师信息")
    @GetMapping("/findAll")
    public R findAll(){
        List<EduTeacher> list = eduTeacherService.list(null);
        return R.ok().data("items", list);
    }

    /**
     * 讲师逻辑删除
     * @param id
     * @return
     */
    @ApiOperation(value = "根据ID逻辑删除讲师")
    @DeleteMapping("/{id}")
    public R removeTeacher(@ApiParam(name = "id", value = "讲师ID", required = true) @PathVariable("id") String id){
        boolean flag = eduTeacherService.removeById(id);
        if(flag) {
            return R.ok();
        } else {
            return R.error();
        }
    }

5、讲师分页功能

5.1、配置分页插件

在 EduConfig 配置分页插件

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

5.2、Controller 方法

    /**
     * 分页获取讲师信息
     * @param current 当前页码
     * @param limit 每页数据量
     * @return
     */
    @ApiOperation("分页获取讲师信息")
    @GetMapping("/pageTeacher/{current}/{limit}")
    public R pageListTeacher(
            @ApiParam(name = "current", value = "当前页码", required = true) @PathVariable("current") long current,
            @ApiParam(name = "limit", value = "每页数据量", required = true) @PathVariable("limit") long limit
    ){
        Page<EduTeacher> page = new Page<>(current, limit);
        eduTeacherService.page(page, null); // 调用后分页所有数据会封装到page对象中
        long total = page.getTotal();
        List<EduTeacher> records = page.getRecords();
        Map<String, Object> map = new HashMap();
        map.put("total", total);
        map.put("records", records);
        return R.ok().data(map);
    }

6、带条件分页查询

6.1、创建查询对象的 VO 实体类

在 entity 包下创建 VO 包,创建 TeacherQuery 类

@Data
public class TeacherQuery 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;

}

6.2、Controller 方法

    /**
     * 带条件分页获取讲师信息
     * @param current 当前页码
     * @param limit 每页记录数
     * @param teacherQuery 查询对象
     * @return
     */
    @ApiOperation("带条件分页获取讲师信息")
    @PostMapping("/pageTeacherCondition/{current}/{limit}")
    public R pageTeacherCondition(
            @ApiParam(name = "current", value = "当前页码", required = true) @PathVariable("current") long current,
            @ApiParam(name = "limit", value = "每页记录数", required = true) @PathVariable("limit") long limit,
            @ApiParam(name = "teacherQuery", value = "查询对象", required = false) @RequestBody(required = false) TeacherQuery teacherQuery
    ){
        Page<EduTeacher> page = new Page<>(current, limit);
        LambdaQueryWrapper<EduTeacher> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.like(!StringUtils.isEmpty(teacherQuery.getName()), EduTeacher::getName, teacherQuery.getName());
        queryWrapper.eq(!StringUtils.isEmpty(teacherQuery.getLevel()), EduTeacher::getLevel, teacherQuery.getLevel());
        queryWrapper.ge(!StringUtils.isEmpty(teacherQuery.getBegin()), EduTeacher::getGmtCreate, teacherQuery.getBegin());
        queryWrapper.le(!StringUtils.isEmpty(teacherQuery.getEnd()), EduTeacher::getGmtCreate, teacherQuery.getEnd());

        eduTeacherService.page(page, queryWrapper);

        long total = page.getTotal();
        List<EduTeacher> records = page.getRecords();
        Map<String, Object> map = new HashMap();
        map.put("total", total);
        map.put("records", records);
        return R.ok().data(map);
    }

7、新增讲师

7.1、在实体类添加自动填充注解

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

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

7.2、创建自动填充类

在 service_base 模块下创建 MyMetaObjectHandle 

这里后来测试在 updateFill 发现无法更新值,只好使用老方法

@Component
public class MyMetaObjectHandle implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        metaObject.setValue("gmtCreate", new Date());
        metaObject.setValue("gmtModified", new Date());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        /**
         * MetaObjectHandler提供的默认方法的策略均为: 如果属性有值则不覆盖, 如果填充值为null则不填充。
         * 也就是说,MP的自动填充功能的前提是填充字段要求为null。
         * 使用以下语句无法更新
         */
        //metaObject.setValue("gmtModified", new Date());
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }

}

7.3、Controller 方法

    /**
     * 新增讲师
     * @param eduTeacher 讲师对象
     * @return
     */
    @ApiOperation(value = "新增讲师")
    @PostMapping("/addTeacher")
    public R addTeacher(
        @ApiParam(name = "teacher", value = "讲师对象", required = true) @RequestBody EduTeacher eduTeacher
    ){
        boolean save = eduTeacherService.save(eduTeacher);
        if(save){
            return R.ok();
        } else {
            return R.error();
        }
    }

8、讲师修改

8.1、根据 ID 查询讲师

    /**
     * 根据ID查询讲师
     * @param id 讲师ID
     * @return
     */
    @ApiOperation(value = "根据ID查询讲师")
    @GetMapping("/getTeacher/{id}")
    public R getTeacher(
            @ApiParam(name = "id", value = "讲师ID", required = true) @PathVariable("id") String id,
    ){
        EduTeacher teacher = eduTeacherService.getById(id);
        return R.ok().data("teacher", teacher);
    }

8.2、根据 ID 修改讲师

    /**
     * 根据ID修改讲师
     * @param eduTeacher 讲师对象
     * @return
     */
    @ApiOperation(value = "根据ID修改讲师")
    @PutMapping("/{id}")
    public R updateById(
            @ApiParam(name = "teacher", value = "讲师对象", required = true) @RequestBody EduTeacher eduTeacher
    ) {
        boolean flag = eduTeacherService.updateById(eduTeacher);
        if(flag) {
            return R.ok();
        } else {
            return R.error();
        }
    }

9、统一异常处理

让异常结果也显示为统一的返回结果对象,并且统一处理系统的异常信息.

9.1、创建统一异常处理器

在 service_base 中创建统一异常处理类 GlobalExceptionHandler.java

@ControllerAdvice
public class GlobalExceptionHandle {

    /**
     * 全局异常处理器
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public R error(Exception e){
        e.printStackTrace();
        return R.error().message("全局异常处理:" + e.getMessage());
    }

}

9.2、处理特定异常

    /**
     * 特定异常处理器
     * @param e
     * @return
     */
    @ExceptionHandler(ArithmeticException.class)
    @ResponseBody
    public R error(ArithmeticException e){
        e.printStackTrace();
        return R.error().message("---" + e.getMessage());
    }

9.3、处理自定义异常

9.3.1、自定义异常类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class GuliException extends RuntimeException{

    private Integer code;

    private String msg;

}

9.3.2、自定义异常处理器

    /**
     * 自定义异常处理器
     * @param e
     * @return
     */
    @ExceptionHandler(GuliException.class)
    @ResponseBody
    public R error(GuliException e){
        e.printStackTrace();
        return R.error().code(e.getCode()).message(e.getMsg());
    }

10、统一日志处理

10.1、配置日志级别

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

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

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

# 设置日志级别
logging.level.root=WARN

10.2、Logback 日志

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

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

logback相对于log4j的一些优点:比log4j更好的logback、简介和优点详解_小雄哥的博客-CSDN博客

10.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:\\guli_log\\edu" />

    <!-- 彩色日志 -->
    <!-- 配置格式变量: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>

10.2.2、将错误日志输出到文件

在异常处理器的类上加注解 @Slf4j

然后在里面的方法要输出错误信息的位置加上

log.error(e.getMessage());

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

定义工具类,创建util包,创建 ExceptionUtil.java 工具类

package com.guli.common.util;

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();
	}
}

自定义异常类中创建toString方法 

输出调用

log.error(ExceptionUtil.getMessage(e));

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值