Grain College 1 -- lecturer management module

1, Overview of grain College

1. Business model

Common B2C, B2B2C

2. Project structure

2, Instructor management module - environment construction

1. Overview

2. Front and rear end separation concept

3. Teacher's watch design and creation

Design:

Table creation

CREATE TABLE `edu_teacher` (
  `id` char(19) NOT NULL COMMENT 'lecturer ID',
  `name` varchar(20) NOT NULL COMMENT 'Lecturer name',
  `intro` varchar(500) NOT NULL DEFAULT '' COMMENT 'Trainer Introduction ',
  `career` varchar(500) DEFAULT NULL COMMENT 'Lecturer qualifications,One sentence explains the instructor',
  `level` int(10) unsigned NOT NULL COMMENT 'Title 1 senior lecturer 2 chief lecturer',
  `avatar` varchar(255) DEFAULT NULL COMMENT 'Lecturer portrait',
  `sort` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'sort',
  `is_deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'Logical deletion 1( true)Deleted, 0( false)Not deleted',
  `gmt_create` datetime NOT NULL COMMENT 'Creation time',
  `gmt_modified` datetime NOT NULL COMMENT 'Update time',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='lecturer';

INSERT INTO `edu_teacher` VALUES ('1','Zhang San','In recent years, he has presided over the National Natural Science Foundation of China (6), the transformation projects of major scientific and technological achievements in Jiangsu Province (5), and the forward-looking joint research projects of industry, University and research in Jiangsu Province (3) There are more than 40 major scientific research projects at provincial and ministerial levels and their enterprises, such as provincial industrial science and technology support, provincial high technology and Provincial Natural Science Foundation. Many projects have been successfully transformed in enterprises, resulting in good economic, social and environmental benefits. We have actively carried out industry university research scientific and technological cooperation, and established Jiangsu graduate workstations with 16 enterprises in the province, of which 6 are excellent graduate work in Jiangsu Province station','senior',1,'https://guli-file-190513.oss-cn-beijing.aliyuncs.com/avatar/default.jpg',0,0,'2019-10-30 14:18:46','2019-11-12 13:36:36'),('1189389726308478977', 'sunny day', 'introduction to senior lecturer', 'senior lecturer qualification', 2,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/teacher/2019/10/30/de47ee9b-7fec-43c5-8173-13c5f7f689b2.png',1,0,'2019-10-30 11:53:03','2019-10-30 11:53:03'),('1189390295668469762 ',' Li Gang ',' introduction to senior lecturer ',' senior lecturer ', 2,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/teacher/2019/10/30/b8aa36a2-db50-4eca-a6e3-cc6e608355e0.png',2,0,'2019-10-30 11:55:19','2019-11-12 13:37:52'),('1189426437876985857 ',' Wang Er ',' introduction to senior lecturer ',' senior lecturer ', 1,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/teacher/2019/11/08/e44a2e92-2421-4ea3-bb49-46f2ec96ef88.png',0,0,'2019-10-30 14:18:56','2019-11-12 13:37:35'),('1189426464967995393 ',' Wang Wu ',' introduction to senior lecturer ',' senior lecturer ', 1,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/teacher/2019/10/30/65423f14-49a9-4092-baf5-6d0ef9686a85.png',0,0,'2019-10-30 14:19:02','2019-11-12 13:37:18'),('1192249914833055746', 'Li Si', 'introduction to senior lecturer', 'senior lecturer', 1,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/teacher/2019/11/07/91871e25-fd83-4af6-845f-ea8d471d825d.png',0,0,'2019-11-07 09:18:25','2019-11-12 13:37:01'),('1192327476087115778','1222-12-12','1111','11',1,'https://online-teach-file.oss-cn-beijing.aliyuncs.com/teacher/2019/11/08/5805c6cd-c8ad-4a77-aafd-d2e083bfd8a4.png',0,1,'2019-11-07 14:26:37','2019-11-11 16:26:26'),('1195337453429129218','test','sdfsdf','sdfdf',1,'https://guli-file-190513.oss-cn-beijing.aliyuncs.com/avatar/default.jpg',0,1,'2019-11-15 21:47:12','2019-11-15 21:47:27');


4. Structure analysis of instructor management module

5. Build parent project

pom file. The packaging method is set to pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.atguigu</groupId>
    <artifactId>guli_parent</artifactId>
    <packaging>pom</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>guli_parent</name>
    <description>Demo project for Spring Boot</description>


    <properties>
        <java.version>1.8</java.version>
        <guli.version>0.0.1-SNAPSHOT</guli.version>
        <mybatis-plus.version>3.0.5</mybatis-plus.version>
        <velocity.version>2.0</velocity.version>
        <swagger.version>2.7.0</swagger.version>
        <aliyun.oss.version>2.8.3</aliyun.oss.version>
        <jodatime.version>2.10.1</jodatime.version>
        <poi.version>3.17</poi.version>
        <commons-fileupload.version>1.3.1</commons-fileupload.version>
        <commons-io.version>2.6</commons-io.version>
        <httpclient.version>4.5.1</httpclient.version>
        <jwt.version>0.7.0</jwt.version>
        <aliyun-java-sdk-core.version>4.3.3</aliyun-java-sdk-core.version>
        <aliyun-sdk-oss.version>3.1.0</aliyun-sdk-oss.version>
        <aliyun-java-sdk-vod.version>2.15.2</aliyun-java-sdk-vod.version>
        <aliyun-java-vod-upload.version>1.4.11</aliyun-java-vod-upload.version>
        <aliyun-sdk-vod-upload.version>1.4.11</aliyun-sdk-vod-upload.version>
        <fastjson.version>1.2.28</fastjson.version>
        <gson.version>2.8.2</gson.version>
        <json.version>20170516</json.version>
        <commons-dbutils.version>1.7</commons-dbutils.version>
        <canal.client.version>1.1.0</canal.client.version>
        <docker.image.prefix>zx</docker.image.prefix>
        <cloud-alibaba.version>0.2.2.RELEASE</cloud-alibaba.version>
    </properties>

    <!--Dependency management-->
    <dependencyManagement>
        <dependencies>
            <!--Spring Cloud-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--mybatis-plus Persistent layer-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus.version}</version>
            </dependency>
            <!-- velocity template engine, Mybatis Plus Code generator needs -->
            <dependency>
                <groupId>org.apache.velocity</groupId>
                <artifactId>velocity-engine-core</artifactId>
                <version>${velocity.version}</version>
            </dependency>

            <!--swagger-->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>${swagger.version}</version>
            </dependency>
            <!--swagger ui-->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
                <version>${swagger.version}</version>
            </dependency>
            <!--aliyunOSS-->
            <dependency>
                <groupId>com.aliyun.oss</groupId>
                <artifactId>aliyun-sdk-oss</artifactId>
                <version>${aliyun.oss.version}</version>
            </dependency>
            <!--Date time tool-->
            <dependency>
                <groupId>joda-time</groupId>
                <artifactId>joda-time</artifactId>
                <version>${jodatime.version}</version>
            </dependency>
            <!--xls-->
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>${poi.version}</version>
            </dependency>
            <!--xlsx-->
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>${poi.version}</version>
            </dependency>
            <!--File upload-->
            <dependency>
                <groupId>commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>${commons-fileupload.version}</version>
            </dependency>
            <!--commons-io-->
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>${commons-io.version}</version>
            </dependency>
            <!--httpclient-->
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>${httpclient.version}</version>
            </dependency>
            <dependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
                <version>${gson.version}</version>
            </dependency>
            <!-- JWT -->
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>${jwt.version}</version>
            </dependency>
            <!--aliyun-->
            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>aliyun-java-sdk-core</artifactId>
                <version>${aliyun-java-sdk-core.version}</version>
            </dependency>
            <dependency>
                <groupId>com.aliyun.oss</groupId>
                <artifactId>aliyun-sdk-oss</artifactId>
                <version>${aliyun-sdk-oss.version}</version>
            </dependency>
            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>aliyun-java-sdk-vod</artifactId>
                <version>${aliyun-java-sdk-vod.version}</version>
            </dependency>
            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>aliyun-java-vod-upload</artifactId>
                <version>${aliyun-java-vod-upload.version}</version>
            </dependency>
            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>aliyun-sdk-vod-upload</artifactId>
                <version>${aliyun-sdk-vod-upload.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>${fastjson.version}</version>
            </dependency>
            <dependency>
                <groupId>org.json</groupId>
                <artifactId>json</artifactId>
                <version>${json.version}</version>
            </dependency>
            <dependency>
                <groupId>commons-dbutils</groupId>
                <artifactId>commons-dbutils</artifactId>
                <version>${commons-dbutils.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba.otter</groupId>
                <artifactId>canal.client</artifactId>
                <version>${canal.client.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

6. Question: About Red explosion

Solution to spring boot starter parent red reporting
Problem description
In maven Project, if you want to import SpringBoot, the spring boot starter parent that the parent depends on will usually appear the error prompt of Project 'org. Springframework. Boot: spring boot starter parent: x.x.x' not found.

IntelliJ IDEA Ultimate 2020.3 is used, maven version 3.6.3 is used, and parent version 2.4.3 is imported.

Train of thought analysis
In fact, all the statements found on the Internet say that it is a compatibility problem between maven and spring, balabala, and various methods such as changing the image. However, after many attempts, I found that the key problem is that as long as one version cannot be imported and not found is displayed, the other versions will not work. However, as long as the project is imported for the first time, the configured SpringBoot will pass, which is very confusing Confused.

resolvent
Finally, I found a solution in StackOverFlow.

File - > invalidate caches / restart... - > invalidate and restart.

summary
Of course, this is equivalent to clearing the cache and restarting the IDEA. This is only one method and the simplest. I will post more detailed methods of other bloggers below for reference.

7. Service module construction

pom of service module

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>guli_parent</artifactId>
        <groupId>com.atguigu</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service</artifactId>
    <packaging>pom</packaging>

    <dependencies>
       <!-- <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>-->
        <!--hystrix Dependency, mainly with @HystrixCommand -->
      <!--  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>-->
        <!--Service registration-->
       <!-- <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>-->
        <!--Service call-->
        <!--<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>-->


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- velocity template engine, Mybatis Plus Code generator needs -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
        </dependency>
        <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
        </dependency>
        <!--lombok Used to simplify entity classes: need to install lombok plug-in unit-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--xls-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
        </dependency>
        <!--httpclient-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        <!--commons-io-->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
        </dependency>
        <!--gson-->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

    </dependencies>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

</project>

8. Problem: pom file darkened with horizontal lines

reason:
The pom.xml file is set in the maven ignore file list

resolvent:
File -- > setting – > maven – > ignored files uncheck the pom.xml file of the corresponding item in the list;
If there is a horizontal line in the middle of the pom.xml file in the workspace of the idea after unchecking, you need to reload the project or restart the idea to restore normal, as shown in the following figure:

3, Instructor management module – implementation of simple query function

Module location:

1. Writing packages using code generators

Code generator

package com.atguigu.demo;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.Test;

public class CodeGenerator {

    @Test
    public void run() {

        // 1. Create code generator
        AutoGenerator mpg = new AutoGenerator();

        // 2. Global configuration
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir("D:\\AScience\\guli_parent\\service\\service_edu" + "/src/main/java"); //Output directory******

        gc.setAuthor("dz"); //Author name
        gc.setOpen(false); //Whether to open Explorer after generation -- basically useless
        gc.setFileOverride(false); //Whether the file is overwritten during regeneration

        gc.setServiceName("%sService");	//Remove the initial I of the Service interface -- naming convention
        gc.setIdType(IdType.ID_WORKER_STR); //The primary key policy -- str stands for string -- long does not need to be added*********
        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 --- configure one separately**********
        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("123123");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4. Package configuration
        PackageConfig pc = new PackageConfig();

        //Build package: com.atguigu.eduservice***********
        pc.setModuleName("eduservice"); //Module name
        pc.setParent("com.atguigu");

        //Build package: com.atguigu.eduservice.controller
        pc.setController("controller");

        pc.setEntity("entity");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 5. Policy configuration - Reverse Engineering - generate code according to the table
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("edu_teacher");//According to which table in the database is generated, add commas to continue filling in multiple tables*************

        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 Controller interface

Writing of Controller interface:

package com.atguigu.eduservice.controller;


import com.atguigu.eduservice.entity.EduTeacher;
import com.atguigu.eduservice.service.EduTeacherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * <p>
 * Instructor front end controller
 * </p>
 *
 * @author dz
 * @since 2021-10-24
 */
@RestController//Leave it to spring for management and return json data
@RequestMapping("/eduservice/teacher")
public class EduTeacherController {
    //Inject service
    @Autowired
    private EduTeacherService teacherService;

    //rest style
    @GetMapping("findAll")
    public List<EduTeacher> findAllTeacher(){
        List<EduTeacher> list = teacherService.list(null);
        return list;
    }
}


3. Create startup class

package com.atguigu.eduservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

4. Configure class scanning

Scan mapper interface ---- write a configuration class and annotate it

package com.atguigu.eduservice.config;


import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

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

5. Configuration file application.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=123123
# mybatis log
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

Question:

Add in 'application'

#Returns the global time format of json
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8

4, Instructor management module – implementation of logical deletion function

1. Configure plug-ins

@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}

2. Annotate the idDelete attribute

@TableLogic
private Boolean isDeleted;

3. Method of writing Controller

  //Delete instructor logically
    @DeleteMapping("/deleteTeacherById/{id}")//id passed by path
    public boolean deleteTeacherById(@PathVariable String id){//Gets the id in the path
        return teacherService.removeById(id);
    }

Question:

You can't test with a browser

With some tools to test, swagger and postman came

5, Instructor management module – integrate Swagger

1. Function

Generate interface documentation and test

2. Create module

Create a common module so that all modules can be used

Create a module common under Guli parent and create a service_base

3. Import dependency

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>guli_parent</artifactId>
        <groupId>com.atguigu</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>common</artifactId>
    <packaging>pom</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

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

</project>

4. Write configuration class

Create the base module under common

package com.atguigu.servicebase;

import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
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//swagger annotation
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("dz", "http://dz.com",
                        "319374198@qq.com"))
                .build();
    }
}

5. Introduce the configuration class of swagger into the original project

Introduced under pom of service

<dependency>
            <groupId>com.atguigu</groupId>
            <artifactId>service_base</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

6. Configuration of scanning swagger

- > in service_edu startup class plus

@ComponentScan(basePackages = {"com.atguigu"})

7. Access swagger address

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

To test, click try it out

8. Problem: a pop-up window appears in swagger

Refresh maven and restart idea

- note: when entering the document, do not click the browsing record, but re-enter the website

9. Swagger annotation

Function: you can add some custom settings to facilitate viewing interface information

Defined on class: @ Api

Defined on method: @ ApiOperation

Defined on parameter: @ ApiParam

@RestController
@CrossOrigin //Solve cross domain problems
@RequestMapping("/eduservice/edu-teacher")
@Api(description="Instructor management")
public class EduTeacherController {

    @Autowired
    private EduTeacherService eduTeacherService;

    //Query all data of the lecturer table
    @ApiOperation(value = "List of all instructors")
    @GetMapping("/findAll")
    public List<EduTeacher> list(){
        return eduTeacherService.list(null);
    }

    //Delete instructor logically
    @ApiOperation(value = "according to ID Delete instructor")
    @DeleteMapping("/deleteTeacherById/{id}")
    public boolean deleteTeacherById(@PathVariable String id){
        return eduTeacherService.removeById(id);
    }

}

6, Instructor management module – unified return data format

1. json function and data format

Function: make the returned and input data have the same format and more standardized

Format: (1) object (2) array is usually mixed

format

{
"success": Boolean, //Is the response successful
"code": number, //Response code
"message": character string, //Return message
"data": HashMap //Return data in key value pairs
}

2. Status code setting

Create common under common_utils

Create an interface and define the data return status code

Success: 20000

Failed: 20001

package com.atguigu.commonutils;

public interface ResultCode {
    //Status code: successful
    public static Integer SUCCESS = 20000;
    //Status code: failed
    public static Integer ERROR = 20001;
}

3. Writing of result class

Function: encapsulate the results in this class to achieve unified format

package com.atguigu.commonutils;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.HashMap;
import java.util.Map;

@Data
public class R {
    @ApiModelProperty("Is it successful")
    private boolean success;

    @ApiModelProperty("Response code")
    private Integer code;

    @ApiModelProperty("Return information")
    private String message;

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

    //Parameterless construction method
    private R() {
    }

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

    //Failed static method
    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;//this here is the object of the current class, which can realize chain programming
    }

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

    public R message(String message){
        this.setMessage(message);
        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. Use of result classes

(1) Introduce commonutil dependency to service

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

(2) Set the return values of the interface to R

package com.atguigu.eduservice.controller;


import com.atguigu.commonutils.R;
import com.atguigu.eduservice.entity.EduTeacher;
import com.atguigu.eduservice.service.EduTeacherService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * <p>
 * Instructor front end controller
 * </p>
 *
 * @author dz
 * @since 2021-10-24
 */
@Api(description="Instructor management")
@RestController//Leave it to spring for management and return json data
@RequestMapping("/eduservice/teacher")
public class EduTeacherController {
    //Inject service
    @Autowired
    private EduTeacherService teacherService;

    //rest style
    @ApiOperation(value = "List of all instructors")
    @GetMapping("findAll")//With or without slashes
    public R findAllTeacher(){
        List<EduTeacher> list = teacherService.list(null);
        return R.ok().data("items",list);
    }

    //Delete instructor logically
    @ApiOperation(value = "according to ID Delete instructor")
    @DeleteMapping("/deleteTeacherById/{id}")//id passed by path
    public R deleteTeacherById(
            @ApiParam(name = "id", value = "lecturer ID", required = true)
            @PathVariable String id){//Gets the id in the path
        boolean flag = teacherService.removeById(id);
        if(flag){
            return R.ok();
        }
        else {
            return R.error();
        }
    }

}


7, Instructor management module – implementation of simple paging

1. Configure plug-ins

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

2. Write Controller to realize paging

    @GetMapping("pageTeacher/{current}/{limit}")
    public  R pageListTeacher(@PathVariable long current
                                ,@PathVariable long limit    ){
        //Create paage object
        Page<EduTeacher>  pageTeacher =new Page<>(current,limit);
        teacherService.page(pageTeacher,null);//Realize paging and underlying encapsulation, and encapsulate all paging data into pageTeacher 
        long total = pageTeacher.getTotal();//Total records
        List<EduTeacher> records = pageTeacher.getRecords();// list collection
        Map map =new HashMap();
        map.put("total",total);
        map.put("rows",records);
        //return R.ok().data("total",total).data("rows",records); Method 2
        return R.ok().data(map);
    }
    

8, Instructor management module – multi condition query + Pagination

1. Write conditional entity classes

Pass the condition value to the interface

Encapsulate the condition value into the object and pass the object to the interface (vo)

So write the condition object

package com.atguigu.eduservice.entity.vo;

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

import java.io.Serializable;

@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. Write controller to realize conditional query + paging

  @PostMapping("pageTeacherCondition/{current}/{limit}")
    public  R pageTeacherCondition(@PathVariable long current, @PathVariable long limit, @RequestBody(required=false)   TeacherQuery teacherQuery){
        //Create page object
        Page<EduTeacher> pageTeacher =new Page<>(current,limit);
        //Construction conditions
        QueryWrapper<EduTeacher> wrapper=new QueryWrapper<>();
        //Judge whether the condition is empty
         String name=teacherQuery.getName();
        Integer level = teacherQuery.getLevel();
        String begin = teacherQuery.getBegin();
        String end = teacherQuery.getEnd();
        if(!StringUtils.isEmpty(name)){
            wrapper.like("name",name);//For fuzzy query, the first is the field, and the second is the passed value. Query the value of name like name
        }
        if (!StringUtils.isEmpty(level)){
            wrapper.eq("level",level);//Query level
        }
        if (!StringUtils.isEmpty(begin)){
            wrapper.ge("gmt_create",begin);//The query creation time is greater than the value of begin
        }if (!StringUtils.isEmpty(end)){
            wrapper.le("gmt_create",end);//Value with query creation time less than end
        }
        //paging
        teacherService.page(pageTeacher,wrapper);
        long total=pageTeacher.getTotal();
        List<EduTeacher> records = pageTeacher.getRecords();
        return R.ok().data("total",total).data("rows",records);

    }

3. Review RequsetBody and ResponseBody

@RequestBody(required=false)

Using json to transfer data can encapsulate json data into objects. You need to change the request to post (that is, the incoming json data)

@ResponstBody

Return json data

9, Instructor management module – add instructor

1. Implementation of automatic filling time

(1) Add annotation on entity class

    @TableField(fill = FieldFill.INSERT)
    @ApiModelProperty(value = "Creation time")
    private Date gmtCreate;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    @ApiModelProperty(value = "Update time")
    private Date gmtModified;

(2) Create autofill class

package com.atguigu.servicebase.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    
    @Override
    public void insertFill(MetaObject metaObject) {
        //Parameter 1: attribute name in the corresponding entity class
        this.setFieldValByName("gmtCreate", new Date(), metaObject);
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }
}


(3) Configure scanning this package (configured)

2. Write Controller

@PostMapping("addTeacher")
    public R addTeacher(@RequestBody EduTeacher eduTeacher){
        boolean save = teacherService.save(eduTeacher);
        if(save){
            return R.ok();
        }
        else {
            return R.error();
        }
    }

10, Instructor management module – modify instructor

Query according to the instructor id, and then modify it

  @GetMapping("getTeacher/{id}")
    public R getTeacher(@PathVariable String id){
        EduTeacher eduTeacher = teacherService.getById(id);
        return R.ok().data("teacher",eduTeacher);
    }
    
    @PostMapping("updateTeacher")
    public R updateTeacher(@RequestBody EduTeacher eduTeacher){
        boolean flag = teacherService.updateById(eduTeacher);
        if (flag){
            return R.ok();
        }
        else {
            return R.error();
        }
    }

11, Unified exception handling

1. Global exception handling

When there is an exception, it can handle the exception

(1) Location

(2) In common service_ Introducing dependency into pom of base

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

(3) Create exception handler (as shown above)

package com.atguigu.servicebase.exceptionhandler;
import com.atguigu.commonutils.R;
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 {

    //Specifies what exception will execute this method
    @ExceptionHandler(Exception.class)


    //Because he's not here. There is no @ RestController, so the data will not be returned. You need to add @ ResponseBody to return the data
    @ResponseBody
    public R error(Exception e){
        e.printStackTrace();
        return R.error().message("Global exception handling performed...");
    }

}

(4) Problem: pom repeated references

Service is introduced into service_base

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

And service_ Common is introduced into base_ Utils means common in the service_ Utils repeated

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

Therefore, it should be deleted

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

This is dependency passing

2. Specific exception handling

Configure in exception handler

@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public R error(ArithmeticException e){
    e.printStackTrace();
    return R.error().message("Specific exception handling performed...");
}

3. Custom exception

(1) Create a custom exception class, inherit RuntimeException, and write exception properties

package com.atguigu.servicebase.exceptionhandler;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class GuliException extends RuntimeException{
    private Integer code;  //Status code
    private String msg;  //Abnormal information
}

(2) Configure in exception handler

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

(3) During the test, throw the exception manually

12, Unified log processing

1. Log level

(high level) (low level)

OFF,FATAL,ERROR,WARN,INFO,DEBUG,ALL

What is the default level: only levels and above are displayed

Default level settings:

In application

# Set log level
logging.level.root=WARN

After running in this way, only information above the warning level is displayed, including warnings

2,Logback

Function: output the log not only to the console, but also to a file

use:

(1) Delete the log configuration in the application

(2) Create logback-spring.xml (fixed) in resources

(3) Write code (fixed)

<?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
    Set as 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 by default
    by true -->
    <!-- scanPeriod:Set the time interval for monitoring whether the configuration file is modified. If no time unit is given, it defaults to
    The 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 check
    see 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
    reach logger In context. After defining variables, you can make“ ${}"To use variables. -->
    <!--Where is the log output in the folder-->
   <property name="log.path" value="logs"/>

    <!-- 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 greater than or equal to
        Log information equal to this level-->
        <!-- For example, if you configure INFO Level, even if other locations are configured DEBUG Level day
        Records 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
    set<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 think
    To view sql Statement, there are two operations:
        First handle<root level="INFO">Change to<root level="DEBUG">This will print sql,however
            So 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 Statements can be typed
            India, others are still 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>

(4) Want to output exception information to a file

Add to exception handler

@Slf4j

Add in the interface of exception output

log.error(e.getMessage());

3. logback log location description

logback.xml configuration description

File relative saving path settings can be divided into the following three types:

value = "logs" – indicates the directory where the item is saved
value = "/ logs" - under the root path of the disk where the project is located
value = "... / logs" – indicates to save to the parent directory of the project

Keywords: Java

Added by loony383 on Wed, 27 Oct 2021 07:31:10 +0300