大事件板块一

一、项目整体信息

技术栈

  • SpringBoot 3
  • SpringMVC
  • MyBatis
  • MySQL
  • JWT(登录令牌)
  • Validation(参数校验)
  • ThreadLocal(线程内存用户)
  • MD5(密码加密)

统一返回结果 Result

java

运行

复制代码
@Data
public class Result {
    private Integer code; // 0成功 1失败
    private String msg;
    private Object data;

    public static Result success(){...}
    public static Result success(Object data){...}
    public static Result error(String msg){...}
}

二、核心技术详解(带介绍 + 注解 + 用法)

1)Validation 参数校验

作用

自动校验前端传参是否合法,不用手写 if 判断

核心注解

  • @Validated
    • 写在Controller 类上:开启普通参数校验
    • 写在实体参数前:开启对象内部字段校验
  • @Pattern(regexp="^\\S{5,16}$"):正则匹配
  • @NotNull:不能为 null
  • @NotEmpty:字符串不能 null 且不能为空
  • @Email:邮箱格式
  • @URL:必须是合法网址

生效规则(必背)

  • 普通参数(String/Integer)→ Controller 类上加 @Validated
  • 实体对象(User)→ 参数前加 @Validated
  • 两个都加,实体类校验才生效

2)JWT 登录认证

作用

无状态登录,前端带令牌访问,后端识别身份

结构

Header.Payload.Signature

JWT 工具类代码

java

运行

复制代码
//生成token
public static String genToken(Map<String, Object> claims) {
    return JWT.create()
            .withClaim("claims", claims)
            .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))
            .sign(Algorithm.HMAC256("itheima"));
}

//解析token
public static Map<String, Object> parseToken(String token) {
    return JWT.require(Algorithm.HMAC256("itheima"))
            .build()
            .verify(token)
            .getClaim("claims")
            .asMap();
}

3)登录拦截器 LoginInterceptor

作用

请求进入 Controller 前,统一校验是否登录

执行顺序

请求 → 拦截器 → Controller → Service → Mapper

核心逻辑

  • 拿请求头Authorization的 token
  • 解析 token 是否合法
  • 存用户到 ThreadLocal
  • 放行 / 拦截

拦截器代码

java

运行

复制代码
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("Authorization");
        try {
            Map<String, Object> map = JwtUtil.parseToken(token);
            ThreadLocalUtil.set(map);
            return true; //放行
        } catch (Exception e) {
            response.setStatus(401);
            return false; //拦截
        }
    }

    @Override
    public void afterCompletion(...) {
        ThreadLocalUtil.remove(); //必须清除
    }
}

关键知识点

  • return true:给 SpringBoot,放行去 Controller
  • return false:给 SpringBoot,拦截,不走 Controller
  • 拦截器不能 return Result,只能设置 401 状态码
  • 拦截器异常自己 try-catch,全局异常捕获不到

4)ThreadLocal 线程本地变量

作用

同一个请求线程内安全存储用户信息,随处可拿

ThreadLocalUtil 代码

java

运行

复制代码
public class ThreadLocalUtil {
    private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL = new ThreadLocal<>();

    public static void set(Map<String, Object> map) {
        THREAD_LOCAL.set(map);
    }
    public static Map<String, Object> get() {
        return THREAD_LOCAL.get();
    }
    public static void remove() {
        THREAD_LOCAL.remove();
    }
}

关键点

  • 拦截器set
  • Controller/Serviceget
  • 请求结束remove,防内存泄漏

5)全局异常处理器

作用

统一捕获 Controller/Service/Mapper 异常,返回友好提示

代码

java

运行

复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public Result handleException(Exception e) {
        e.printStackTrace();
        return Result.error(e.getMessage());
    }
}

捕获范围

  • Controller 异常 ✅
  • Service 异常 ✅
  • Mapper 异常 ✅
  • 拦截器异常 ❌ 管不到

三、用户模块所有接口(带代码 + 注解)

1)注册 POST /user/register

java

运行

复制代码
@PostMapping("/register")
public Result register(
    @Pattern(regexp = "^\\S{5,16}$") String username,
    @Pattern(regexp = "^\\S{5,16}$") String password
) {
    User u = userService.findByUserName(username);
    if (u == null) {
        userService.register(username, password);
        return Result.success();
    } else {
        return Result.error("用户名已存在");
    }
}

