企业开发使用方式:
mysql -u用户名 -p密码 [-h数据库服务器IP地址 -p端口号]
数据模型:关系型数据库,建立在关键模型基础上,由多张相互连接的二维表组成的数据库
用来定义数据库、表
where
比较运算符 | 功能 |
---|---|
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
= | 等于 |
<> 或者 != | 不等于 |
between ... and ... | 在某个范围之内(含最小、最大值) |
in( ... ) | 在 in 之后的列表中的值,多选一 |
like 占位符 | 模糊匹配(- 匹配单个字符,% 匹配任意个字符) |
is null | 是 null |
逻辑运算符 | 功能 |
---|---|
and 或 && | 并且(多个条件同时成立) |
or 或 | | | 或者(多个条件任意一个成立) |
not 或 ! | 非,不是 |
表中多个数据: 类似Java中的case
case 表达式 when 值1 then 结果1 when 值2 then 结果2 ... else ... end
group by having
聚合函数
介绍:将一列数据作为一个整体,进行纵向计算
语法:select 聚合函数(字段列表) from 表名;
函数 | 功能 |
---|---|
count | 统计数量 |
max | 最大值 |
min | 最小值 |
avg | 平均值 |
sum | 求和 |
分组查询:
select 字段列表 from 表名 [where 条件] group by 分组字段名 [having 分组后过滤的条件];
order by
select 字段列表 from 表名 [where 条件列表] [group by 分组字段] order by 字段1 排序方式1, 字段2 排序方式2 … ;
ASC:升序(默认)
DESC:降序
limit
select 字段列表 from 表名 limit 起始索引, 查询记录数;
if (表达式, tvalue, fvalue); -- 当表达式为true时,取tvalue;当表达式为false时,取fvalue
case expr when value1 then result1 [when value2 then result2 ...] [else result] end -- 类似于switch语句
一对多:在多的一方添加外键关联一的一方的主键
-- 部门管理
create table tb_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 '部门表';
-- 员工管理(带约束)
create table tb_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 教研主管',
entrydate date comment '入职时间',
dept_id int unsigned comment '部门ID',
create_time datetime not null comment '创建时间',
update_time datetime not null comment '修改时间',
constraint fk_dept foreign key (dept_id) references tb_dept(id)
) comment '员工表';
一对一:
create table tb_user
(
id int auto_increment primary key comment '主键ID',
name varchar(10) comment '姓名',
age int comment '年龄',
gender char(1) comment '1: 男,2:女',
phone char(11) comment '手机号'
) comment '用户基本信息表';
create table tb_user_edu
(
id int auto_increment primary key comment '主键ID',
degree varchar(20) comment '学历',
major varchar(50) comment '专业',
primaryschool varchar(50) comment '小学',
middleschool varchar(50) comment '中学',
university varchar(50) comment '大学',
userid int unique comment '用户ID', -- 外键关联基本信息表的主键(加上了unique唯一约束)
constraint fk_userid foreign key (userid) references tb_user (id)
) comment '用户教育信息表';
多对多:
create table student
(
id int auto_increment primary key comment '主键ID',
name varchar(10) comment '姓名',
no varchar(10) comment '学号'
) comment '学生表';
insert into student
values (null, '黛绮丝', '2000100101'),
(null, '谢逊', '2000100102'),
(null, '韦一笑', '2000200103'),
(null, '殷天正', '2000200103'),
(null, '韦一笑', '2000200104');
create table course
(
id int auto_increment primary key comment '主键ID',
name varchar(10) comment '课程名称'
) comment '课程表';
insert into course
values (null, 'Java'),
(null, 'PHP'),
(null, 'MySQL'),
(null, 'Hadoop');
create table student_course
(
id int auto_increment comment '主键' primary key,
studentid int not null comment '学生ID',
courseid int not null comment '课程ID',
constraint fk_courseid foreign key (courseid) references course (id),
constraint fk_studentid foreign key (studentid) references course (id)
) comment '学生课程中间表';
insert into student_course value (null, 1, 1), (null, 1, 2), (null, 1, 3), (null, 2, 2), (null, 2, 3), (null, 3, 4);
隐式内连接:
select 字段列表 from 表1, 表2 where 条件 ……;
显式内连接:
select 字段列表 from 表1 [inner] join 表2 on 连接条件 ……;
默认MySQL的事务时自动提交的,也就是说当执行一条DML语句,MySQL会立即隐式的提交事务。
是一款优秀的 持久层 框架,用于简化 JDBC 的开发
官网:https://mybatis.org/mybatis-3/zh/index.html
create table user
( id int unsigned primary key auto_increment comment 'ID',
name varchar(100) comment '姓名',
age tinyint unsigned comment '年龄',
gender tinyint unsigned comment '性别, 1:男, 2:女',
phone varchar(11) comment '手机号'
) comment '用户表';
insert into user(id, name, age, gender, phone)
VALUES (null,'白眉鹰王',55,'1','18800000000');
insert into user(id, name, age, gender, phone)
VALUES (null,'金毛狮王',45,'1','18800000001');
insert into user(id, name, age, gender, phone)
VALUES (null,'青翼蝠王',38,'1','18800000002');
insert into user(id, name, age, gender, phone)
VALUES (null,'紫衫龙王',42,'2','18800000003');
insert into user(id, name, age, gender, phone)
VALUES (null,'光明左使',37,'1','18800000004');
insert into user(id, name, age, gender, phone)
VALUES (null,'光明右使',48,'1','18800000005');
@Data @NoArgsConstructor
//无参构造
@AllArgsConstructor
//全参构造
public class User {
private Integer id;
private String name;
private short age;
private short gender;
private String phone;
}
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=123456
@Mapper
//在运行时,会自动生成该接口的实现类对象(代理对象),并且将该对象交给IOC容器管理
public interface UserMapper {
//查询全部用户信息
@Select("select * from user")
public List<User> list();
}
@SpringBootTest
//springboot整合单元测试的注解
class SpringbootMybatisQuickstartApplicationTests {
@Autowired //依赖注入
private UserMapper userMapper;
@Test
public void testListUser(){
List<User> userList = userMapper.list();
userList.stream().forEach(user -> {
System.out.println(user);
});
}
}
JDBC:使用 Java 语言操作关系型数据库的一套API
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter / setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化Java开发,提高效率
注解 | 作用 |
---|---|
@Getter / @Setter | 为所有的属性提供 get / set 方法 |
@ToString | 会给类自动生成易阅读的 toString 方法 |
@EqualsAndHashCode | 根据类拥有的非静态字段自动重写 equals 方法和 hashCode 方法 |
@Data | 提供了更综合的生成代码功能(@Getter + @Setter + @ToString + @NoArgsConstructor) |
@NoArgsConstructor | 为实体类生成无参的构造器方法 |
@AllArgsConstructor | 为实体类生成除了 static 修饰的字段之外带有各参数的构造器方法 |
注意:Lombok 会再编译时自动生成 Java 代码。我们使用Lombok时,还需安装一个 lombok 的插件(idea自带)
根据主键删除:
delete from emp where id = 17;
//根据ID删除数据
@Delete("delete from emp where id = #{id}") //可以使用$代替#,#能预防sql注入
//根据传输进来的id动态删除表中的内容
public void delete(Integer id);//有返回值,返回值代表影响操作的记录数
日志输出
#配置mybatis的日志,指定输出到控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
SQL语句:
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})
接口方法:
@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})")
public void insert(Emp emp);
主键返回:
描述:在数据添加成功后,需要获取插入数据库数据的主键
@Options(useGeneratedKeys = true, keyProperty = "id") //会自动将生成的主键值,赋值给emp对象的id属性
@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})")
public void insert(Emp emp);
接口方法
@Update("update emp set username = #{username}, name = #{name}, gender = #{gender}, image = #{image}, job = #{job}, entrydate = #{entrydate},dept_id = #{deptId}, update_time = #{updateTime} where id = #{id}")
public void update(Emp emp);
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);
@Select("select id, username, password, name, gender, image, job, entrydate, " +
"dept_id deptId, create_time createTime, update_time updateTime from emp where id = #{id}")
public Emp getById(Integer id)
@Results({
@Result(column = "dept_id", property = "deptId"),
@Result(column = "create_time", property = "createTime"),
@Result(column = "update_time", property = "updateTime")
})
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);
//条件查询员工
@Select("select * from emp where name like '%${name}%' and gender = #{gender} and " +
"entrydate between #{begin} and #{end} order by update_time desc ;")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end
//条件查询员工
@Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and " +
"entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
Mapper接口:
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
XML 映射文件:
<?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.itheima.mapper.EmpMapper">
<select id="list" resultType="com.itheima.pojo.Emp">
select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and
entrydate between #{begin} and #{end} order by update_time desc
</select>
</mapper>
使用 Mybatis 的注解,主要是来完成一些简单的增删改查功能,如果需要实现复杂的SQL功能,建议使用XML来排至映射的语句
官方说明:https://mybatis.net.cn/getting-started.html
随着用户的输入或外部条件变化而变化的 SQL 语句
<if>
:用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接
<where>
:where 元素只会在子标签有内容的情况下才插入 where 子句。而且会自动去除子句的开头的 and 或 or
<set>
:动态的在行首插入 SET 关键字,并会删掉额外的逗号(用在 update 语句中)
<select id="list" resultType="com.itheima.pojo.Emp">
select *
from emp
<where>
<if test="name != null">
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>
案例:完善更新员工功能,修改为动态更新员工数据信息
<!--动态更新员工信息-->
<update id="update2">
update emp
<set>
<if test="username != null">
username = #{username},
</if>
<if test="name != null">
name = #{name},
</if>
<if test="gender != null">
gender = #{gender},
</if>
<if test="image">
image = #{image},
</if>
<if test="job != null">
job = #{job},
</if>
<if test="entrydate">
entrydate = #{entrydate},
</if>
<if test="deptId != null">
dept_id = #{deptId},
</if>
<if test="updateTime">
update_time = #{updateTime}
</if>
</set>
where id = #{id}
</update>
//批量删除员工
public void deleteByIds(List<Integer> ids);
<delete id="deleteByIds">
delete
from emp
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<sql>
:定义可重用的 SQL 片段
<include>
:通过属性 refid,指定包含的 sql 片段
<sql id="commonSelect">
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time
from emp
</sql>
<select id="list" resultType="com.itheima.pojo.Emp">
<include refid="commonSelect"/>
<where>
<if test="name != null">
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>
https://localhost:8080/users/1 get:查询id为1的用户
https://localhost:8080/users post:新增用户
https://localhost:8080/users put:修改用户
https://localhost:8080/users/1 delete:删除id为1的用户
@Slf4j //可以直接调用log下面的info方法来记录日志
@RestController
public class DeptController {
@Autowired //注入service对象
private DeptService deptService;
//@RequestMapping(value = "/depts", method = RequestMethod.GET)
@GetMapping("/depts") /*限定请求方式为 get ,post请求调用 @PostMapping*/
public Result list(){
log.info("查询全部部门数据");
//调用service查询部门数据
List<Dept> deptList = deptService.list();
return Result.success(deptList);
}
}
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Override
public List<Dept> list() {
return deptMapper.list();
}
}
@Mapper
public interface DeptMapper {
/**
* 查询全部部门数据
* @return
*/
@Select("select * from dept")
List<Dept> list();
}
/**
* 部门管理Controller
*/
@Slf4j //可以直接调用log下面的info方法来记录日志
@RestController
@RequestMapping("/depts")
public class DeptController {
@Autowired //注入service对象
private DeptService deptService;
/**
* 查询部门数据
* @return Result
*/
//@RequestMapping(value = "/depts", method = RequestMethod.GET)
@GetMapping /*限定请求方式为 get ,post请求调用 @PostMapping*/
public Result list(){
log.info("查询全部部门数据");
//调用service查询部门数据
List<Dept> deptList = deptService.list();
return Result.success(deptList);
}
/**
* 删除部门
* @return Result
*/
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id){
log.info("根据id删除部门:{}",id);
//调用service删除部门
deptService.delete(id);
return Result.success();
}
/**
* 新增部门
* @return Result
*/
@PostMapping
public Result add(@RequestBody Dept dept){
log.info("新增部门:{}", dept);
deptService.add(dept);
return Result.success();
}
}
@RequestParam(defaultValue="1") //设置请求参数默认值
//引入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.6</version>
</dependency>
PageHelper.startPage(pageNum, pageSize);
List<Emp> list = empMapper.list();
Page<Emp> page = (Page<Emp>)list;
@Slf4j
@RestController
public class EmpController {
@Autowired
private EmpService empService;
@GetMapping("/emps")
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){
//@RequestParam:设置默认值,如果前端没设置,默认值是1
log.info("分页查询,参数:{},{},{},{},{},{}",page, pageSize, name, gender, begin, end);
//调用service分页查询
PageBean pageBean = empService.page(page, pageSize, name, gender, begin, end);
return Result.success(pageBean);
}
}
public interface EmpService {
/**
* 分页查询
* @param page
* @param pageSize
* @return
*/
PageBean page(Integer page, Integer pageSize,String name, Short gender, LocalDate begin, LocalDate end);
}
@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
@Override
public PageBean page(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {
//设置分页参数
PageHelper.startPage(page, pageSize);
//执行查询
List<Emp> empList = empMapper.list(name, gender, begin, end);
Page<Emp> p = (Page<Emp>) empList;
//封装PageBean对象
PageBean pageBean = new PageBean(p.getTotal(), p.getResult());
return pageBean;
}
}
@Mapper
public interface EmpMapper {
/**
* 查询总记录数
* @return long
*/
public List<Emp> list(@Param("name") String name, @Param("gender") Short gender, @Param("begin") LocalDate begin, @Param("end") LocalDate end);
}
<mapper namespace="com.example.mapper.EmpMapper">
<!--条件查询-->
<select id="list" resultType="com.example.pojo.Emp">
select *
from emp
<where>
<if test="name != null">
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>
@DeleteMapping("/{ids}")
public Result delete(@PathVariable List<Integer> ids){
log.info("批量删除,ids:{}", ids);
empService.delete(ids);
return Result.success();
}
void delete(List<Integer> ids);
@Override
public void delete(List<Integer> ids) {
empMapper.delete(ids);
}
void delete(List<Integer> ids);
<!--批量删除 (1, 2, 3)-->
<delete id="delete">
delete
from emp
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
@PostMapping
public Result save(@RequestBody Emp emp){
log.info("新增员工, emp:{}", emp);
empService.save(emp);
return Result.success();
}
@Override
public void save(Emp emp) {
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
empMapper.insert(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);
@Slf4j
@RestController
public class UploadController {
public Result upload(String username, Integer age, MultipartFile image){
log.info("文件上传:{}, {}, {}", username,age, image);
return Result.success();
}
}
@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();
//构造唯一的文件名(不能重复) -- uuid(通用唯一识别码)
int index = originalFilename.lastIndexOf("."); //用 . 分割
String extname = originalFilename.substring(index); //截取后缀名
String newFileName = UUID.randomUUID().toString() + extname; //获取新的字符串作为name
log.info("新的文件名:{}", newFileName);
/*
String newFileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
*/
//将文件存储在服务器的磁盘目录中
image.transferTo(new File("D:\\DeliveryOptimization\\Cache" + newFileName));
return Result.success();
}
}
#配置单个文件上传大小的限制
spring.servlet.multipart.max-file-size=10MB
#配置单个请求最大大小的限制(一次请求可以上传多个文件)
spring.servlet.multipart.max-request-size=100MB
阿里云
查询回显
@GetMapping("/{id}") //id为路径参数
public Result getById(@PathVariable Integer id) {
log.info("根据id查询员工信息,id: {}", id);
Emp emp = empService.getById(id);
return Result.success();
}
@Override
public Emp getById(Integer id) {
return empMapper.getById(id);
}
@Select("select * from emp where id = #{id}")
Emp getById(Integer id);
修改员工
@PutMapping
public Result update(@RequestBody Emp emp){
//json格式数据想封装到实体类中,需要加@RequestBody注解
log.info("更新员工信息:{}", emp);
empService.update(emp);
return Result.success();
}
@Override
public void update(Emp emp) {
emp.setUpdateTime(LocalDateTime.now());
empMapper.update(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>
aliyun.oss.endpoint=https://oss-cn-hhangzhou.aliyuncs.com
aliyun.oss.accessKeyId=LTAI4GCH1vX6DKqJWxd6nEuW
aliyun.oss.accessKeySecret=yBshYweHOpqDuhCArrVHwIiBKpyqSL
aliyun.oss.bucketName=web-tlias
@Component
public class AliOSSUtils {
@Value("${}")
private String endpoint;
@Value("${}")
private String accessKeyId;
@Value("${}")
private String accessKeySecret;
@Value("${}")
private String bucketName;
}
<server>
<port>8080</port>
<address>127.0.0.1</address>
</server>
server.port=8080 server.address=127.0.0.1
server: port: 8080 address: 127.0.0.1
spring:
#数据库连接信息的配置
datasource:
driver-class-name: com.mysql.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
@Value
相同点:@Slf4j
@RestController
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("用户名或密码错误");
}
}
@Select("select * from emp where username = #{username} and password = #{password}")
Emp getByUsernameAndPassword(Emp emp);
Cookie
Session
令牌技术(主流方案)
对应依赖:
<!--JWP令牌-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
生成:
/**
* 生成JWT
*/
@Test
public void testGenJWT(){
Map<String, Object> claims = new HashMap<>();
claims.put("id", 1);
claims.put("name", "Tom");
String jwt = Jwts.builder() //构建Jwt令牌
.signWith(SignatureAlgorithm.HS256, "example")//签名算法
.setClaims(claims)//设置自定义内容(载荷)
.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))//设置有效期为 1h
.compact();
System.out.println(jwt);
}
解析:
/**
* 校验JWT
*/
@Test
public void testParseJwt(){
Claims claims = Jwts.parser()
.setSigningKey("example") //指定签名密钥
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVG9tIiwiaWQiOjEsImV4cCI6MTY5MDAyOTI4Nn0.bxU-aSO5VpOAi7U56Uz2jazLSzj9cu0E-MSE8VkKbSo") //解析令牌
.getBody();
System.out.println(claims);
}
@Slf4j
@RestController
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("用户名或密码错误");
}
}
定义 Filter:定义一个类,实现 Filter 接口,并重写其所有方法
配置 Filter:Filter 类上加 @WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启 Servlet 组件支持
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {
@Override //初始化方法,只调用一次
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("拦截");
//放行
chain.doFilter(request, response);
}
@Override //销毁方法,只调用一次
public void destroy() {
System.out.println("init销毁");
}
}
启动类中:
@ServletComponentScan //Filter是JavaWeb三大组件之一,想在springboot上使用JavaWeb组件必须使用注解
@SpringBootApplication
public class TliasWebManagementApplication {
public static void main(String[] args) {
SpringApplication.run(TliasWebManagementApplication.class, args);
}
}
执行流程:
请求 ----> 放行前逻辑 --->放行 --> 资源 --->放行后逻辑
拦截路径
Filter 可以根据需求,配置不同的拦截资源路径:
@WebFilter(urlPatterns = "/depts")
public class DemoFilter implements Filter {
}
拦截路径 | urlPatterns | 含义 |
---|---|---|
拦截具体路径 | /login | 只有访问 /login 路径时,才会被拦截 |
目录拦截 | /emps/* | 访问 /emps 下的所有资源,都会被拦截 |
拦截所有 | /* | 访问所有资源,都会被拦截 |
过滤器链
登录校验
@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
/*获取请求url*/
String url = request.getRequestURI().toString();
log.info("请求的url:{}", url);
/*判断请求url是否包含login,如果包含,说明是登录操作,放行*/
if (url.contains("login")) { //如果包含了login关键字是登录请求
log.info("登录操作,放行……");
filterChain.doFilter(servletRequest, servletResponse);
return;
}
/*获取请求头中的令牌(token)*/
String jwt = request.getHeader("token");
/*判断令牌是否存在,如果不存在,返回错误结果(未登录)*/
if (!StringUtils.hasLength(jwt)) {
log.info("请求头token为空,返回未登录信息");
Result error = Result.error("NOT_LOGIN");
//手动转换 对象 -->json ---------阿里巴巴fastJSON
String notLogin = JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
}
/*解析token,如果解析失败,返回错误结果(未登录)*/
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) {
e.printStackTrace();
log.info("解析令牌失败,返回未登录错误信息");
Result error = Result.error("NOT_LOGIN");
//手动转换 对象 -->json ---------阿里巴巴fastJSON
String notLogin = JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return;
}
/*放行*/
log.info("令牌合法");
filterChain. doFilter(servletRequest, servletResponse);
}
}
入门
@Component
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;
}
//Controller方法运行
@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 ...");;
}
}
@Configuration //配置类
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");//拦截所有资源
}
}
详解
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
// 需要拦截哪些资源 不需要拦截哪些资源
}
拦截路径 | 含义 | 举例 |
---|---|---|
/* | 一级路径 | 能匹配/depts,/emps,/login,不能匹配 /depts/1 |
/** | 任意级路径 | 能匹配 /depts,/depts/1,/depts/1/2 |
/depts/* | /depts 下的一级路径 | 能匹配 /depts/1,不能匹配 /depts/1/2,/depts |
/depts/** | /depts 下的任意级路径 | 能匹配 /depts,/depts/1,/depts/1/2,不能匹配 /emps/1 |
登录校验 - Interceptor
@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override //目标资源方法运行前运行,返回true 放行;false 不放行
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
/*获取请求url*/
String url = req.getRequestURI().toString();
log.info("请求的url:{}", url);
/*判断请求url是否包含login,如果包含,说明是登录操作,放行*/
if (url.contains("login")) { //如果包含了login关键字是登录请求
log.info("登录操作,放行……");
return true;
}
/*获取请求头中的令牌(token)*/
String jwt = req.getHeader("token");
/*判断令牌是否存在,如果不存在,返回错误结果(未登录)*/
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;
}
/*解析token,如果解析失败,返回错误结果(未登录)*/
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) {
e.printStackTrace();
log.info("解析令牌失败,返回未登录错误信息");
Result error = Result.error("NOT_LOGIN");
//手动转换 对象 -->json ---------阿里巴巴fastJSON
String notLogin = JSONObject.toJSONString(error);
resp.getWriter().write(notLogin);
return false;
}
/*放行*/
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 ...");
}
}
@RestControllerAdvice
@ExceptionHandler(Exception.class) //捕获所有异常
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。