Lecturer management module of grain College (back end) | swagger | unified log | unified return result

Posted by mattd8752 on Wed, 09 Feb 2022 19:28:16 +0100

1, Instructor query function

1. Write query controller code content

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

    @Autowired
    private EduTeacherService eduTeacherService;

    // Instructor query all data list
    // Use restful style
    @GetMapping("findAll")
    public List<EduTeacher> findAll(){
        List<EduTeacher> list = eduTeacherService.list(null);
        return list;
    }  
}

2. Create configuration classes, configure mapper scanning and other

@Configuration
@MapperScan("com.kuang.eduservice.mapper")
public class EduConfig {
}

3. Configure SQL execution performance analysis plug-in

/**
     * SQL Execute performance analysis plug-in
     * It is not recommended to use the development environment online. maxTime refers to the maximum execution time of sql
     */
@Bean
@Profile({"dev","test"})// Set dev test environment on
public PerformanceInterceptor performanceInterceptor() {
    PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
    performanceInterceptor.setMaxTime(1000);//ms, beyond the ms set here, sql will not be executed
    performanceInterceptor.setFormat(true);
    return performanceInterceptor;
}

4. Create main startup class

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

5. Test start

visit: http://localhost:8001/eduservice/teacher/findAll

6. Unify the returned json time format

By default, json time format has time zone and is world standard time, which is eight hours away from our time

In application Set in YML:

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8

2, Instructor logical deletion function

1. Configure logical deletion plug-in

 //Logical delete component
@Bean
public ISqlInjector sqlInjector(){
   return new LogicSqlInjector();
}

2. Add a comment on the logical deletion attribute

@TableLogic
private Boolean isDeleted;

3. Write Controller deletion method

//Logical deletion method
@DeleteMapping("removeById/{id}")
public boolean removeById(@PathVariable String id){
    boolean flag = eduTeacherService.removeById(id);
    return flag;
}

4. How to test

Test with some tools

  • swagger testing (emphasis): generate online interface documents to facilitate interface testing.
  • postman (understand)

3, Configure Swagger2

1. Create a common module - in Guli_ Create common under Parent

2. Introduce related dependencies

<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 Used to simplify entity classes: need to install lombok plug-in unit-->
    <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 integrate redis what is needed common-pool2
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.0</version>
        </dependency>-->
</dependencies>

3. Create configuration class for swagger

Create a sub module service under common_ Base, and create the configuration class of swagger in this module

@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/.*")))
                .paths(Predicates.not(PathSelectors.regex("/error.*")))
                .build();

    }

    private ApiInfo webApiInfo(){

        return new ApiInfoBuilder()
                .title("website-Course Center API file")
                .description("This document describes the definition of course center microservice interface")
                .version("1.0")
                .contact(new Contact("lxy", "www.baidu.com", "2422737092@qq.com"))
                .build();
    }
}

4. Specific use of Swagger2

  • In service_edu import service_base dependency
  • Finally, in the service_ Add annotation on edu startup class and set package scanning rules

  • Access test: http://localhost:8001/swagger-ui.html

5. Define interface description and parameter description

  • Defined on class: @ Api
  • Defined on method: @ ApiOperation
  • Defined on parameters: @ ApiParam
@Api(description = "Instructor management")
@RestController
@RequestMapping("/eduservice/teacher")
public class EduTeacherController {

    @Autowired
    private EduTeacherService eduTeacherService;

    // Query all data in instructor list
    // Use restful style
    @ApiOperation(value = "List of all instructors")
    @GetMapping("findAll")
    public List<EduTeacher> findAll(){
        List<EduTeacher> list = eduTeacherService.list(null);
        return list;
    }

    //Logical deletion method
    @ApiOperation(value = "Delete instructor logically")
    @DeleteMapping("{id}")
    public boolean removeById(
            @ApiParam(name = "id", value = "lecturer ID",required = true)
            @PathVariable String id){
        boolean flag = eduTeacherService.removeById(id);
        return flag;
    }
}