2)登录 POST /user/login

java

运行

复制代码
@PostMapping("/login")
public Result<String> login(
    @Pattern(regexp = "^\\S{5,16}$") String username,
    @Pattern(regexp = "^\\S{5,16}$") String password
) {
    User loginUser = userService.findByUserName(username);
    if (loginUser == null) return Result.error("用户名不存在");

    if (Md5Util.getMD5String(password).equals(loginUser.getPassword())) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", loginUser.getId());
        map.put("username", loginUser.getUsername());
        String token = JwtUtil.genToken(map);
        return Result.success(token);
    }
    return Result.error("密码错误");
}

3)获取用户信息 GET /user/userInfo

java

运行

复制代码
@GetMapping("/userInfo")
public Result<User> userInfo() {
    Map<String, Object> map = ThreadLocalUtil.get();
    String username = (String) map.get("username");
    User user = userService.findByUserName(username);
    return Result.success(user);
}

4)更新用户信息 PUT /user/update

java

运行

复制代码
@PutMapping("/update")
public Result update(@RequestBody @Validated User user) {
    userService.update(user);
    return Result.success();
}

5)更新头像 PATCH /user/updateAvatar

java

运行

复制代码
@PatchMapping("/updateAvatar")
public Result updateAvatar(@RequestParam @URL String avatar) {
    userService.updateAvatar(avatar);
    return Result.success();
}

6)修改密码 PATCH /user/updatePwd

java

运行

复制代码
@PatchMapping("/updatePwd")
public Result updatePwd(@RequestBody Map<String, String> params) {
    String oldPwd = params.get("oldPwd");
    String newPwd = params.get("newPwd");
    String rePwd = params.get("re_pwd");

    if (!StringUtils.hasLength(oldPwd) || !StringUtils.hasLength(newPwd) || !StringUtils.hasLength(rePwd)) {
        return Result.error("参数不能为空");
    }

    Map<String, Object> map = ThreadLocalUtil.get();
    String username = (String) map.get("username");
    User user = userService.findByUserName(username);

    if (!user.getPassword().equals(Md5Util.getMD5String(oldPwd))) {
        return Result.error("旧密码错误");
    }
    if (!newPwd.equals(rePwd)) {
        return Result.error("两次密码不一致");
    }

    userService.updatePwd(newPwd);
    return Result.success();
}

四、请求方法规范(背会)

  • 查询 → @GetMapping
  • 新增 → @PostMapping
  • 全量更新 → @PutMapping
  • 局部更新 → @PatchMapping
  • 删除 → @DeleteMapping

五、整套流程逻辑(最清晰总结)

  1. 前端登录 → 后端验证密码 → 生成 JWT 令牌返回
  2. 前端每次请求在请求头带:Authorization: Bearer token
  3. 拦截器 统一校验 token
    • 合法 → 存 ThreadLocal → 放行到 Controller
    • 不合法 → 返回 401 → 拦截
  4. Controller/Service 从 ThreadLocal 拿当前用户
  5. 异常统一由全局异常处理器返回 Result
  6. 请求结束 → 清除 ThreadLocal
相关推荐
wuminyu1 小时前
Java锁机制之Java对象重量级锁源码剖析
java·linux·c语言·jvm·c++
艾利克斯冰1 小时前
Java设计模式-创建型设计模式
java
心之伊始1 小时前
MySQL EXPLAIN 执行计划实战:从 type、Extra 到慢 SQL 定位与优化
java·架构·源码分析·csdn
Java_2017_csdn1 小时前
ComplexKeysShardingAlgorithm 小结
java·大数据·算法
海梨花1 小时前
快手面试高频算法题
java·算法·面试
云烟成雨TD1 小时前
Spring AI 1.x 系列【37】RAG 知识库平台案例:知识库管理
java·人工智能·spring
KANGBboy2 小时前
java知识四(面向对象编程)
android·java·开发语言
tongluowan0072 小时前
ThreadLocal,InheritableThreadLocal,TransmittableThreadLocal详解
java·多线程·上下文
qq_2518364572 小时前
基于java Web 日化商超库存管理系统设计与实现
java·开发语言·前端
破土士V2 小时前
【Java基础语法10】继承、多态、抽象类接口、字符串与异常等
java·开发语言