Web后端开发---SpringBootWeb案例【5】
一.准备工作
1.1 需求&开发环境
-- 部门管理
create table dept
(
id int unsigned primary key auto_increment comment '主键ID',
name varchar(10) not null unique comment '部门名称',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '部门表';
insert into dept (id, name, create_time, update_time)
values (1, '学工部', now(), now()),
(2, '教研部', now(), now()),
(3, '咨询部', now(), now()),
(4, '就业部', now(), now()),
(5, '人事部', now(), now());
-- 员工管理(带约束)
create table emp
(
id int unsigned primary key auto_increment comment 'ID',
username varchar(20) not null unique comment '用户名',
password varchar(32) default '123456' comment '密码',
name varchar(10) not null comment '姓名',
gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
image varchar(300) comment '图像',
job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
entrydate date comment '入职时间',
dept_id int unsigned comment '部门ID',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间'
) comment '员工表';
INSERT INTO emp
(id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time)
VALUES (1, 'jinyong', '123456', '金庸', 1, '1.jpg', 4, '2000-01-01', 2, now(), now()),
(2, 'zhangwuji', '123456', '张无忌', 1, '2.jpg', 2, '2015-01-01', 2, now(), now()),
(3, 'yangxiao', '123456', '杨逍', 1, '3.jpg', 2, '2008-05-01', 2, now(), now()),
(4, 'weiyixiao', '123456', '韦一笑', 1, '4.jpg', 2, '2007-01-01', 2, now(), now()),
(5, 'changyuchun', '123456', '常遇春', 1, '5.jpg', 2, '2012-12-05', 2, now(), now()),
(6, 'xiaozhao', '123456', '小昭', 2, '6.jpg', 3, '2013-09-05', 1, now(), now()),
(7, 'jixiaofu', '123456', '纪晓芙', 2, '7.jpg', 1, '2005-08-01', 1, now(), now()),
(8, 'zhouzhiruo', '123456', '周芷若', 2, '8.jpg', 1, '2014-11-09', 1, now(), now()),
(9, 'dingminjun', '123456', '丁敏君', 2, '9.jpg', 1, '2011-03-11', 1, now(), now()),
(10, 'zhaomin', '123456', '赵敏', 2, '10.jpg', 1, '2013-09-05', 1, now(), now()),
(11, 'luzhangke', '123456', '鹿杖客', 1, '11.jpg', 5, '2007-02-01', 3, now(), now()),
(12, 'hebiweng', '123456', '鹤笔翁', 1, '12.jpg', 5, '2008-08-18', 3, now(), now()),
(13, 'fangdongbai', '123456', '方东白', 1, '13.jpg', 5, '2012-11-01', 3, now(), now()),
(14, 'zhangsanfeng', '123456', '张三丰', 1, '14.jpg', 2, '2002-08-01', 2, now(), now()),
(15, 'yulianzhou', '123456', '俞莲舟', 1, '15.jpg', 2, '2011-05-01', 2, now(), now()),
(16, 'songyuanqiao', '123456', '宋远桥', 1, '16.jpg', 2, '2007-01-01', 2, now(), now()),
(17, 'chenyouliang', '123456', '陈友谅', 1, '17.jpg', NULL, '2015-03-21', NULL, now(), now());
- pom.xml
<?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.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.itcast</groupId>
<artifactId>tlias-web-management_2013_p1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>tlias-web-management_2013_p1</name>
<description>tlias-web-management_2013_p1</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<!--web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis起步依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--springboot单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
- application.properties
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/tlias
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=123456
#配置mybatis的日志, 指定输出到控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#开启mybatis的驼峰命名自动映射开关 a_column ------> aCloumn
mybatis.configuration.map-underscore-to-camel-case=true
- Dept.java
package com.itcast.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 部门实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
private Integer id; //ID
private String name; //部门名称
private LocalDateTime createTime; //创建时间
private LocalDateTime updateTime; //修改时间
}
- Emp.java
package com.itcast.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 员工实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
private Integer id; //ID
private String username; //用户名
private String password; //密码
private String name; //姓名
private Short gender; //性别 , 1 男, 2 女
private String image; //图像url
private Short job; //职位 , 1 班主任 , 2 讲师 , 3 学工主管 , 4 教研主管 , 5 咨询师
private LocalDate entrydate; //入职日期
private Integer deptId; //部门ID
private LocalDateTime createTime; //创建时间
private LocalDateTime updateTime; //修改时间
}
- Result.java
package com.itcast.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private Integer code;//响应码,1 代表成功; 0 代表失败
private String msg; //响应信息 描述字符串
private Object data; //返回的数据
//增删改 成功响应
public static Result success(){
return new Result(1,"success",null);
}
//查询 成功响应
public static Result success(Object data){
return new Result(1,"success",data);
}
//失败响应
public static Result error(String msg){
return new Result(0,msg,null);
}
}
1.2 开发规范
二.tlias智能学习辅助系统接口文档-V1.0
1. 部门管理
1.1 部门列表查询
1.1.1 基本信息
请求路径:/depts
请求方式:GET
接口描述:该接口用于部门列表数据查询
1.1.2 请求参数
无
1.1.3 响应数据
参数格式:application/json
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
code | number | 必须 | 响应码,1 代表成功,0 代表失败 |
msg | string | 非必须 | 提示信息 |
data | object[ ] | 非必须 | 返回的数据 |
|- id | number | 非必须 | id |
|- name | string | 非必须 | 部门名称 |
|- createTime | string | 非必须 | 创建时间 |
|- updateTime | string | 非必须 | 修改时间 |
响应数据样例:
{
"code": 1,
"msg": "success",
"data": [
{
"id": 1,
"name": "学工部",
"createTime": "2022-09-01T23:06:29",
"updateTime": "2022-09-01T23:06:29"
},
{
"id": 2,
"name": "教研部",
"createTime": "2022-09-01T23:06:29",
"updateTime": "2022-09-01T23:06:29"
}
]
}
1.2 删除部门
1.2.1 基本信息
请求路径:/depts/{id}
请求方式:DELETE
接口描述:该接口用于根据ID删除部门数据
1.2.2 请求参数
参数格式:路径参数
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
id | number | 必须 | 部门ID |
请求参数样例:
/depts/1
1.2.3 响应数据
参数格式:application/json
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
code | number | 必须 | 响应码,1 代表成功,0 代表失败 |
msg | string | 非必须 | 提示信息 |
data | object | 非必须 | 返回的数据 |
响应数据样例:
{
"code":1,
"msg":"success",
"data":null
}
1.3 添加部门
1.3.1 基本信息
请求路径:/depts
请求方式:POST
接口描述:该接口用于添加部门数据
1.3.2 请求参数
格式:application/json
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
name | string | 必须 | 部门名称 |
请求参数样例:
{
"name": "教研部"
}
1.3.3 响应数据
参数格式:application/json
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
code | number | 必须 | 响应码,1 代表成功,0 代表失败 |
msg | string | 非必须 | 提示信息 |
data | object | 非必须 | 返回的数据 |
响应数据样例:
{
"code":1,
"msg":"success",
"data":null
}
1.4 根据ID查询
1.4.1 基本信息
请求路径:/depts/{id}
请求方式:GET
接口描述:该接口用于根据ID查询部门数据
1.4.2 请求参数
参数格式:路径参数
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
id | number | 必须 | 部门ID |
请求参数样例:
/depts/1
1.4.3 响应数据
参数格式:application/json
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
code | number | 必须 | 响应码,1 代表成功,0 代表失败 |
msg | string | 非必须 | 提示信息 |
data | object | 非必须 | 返回的数据 |
|- id | number | 非必须 | id |
|- name | string | 非必须 | 部门名称 |
|- createTime | string | 非必须 | 创建时间 |
|- updateTime | string | 非必须 | 修改时间 |
响应数据样例:
{
"code": 1,
"msg": "success",
"data": {
"id": 1,
"name": "学工部",
"createTime": "2022-09-01T23:06:29",
"updateTime": "2022-09-01T23:06:29"
}
}
1.5 修改部门
1.5.1 基本信息
请求路径:/depts
请求方式:PUT
接口描述:该接口用于修改部门数据
1.5.2 请求参数
格式:application/json
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
id | number | 必须 | 部门ID |
name | string | 必须 | 部门名称 |
请求参数样例:
{
"id": 1,
"name": "教研部"
}
1.5.3 响应数据
参数格式:application/json
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
code | number | 必须 | 响应码,1 代表成功,0 代表失败 |
msg | string | 非必须 | 提示信息 |
data | object | 非必须 | 返回的数据 |
响应数据样例:
{
"code":1,
"msg":"success",
"data":null
}
2. 员工管理
2.1 员工列表查询
2.1.1 基本信息
请求路径:/emps
请求方式:GET
接口描述:该接口用于员工列表数据的条件分页查询
2.1.2 请求参数
参数格式:queryString
参数说明:
参数名称 | 是否必须 | 示例 | 备注 |
---|---|---|---|
name | 否 | 张 | 姓名 |
gender | 否 | 1 | 性别 , 1 男 , 2 女 |
begin | 否 | 2010-01-01 | 范围匹配的开始时间(入职日期) |
end | 否 | 2020-01-01 | 范围匹配的结束时间(入职日期) |
page | 是 | 1 | 分页查询的页码,如果未指定,默认为1 |
pageSize | 是 | 10 | 分页查询的每页记录数,如果未指定,默认为10 |
请求数据样例:
/emps?name=张&gender=1&begin=2007-09-01&end=2022-09-01&page=1&pageSize=10
2.1.3 响应数据
参数格式:application/json
参数说明:
名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
---|---|---|---|---|---|
code | number | 必须 | 响应码, 1 成功 , 0 失败 | ||
msg | string | 非必须 | 提示信息 | ||
data | object | 必须 | 返回的数据 | ||
|- total | number | 必须 | 总记录数 | ||
|- rows | object [] | 必须 | 数据列表 | item 类型: object | |
|- id | number | 非必须 | id | ||
|- username | string | 非必须 | 用户名 | ||
|- name | string | 非必须 | 姓名 | ||
|- password | string | 非必须 | 密码 | ||
|- entrydate | string | 非必须 | 入职日期 | ||
|- gender | number | 非必须 | 性别 , 1 男 ; 2 女 | ||
|- image | string | 非必须 | 图像 | ||
|- job | number | 非必须 | 职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师 | ||
|- deptId | number | 非必须 | 部门id | ||
|- createTime | string | 非必须 | 创建时间 | ||
|- updateTime | string | 非必须 | 更新时间 |
响应数据样例:
{
"code": 1,
"msg": "success",
"data": {
"total": 2,
"rows": [
{
"id": 1,
"username": "jinyong",
"password": "123456",
"name": "金庸",
"gender": 1,
"image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-02-00-27-53B.jpg",
"job": 2,
"entrydate": "2015-01-01",
"deptId": 2,
"createTime": "2022-09-01T23:06:30",
"updateTime": "2022-09-02T00:29:04"
},
{
"id": 2,
"username": "zhangwuji",
"password": "123456",
"name": "张无忌",
"gender": 1,
"image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-02-00-27-53B.jpg",
"job": 2,
"entrydate": "2015-01-01",
"deptId": 2,
"createTime": "2022-09-01T23:06:30",
"updateTime": "2022-09-02T00:29:04"
}
]
}
}
2.2 删除员工
2.2.1 基本信息
请求路径:/emps/{ids}
请求方式:DELETE
接口描述:该接口用于批量删除员工的数据信息
2.2.2 请求参数
参数格式:路径参数
参数说明:
参数名 | 类型 | 示例 | 是否必须 | 备注 |
---|---|---|---|---|
ids | 数组 array | 1,2,3 | 必须 | 员工的id数组 |
请求参数样例:
/emps/1,2,3
2.2.3 响应数据
参数格式:application/json
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
code | number | 必须 | 响应码,1 代表成功,0 代表失败 |
msg | string | 非必须 | 提示信息 |
data | object | 非必须 | 返回的数据 |
响应数据样例:
{
"code":1,
"msg":"success",
"data":null
}
2.3 添加员工
2.3.1 基本信息
请求路径:/emps
请求方式:POST
接口描述:该接口用于添加员工的信息
2.3.2 请求参数
参数格式:application/json
参数说明:
名称 | 类型 | 是否必须 | 备注 |
---|---|---|---|
username | string | 必须 | 用户名 |
name | string | 必须 | 姓名 |
gender | number | 必须 | 性别, 说明: 1 男, 2 女 |
image | string | 非必须 | 图像 |
deptId | number | 非必须 | 部门id |
entrydate | string | 非必须 | 入职日期 |
job | number | 非必须 | 职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师 |
请求数据样例:
{
"image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-03-07-37-38222.jpg",
"username": "linpingzhi",
"name": "林平之",
"gender": 1,
"job": 1,
"entrydate": "2022-09-18",
"deptId": 1
}
2.3.3 响应数据
参数格式:application/json
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
code | number | 必须 | 响应码,1 代表成功,0 代表失败 |
msg | string | 非必须 | 提示信息 |
data | object | 非必须 | 返回的数据 |
响应数据样例:
{
"code":1,
"msg":"success",
"data":null
}
2.4 根据ID查询
2.4.1 基本信息
请求路径:/emps/{id}
请求方式:GET
接口描述:该接口用于根据主键ID查询员工的信息
2.4.2 请求参数
参数格式:路径参数
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
id | number | 必须 | 部门ID |
请求参数样例:
/emps/1
2.4.3 响应数据
参数格式:application/json
参数说明:
名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
---|---|---|---|---|---|
code | number | 必须 | 响应码, 1 成功 , 0 失败 | ||
msg | string | 非必须 | 提示信息 | ||
data | object | 必须 | 返回的数据 | ||
|- id | number | 非必须 | id | ||
|- username | string | 非必须 | 用户名 | ||
|- name | string | 非必须 | 姓名 | ||
|- password | string | 非必须 | 密码 | ||
|- entrydate | string | 非必须 | 入职日期 | ||
|- gender | number | 非必须 | 性别 , 1 男 ; 2 女 | ||
|- image | string | 非必须 | 图像 | ||
|- job | number | 非必须 | 职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师 | ||
|- deptId | number | 非必须 | 部门id | ||
|- createTime | string | 非必须 | 创建时间 | ||
|- updateTime | string | 非必须 | 更新时间 |
响应数据样例:
{
"code": 1,
"msg": "success",
"data": {
"id": 2,
"username": "zhangwuji",
"password": "123456",
"name": "张无忌",
"gender": 1,
"image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-02-00-27-53B.jpg",
"job": 2,
"entrydate": "2015-01-01",
"deptId": 2,
"createTime": "2022-09-01T23:06:30",
"updateTime": "2022-09-02T00:29:04"
}
}
2.5 修改员工
2.5.1 基本信息
请求路径:/emps
请求方式:PUT
接口描述:该接口用于修改员工的数据信息
2.5.2 请求参数
参数格式:application/json
参数说明:
名称 | 类型 | 是否必须 | 备注 |
---|---|---|---|
id | number | 必须 | id |
username | string | 必须 | 用户名 |
name | string | 必须 | 姓名 |
gender | number | 必须 | 性别, 说明: 1 男, 2 女 |
image | string | 非必须 | 图像 |
deptId | number | 非必须 | 部门id |
entrydate | string | 非必须 | 入职日期 |
job | number | 非必须 | 职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师 |
请求数据样例:
{
"id": 1,
"image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-03-07-37-38222.jpg",
"username": "linpingzhi",
"name": "林平之",
"gender": 1,
"job": 1,
"entrydate": "2022-09-18",
"deptId": 1
}
2.5.3 响应数据
参数格式:application/json
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
code | number | 必须 | 响应码,1 代表成功,0 代表失败 |
msg | string | 非必须 | 提示信息 |
data | object | 非必须 | 返回的数据 |
响应数据样例:
{
"code":1,
"msg":"success",
"data":null
}
2.6 文件上传
2.6.1 基本信息
请求路径:/upload
请求方式:POST
接口描述:上传图片接口
2.6.2 请求参数
参数格式:multipart/form-data
参数说明:
参数名称 | 参数类型 | 是否必须 | 示例 | 备注 |
---|---|---|---|---|
image | file | 是 |
2.6.3 响应数据
参数格式:application/json
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
---|---|---|---|
code | number | 必须 | 响应码,1 代表成功,0 代表失败 |
msg | string | 非必须 | 提示信息 |
data | object | 非必须 | 返回的数据,上传图片的访问路径 |
响应数据样例:
{
"code": 1,
"msg": "success",
"data": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-02-00-27-0400.jpg"
}
3. 其他接口
3.1 登录
3.1.1 基本信息
请求路径:/login
请求方式:POST
接口描述:该接口用于员工登录Tlias智能学习辅助系统,登录完毕后,系统下发JWT令牌。
3.1.2 请求参数
参数格式:application/json
参数说明:
名称 | 类型 | 是否必须 | 备注 |
---|---|---|---|
username | string | 必须 | 用户名 |
password | string | 必须 | 密码 |
请求数据样例:
{
"username": "jinyong",
"password": "123456"
}
3.1.3 响应数据
参数格式:application/json
参数说明:
名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
---|---|---|---|---|---|
code | number | 必须 | 响应码, 1 成功 ; 0 失败 | ||
msg | string | 非必须 | 提示信息 | ||
data | string | 必须 | 返回的数据 , jwt令牌 |
响应数据样例:
{
"code": 1,
"msg": "success",
"data": "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi6YeR5bq4IiwiaWQiOjEsInVzZXJuYW1lIjoiamlueW9uZyIsImV4cCI6MTY2MjIwNzA0OH0.KkUc_CXJZJ8Dd063eImx4H9Ojfrr6XMJ-yVzaWCVZCo"
}
3.1.4 备注说明
用户登录成功后,系统会自动下发JWT令牌,然后在后续的每次请求中,都需要在请求头header中携带到服务端,请求头的名称为 token ,值为 登录时下发的JWT令牌。
如果检测到用户未登录,则会返回如下固定错误信息:
{ "code": 0, "msg": "NOT_LOGIN", "data": null }
三.部门管理
3.1 查询部门
- DeptController.java
/**
* 部门管理Controller
*/
@Slf4j
@RestController
public class DeptController {
//获取日志记录对象
//private static Logger logger = LoggerFactory.getLogger(DeptController.class);
@Autowired //注入
private DeptService deptService;
/**
* 部门列表数据查询
*
* @return
*/
//@RequestMapping(value = "/depts",method = RequestMethod.GET) //指定请求方式为get
@GetMapping("/depts")
public Result list() {
//logger.info("查询部门全部数据");
log.info("查询部门全部数据");
//调用service查询部门数据
List<Dept> deptList = deptService.list();
return Result.success(deptList);
}
}
- DeptService.java
/**
* 部门管理
*/
public interface DeptService {
/**
* 查询部门全部数据
* @return
*/
List<Dept> list();
}
- DeptServiceImpl.java
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Override
public List<Dept> list() {
return deptMapper.list();
}
}
- DeptMapper.java
/**
* 部门管理
*/
@Mapper
public interface DeptMapper {
/**
* 查询部门全部数据
* @return
*/
@Select("select * from dept")
List<Dept> list();
}
3.2 前后端联调
3.3 删除部门
@Mapper
public interface DeptMapper {
/**
* 根据id删除部门
* @param id
*/
@Delete("delete from dept where id = #{id}")
void deleteById(Integer id);
}
@Service
public class DeptServiceImpl implements DeptService {
@Override
public void delete(Integer id) {
deptMapper.deleteById(id);
}
}
public interface DeptService {
/**
* 删除部门
* @param id
*/
void delete(Integer id);
}
@Slf4j
@RestController
public class DeptController {
@Autowired //注入
private DeptService deptService;
/**
* 删除部门
* @return
*/
@DeleteMapping("/depts/{id}")
public Result delete(@PathVariable Integer id){
log.info("根据id删除部门:{}",id);
//调用service根据id删除部门
deptService.delete(id);
return Result.success();
}
}
3.4 新增部门
/**
* 新增部门
* @param dept 部门接收JSON数据
* @return
*/
@PostMapping("/depts")
public Result add(@RequestBody Dept dept){
log.info("新增部门:{}", dept);
//调用service新增部门
deptService.add(dept);
return Result.success();
}
/**
* 新增部门
* @param dept
*/
void add(Dept dept);
@Override
public void add(Dept dept) {
dept.setCreateTime(LocalDateTime.now());
dept.setUpdateTime(LocalDateTime.now());
deptMapper.insert(dept);
}
/**
* 新增部门信息
* @param dept
*/
@Insert("insert into dept (name, create_time,update_time) values (#{name},#{createTime},#{updateTime})")
void insert(Dept dept);
3.5 修改部门
/**
* 根据id查询部门数据
* @param id
* @return
*/
@GetMapping("/{id}")
public Result getDeptById(@PathVariable Integer id) {
log.info("根据id查询部门数据:{}", id);
//调用service根据id查询部门
Dept dept = deptService.getDeptById(id);
return Result.success(dept);
}
/**
* 修改部门
*
* @param dept
* @return
*/
@PutMapping
public Result update(@RequestBody Dept dept) {
log.info("根据id修改部门:{}", dept);
//调用service的更新部门
deptService.updateDeptById(dept);
return Result.success();
}
/**
* 根据id查询部门
*
* @param id
* @return
*/
Dept getDeptById(Integer id);
/**
* 更新部门
*
* @param dept
*/
void updateDeptById(Dept dept);
@Override
public Dept getDeptById(Integer id) {
return deptMapper.getById(id);
}
@Override
public void updateDeptById(Dept dept) {
dept.setUpdateTime(LocalDateTime.now());
deptMapper.updateById(dept);
}
/**
* 根据id查询部门
*
* @param id
* @return
*/
@Select("select * from dept where id = #{id}")
Dept getById(Integer id);
/**
* 更新部门
*
* @param dept
*/
@Update("update dept set name = #{name},update_time = #{updateTime} where id=#{id}")
void updateById(Dept dept);
3.6 小结
四.员工管理
4.1 分页查询
-- 分页查询语法
-- 参数1:起始索引 = (页码 - 1) * 每页展示的记录数
-- 参数2:查询返回记录数 = 每页展示的记录数
select * from emp limit 0,5;
-- 查询第一页数据,每页展示5条记录;
select * from emp limit 0,5;
-- 查询第二页数据,每页展示5条记录;
select * from emp limit 5,5;
-- 查询第二页数据,每页展示5条记录;
select * from emp limit 10,5;
-- 获取总记录数
select count(*) from emp;
代码
- PageBean.java
/**
* 分页查询结果的封装类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean {
private Long total;//总记录数
private List rows;//数据列表
}
- EmpMapper.java
/**
* 员工管理
*/
@Mapper
public interface EmpMapper {
/**
* 查询总记录数
*
* @return
*/
@Select("select count(*) from emp")
public Long count();
/**
* 分页查询获取列表数据的方法
* @param start
* @param pageSize
* @return
*/
@Select("select * from emp limit #{start},#{pageSize}")
public List<Emp> page(Integer start, Integer pageSize);
}
- EmpController.java
/**
* 员工管理Controller
*/
@Slf4j
@RestController
@RequestMapping("/emps")
public class EmpController {
@Autowired
private EmpService empService;
/**
* 分页查询
* @param page
* @param pageSize
* @return
*/
@GetMapping
public Result page(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize) {
log.info("分页查询,参数:{},{}", page, pageSize);
//调用service分页查询
PageBean pageBean = empService.page(page, pageSize);
return Result.success(pageBean);
}
}
- EmpService.java
/**
* 员工管理
*/
public interface EmpService {
/**
* 分页查询
* @param page
* @param pageSize
* @return
*/
PageBean page(Integer page, Integer pageSize);
}
- EmpServiceImpl.java
@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
@Override
public PageBean page(Integer page, Integer pageSize) {
//1.获取总记录数
Long count = empMapper.count();
//2.获取分页查询的列表
Integer start = (page - 1) * pageSize;
List<Emp> empList = empMapper.page(start, pageSize);
//3.封装pageBean对象
PageBean pageBean = new PageBean(count,empList);
return pageBean;
}
}
@RequestParam defaultValue
小结
分页插件PageHelper
<!--pagehelper分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>
/**
* 员工管理
*/
@Mapper
public interface EmpMapper {
/**
* 员工信息查询
* @return
*/
@Select("select * from emp")
public List<Emp> list();
}
@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
@Override
public PageBean page(Integer page, Integer pageSize) {
//1.设置分页操作
PageHelper.startPage(page, pageSize);
//2.执行查询
List<Emp> empList = empMapper.list();
Page<Emp> p = (Page<Emp>) empList;
//3.封装pageBean对象
PageBean pageBean = new PageBean(p.getTotal(), p.getResult());
return pageBean;
}
}
4.2 条件分页查询(带条件)
-- 条件查询员工 - 姓名、性别、入职时间
select *
from emp
where name like concat('%', '张', '%')
and gender = 1
and entrydate between '2000-01-01' and '2020-01-01'
order by update_time desc;
/**
* 分页查询
*
* @param page
* @param pageSize
* @return
*/
@GetMapping
public Result page(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize,
String name, Short gender,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
log.info("分页查询,参数:{},{},{},{},{},{}", page, pageSize, name, gender, begin, end);
//调用service分页查询
PageBean pageBean = empService.page(page, pageSize, name, gender, begin, end);
return Result.success(pageBean);
}
@Override
public PageBean page(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {
//1.设置分页操作
PageHelper.startPage(page, pageSize);
//2.执行查询
List<Emp> empList = empMapper.list(name, gender, begin, end);
Page<Emp> p = (Page<Emp>) empList;
//3.封装pageBean对象
PageBean pageBean = new PageBean(p.getTotal(), p.getResult());
return pageBean;
}
/**
* 员工信息查询
* @return
*/
//@Select("select * from emp")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itcast.mapper.EmpMapper">
<!--条件查询-->
<select id="list" resultType="com.itcast.pojo.Emp">
select *
from emp
<where>
<if test="name != null and name != ''">
name like concat('%', #{name}, '%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>
</mapper>
4.3 删除员工
@DeleteMapping("/{ids}")
public Result delete(@PathVariable List<Integer> ids) { //PathVariable:路径参数
log.info("批量删除员工,参数ids:{}", ids);
//调用service删除员工
empService.delete(ids);
return Result.success();
}
/**
* 批量删除员工操作
* @param ids
*/
void delete(List<Integer> ids);
@Override
public void delete(List<Integer> ids) {
empMapper.delete(ids);
}
/**
* 批量删除员工操作
* @param ids
*/
void delete(List<Integer> ids);
<!--批量删除员工的操作-->
<delete id="delete">
delete
from emp
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
4.4 新增员工
@PostMapping
public Result save(@RequestBody Emp emp){
log.info("新增员工,emp:{}", emp);
empService.save(emp);
return Result.success();
}
/**
* 新增员工
* @param emp
*/
void save(Emp emp);
@Override
public void save(Emp emp) {
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
empMapper.insert(emp);
}
/**
* 新增员工
*
* @param emp
*/
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)" +
"values (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
void insert(Emp emp);
{
"image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-03-07-37-38222.jpg",
"username": "linpingzhi",
"name": "林平之",
"gender": 1,
"job": 1,
"entrydate": "2022-09-18",
"deptId": 1
}
4.5 文件上传
简介
@Slf4j
@RestController
public class UploadController {
@PostMapping("/upload")
public Result upload(String username, Integer age, MultipartFile image) {
log.info("文件上传:{},{},{}", username, age, image);
return Result.success();
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
姓名: <input type="text" name="username"><br>
年龄: <input type="text" name="age"><br>
头像: <input type="file" name="image"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
本地存储
@Slf4j
@RestController
public class UploadController {
@PostMapping("/upload")
public Result upload(String username, Integer age, MultipartFile image) throws Exception {
log.info("文件上传:{},{},{}", username, age, image);
//获取原始文件名
String originalFilename = image.getOriginalFilename();
log.info("原始文件名:{}", originalFilename);
//构造唯一的文件名(不能重复) - uuid(通用唯一识别码) c6b09b01-f7c6-42e2-9917-e3bc51bc72ec
int index = originalFilename.lastIndexOf(".");
String extname = originalFilename.substring(index);
String newFileName = UUID.randomUUID().toString() + extname;
log.info("新的文件名:{}", newFileName);
//将接收到在服务器的磁盘目录 D:\images
image.transferTo(new File("D:\\images\\" + newFileName));
return Result.success();
}
}
阿里云OSS–集成
<!--阿里云OSS云存储-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import java.io.FileInputStream;
import java.io.InputStream;
public class AliOssTest {
public static void main(String[] args) throws Exception {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
//EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
//打开CMD
//set OSS_ACCESS_KEY_ID=LTAI4GDty8ab9W4Y1D****
//set OSS_ACCESS_KEY_SECRET=IrVTNZNy5yQelTETg0cZML3TQn****
// String accessKeyId = "";
// String accessKeySecret = "";
// EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newDefaultCredentialProvider();
// 嵌入代码
// RAM用户的访问密钥(AccessKey ID和AccessKey Secret)。注意修改xxx的值
String accessKeyId = "LTAI5tKyzrTK3ooL4jBSuNqY";
String accessKeySecret = "lqn8XufEwjCmbYZLPG1IAgdiH10fp1";
// 使用代码嵌入的RAM用户的访问密钥配置访问凭证。
CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
// 填写Bucket名称,例如examplebucket。
String bucketName = "web-tlias-20231216";
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
String objectName = "file/20231216.jpg";
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
String filePath= "C:\\Users\\64935\\Desktop\\壁纸\\1.jpg";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
try {
InputStream inputStream = new FileInputStream(filePath);
// 创建PutObjectRequest对象。
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
// 创建PutObject请求。
PutObjectResult result = ossClient.putObject(putObjectRequest);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}
- AliOSSUtils【阿里云 OSS 工具类】
/**
* 阿里云 OSS 工具类
*/
@Slf4j
@Component
public class AliOSSUtils {
private String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
private String accessKeyId = "LTAI5tKyzrTK3ooL4jBSuNqY";
private String accessKeySecret = "lqn8XufEwjCmbYZLPG1IAgdiH10fp1";
private String bucketName = "web-tlias-20231216";
/**
* 实现上传图片到OSS
*/
public String upload(MultipartFile file) throws IOException {
// 获取上传的文件的输入流
InputStream inputStream = file.getInputStream();
// 避免文件覆盖
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
log.info("文件的原始名字为:{}", originalFilename);
log.info("上传文件的名字为:{}", fileName);
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ossClient.putObject(bucketName, fileName, inputStream);
//文件访问路径
String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
log.info("文件访问路径:{}", url);
// 关闭ossClient
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
}
- UploadController
@Slf4j
@RestController
public class UploadController {
@Autowired
private AliOSSUtils aliOSSUtils;
@PostMapping("/upload")
public Result upload(MultipartFile image) throws IOException {
log.info("文件上传,文件名:{}", image.getOriginalFilename());
//调用阿里云OSS工具类进行文件上传
String url = aliOSSUtils.upload(image);
log.info("文件上传完成,文件访问的url:{}", url);
return Result.success(url);
}
}
4.6 修改员工
查询回显
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {
log.info("根据id查询员工信息:{}", id);
Emp emp = empService.getById(id);
return Result.success(emp);
}
/**
* 根据ID查询员工
* @param id
* @return
*/
Emp getById(Integer id);
@Override
public Emp getById(Integer id) {
return empMapper.getById(id);
}
/**
* 根据ID查询员工
* @param id
* @return
*/
@Select("select * from emp where id = #{id}")
Emp getById(Integer id);
修改员工
@PutMapping
public Result update(@RequestBody Emp emp) {
log.info("更新员工信息:{}", emp);
empService.update(emp);
return Result.success();
}
/**
* 更新员工
* @param emp
*/
void update(Emp emp);
@Override
public void update(Emp emp) {
emp.setUpdateTime(LocalDateTime.now());
empMapper.update(emp);
}
/**
* 更新员工
* @param emp
*/
void update(Emp emp);
<!--更新员工-->
<update id="update">
update emp
<set>
<if test="username!=null and username!=''">
username = #{username},
</if>
<if test="password!=null and password!=''">
password = #{password},
</if>
<if test="name!=null and name!=''">
name = #{name},
</if>
<if test="gender!=null">
gender = #{gender},
</if>
<if test="image!=null and image!=''">
image = #{image},
</if>
<if test="job!=null">
job = #{job},
</if>
<if test="entrydate!=null">
entrydate = #{entrydate},
</if>
<if test="deptId!=null">
dept_id = #{deptId},
</if>
<if test="updateTime!=null">
update_time=#{updateTime}
</if>
</set>
where id = #{id};
</update>
4.7 配置文件
参数配置化
yml配置文件
server:
port: 9000
#定义对象/Map集合
user:
name: Tom
age: 20
address: beijing
#数组/List/Set集合
hobby:
- Java
- Python
- C
- C++
- html
- css
- web
spring:
#数据库连接信息
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/tlias
username: root
password: 123456
#文件上传的配置
servlet:
multipart:
max-file-size: 10MB
max-request-size: 100MB
#Mybatis配置
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
#阿里云OSS
aliyun:
oss:
endpoint: https://oss-cn-hangzhou.aliyuncs.com
accessKeyId: ****************
accessKeySecret: *************
bucketName: web-tlias-20231216
@ConfigurationProperties
- application.yml
#阿里云OSS
aliyun:
oss:
endpoint: https://oss-cn-hangzhou.aliyuncs.com
accessKeyId: ****************************
accessKeySecret: ****************************
bucketName: web-tlias-20231216
- AliOSSProperties.java
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}
- AliOSSUtils.java
/**
* 阿里云 OSS 工具类
*/
@Slf4j
@Component
public class AliOSSUtils {
@Autowired
private AliOSSProperties aliOSSProperties;
/**
* 实现上传图片到OSS
*/
public String upload(MultipartFile file) throws IOException {
//获取阿里云OSS参数
String endpoint = aliOSSProperties.getEndpoint();
String accessKeyId = aliOSSProperties.getAccessKeyId();
String accessKeySecret = aliOSSProperties.getAccessKeySecret();
String bucketName = aliOSSProperties.getBucketName();
// 获取上传的文件的输入流
InputStream inputStream = file.getInputStream();
// 避免文件覆盖
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
log.info("文件的原始名字为:{}", originalFilename);
log.info("上传文件的名字为:{}", fileName);
//fileName上传到OSS指定文件目录
fileName = "tlias" + "/" + fileName;
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ossClient.putObject(bucketName, fileName, inputStream);
//文件访问路径
String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
log.info("文件访问路径:{}", url);
// 关闭ossClient
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
}
- 另一种
- oss.properties
##阿里云OSS配置
aliyun.oss.endpoint=https://oss-cn-hangzhou.aliyuncs.com
aliyun.oss.accessKeyId=****************************
aliyun.oss.accessKeySecret=****************************
aliyun.oss.bucketName=web-tlias-20231216
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Data
@Component
@PropertySource("classpath:oss.properties")//读取阿里云配置文件
@ConfigurationProperties(prefix = "aliyun.oss")//读取oss节点
public class AliOSSProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}
4.8 解除配置文件警告信息–提示配置信息
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
4.9 @ConfigurationProperties与@value
@Data
@Component
@PropertySource("classpath:oss.properties")//读取阿里云配置文件
@ConfigurationProperties(prefix = "aliyun.oss")//读取oss节点
public class AliOSSProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}
@Value("${aliyun.oss.endpoint}")
private String endpoint;
@Value("${aliyun.oss.accessKeyId}")
private String accessKeyId;
@Value("${aliyun.oss.accessKeySecret}")
private String accessKeySecret;
@Value("${aliyun.oss.bucketName}")
private String bucketName;
五、Spring Boot整合swagger使用教程
5.1 添加依赖包
- pom.xml
<!--swagger 相关依赖-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-spring-web</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!--Swagger ui,展示接口文档和测试页面-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
5.2 编写配置信息
- SwaggerConfig.java
@Configuration //标明配置类
@EnableSwagger2 //开启 Swagger2 的自动配置功能
//启动下服务,输入:http://localhost:8080/swagger-ui.html# 即可查看Swagger文档
public class SwaggerConfig {
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder().title("tlias智能学习辅助系统").build());
}
}
@Configuration // 标明是配置类
@EnableSwagger2 //开启swagger功能
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2) // DocumentationType.SWAGGER_2 固定的,代表swagger2
// .groupName("分布式任务系统") // 如果配置多个文档的时候,那么需要配置groupName来分组标识
.apiInfo(apiInfo()) // 用于生成API信息
.select() // select()函数返回一个ApiSelectorBuilder实例,用来控制接口被swagger做成文档
.apis(RequestHandlerSelectors.basePackage("com.itcast.controller")) // 用于指定扫描哪个包下的接口
.paths(PathSelectors.any())// 选择所有的API,如果你想只为部分API生成文档,可以配置这里
.build();
}
/**
* 用于定义API主界面的信息,比如可以声明所有的API的总标题、描述、版本
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("XX项目API") // 可以用来自定义API的主标题
.description("XX项目SwaggerAPI管理") // 可以用来描述整体的API
.termsOfServiceUrl("") // 用于定义服务的域名
.version("1.0") // 可以用来定义版本。
.build(); //
}
}
@Bean
public Docket docket() {
// 创建一个 swagger 的 bean 实例
return new Docket(DocumentationType.SWAGGER_2)
//配置基本信息
.apiInfo(apiInfo())
// 配置接口信息
.select() // 设置扫描接口
// 配置如何扫描接口
.apis(RequestHandlerSelectors
//.any() // 扫描全部的接口,默认
//.none() // 全部不扫描
.basePackage("com.swagger.controller") // 扫描指定包下的接口,最为常用
//.withClassAnnotation(RestController.class) // 扫描带有指定注解的类下所有接口
//.withMethodAnnotation(PostMapping.class) // 扫描带有只当注解的方法接口
)
.paths(PathSelectors
.any() // 满足条件的路径,该断言总为true
//.none() // 不满足条件的路径,该断言总为false(可用于生成环境屏蔽 swagger)
//.ant("/user/**") // 满足字符串表达式路径
//.regex("") // 符合正则的路径
)
.build();
}
5.3 解决问题
不能调用"org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()“,因为"this.condition”为null
这个问题是由SpringBoot2.6中引入的新PathPatternParser引起的
- application.yaml
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
5.4 定义接口组
@Api(tags = "用户管理") // tags:你可以当作是这个组的名字。
@RestController
public class UserController {
}
@ApiOperation(value = "用户测试",notes = "用户测试notes")
@GetMapping("/test")
public String test(String id){
return "test";
}
常用配置项:
value:可以当作是接口的简称
notes:接口的描述
tags:可以额外定义接口组,比如这个接口外层已经有@Api(tags = "用户管理")
,将接口划分到了“用户管理”中,但你可以额外的使用tags,例如tags = "角色管理"
让角色管理中也有这个接口文档。
六、登录认证
6.1 登录功能
- LoginController.java
@Slf4j
@RestController
@Api(value = "登录")
public class LoginController {
@Autowired
private EmpService empService;
@PostMapping("/login")
public Result login(@RequestBody Emp emp) {
log.info("员工登录:{}", emp);
Emp e = empService.login(emp);
return e != null ? Result.success() : Result.error("用户名或者密码错误");
}
}
/**
* 员工登录操作
*
* @param emp
* @return
*/
Emp login(Emp emp);
@Override
public Emp login(Emp emp) {
return empMapper.getByUsernameAndPassword(emp);
}
/**
* 根据用户名和密码查询员工
*
* @param emp
* @return
*/
@Select("select * from emp where username = #{username} and password = #{password}")
Emp getByUsernameAndPassword(Emp emp);
6.2 登录校验(重点)
会话技术
- SessionController.java
/**
* Cookie , HttpSession演示
*/
@Slf4j
@RestController
@Api(value = "Cookie , HttpSession演示")
public class SessionController {
//设置Cookie
@GetMapping("/c1")
public Result cookie1(HttpServletResponse response) {
response.addCookie(new Cookie("login_username", "itcast")); // 设置Cookie/响应Cookie
return Result.success();
}
//获取Cookie
@GetMapping("/c2")
public Result cookie2(HttpServletRequest request) {
Cookie[] cookies = request.getCookies(); // 获取所有的Cookie
for (Cookie cookie : cookies) {
if (cookie.getName().equals("login_username")) { // 输出name为login_username 的 cookie
System.out.println("login_username" + cookie.getValue());
}
}
return Result.success();
}
}
- SessionController.java
/**
* Cookie , HttpSession演示
*/
@Slf4j
@RestController
@Api(value = "Cookie , HttpSession演示")
public class SessionController {
//设置Cookie
@GetMapping("/c1")
public Result cookie1(HttpServletResponse response) {
response.addCookie(new Cookie("login_username", "itcast")); // 设置Cookie/响应Cookie
return Result.success();
}
//获取Cookie
@GetMapping("/c2")
public Result cookie2(HttpServletRequest request) {
Cookie[] cookies = request.getCookies(); // 获取所有的Cookie
for (Cookie cookie : cookies) {
if (cookie.getName().equals("login_username")) { // 输出name为login_username 的 cookie
System.out.println("login_username:" + cookie.getValue());
}
}
return Result.success();
}
//往HttpSession中存储值
@GetMapping("/s1")
public Result session1(HttpSession session) {
log.info("HttpSession-s1:{}", session.hashCode());
session.setAttribute("loginUser", "tom");//往seeion中存储数据
return Result.success();
}
//往HttpSession中获取值
@GetMapping("/s2")
public Result session2(HttpServletRequest request) {
HttpSession session = request.getSession();
log.info("HttpSession-s2:{}", session.hashCode());
Object loginUser = session.getAttribute("loginUser"); //从session中获取数据
log.info("loginUser:{}", loginUser);
return Result.success(loginUser);
}
}
JWT令牌
<!--JWT令牌-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
- JwtTest.java
public class JwtTest {
/**
* 生成JWT
*/
@Test
public void testGenJwt() {
Map<String, Object> claims = new HashMap<>();
claims.put("id", 1);
claims.put("username", "Tom");
String jwt = Jwts.builder()
.signWith(SignatureAlgorithm.HS256, "itcast") //签名算法
.setClaims(claims) //自定义内容(载荷)
.setExpiration(new Date(System.currentTimeMillis() + 12 * 3600 * 1000)) // 设置有效期为12小时
.compact();
System.out.println(jwt);
}
/**
* 解析JWT
*/
@Test
public void testParseJwt() {
Claims claims = Jwts.parser()
.setSigningKey("itcast") //指定签名秘钥
.parseClaimsJws(getJwt()) //解析令牌
.getBody();
System.out.println(claims);
}
public String getJwt() {
Map<String, Object> claims = new HashMap<>();
claims.put("id", 1);
claims.put("username", "Tom");
String jwt = Jwts.builder()
.signWith(SignatureAlgorithm.HS256, "itcast") //签名算法
.setClaims(claims) //自定义内容(载荷)
.setExpiration(new Date(System.currentTimeMillis() + 12 * 3600 * 1000)) // 设置有效期为12小时
.compact();
System.out.println(jwt);
return jwt;
}
}
- JwtUtils.java
public class JwtUtils {
private static String signkey = "itcast";
private static long expire = 43200000L; //12H
/**
* 生成JWT令牌
*
* @param claims JWT第二部分负载playload中存储的内容
* @return
*/
public static String generateJwt(Map<String, Object> claims) {
String jwt = Jwts.builder()
.addClaims(claims)
.signWith(SignatureAlgorithm.HS256, signkey)
.setExpiration(new Date(System.currentTimeMillis() + expire))
.compact();
return jwt;
}
/**
* 解析JWT令牌
* @param jwt JWT令牌
* @return JWT第二部分负载playload中存储的内容
*/
public static Claims parseJWT(String jwt) {
Claims claims = Jwts.parser()
.setSigningKey(signkey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}
- LoginController.java
@Slf4j
@RestController
@Api(value = "登录")
public class LoginController {
@Autowired
private EmpService empService;
@PostMapping("/login")
public Result login(@RequestBody Emp emp) {
log.info("员工登录:{}", emp);
Emp e = empService.login(emp);
//登录成功,生成令牌,下发令牌
if (e != null) {
Map<String, Object> claims = new HashMap<>();
claims.put("id", e.getId());
claims.put("name", e.getName());
claims.put("username", e.getUsername());
String jwt = JwtUtils.generateJwt(claims); //jwt包含了当前登录的员工信息
return Result.success(jwt);
}
//登录失败,返回错误信息
return Result.error("NOT_LOGIN");
//return e != null ? Result.success() : Result.error("用户名或者密码错误");
}
}
过滤器Filter
Filter快速入门
- TliasWebManagement2013P1Application.java
@ServletComponentScan //开启了对servlet组件的支持
@SpringBootApplication
public class TliasWebManagement2013P1Application {
public static void main(String[] args) {
SpringApplication.run(TliasWebManagement2013P1Application.class, args);
}
}
- DemoFilter.java
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {
@Override //初始化方法,Web服务器启动,创建Filter时调用,只调用一次
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Init 初始化方法执行了");
}
@Override // 拦截到请求之后调用,调用多次
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("拦截到了请求");
}
@Override //销毁方法,服务器关闭时调用,只调用一次
public void destroy() {
System.out.println("destroy 销毁方法执行了");
}
}
详解(执行流程、拦截路径、过滤器链)
登录校验-Filter
<!--阿里巴巴fastJSON工具包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
- LoginCheckFilter.java
/**
* 登录校验过滤器的逻辑
*/
@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//1.获取请求的url
//2.判断请求的url是否包含login,如果包含,说明是登录操作,放行。
//3.获取请求头中的令牌(token)。
//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)。
//5.解析token,如果解析失败,返回错误结果(未登录)。
//6.放行。
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
//1.获取请求的url
String url = req.getRequestURL().toString();
log.info("请求的url:{}", url);
//2.判断请求的url是否包含login,如果包含,说明是登录操作,放行。
if (url.contains("login")) {
log.info("登录操作,放行....");
chain.doFilter(request, response);
return;
}
//3.获取请求头中的令牌(token)。
String jwt = req.getHeader("token");
//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)。
if (!StringUtils.hasLength(jwt)) {
log.info("请求头token为空,返回未登录的信息");
Result error = Result.error("NOT_LOGIN");
//手动转换 -- json ----->阿里巴巴fastJSON工具包
String notLogin = JSONObject.toJSONString(error);
resp.getWriter().write(notLogin);
return;
}
//5.解析token,如果解析失败,返回错误结果(未登录)。
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) {//jwt令牌解析失败
e.printStackTrace();
log.info("解析令牌失败,返回未登录的错误信息");
Result error = Result.error("NOT_LOGIN");
//手动转换 -- json ----->阿里巴巴fastJSON工具包
String notLogin = JSONObject.toJSONString(error);
resp.getWriter().write(notLogin);
return;
}
//6.放行。
log.info("令牌合法");
chain.doFilter(request, response);
}
}
拦截器Interceptor
简介&快速入门
- LoginCheckInterceptor.java
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 定义拦截器,实现HandlerInterceptor接口,并重写其所有方法。
*/
@Component //交给IOC容器管理
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override //目标资源方法执行前执行,返回true:放行,返回false:不放行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle......");
return true;
}
@Override //目标资源方法执行后执行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle......");
}
@Override //视图渲染完毕后执行,最后执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion......");
}
}
- WebConfig.java
/**
* 注册拦截器
*/
@Configuration //配置类
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册拦截器,拦截器拦截所有资源
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");
}
}
详解(拦截路径、执行流程)
登录校验–Interceptor
- LoginCheckInterceptor.java
/**
* 定义拦截器,实现HandlerInterceptor接口,并重写其所有方法。
*/
@Slf4j
@Component //交给IOC容器管理
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override //目标资源方法执行前执行,返回true:放行,返回false:不放行
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
System.out.println("preHandle......");
//1.获取请求的url
//2.判断请求的url是否包含login,如果包含,说明是登录操作,放行。
//3.获取请求头中的令牌(token)。
//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)。
//5.解析token,如果解析失败,返回错误结果(未登录)。
//6.放行。
//1.获取请求的url
String url = req.getRequestURL().toString();
log.info("请求的url:{}", url);
//2.判断请求的url是否包含login,如果包含,说明是登录操作,放行。
if (url.contains("login")) {
log.info("登录操作,放行....");
return true;
}
//3.获取请求头中的令牌(token)。
String jwt = req.getHeader("token");
//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)。
if (!StringUtils.hasLength(jwt)) {
log.info("请求头token为空,返回未登录的信息");
Result error = Result.error("NOT_LOGIN");
//手动转换 -- json ----->阿里巴巴fastJSON工具包
String notLogin = JSONObject.toJSONString(error);
resp.getWriter().write(notLogin);
return false;
}
//5.解析token,如果解析失败,返回错误结果(未登录)。
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) {//jwt令牌解析失败
e.printStackTrace();
log.info("解析令牌失败,返回未登录的错误信息");
Result error = Result.error("NOT_LOGIN");
//手动转换 -- json ----->阿里巴巴fastJSON工具包
String notLogin = JSONObject.toJSONString(error);
resp.getWriter().write(notLogin);
return false;
}
//6.放行。
log.info("令牌合法");
return true;
}
@Override //目标资源方法执行后执行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle......");
}
@Override //视图渲染完毕后执行,最后执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion......");
}
}
6.3 异常处理 【全局异常处理器】
- GlobalExceptionHandler.java
/**
* 全局异常处理器
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class) //捕获所有的异常
public Result ex(Exception ex){
ex.printStackTrace();
return Result.error("对不起,操作失败,请联系管理员");
}
}