4, Unified return result object

1. Unified return data format

In the project, we will encapsulate the response into json return. Generally, we will unify the data format of all interfaces to make the data operation of the front end (IOS, Android, web) more consistent and easy.

Generally, the unified return data format has no fixed format, as long as it can clearly describe the returned data status and the specific data to be returned. However, it usually includes status code, return message and data

For example, the basic data format required by our system is as follows:

  • Data carried successfully
{
  "success": true,
  "code": 20000,
  "message": "success",
  "data": {
    "items": [
      {
        "id": "1",
        "name": "Lau Andy",
        "intro": "Graduated from the Mathematics Department of Normal University, he loves education and has taught mathematical thinking for more than 6 years"
      }
    ]
  }
}

  • Data carried successfully (paging)
{
  "success": true,
  "code": 20000,
  "message": "success",
  "data": {
    "total": 17,
    "rows": [
      {
        "id": "1",
        "name": "Lau Andy",
        "intro": "Graduated from the Mathematics Department of Normal University, he loves education and has taught mathematical thinking for more than 6 years"
      }
    ]
  }
}

  • No data returned successfully
{
  "success": true,
  "code": 20000,
  "message": "success",
  "data": {}
}
  • No return data failed
{
  "success": false,
  "code": 20001,
  "message": "fail",
  "data": {}
}
  • Therefore, we unify the results
{
  "success": Boolean, //Is the response successful
  "code": number, //Response code
  "message": character string, //Return message
  "data": HashMap //Return data in key value pairs
}

2. Unified result return class

  • Create sub module common under common module_ utils

  • Create interface definition return code - create package com rg. Commonutils, create interface ResultCode

public interface ResultCode {
    public static Integer SUCCESS = 20000;//success
    public static Integer ERROR = 20001;//fail
}
  • Create result class - create R class
@Data
public class R {

    @ApiModelProperty(value = "Is it successful")
    private Boolean success;

    @ApiModelProperty(value = "Return code")
    private Integer code;

    @ApiModelProperty(value = "Return message")
    private String message;

    @ApiModelProperty(value = "Return data")
    private Map <String, Object> data = new HashMap <String, Object>();

    private R(){}  //Privatization of construction methods Purpose: it is forbidden to use the new method arbitrarily, and only the method we define can be used

    public static R ok(){//Define success method
        R r = new R();
        r.setSuccess(true);
        r.setCode(ResultCode.SUCCESS);
        r.setMessage("success");
        return r;//For chain programming
    }

    public static R error(){//Define failed method
        R r = new R();
        r.setSuccess(false);
        r.setCode(ResultCode.ERROR);
        r.setMessage("fail");
        return r;//For chain programming
    }

    //Related methods of custom attributes (with chain programming function)
    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;
    }

}

3. Unified use of returned results

  • Add dependency - common in the service module_ utils

  • Modify the returned results in the Controller

//1. Query all data of lecturer and use Rest style
@ApiOperation("List of all instructors")
@GetMapping("findAll")
public List <EduTeacher> findAll() {
    List <EduTeacher> eduTeacherList = eduTeacherService.list(null);
    return eduTeacherList;
}

//2. Delete instructor logically through id
@ApiOperation("according to ID Delete instructor")
@DeleteMapping("removeById/{id}")
public R removeById(@ApiParam(name = "id", value = "lecturer ID", required = true) @PathVariable String id) {
    boolean flag = eduTeacherService.removeById(id);
    if (flag) {
        return R.ok();
    } else {
        return R.error();
    }
}

5, Instructor paging query

1. Configuring paging plug-in in EduConfig

/**
     * Paging plug-in
     */
@Bean
public PaginationInterceptor paginationInterceptor(){
    return new PaginationInterceptor();
}

2. Add paging method in EduTeacherController

