抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

Hello world!

背景

​ 今天准备写一个ssm整合的crud简单项目,然后顺便应付一下学校课程,然后被spring的注释气到了(注释代码什么都写得一模一样,就是idea报找不到bean,结果我重写了几遍之后莫名的好了,离谱!),被jsp气到了(这个错误之前遇到好几次了,也是代码一模一样,就是报404,离谱!),实在是不想在这些上面折腾了,今天在实验室有一半的时间都在叹气,于是果断放弃了它,投入了springboot+vue的怀抱。

项目简介

项目商业模式

B2C(当前项目)

Business To Customers

两个角色:
管理员:添加、修改、删除
普通用户:查询

B2B2C

Business To Business To Customers

例子:淘宝

项目实现功能模块

后台(管理员)

  1. 讲师管理
  2. 课程分类管理
  3. 课程管理
    • 视频
  4. 统计分析
    • 课程相关
  5. 订单管理
  6. banner(轮播图)管理
  7. 权限管理

前台(普通用户)

  1. 首页数据显示
  2. 讲师列表和详情
  3. 课程列表和详情
    • 视频在线播放
  4. 登录和注册
  5. 微信扫码登录
  6. 微信支付

项目使用的技术点

后端技术

  1. SpringBoot
  2. SpringCloud
  3. MyBatisPlus
  4. SpringSecurity
  5. redis,maven,easyExcel,jwt,OAuth2
  6. ……

前端技术

  1. vue
  2. element-ui
  3. axios
  4. node.js
  5. ……

其他技术

  1. 阿里云oss
  2. 阿里云视频点播服务
  3. 阿里云短信服务
  4. 微信支付和登录
  5. docker,git,Jenkins
  6. ……

MyBatisPlus介绍

详见单独的文档说明

搭建项目环境

数据库

详见资料

项目结构

父工程:pom类型,用于管理以来版本和放公共依赖

子模块n:实现各个模块

创建springboot父项目

配置父项目的pom.xml

配置打包方式、删除dependencies、添加properties和dependencyManagement、删除src文件夹等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
<?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.5.4</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>guli_parent</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>

<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 持久层-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>

<!-- velocity 模板引擎, Mybatis Plus 代码生成器需要 -->
<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>

<!--日期时间工具-->
<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>

<!--文件上传-->
<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>

创建子模块

右键new model创建即可,子项目service等

配置pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<dependencies>

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

<!--<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>-->

<!--hystrix依赖,主要是用 @HystrixCommand -->
<!--<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>-->

<!--服务注册-->
<!-- <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>-->
<!--服务调用-->
<!-- <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 模板引擎, Mybatis Plus 代码生成器需要 -->
<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用来简化实体类:需要安装lombok插件-->
<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>

创建子子模块

service_edu、service_vod

当前项目结构

image-20210920162644497

common模块

swagger工具

创建子模块

命名为common,该模块不需要src文件夹

配置依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?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用来简化实体类:需要安装lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>

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

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

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

</project>

创建子子模块

service_base

创建SwaggerConfig.java配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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注解
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("网站-课程中心API文档")
.description("本文档描述了课程中心微服务接口定义")
.version("1.0")
.contact(new Contact("java", "http://atguigu.com", "1123@qq.com"))
.build();
}

}

引入swagger子模块

需要在service模块中引入swagger模块的子模块servicebase模块,即在service模块的pom.xml文件中添加依赖即可(因为想要在service模块的子模块中使用,且都写上了pom打包,所以只要在service模块的pom.xml中添加即可)

1
2
3
4
5
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>service_base</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

启动类添加组件扫描

EduApplication是service_edu模块下的启动类,由于service_base模块中的swaggerconfig配置类所在包地址也是com.atguigu.xxx,所以可以通过这个扫描到,否则只会扫描启动类所在及子包下的类(所以启动类要放在所有package的同级),如果是别的地址再额外添加即可({“com.atguigu”,”com.xxx”})

1
2
3
4
5
6
7
8
9
@SpringBootApplication
@ComponentScan(basePackages = {"com.atguigu"})
public class EduApplication {

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

}

测试(访问)swagger

启动xxxApplication启动类

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

API文档提示编写

