26春期学习总结
Springboot4入门
1.jdk21的下载
2.介绍spring boot的核心:
自动装配:无需手动编写大量的XML配置,框架根据依赖自动配置
内嵌服务器:内置Tomcat,无需手动部署
简化部署:可打包成可执行JAR包,无需手动部署
3.常用注解
@SpringBootApplication(scanBasePackages = "com.xxgc")
包含 @Configuration + @EnableAutoConfiguration + @ComponentScan
有两个功能,自动装配,自动读取项目的配置文件,包路径扫描
配置文件
SpringBoot的配置文件有两种 Yml 和 Properties
| yml | properties | |
|---|---|---|
| 优先级 | 低 | 高 |
| 格式要求 | 高 | 低 |
启动配置读环境 > 指定环境的配置文件 > properties > yml > 默认
读取配置文件
读取方式有两种
方式一: @Value("${属性名}") 适合单个属性
方式二:@ConfigurationProperties 适合批量属性
启动配置
java -jar 包名.jar --参数名1=值1 --参数名2=值2
热部署
<!--导入热部署依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>4.0.0</version>
<scope>runtime</scope>
<!--防止依赖传递-->
<optional>true</optional>
</dependency>
在idea打开对应的配置,注意每个版本的idea的位置都不一样百度搜索。
VO和DTO
核心原则是隔离不同层级读数据交互,避免直接暴露领域模型或数据库实体。
- DTO(数据传输对象):核心作用是跨进程、跨服务传输数据,专注于数据传输
- VO(值对象):核心作用是向客户端(前端)展示数据,专注于数据展示
TODO的用法
// TODO 代号 内容
用于给指定代码打上标记,方便后续查找维护
接口命名风格
- 要求所有接口必须以/api开头
- 接口必须加上版本号如/v1
- url小写加中横线
配置Mybatis-Plus分页插件
1. 添加依赖
2. 编写配置类
创建一个配置类,通过 @Bean 将 MybatisPlusInterceptor 注入到 Spring 容器中。
3.使用分页插件
校验规则复习
1. 引入依赖(spring-boot-starter-web 已包含,无需额外添加)
2. 常用注解
| 注解 | 作用 |
|---|---|
@NotNull |
不能为 null |
@NotBlank |
字符串不能为空串(trim后长度>0) |
@NotEmpty |
集合/字符串不能为空 |
@Size(min, max) |
长度/大小范围 |
@Min / @Max |
数值最小值/最大值 |
@Pattern(regexp) |
正则校验 |
@Email |
邮箱格式 |
全局异常处理器
引入概念:不给错误信息有错误信息直接报错,用异常处理器处理
/**
* 全局异常拦截
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
//参数校验异常拦截
@ExceptionHandler({BindException.class, MethodArgumentNotValidException.class, ConstraintViolationException.class})
public ResponseEntity<Result<List<String>>> handleValidationException(Exception e) {
Result<List<String>> result = null;
if (e instanceof MethodArgumentNotValidException methodArgumentNotValidException) {
result = Result.fail("参数校验异常",
methodArgumentNotValidException.getBindingResult().getAllErrors().stream()
.filter(FieldError.class::isInstance)
.map(error -> ((FieldError) error).getDefaultMessage())
.collect(Collectors.toList())).code(400);
}else if (e instanceof BindException bindException) {
result = Result.fail( "参数校验异常",
bindException.getAllErrors().stream()
.filter(FieldError.class::isInstance)
.map(error -> ((FieldError) error).getDefaultMessage())
.collect(Collectors.toList())).code(400);
}
return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
}
}
封装完整的返回类
@Data
public class Result<T> {
private Integer code;
private String message;
private T data;
// 私有构造方法(仅内部使用)
private Result(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
// ====================== 链式调用方法 ======================
public Result<T> code(Integer code) {
this.code = code;
return this;
}
public Result<T> message(String message) {
this.message = message;
return this;
}
public Result<T> data(T data) {
this.data = data;
return this;
}
// ====================== 快捷构建方法(核心:移除private build()) ======================
/**
* 成功响应(无数据)
*/
public static <T> Result<T> success() {
return new Result<>(200, "操作成功", null);
}
/**
* 成功响应(带数据)
*/
public static <T> Result<T> success(T data) {
return new Result<>(200, "操作成功", data);
}
/**
* 失败响应(默认状态码+提示)
*/
public static <T> Result<T> fail() {
return new Result<>(500, "操作失败", null);
}
/**
* 失败响应(自定义提示)
*/
public static <T> Result<T> fail(String message) {
return new Result<>(500, message, null);
}
/**
* 失败响应(自定义状态码+提示)
*/
public static <T> Result<T> fail(Integer code, String message) {
return new Result<>(code, message, null);
}
/**
* 失败响应(自定义状态码+参数)
*/
public static <T> Result<T> fail(String message,T data) {
return new Result<>(500, message, data);
}
/**
* 空构造(备用,防止Lombok/JDK编译识别问题)
*/
private Result() {}
}
UUID的研究
可重写内置方法实现自定义类型的UUID
注解鉴权
注册 Sa-Token 拦截器,校验规则为 StpUtil.checkLogin() 登录校验。
引入token概念
敏感词过滤
@Component
public class SensitiveWordFilter {
// 敏感词树根节点
private final Map<Character, Object> sensitiveTree = new HashMap<>();
@PostConstruct
public void init() {
// 从数据库/配置文件加载敏感词列表
List<String> words = Arrays.asList("色情", "暴力", "赌博");
for (String word : words) {
Map<Character, Object> currentNode = sensitiveTree;
for (char c : word.toCharArray()) {
currentNode = (Map<Character, Object>) currentNode.computeIfAbsent(c, k -> new HashMap<>());
}
currentNode.put('ε', true); // 结束标记
}
}
/**
* 检测文本是否包含敏感词
*/
public boolean contains(String text) {
for (int i = 0; i < text.length(); i++) {
Map<Character, Object> node = sensitiveTree;
for (int j = i; j < text.length(); j++) {
char c = text.charAt(j);
if (!node.containsKey(c)) break;
node = (Map<Character, Object>) node.get(c);
if (node.containsKey('ε')) return true; // 匹配到敏感词
}
}
return false;
}
/**
* 替换敏感词为 ***
*/
public String replace(String text, char replaceChar) {
// 实现略,原理同上,匹配到则替换
}
}
自动建库建表
正向工程
JPA/Hibernate(最常用,上手最快)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
@Data
@Entity
@Table(name = "tb_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username", nullable = false, unique = true, length = 50)
private String username;
@Column(name = "password", nullable = false, length = 255)
private String password;
@Column(name = "email", length = 100)
private String email;
@Column(name = "age")
private Integer age;
@Column(name = "create_time")
private LocalDateTime createTime;
@Column(name = "update_time")
private LocalDateTime updateTime;
}
关于高并发问题解决
Redis
什么是Redis?
全称:Remote Dictionary Server (远程字典服务),开源,基于内存,支持持久化的NoSQL数据库。
核心优势: 读写性能极高(单机10万QPS+),5种数据库结构,单线程+I/O多路复用。
基础命令(必背)
keys * # 查找所有key(生产慎用)
keys na* # 模糊查找
exists name # 判断key是否存在
del name # 删除key
expire key 20 # 给key设置一个过期时间
ttl key # 查看key的过期世界
flushdb # 清空当前库
select 1 # 切换到第二个数据库(一共16个库)
flushall # 清空所有库
5大数据结构(面试+开发必考)
String (字符串)
最常用,存缓存,计数器,token
set key value # 设置一个值
get key # 获取值
# 计数器 如果存的是一个数值
incr key # 自增加1
decr key # 自减
incrby key 5 # 加5
setex key 10 value # 带过期时间的设置
setnx key value # 不存在才设置(分布式锁基础)
Hash (对象)
适合存用户信息,商品信息
hset objkey key1 value1 key2 value2.... # 设置一个对象
hget objkey key # 获取对象的属性值
hgetall objkey # 获取对象当全部值
hkeys objkey # 只获取对象的key
hvals objkey # 只获取对象的value
List(列表)
有序、可重复,做消息队列,时间线,评论列表
lpush key value # 左边插入
rpush key value # 右边插入
lpop key # 左边弹出
rpop key # 右边弹出
lrange msg 0 -1 # 查看全部
Set(集合)
无序、不可重复,可用于去重、共同好友,抽奖
sadd key value1 value2 ... # 添加值到集合
smembers key # 查看所有
srem key # 删除值
sismember key value # 是否存在
ZSet (有序集合)
用于做,排行榜,热度榜,延时队列
zadd key 分数1 值1 分数2 值2 分数3 值3 # 添加数据
zrange key 0 2 withscores # 查询前三 正序
zrevrange key 0 -1 withscores # 查询所有 倒序
zrem key 值 # 移除数据
项目预热
系统启动前/启动中,提前把高频热点数据加载到redis中,让用户一进来就直接读缓存,不用查询数据库。
为什么要这么做?
- 防止刚上线大量请求直接打到数据库,导致数据库压力过大。
- 提升接口响应速度,减少缓存未命中
- 避免刚启动就出现大量缓存击穿,雪崩。
怎么做?
1、项目启动时自动加载
@PostConstruct
ApplicationRunner
CommandLineRunner
@Slf4j
@Component
public class CacheWarming {
@Autowired
private RedisUtil redisUtil;
/**
* 项目启动时自动执行
* 此方法用来预热数据
*/
@PostConstruct
public void preheatData(){
log.info("=================执行了=================");
}
}
@Slf4j
@Component
public class CacheWarming1 implements ApplicationRunner {
/**
* 触发时机:SpringBoot项目完全启动后执行
* @param args
* @throws Exception
*/
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("---------------ApplicationRunner--------------------");
}
}
@Slf4j
@Component
public class CacheWarming2 implements CommandLineRunner {
/**
* 触发时机:项目完全启动后执行
* @param args
* @throws Exception
*/
@Override
public void run(String... args) throws Exception {
log.info("================CommandLineRunner====================");
}
}
数据库密码字段的保密性
| 原则 | 说明 |
|---|---|
| 绝不存储明文 | 明文密码一旦泄露,用户所有账号都可能被盗 |
| 不可逆加密 | 存储的是哈希值,无法反向推导出原始密码 |
| 加盐处理 | 相同密码不同用户存储不同值,防止彩虹表攻击 |
| 慢哈希算法 | 故意设计为计算慢,增加暴力破解成本 |
| 传输加密 | 密码在网络传输过程中也必须加密(HTTPS) |
设计页面工具教学
蓝湖,pixso等
WebSocket
用户上线后台广播 用户认证后,broadcast() 发系统消息
用户发送消息频率限制(防刷)
后台通过ip限制登陆 握手拦截器中获取 IP,比对黑白名单
hutool工具箱
一个功能全面的 Java 工具类库
vue3
Vue 3 是用 JS + HTML + CSS 构建 UI 的框架
重点学习组件+api
前后端发起请求
Swagger
| 功能 | 说明 |
|---|---|
| 接口可视化 | 展示所有 Controller 的接口列表、请求参数、返回示例 |
| 在线调试 | 直接在页面上填写参数,点击"发送"即可测试接口 |
| 分组管理 | 按模块或版本分组展示接口 |
| 文档导出 | 支持导出 OpenAPI 规范的 JSON/YAML 文件 |
自动化编程
通过后端编写代码实现,写中文名自动创建XXXService,XXXServiceImpl等模板文件
发送邮件
spring-boot-starter-mail |
Spring Boot官方邮件启动器,封装了JavaMail API,是基础中的基础。 |
|---|---|
| 邮件协议 | 通常使用 SMTP (简单邮件传输协议) 发送邮件。你需要配置你的邮箱(或公司邮件服务器)的SMTP服务器地址、端口、账号和授权码/密码。 |
配置类 (MailProperties) |
Spring Boot会自动配置,你只需在application.yml中配置spring.mail相关属性即可。 |
@Async 异步任务 |
核心。发送邮件是IO操作,耗时较长,必须异步执行。否则会阻塞主业务流程(如用户注册后等待邮件发送成功才返回)。 |
|---|---|
@Scheduled 定时任务 |
如果需要周期性发送邮件,例如每天早上8点发送报表,可以使用此注解。 |
若依(RuoYi)
一套基于 Spring Boot 的企业级快速开发平台,它的核心价值在于把开发通用后台管理系统的重复性工作做了高度封装

浙公网安备 33010602011771号