//3. Query lecturers by page
@ApiOperation("Paging query instructor")
@GetMapping("pageList/{current}/{limit}")
public R pageList(@ApiParam(name = "current", value = "Current page number", required = true)
                  @PathVariable("current") Integer current,
                  @ApiParam(name = "limit", value = "Records per page", required = true)
                  @PathVariable("limit") Integer limit) {
    Page <EduTeacher> page = new Page <>(current, limit);

    //Paging query
    eduTeacherService.page(page, null);//Finally, these attributes can be obtained through page or iPage, because the paged data will be re encapsulated into these objects

    // Map <String, Object> map = new HashMap <>();
    // map.put("total",page.getTotal());
    // map.put("rows", page.getRecords());
    // return R.ok().data(map);

    return R.ok().data("total", page.getTotal()).data("rows", page.getRecords());
}

6, Instructor condition query with pagination

Requirements: query according to lecturer name, lecturer Title level and lecturer residence time

1. Create query object

Create com rg. eduservice. entiy. VO package, create TeacherQuery class query object

@ApiModel(value = "Teacher Query object",description = "Instructor query object encapsulation")
@Data
public class TeacherQuery implements Serializable {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "Teacher name,Fuzzy query")
    private String name;

    @ApiModelProperty(value = "Title 1 senior lecturer 2 chief lecturer")
    private Integer level;

    @ApiModelProperty(value = "Query start time", example = "2019-01-01 10:10:10")
    private String begin;

    @ApiModelProperty(value = "Query end time", example = "2019-12-01 10:10:10")
    private String end;
}

2. Write controller

//4. Query lecturers according to conditions
@ApiOperation("Query lecturers by criteria")
@PostMapping("pageQuery/{current}/{limit}") //@RequestBody: pass data through json and encapsulate the data into objects json data can only be encapsulated in the request body, so POST requests are needed
public R pageQuery(@ApiParam(name = "current", value = "Current page number", required = true)
                   @PathVariable("current") Integer current,
                   @ApiParam(name = "limit", value = "Records per page", required = true)
                   @PathVariable("limit") Integer limit,
                   @ApiParam(name = "teacherQuery",value = "query criteria",required = false) @RequestBody(required = false) TeacherQuery teacherQuery){//required = false, indicating that the condition is optional
    Page <EduTeacher> page = new Page <>(current, limit);
    //Construction conditions
    QueryWrapper <EduTeacher> wrapper = new QueryWrapper <>();
    String name = teacherQuery.getName();
    Integer level = teacherQuery.getLevel();
    String begin = teacherQuery.getBegin();
    String end = teacherQuery.getEnd();
    //We have learned dynamic sql in mybatis. Here we can use MP to simplify operations
    if(!StringUtils.isEmpty(name)){
        wrapper.like("name", name);
    }
    if(!StringUtils.isEmpty(level)){
        wrapper.eq("level", level);
    }
    if(!StringUtils.isEmpty(begin)){
        wrapper.ge("gmt_create", begin);
    }
    if(!StringUtils.isEmpty(end)){
        wrapper.le("gmt_modified", end);
    }

    eduTeacherService.page(page, wrapper);//Paging query
    return R.ok().data("total", page.getTotal()).data("rows", page.getRecords());
}

7, Auto fill package

1. Create autofill class in service base

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        //The property name is set here, not the field name
        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. Add auto fill annotation to entity class

8, Instructor add function

1. Add auto fill annotation to entity class

2. New method in eduteachercontroller

//5. Add lecturer
@ApiOperation("Add lecturer")
@PostMapping("addTeacher")
public R addTeacher(@ApiParam(value = "eduTeacher",name = "Instructor information") @RequestBody EduTeacher eduTeacher){
    boolean flag = eduTeacherService.save(eduTeacher);
    if (flag){
        return R.ok();
    }else{
        return R.error();
    }
}

3. Test in swagger

9, Instructor modification function

1. New method in eduteachercontroller

//6. Query according to instructor Id -- > Data echo function
@GetMapping("getById/{id}")
@ApiOperation("according to id Query lecturer")
public R getById(@ApiParam(name = "id",value = "lecturer ID",required = true) @PathVariable String id){
    EduTeacher eduTeacher = eduTeacherService.getById(id);
    return R.ok().data("teacher", eduTeacher);
}