一下以controller为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.atguigu.eduservice.controller;


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>
* 讲师 前端控制器
* </p>
*
* @author testjava
* @since 2021-09-20
*/
@Api(tags = {"讲师管理"})
@RestController
@RequestMapping("/eduservice/edu-teacher")
public class EduTeacherController {

@Autowired
private EduTeacherService teacherService;

// REST风格
// 1、查询讲师表的所有数据
// 地址:localhost:8001//eduservice/edu-teacher/findAll
@ApiOperation(value = "所有讲师列表")
@GetMapping("findAll")
public List<EduTeacher> findAllTeacher() {
// 调用Service的方法
List<EduTeacher> list = teacherService.list(null);
return list;
}

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

当前项目结构

image-20210921130942041

统一结果返回格式

统一结果的格式

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

创建子模块

common模块下创建common_utils模块

设定状态码

可以写成接口,或者其他形式

1
2
3
4
5
6
7
package com.atguigu.commonutils;

public interface ResultCode {
// 状态码
public static Integer SUCCESS = 20000; //成功
public static Integer ERROR = 20001; //失败
}

定义返回数据格式

创建一个统一返回结果类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.atguigu.commonutils;

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

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

//统一返回结果的类
@Data
public class R {
// 以下属性为返回内容key

@ApiModelProperty(value = "是否成功")
private Boolean success;

@ApiModelProperty(value = "返回码")
private Integer code;

@ApiModelProperty(value = "返回消息")
private String message;

@ApiModelProperty(value = "返回数据")
private Map<String, Object> data = new HashMap<String, Object>();

//把构造方法私有
private R() {
}

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

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

// 以下的return this返回的是r
// 可以实现链式编程(R.success().message().……)
public R success(Boolean success) {
this.setSuccess(success);
return this;
}

public R message(String message) {
this.setMessage(message);
return this;
}

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

public R data(String key, Object value) {
this.data.put(key, value);
return this;
}

public R data(Map<String, Object> map) {
this.setData(map);
return this;
}

}

使用统一返回结果格式

先在模块的pom.xml中引入已经定义好的统一返回结果类所在

将接口方法(controller中的方法)返回结果改为R即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 未使用统一结果格式
@Api(tags = {"讲师管理"})
@RestController
@RequestMapping("/eduservice/edu-teacher")
public class EduTeacherController {

@Autowired
private EduTeacherService teacherService;

// REST风格
// 1、查询讲师表的所有数据
// 地址:localhost:8001//eduservice/edu-teacher/findAll
@ApiOperation(value = "所有讲师列表")
@GetMapping("findAll")
public List<EduTeacher> findAllTeacher() {
// 调用Service的方法
List<EduTeacher> list = teacherService.list(null);
return list;
}

// 2、逻辑删除讲师
@ApiOperation(value = "根据id逻辑删除讲师")
@DeleteMapping("{id}")
public boolean removeTeacher(@ApiParam(name = "id", value = "讲师ID", required = true) @PathVariable("id") String id) {
boolean flag = teacherService.removeById(id);
return flag;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 使用统一结果格式
@Api(tags = {"讲师管理"})
@RestController
@RequestMapping("/eduservice/edu-teacher")
public class EduTeacherController {

@Autowired
private EduTeacherService teacherService;

// REST风格
// 1、查询讲师表的所有数据
// 地址:localhost:8001//eduservice/edu-teacher/findAll
@ApiOperation(value = "所有讲师列表")
@GetMapping("findAll")
public R findAllTeacher() {
// 调用Service的方法
List<EduTeacher> list = teacherService.list(null);
return R.ok().data("teacherList", list);
}

// 2、逻辑删除讲师
@ApiOperation(value = "根据id逻辑删除讲师")
@DeleteMapping("{id}")
public R removeTeacher(@ApiParam(name = "id", value = "讲师ID", required = true) @PathVariable("id") String id) {
boolean flag = teacherService.removeById(id);
return flag ? R.ok() : R.error();
}
}

当前项目结构

image-20210921131024571

统一异常处理

统一异常处理类

在common模块中的service_base中添加即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 统一异常处理类
*/
@ControllerAdvice // 增强的controller,可以用于全局异常处理
public class GlobalExceptionHandler {

// 全局异常处理
@ExceptionHandler(Exception.class) // 指定出现什么异常才会执行这个方法
@ResponseBody // 用于返回数据
public R error(Exception e) {
e.printStackTrace();
return R.error().message("产生了异常!");
}

}

这里有一个依赖的问题,需要注意

特定异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 统一异常处理类
*/
@ControllerAdvice // 增强的controller,可以用于全局异常处理
public class GlobalExceptionHandler {

// 全局异常处理
@ExceptionHandler(Exception.class) // 指定出现什么异常才会执行这个方法
@ResponseBody // 用于返回数据
public R error(Exception e) {
e.printStackTrace();
return R.error().message("产生了异常!");
}

// 特定异常处理
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public R error(ArithmeticException e) {
e.printStackTrace();
return R.error().message("产生了ArithmeticException异常!");
}

}

自定义异常处理

创建自定义异常类

1
2
3
4
5
6
7
8
9
10
11
@Data
@NoArgsConstructor
@AllArgsConstructor
public class GuliException extends RuntimeException {

private Integer code; // 状态码
private String msg; // 异常信息

//……

}

在统一异常处理类中创建方法

1
2
3
4
5
6
7
// 自定义异常处理
@ExceptionHandler(GuliException.class)
@ResponseBody
public R error(GuliException e) {
e.printStackTrace();
return R.error().code(e.getCode()).message(e.getMsg());
}

抛出自定义异常

1
2
3
4
5
try {
int i = 1 / 0;
} catch (Exception e) {
throw new GuliException(20001, "zzzzz");
}

当前项目结构

image-20210921154934229

统一日志处理

配置日志级别

application.properties文件中配置即可

1
logging.level.root=INFO

logback日志工具

log4j,logback等可以将日志输出到文件中

注意:需要先将application.properties中的有关日志的配置注释掉

配置工具的配置文件

在resource文件夹下创建logback-spring.xml配置文件

注意 的路径即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->

<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
<property name="log.path" value="D:/MyProject/log/guli_edu" />

<!-- 彩色日志 -->
<!-- 配置格式变量:CONSOLE_LOG_PATTERN 彩色日志格式 -->
<!-- magenta:洋红 -->
<!-- boldMagenta:粗红-->
<!-- cyan:青色 -->
<!-- white:白色 -->
<!-- magenta:洋红 -->
<property name="CONSOLE_LOG_PATTERN"
value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)" />


<!--输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<!-- 例如:如果此处配置了INFO级别,则后面其他位置即使配置了DEBUG级别的日志,也不会被输出 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>


<!--输出到文件-->

<!-- 时间滚动输出 level为 INFO 日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_info.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<!-- 时间滚动输出 level为 WARN 日志 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_warn.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>


<!-- 时间滚动输出 level为 ERROR 日志 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_error.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<!--
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。
<logger>仅有一个name属性,
一个可选的level和一个可选的addtivity属性。
name:用来指定受此logger约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
如果未设置此属性,那么当前logger将会继承上级的级别。
-->
<!--
使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
第一种把<root level="INFO">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
第二种就是单独给mapper下目录配置DEBUG模式,代码如下,这样配置sql语句会打印,其他还是正常DEBUG级别:
-->
<!--开发环境:打印控制台-->
<springProfile name="dev">
<!--可以输出项目中的debug日志,包括mybatis的sql日志-->
<logger name="com.guli" level="INFO" />

<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,默认是DEBUG
可以包含零个或多个appender元素。
-->
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
</springProfile>


<!--生产环境:输出到文件-->
<springProfile name="pro">

<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
<appender-ref ref="WARN_FILE" />
</root>
</springProfile>

</configuration>

输出错误日志

在统一异常处理类上添加注释,并且在异常处理的时候调用log.error()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 统一异常处理类
*/
@ControllerAdvice // 增强的controller,可以用于全局异常处理
@Slf4j // 输出错误日志
public class GlobalExceptionHandler {
// 特定异常处理
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public R error(ArithmeticException e) {
e.printStackTrace();
log.error(e.getMessage()); // 将错误日志的内容输出到文件当中
return R.error().message("产生了ArithmeticException异常!");
}
// ……
}

在配置的路径中即可看到日志文件

当前目录结构

image-20210921155023827

service_edu讲师管理模块(后端)

快速前置配置

配置文件application.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 端口号
server.port=8001
# 服务名
spring.application.name=service-edu
# 环境
spring.profiles.active=dev
# mysql数据库信息
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=123456789
# 返回JSON的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

mybatisplus代码生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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、创建代码生成器
AutoGenerator mpg = new AutoGenerator();

// 2、全局配置
GlobalConfig gc = new GlobalConfig();
// String projectPath = System.getProperty("user.dir");
// gc.setOutputDir(projectPath + "/src/main/java");
// 建议写成绝对路径
gc.setOutputDir("D:\\MyProject\\springboot\\guli_parent\\service\\service_edu" + "/src/main/java");

gc.setAuthor("testjava");
gc.setOpen(false); //生成后是否打开资源管理器
gc.setFileOverride(false); //重新生成时文件是否覆盖
gc.setServiceName("%sService"); //去掉Service接口的首字母I

// id类型如果是Long则改为ID_WORKER
gc.setIdType(IdType.ID_WORKER_STR); //主键策略
gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
gc.setSwagger2(true);//开启Swagger2模式

mpg.setGlobalConfig(gc);

// 3、数据源配置
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("123456789");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);

// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("eduservice"); //模块名
pc.setParent("com.atguigu");
pc.setController("controller");
pc.setEntity("entity");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);

