Development of online education lecturer management interface
01 - instructor management module configuration and generation code
1, Instructor management module configuration
1. Create a configuration file in the service edu module under service
Create the file application. In the resources directory properties
# Service port server.port=8001 # service name spring.application.name=service-edu # Environment settings: dev, test, prod spring.profiles.active=dev # mysql database connection spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=root #mybatis log mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
Or create the file application. In the resources directory yml
#### application.yml spring: application: name: service-edu profiles: active: dev #### application-dev.yml server: port: 8001 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl mapper-locations: classpath:com/atguigu/service/*/mapper/*.xml global-config: db-config: logic-delete-value: 1 logic-not-delete-value: 0 spring: datasource: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8 username: root password: root hikari: connection-test-query: SELECT 1 connection-timeout: 60000 idle-timeout: 500000 max-lifetime: 540000 maximum-pool-size: 12 minimum-idle: 10 pool-name: GuliHikariPool jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8
2. Create MP code generator
Create the package com. In the test/java directory atguigu. Eduservice, create a code generator: codegenerator java
public class getCode { @Test public void main1() { // 1. Create code generator AutoGenerator mpg = new AutoGenerator(); // 2. Global configuration GlobalConfig gc = new GlobalConfig(); String projectPath = System.getProperty("user.dir"); System.out.println(projectPath); gc.setOutputDir(projectPath + "/src/main/java"); gc.setAuthor("atguigu"); gc.setOpen(false); //Open Explorer after build gc.setFileOverride(false); //Whether the file is overwritten during regeneration /* * mp Generate service layer code. The first letter of the default interface name is I * UcenterService * */ gc.setServiceName("%sService"); //Remove the initial I of the Service interface gc.setIdType(IdType.ID_WORKER); //Primary key policy gc.setDateType(DateType.ONLY_DATE);//Defines the date type in the generated entity class gc.setSwagger2(true);//Turn on Swagger2 mode mpg.setGlobalConfig(gc); // 3. Data source configuration DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8"); dsc.setDriverName("com.mysql.cj.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("root"); dsc.setDbType(DbType.MYSQL); mpg.setDataSource(dsc); // 4. Package configuration PackageConfig pc = new PackageConfig(); pc.setModuleName("serviceedu"); //Module name pc.setParent("com.atguigu"); pc.setController("controller"); pc.setEntity("entity"); pc.setService("service"); pc.setMapper("mapper"); mpg.setPackageInfo(pc); // 5. Policy configuration StrategyConfig strategy = new StrategyConfig(); strategy.setInclude("edu_teacher"); strategy.setNaming(NamingStrategy.underline_to_camel);//Naming policy for mapping database tables to entities strategy.setTablePrefix(pc.getModuleName() + "_"); //Remove table prefix when generating entities strategy.setColumnNaming(NamingStrategy.underline_to_camel);//Naming policy for mapping database table fields to entities strategy.setEntityLombokModel(true); // lombok model @ accessories (chain = true) setter chain operation strategy.setRestControllerStyle(true); //restful api style controller strategy.setControllerMappingHyphenStyle(true); //Hump to hyphen in url mpg.setStrategy(strategy); // 6. Execute mpg.execute(); } }
2, Write background management api interface
1. Write controller code
@Autowired private TeacherService teacherService; @GetMapping public List<Teacher> list(){ return teacherService.list(null); }
2. Create SpringBoot configuration class
Create the config package under the edu package and create mybatisplusconfig java
package com.guli.edu.config; @Configuration @EnableTransactionManagement @MapperScan("com.atguigu.eduservice.mapper") public class MyBatisPlusConfig { }
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 sql execution time */ @Bean @Profile({"dev","test"})// Set dev test environment on public PerformanceInterceptor performanceInterceptor() { PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor(); performanceInterceptor.setMaxTime(1000);//ms. if the ms set here is exceeded, sql will not be executed performanceInterceptor.setFormat(true); return performanceInterceptor; }
4. Create a SpringBoot startup class
Create startup class eduapplication Java, pay attention to the creation location of the startup class
@SpringBootApplication public class EduApplication { public static void main(String[] args) { SpringApplication.run(EduApplication.class, args); } }
5. Run startup class
visit http://localhost:8001/eduservice/teacher
Get json data
6. Unified 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 properties
#Returns the global time format of json spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.time-zone=GMT+8
3, Instructor logical deletion function
1. EduTeacherController add delete method
@DeleteMapping("{id}") public boolean removeById(@PathVariable String id){ return teacherService.removeById(id); }
2. Configure logical deletion plug-ins
Configuration in MyBatisPlusConfig
/** * Logical delete plug-in */ @Bean public ISqlInjector sqlInjector() { return new LogicSqlInjector(); }
3. Test deletion using postman
Test result: is in database_ The deleted field is modified to 1
4, Cross domain configuration
1. What is cross domain
When a browser requests the resources of another domain name from the web page of one domain name, the domain name, port and protocol are all cross domain. In the development of front-end and back-end separation, we need to consider the problem of ajax cross domain.
Here we can solve this problem from the server
2. Disposition
Add annotation on Controller class
@CrossOrigin //Cross domain
02 - configure Swagger2 to generate API interface documents
1, Swagger2 introduction
In the front end and back-end separation development mode, api documents are the best way to communicate.
Swagger is a normative and complete framework for generating, describing, invoking, and visualizing RESTful Web services.
Timeliness (timely and accurately notify relevant front and rear end developers after interface changes)
Standardization (and ensure the standardization of the interface, such as interface address, request mode, parameters, response format and error information)
Consistency (the interface information is consistent, and there will be no differences due to the inconsistent document versions obtained by the developers)
Testability (test directly on the interface document to facilitate business understanding)
1, Swagger2 introduction
In the front end and back-end separation development mode, api documents are the best way to communicate.
Swagger is a normative and complete framework for generating, describing, invoking, and visualizing RESTful Web services.
Timeliness (timely and accurately notify relevant front and rear end developers after interface changes)
Standardization (and ensure the standardization of the interface, such as interface address, request mode, parameters, response format and error information)
Consistency (the interface information is consistent, and there will be no differences due to the inconsistent document versions obtained by the developers)
Testability (test directly on the interface document to facilitate business understanding)
2. Introduce related dependencies in common
<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 a sub module service base under common
3. In the module service base, create the configuration class of swagger
Create package com atguigu. servicebase. Config, create the class 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/.*"))) .paths(Predicates.not(PathSelectors.regex("/error.*"))) .build(); } private ApiInfo webApiInfo(){ return new ApiInfoBuilder() .title("website-Course Center API file") .description("This document describes the microservice interface definition of the course center") .version("1.0") .contact(new Contact("Helen", "http://atguigu.com", "55317332@qq.com")) .build(); } }
4. Introduce service base into service module
<dependency> <groupId>com.atguigu</groupId> <artifactId>service-base</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
5. Add annotations on the service edu startup class for testing
6. API model
You can add some custom settings, such as:
Define sample data
@ApiModelProperty(value = "Creation time", example = "2019-01-01 8:00:00") @TableField(fill = FieldFill.INSERT) private Date gmtCreate; @ApiModelProperty(value = "Update time", example = "2019-01-01 8:00:00") @TableField(fill = FieldFill.INSERT_UPDATE) private Date gmtModified;
5. Define interface description and parameter description
Defined on class: @ Api
Defined on method: @ ApiOperation
Defined on parameter: @ ApiParam
@Api(description="Instructor management") @RestController @RequestMapping("/admin/edu/teacher") public class TeacherAdminController { @Autowired private TeacherService teacherService; @ApiOperation(value = "List of all instructors") @GetMapping public List<Teacher> list(){ return teacherService.list(null); } @ApiOperation(value = "according to ID Delete instructor") @DeleteMapping("{id}") public boolean removeById( @ApiParam(name = "id", value = "lecturer ID", required = true) @PathVariable String id){ return teacherService.removeById(id); } }
03 - unified return result object
1, Unified return data format
In the project, we will package 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:
List:
{ "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" } ] } }
Pagination:
{ "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:
{ "success": true, "code": 20000, "message": "success", "data": {} }
Failed:
{ "success": false, "code": 20001, "message": "fail", "data": {} }
Therefore, we define uniform 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, Create a unified result return class
1. Create a sub module common utils under the common module
2. Create interface definition return code
Create package com atguigu. Commonutils, create interface resultcode java
package com.atguigu.commonutils; public interface ResultCode { public static Integer SUCCESS = 20000; public static Integer ERROR = 20001; }
4. Create result class
Create class R.java
@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(){} public static R ok(){ R r = new R(); r.setSuccess(true); r.setCode(ResultCode.SUCCESS); r.setMessage("success"); return r; } public static R error(){ R r = new R(); r.setSuccess(false); r.setCode(ResultCode.ERROR); r.setMessage("fail"); 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; } }
2, Unified use of returned results
1. Add dependency in service module
<dependency> <groupId>com.atguigu</groupId> <artifactId>common_utils</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
2. Modify the returned results in the Controller
list
@ApiOperation(value = "List of all instructors") @GetMapping public R list(){ List<Teacher> list = teacherService.list(null); return R.ok().data("items", list); }
delete
@ApiOperation(value = "according to ID Delete instructor") @DeleteMapping("{id}") public R removeById( @ApiParam(name = "id", value = "lecturer ID", required = true) @PathVariable String id){ teacherService.removeById(id); return R.ok(); }
04 - development of paging and conditional query interface
1, Pagination
1. Configuring paging plug-ins in MyBatisPlusConfig
/** * Paging plug-in */ @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); }
2. Paging Controller method
Add paging method in TeacherAdminController
@ApiOperation(value = "Pagination instructor list") @GetMapping("{page}/{limit}") public R pageList( @ApiParam(name = "page", value = "Current page number", required = true) @PathVariable Long page, @ApiParam(name = "limit", value = "Records per page", required = true) @PathVariable Long limit){ Page<Teacher> pageParam = new Page<>(page, limit); teacherService.page(pageParam, null); List<Teacher> records = pageParam.getRecords(); long total = pageParam.getTotal(); return R.ok().data("total", total).data("rows", records); }
This is more appropriate
@ApiOperation(value = "Paging query instructor list") @GetMapping("getTeacherPage/{current}/{limit}") public R getTeacherPage(@PathVariable Long current, @PathVariable Long limit){ Page<EduTeacher> page = new Page<>(current,limit); teacherService.page(page,null); List<EduTeacher> records = page.getRecords(); long total = page.getTotal(); //1. Save to MAP // Map<String,Object> map = new HashMap<>(); // map.put("list",records); // map.put("total",total); // return R.ok().data(map); //2. Direct splicing return R.ok().data("list",records).data("total",total); }
3. Testing in Swagger
2, Condition query
According to lecturer name, lecturer Title level and lecturer residence time gmt_create query
1. Create query object
Create com guli. edu. Query package, create teacherquery Java query object
package com.guli.edu.query; @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;//Note that the String type is used here, and the data passed from the front end does not need type conversion @ApiModelProperty(value = "Query end time", example = "2019-12-01 10:10:10") private String end; }
2,service
Interface
package com.guli.edu.service; public interface TeacherService extends IService<Teacher> { void pageQuery(Page<Teacher> pageParam, TeacherQuery teacherQuery); }
realization
package com.guli.edu.service.impl; @Service public class TeacherServiceImpl extends ServiceImpl<TeacherMapper, Teacher> implements TeacherService { @Override public void pageQuery(Page<Teacher> pageParam, TeacherQuery teacherQuery) { QueryWrapper<Teacher> 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); } }
3,controller
Modify pageList method in TeacherAdminController:
Add the parameter teacherquery, which is not required
@ApiOperation(value = "Pagination instructor list") @GetMapping("{page}/{limit}") public R pageQuery( @ApiParam(name = "page", value = "Current page number", required = true) @PathVariable Long page, @ApiParam(name = "limit", value = "Records per page", required = true) @PathVariable Long limit, @ApiParam(name = "teacherQuery", value = "Query object", required = false) TeacherQuery teacherQuery){ Page<Teacher> pageParam = new Page<>(page, limit); teacherService.pageQuery(pageParam, teacherQuery); List<Teacher> records = pageParam.getRecords(); long total = pageParam.getTotal(); return R.ok().data("total", total).data("rows", records); }
4. Testing in Swagger
05 - add and modify instructor interface development
1, Auto fill package
1. Add in the service base module
Create a package handler and create an autofill class MyMetaObjectHandler
@Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject 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. Add auto fill annotation to entity class
2, controller method definition
1. Add
@ApiOperation(value = "New lecturer") @PostMapping public R save( @ApiParam(name = "teacher", value = "Lecturer object", required = true) @RequestBody Teacher teacher){ teacherService.save(teacher); return R.ok(); }
2. Query by id
@ApiOperation(value = "according to ID Query lecturer") @GetMapping("{id}") public R getById( @ApiParam(name = "id", value = "lecturer ID", required = true) @PathVariable String id){ Teacher teacher = teacherService.getById(id); return R.ok().data("item", teacher); }
3. Modify according to id
@ApiOperation(value = "according to ID Modify instructor") @PutMapping("{id}") public R updateById( @ApiParam(name = "id", value = "lecturer ID", required = true) @PathVariable String id, @ApiParam(name = "teacher", value = "Lecturer object", required = true) @RequestBody Teacher teacher){ teacher.setId(id); teacherService.updateById(teacher); return R.ok(); } //Don't change the id
07 unified exception handling
1, What is unified exception handling
1. Manufacturing exception
Divide by 0
int a = 10/0;
2. What is unified exception handling
If we want the exception result to be displayed as a unified return result object and the exception information of the system to be handled uniformly, we need unified exception handling
2, Unified exception handling
1. Create unified exception handler
Create a unified exception handling class globalexceptionhandler in service base java:
/** * Unified exception handling class */ @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) @ResponseBody public R error(Exception e){ e.printStackTrace(); return R.error(); } }
2. Testing
Return unified error results
3, Handling specific exceptions
1. Add exception handling method
GlobalExceptionHandler. Add in Java
@ExceptionHandler(ArithmeticException.class) @ResponseBody public R error(ArithmeticException e){ e.printStackTrace(); return R.error().message("Custom exception executed"); }
2. Testing
4, Custom exception
1. Create custom exception class
@Data @AllArgsConstructor @NoArgsConstructor public class GuliException extends RuntimeException { @ApiModelProperty(value = "Status code") private Integer code; private String msg; }
2. GuliException is thrown at the required position in the business
try { int a = 10/0; }catch(Exception e) { throw new GuliException(20001,"Custom exception occurred"); }
3. Add exception handling method
GlobalExceptionHandler. Add in Java
@ExceptionHandler(GuliException.class) @ResponseBody public R error(GuliException e){ e.printStackTrace(); return R.error().message(e.getMsg()).code(e.getCode()); }
4. Testing
08 - unified log processing
1, Log
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 The output of important methods can be added info If you want to debug the parameters of the entry method, just take a look debug Abnormal try crash Time error
This method can only print logs on the console
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 logs
Delete application Log configuration in properties
Install the 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,Is 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 Running 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 defining variables, you can make“ ${}"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, recording 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> <!-- Set character set here --> </encoder> <!-- The rolling strategy of the logger, recording 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, recording 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 print 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 print 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 print level, regardless of case: TRACE, DEBUG, INFO, WARN, ERROR, ALL and OFF,The 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 error log to file
GlobalExceptionHandler. In Java
Class
@Slf4j
Exception output statement
log.error(e.getMessage());
3. Output log stack information to a file
Define tool classes
Create util package under Guli framework common and create exceptionutil Java tool class
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); // 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));
Create toString method in GuliException
@Override public String toString() { return "GuliException{" + "message=" + this.getMessage() + ", code=" + code + '}'; }