//7. Instructor modification function
@ApiOperation("Modify instructor")
@PutMapping("updateById")
public R updateById(@ApiParam(name = "eduTeacher",value = "Instructor information",required = true) @RequestBody EduTeacher eduTeacher){
    boolean flag = eduTeacherService.updateById(eduTeacher);
    if(flag){
        return R.ok();
    }else{
        return R.error();
    }
}

10, Unified exception handling

1. Manufacturing abnormality

int a = 10/0;

2. Unified exception handling

  • Create a unified exception handling class globalexceptionhandler in service base java:
@ControllerAdvice
public class GlobalExceptionHandler {

    //Unified exception handling
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public R error(Exception e){
        e.printStackTrace();
        return R.error();
    }
}
  • Swagger test

3. Handling specific exceptions

  • Added in GlobalExceptionHandler
//Handling specific exceptions
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public R error(ArithmeticException e){
    e.printStackTrace();
    return R.error().message("Custom exception executed");
}
  • Swagger

4. Custom exception

  • Create custom exception class
@Data
@AllArgsConstructor
@NoArgsConstructor
public class GuLiException extends RuntimeException{
    private Integer code;//Status code
    private String msg;//Abnormal information
}
  • Add exception handling method
@ExceptionHandler(GuliException.class)
@ResponseBody
public R error(GuliException e){
    e.printStackTrace();
    return R.error().message(e.getMsg()).code(e.getCode());
}
  • GuliException is thrown at the required position in the business
try {
    int i = 10 / 0;
} catch (Exception e) {
    throw new GuLiException(200001, "Custom exception occurred");
}
  • Swagger test

11, Unified log processing

1. Configure log level

The behavior of the Logger is hierarchical. As shown in the following table:

It is divided into: OFF, FATAL, ERROR, WARN, INFO, DEBUG and ALL

By default, the log level printed by spring boot from the console is only INFO or above. You can configure the log level

# Set log level
logging.level.root=WARN

2. Logback log

spring boot uses Logback internally as the framework for log implementation.

Logback is very similar to log4j. If you are familiar with log4j, you will be handy with logback soon.

Some advantages of logback over log4j: https://blog.csdn.net/caisini_vc/article/details/48551287

1. Configure logback log

Delete application Log configuration in properties

# mybatis log
#mybatis-plus:
#  configuration:
#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

#logging:
#  level: debug

Install idea color log plug-in: grep console