// 5、策略配置
StrategyConfig strategy = new StrategyConfig();

strategy.setInclude("edu_teacher"); //加载表

strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀

strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作

strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符

mpg.setStrategy(strategy);


// 6、执行
mpg.execute();
}
}

当前项目结构

image-20210920164803926

创建配置类

配置包扫描等

1
2
3
4
5
6
7
8
9
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 {
}

创建启动类

启动类位置要放在controller、entity等package的同级,然后run即可启动

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
}

}

简单查询所有讲师

编写controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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>
* 讲师 前端控制器
* </p>
*
* @author testjava
* @since 2021-09-20
*/
@RestController
@RequestMapping("/eduservice/edu-teacher")
public class EduTeacherController {

@Autowired
private EduTeacherService teacherService;

// REST风格
// 1、查询讲师表的所有数据
// 地址:localhost:8001//eduservice/edu-teacher/findAll
@GetMapping("findAll")
public List<EduTeacher> findAllTeacher() {
// 调用Service的方法
List<EduTeacher> list = teacherService.list(null);
return list;
}
}

测试

localhost:8001//eduservice/edu-teacher/findAll

逻辑删除讲师

实体类属性添加注解

为EduTeacher实体类添加相应的注释@TableLogic

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

创建mybatisplus配置类

