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