Create logback spring in resources xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration  scan="true" scanPeriod="10 seconds">
    <!-- The log level is from low to high TRACE < DEBUG < INFO < WARN < ERROR < FATAL,If set to WARN,Lower than WARN No information will be output -->
    <!-- scan:When this property is set to true If the configuration file changes, it will be reloaded. The default value is true -->
    <!-- scanPeriod:Set the time interval for monitoring whether the configuration file is modified. If no time unit is given, the default unit is milliseconds. When scan by true This property takes effect when. The default interval is 1 minute. -->
    <!-- debug:When this property is set to true When, it will be printed out logback Internal log information, real-time viewing logback Operation status. The default value is false.  -->

    <contextName>logback</contextName>
    <!-- name The value of is the name of the variable, value The value defined by the variable. Values defined by are inserted into the logger In context. After the variable is defined, you can“ ${}"To use variables. -->
    <property name="log.path" value="D:/guli_log/edu" />

    <!-- Color log -->
    <!-- Configure format variables: CONSOLE_LOG_PATTERN Color log format -->
    <!-- magenta:Magenta -->
    <!-- boldMagenta:Coarse red-->
    <!-- cyan:Cyan -->
    <!-- white:white -->
    <!-- magenta: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)"/>


    <!--Output to console-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--This log appender It is used for development. Only the lowest level is configured. The log level output from the console is log information greater than or equal to this level-->
        <!-- For example, if you configure INFO Level, even if other locations are configured DEBUG Level logs will not be output -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- Set character set -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>


    <!--output to a file-->

    <!-- Time scrolling output level by INFO journal -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- The path and file name of the log file being recorded -->
        <file>${log.path}/log_info.log</file>
        <!--Log file output format-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- The rolling strategy of the logger is to record by date and by size -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- Daily log archive path and format -->
            <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>
            <!--Log file retention days-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- This log file only records info Rank -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- Time scrolling output level by WARN journal -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- The path and file name of the log file being recorded -->
        <file>${log.path}/log_warn.log</file>
        <!--Log file output format-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- Character set here -->
        </encoder>
        <!-- The rolling strategy of the logger is to record by date and by size -->
        <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>
            <!--Log file retention days-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- This log file only records warn Rank -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <!-- Time scrolling output level by ERROR journal -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- The path and file name of the log file being recorded -->
        <file>${log.path}/log_error.log</file>
        <!--Log file output format-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- Set character set here -->
        </encoder>
        <!-- The rolling strategy of the logger is to record by date and by size -->
        <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>
            <!--Log file retention days-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- This log file only records ERROR Rank -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--
        <logger>Used to set the log printing level of a package or a specific class, and specify<appender>. 
        <logger>Only one name Properties,
        An optional level And an optional addtivity Properties.
        name:Used to specify that this logger A package or a specific class of constraints.
        level:Used to set the printing level, regardless of case: TRACE, DEBUG, INFO, WARN, ERROR, ALL and OFF,
              If this property is not set, the current logger Will inherit the level of the superior.
    -->
    <!--
        use mybatis When I was young, sql Statement is debug It will not be printed until next, and here we only configure it info,So I want to see sql Statement, there are two operations:
        First handle<root level="INFO">Change to<root level="DEBUG">This will print sql,But there will be a lot of other messages in the log
        The second is to give it alone mapper Directory configuration under DEBUG Mode, the code is as follows, which is configured in this way sql The statement will print, and others are normal DEBUG Level:
     -->
    <!--development environment :Print Console -->
    <springProfile name="dev">
        <!--You can output data in a project debug Logs, including mybatis of sql journal-->
        <logger name="com.guli" level="INFO" />

        <!--
            root Node is a required node. It is used to specify the most basic log output level. There is only one node level attribute
            level:Used to set the printing level, regardless of case: TRACE, DEBUG, INFO, WARN, ERROR, ALL and OFF,Default is DEBUG
            Can contain zero or more appender Element.
        -->
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
        </root>
    </springProfile>


    <!--production environment :output to a file-->
    <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>

2. Output the error log to a file

GlobalExceptionHandler. Add annotations to Java classes

 @Slf4j

Add exception output statement in exception handling class:

3. Output log stack information to file

The above operations can only output the first line of error information to the file. If all information is required, the following operations are required

  • Define tool classes

Create util package under Guli framework common and create exceptionutil Java tool class

public class ExceptionUtil {

	public static String getMessage(Exception e) {
		StringWriter sw = null;
		PrintWriter pw = null;
		try {
			sw = new StringWriter();
			pw = new PrintWriter(sw);
			// Output the wrong stack information to 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();
	}
}
  • call
log.error(ExceptionUtil.getMessage(e));
  • Add toString method to GuliException

ingProfile>

```

2. Output the error log to a file

GlobalExceptionHandler. Add annotations to Java classes

 @Slf4j

Add exception output statement in exception handling class:

3. Output log stack information to file

The above operations can only output the first line of error information to the file. If all information is required, the following operations are required

  • Define tool classes

Create util package under Guli framework common and create exceptionutil Java tool class

public class ExceptionUtil {

	public static String getMessage(Exception e) {
		StringWriter sw = null;
		PrintWriter pw = null;
		try {
			sw = new StringWriter();
			pw = new PrintWriter(sw);
			// Output the wrong stack information to 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();
	}
}
  • call
log.error(ExceptionUtil.getMessage(e));
  • Add toString method to GuliException

Topics: JavaEE Microservices