添加逻辑删除插件(注意mybatis版本,低版本是需要添加的,高版本不用,而且TableId自动识别Type AutoGenerator写法也有区别等)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.atguigu.eduservice.config;

import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

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

}

编写controller

注意使用REST风格URI,pathVariable对应路径参数

1
2
3
4
5
6
// 2、逻辑删除讲师
@DeleteMapping("{id}")
public boolean removeTeacher(@PathVariable("id") String id) {
boolean flag = teacherService.removeById(id);
return flag;
}

测试(swagger工具)

整合swagger可以用于接口测试、生成在线接口文档等

分页功能

配置类导入插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Configuration
@MapperScan("com.atguigu.eduservice.mapper")
public class EduConfig {

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

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

}

编写controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 3、分页功能
*
* @param current 当前页
* @param limit 每页记录数
* @return
*/
@GetMapping("pageTeacher/{current}/{limit}")
public R pageListTeacher(@PathVariable long current,
@PathVariable long limit) {
// 创建page对象
Page<EduTeacher> pageTeacher = new Page<>(current, limit);
// 调用方法实现分类
teacherService.page(pageTeacher, null);
long total = pageTeacher.getTotal();
List<EduTeacher> records = pageTeacher.getRecords();
HashMap<String, Object> map = new HashMap<>();
map.put("total", total);
map.put("records", records);
return R.ok().data(map);
}

多条件组合查询分页

创建VO实体对象

