集训总结2

一些重要的

JWT

简介

全称: JSON Web Token(https://jwt.io/)

定义了一种简洁的、自包含的格式,用于通信双方以 json 数据格式安全的传输信息。

组成:

第一部分: Header (头) ,记录令牌类型、签名算法等。例如: {"alg":"HS256","type":"JWT"}

第二部分: Payload (有效载荷) ,携带一些自定义信息、默认信息等。例如: {"id":"1","username":"Tom"}

第三部分: Signature (签名) ,防止 Token 被篡改、确保安全性。将 header、payload,并加入指定秘钥,通过指定签名算法计算而来。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.JTdCJTIybmFtZSUyMiUzQSUyMlRvcSUyMiUyQyUyMm1hdCUyMiUzQTE1MTYyMzkwMjIlNQ=.Sf1KxwRJ5MeKKF2QT4fwpMeJf...

Base64: 是一种基于 64 个可打印字符(A-Z a-z 0-9 + /)来表示二进制数据的编码方式。

如果篡改了头部和载荷部分的数据,那么验证失败

如果秘钥改了,验证失败

注意事项

JWT 校验时使用的签名秘钥,必须和生成 JWT 令牌时使用的秘钥是配套的。

如果 JWT 令牌解析校验时报错,则说明 JWT 令牌被篡改 或 失效了,令牌非法。

Spring Validation对注册接口的参数校验

  1. 引入Spring Validation 起步依赖
  1. 在参数前面添加@Pattern注解

  2. 在Controller类上添加@Validated注解

  1. 在全局异常处理器中处理参数校验失败的异常

ThreadLocal

提供线程局部变量

用来存取数据: set()/get()

使用ThreadLocal存储的数据,线程安全

用完记得调用remove方法释放

public class ThreadLocalTest {

@Test

public void testThreadLocalSetAndGet() {

//同一个ThreadLocal对象为两个线程提供供存储线程的空间,达到线程隔离

//提供一个ThreadLocal对象

ThreadLocal tl = new ThreadLocal();

//开启两个线程

new Thread(() -> {

tl.set("萧炎");

System.out.println(Thread.currentThread().getName() + ": " + tl.get());

System.out.println(Thread.currentThread().getName() + ": " + tl.get());

System.out.println(Thread.currentThread().getName() + ": " + tl.get());

}, "蓝色").start();

new Thread(() -> {

tl.set("药尘");

System.out.println(Thread.currentThread().getName() + ": " + tl.get());

System.out.println(Thread.currentThread().getName() + ": " + tl.get());

System.out.println(Thread.currentThread().getName() + ": " + tl.get());

}, "绿色").start();

}

}

分组校验

更新文章分类和添加文章分类都@Validated了同一个规则

但添加时不需要传入id,更新时需要传入id,导致id校验规则矛盾

分组校验

把校验项进行归类分组,在完成不同的功能的时候,校验指定组中的校验项

  1. 定义分组

  2. 定义校验项时指定归属的分组

  3. 校验时指定要校验的分组

public class Category {

public interface Add {

}

public interface Update {

}

}

public class Category {

@NotNull(groups = Update.class)

private Integer id;//主键ID

@NotEmpty(groups = {Add.class, Update.class})

@Pattern(regexp = "^\\S{1,10}$", groups = {Add.class, Update.class})

private String categoryName;//分类名称

@NotEmpty(groups = {Add.class, Update.class})

@Pattern(regexp = "^\\S{1,10}$", groups = {Add.class, Update.class})

private String categoryAlias;//分类别名

}

@PutMapping

public Result update(@RequestBody @Validated(Category.Update.class) Category category) {

categoryService.update(category);

return Result.success();

}

注意事项

定义校验项时如果没有指定分组,则属于Default分组,分组可以继承

public class Category {

public interface Add extends Default{

}

public interface Update extends Default{

}

}

封装到实体类对象中的参数如何校验

注解 作用

NotNull 值不能为 null

NotEmpty 值不能为 null, 并且内容不为空

Email 满足邮箱格式

参数校验

1.在实体类中添加注解

@Data

public class User {

@NotNull

private Integer id;//主键ID

private String username;//用户名

private String password;//密码

@NotEmpty

@Pattern(regexp = "^\\S{1,10}$")

private String nickname;//昵称

@NotEmpty

@Email

private String email;//邮箱

private String userPic;//用户头像地址

private LocalDateTime createTime;//创建时间

private LocalDateTime updateTime;//更新时间

}

2.在具体使用实体类的前面加上@Validated注解

@PutMapping("/update")

public Result update(@RequestBody @Validated User user){

userService.update(user);

return Result.success();

}

自定义校验

已有的注解不能满足所有的校验需求,特殊的情况需要自定义校验 (自定义校验注解)

1.自定义注解 State

2.创建自定义校验数据的类 StateValidation

实现 ConstraintValidator 接口

3.在需要校验的地方使用自定义注解

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

@Constraint(validatedBy = StateValidation.class)

public @interface State {

String message() default "文章状态只能是:已发布或者草稿";

Class\[\] groups() default {};

Class<? extends Payload>\[\] payload() default {};

}

public class StateValidation implements ConstraintValidator<State, String> {

@Override

public boolean isValid(String value, ConstraintValidatorContext context) {

if (value == null) {

return false;

}

if (value.equals("已发布") || value.equals("草稿")) {

return true;

}

return false;

}

}

@Data

public class Article {

private Integer id;//主键ID

private String title;//文章标题

private String content;//文章内容

private String coverImg;//封面图像

@State

private String state;//发布状态 已发布|草稿

private Integer categoryId;//文章分类id

private Integer createUser;//创建人ID

private LocalDateTime createTime;//创建时间

private LocalDateTime updateTime;//更新时间

}

令牌主动失效机制

登录的问题:

用户两次登录后会生成新旧两个令牌,此时旧的不应该生效

要使旧的失效:

令牌主动失效机制

登录成功后,给浏览器响应令牌的同时,把该令牌存储到redis中

LoginInterceptor拦截器中,需要验证浏览器携带的令牌,并同时需要获取到redis中存储的与之相同的令牌

当用户修改密码成功后,删除redis中存储的旧令牌

SpringBoot 集成 redis

1导入 spring-boot-starter-data-redis 起步依赖

2.在 yml 配置文件中,配置 redis 连接信息

3.调用 API (StringRedisTemplate) 完成字符串的存取操作

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>

application.yml

spring:

data:

redis:

host: localhost

port: 6379

@Test

public void testStringSet(){

stringRedisTemplate.opsForValue().set("username","如花");

}

@Test

public void testStringGet(){

stringRedisTemplate.opsForValue().get("username");

}

SpringBoot多环境开发

开发、测试、生产三种环境下配置信息是不同的

多环境开发 - Profiles

SpringBoot 提供的 Profiles 可以用来隔离应用程序配置的各个部分,并在特定环境下指定部分配置生效

如何分隔不同环境的配置?

使用三个横杠 ---

如何指定哪些配置属于哪个环境?

spring:

config:

activate:

on-profile: 环境名称

如何指定哪个环境的配置生效?

spring:

profiles:

active: 环境名称

相关推荐
大模型码小白15 分钟前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
腾渊信息科技公司1 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
Cloud云卷云舒2 小时前
云卷云舒:从Oracle/MySQL迁移到HaishanDB:迁移评估工具核心技术拆解
mysql·oracle·ai-native·haishandb·信创数据库替换
爱笑的源码基地2 小时前
高并发 Redis 缓存门诊HIS系统源码,含财务统计药房进销存
java·程序·门诊系统·诊所系统·云诊所源码
憧憬成为web高手2 小时前
皮卡丘靶场速通--sql 2
数据库·sql·mybatis
段一凡-华北理工大学2 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
oradh4 小时前
Oracle XTTS实现跨版本迁移和升级(Oracle 11g单库升级至19C RAC集群)
数据库·oracle·11g升级19c·xtts跨版本迁移和升级
莫逸风4 小时前
【AgentScope 2.0】 0. 学习指南
java·llm·agent·agentscope
用户71333585156245 小时前
MySQL - 事务、redo/undo 日志与 MVCC
mysql
z123456789865 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程