把条件值传递到接口里(将条件值封装到VO(ViewObject)实体对象当中,再把对象vo传递到接口中)
浅析VO、DTO、DO、PO的概念、区别和用处_zjrbiancheng的专栏-CSDN博客
实体类(VO,DO,DTO)的划分_xin.wang的博客-CSDN博客

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.atguigu.eduservice.entity.vo;

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

// 条件封装对象
@Data
public class TeacherQuery {

// 一下属性是对应的可被依据的查询条件(注意和表中字段名对应)

@ApiModelProperty(value = "教师名称,模糊查询")
private String name;

@ApiModelProperty(value = "头衔 1高级讲师 2首席讲师")
private Integer level;

@ApiModelProperty(value = "查询开始时间", example = "2019-01-01 10:10:10")
private String begin;//注意,这里使用的是String类型,前端传过来的数据无需进行类型转换

@ApiModelProperty(value = "查询结束时间", example = "2019-12-01 10:10:10")
private String end;

}

编写controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* 4、多条件组合分页
* 参数中可以使用@RequestBody TeacherQuery teacherQuery
* 该注释表示使用JSON格式向后端传递数据,会自动封装到对应对象中,
* 且需要使用POSTMapping才能获取数据,且如果数据有空需要加上(required = false)
*
* @param current 当前页
* @param limit 每页记录数
* @param teacherQuery 条件值(以对象的形式)
* @return
*/
@ApiOperation("多条件组合分页")
@PostMapping("pageTeacherCondition/{current}/{limit}")
public R pageListTeacherCondition(@PathVariable long current,
@PathVariable long limit,
@RequestBody(required = false) TeacherQuery teacherQuery) {
// 创建page对象
Page<EduTeacher> pageTeacher = new Page<>(current, limit);
// 创建wrapper对象
QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();
// 设定条件
String name = teacherQuery.getName();
Integer level = teacherQuery.getLevel();
String begin = teacherQuery.getBegin();
String end = teacherQuery.getEnd();
if (StringUtils.hasLength(name)) {
wrapper.like("name", name);
}
if (level != null) {
wrapper.eq("level", level);
}
if (StringUtils.hasLength(begin)) {
wrapper.ge("gmt_create", begin);
}
if (StringUtils.hasLength(end)) {
wrapper.le("gmt_create", end);
}
// 调用service方法将page对象根据条件分页
teacherService.page(pageTeacher, wrapper);

long total = pageTeacher.getTotal();
List<EduTeacher> records = pageTeacher.getRecords();

return R.ok().data("total", total).data("records", records);
}

添加讲师

实体类属性添加注解

@TableField(fill = FieldFill.xxx)自动填充注解

1
2
3
4
5
6
7
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;

@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;

创建自定义handler类

可以放到service_base模块,然后需要使用导入依赖即可

当对应方法被使用的使用会被调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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) {
this.setFieldValByName("gmtCreate", new Date(), metaObject);
this.setFieldValByName("gmtModified", new Date(), metaObject);
}

@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("gmtModified", new Date(), metaObject);
}
}

注意结构

image-20210921131439930

编写controller

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 5、添加讲师
*
* @param eduTeacher
* @return
*/
@ApiOperation("添加讲师")
@PostMapping("addTeacher")
public R addTeacher(@RequestBody EduTeacher eduTeacher) {
boolean save = teacherService.save(eduTeacher);
return save ? R.ok() : R.error();
}

修改讲师

编写controller

1
2
3
4
5
6
7
8
9
10
11
12
13
@ApiOperation("根据id查询讲师")
@GetMapping("getTeacher/{id}")
public R getTeacher(@PathVariable String id) {
EduTeacher teacher = teacherService.getById(id);
return R.ok().data("teacher", teacher);
}

@ApiOperation("修改讲师")
@PostMapping("updateTeacher")
public R updateTeacher(@RequestBody EduTeacher teacher) {
boolean flag = teacherService.updateById(teacher);
return flag ? R.ok() : R.error();
}

使用@PutMapping如下

1
2
3
4
5
6
7
8
@ApiOperation("修改讲师")
@PutMapping("{id}}")
public R updateTeacher(@PathVariable String id,
@RequestBody EduTeacher teacher) {
teacher.setId(id);
boolean flag = teacherService.updateById(teacher);
return flag ? R.ok() : R.error();
}

待续

评论




🧡💛💚💙💜🖤🤍