大事件板块一

一、项目整体信息

技术栈

  • 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
相关推荐
博风14 分钟前
eclipse中配置maven,以及在本地使用maven。
java·eclipse·maven
云-缩影15 分钟前
实际项目中怎么选排序算法:从面试题到工程落地
java·算法·排序算法
追星星の人17 分钟前
java web项目(eclipse软件)全流程备份
java·servlet
文丑颜不良啊1 小时前
LeetCode1461~1480题目解析
java·leetcode
2301_780789669 小时前
跨平台适配!SDK 游戏盾兼容全终端游戏场景
java·网络·ddos
学长毕设10 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端
步行cgn10 小时前
FormHttpMessageConverter 详解:Spring MVC 中表单数据的读写转换器
java·spring·mvc
龙亘川10 小时前
构建城市公共安全数字底座:亘川智城智慧安防系统全维度解读
java·大数据·开发语言·人工智能·信息可视化
金銀銅鐵10 小时前
[Java] 用 CLI 展示 EnumMap 增删键值对时的内部变化
java·源码·ai编程
秋天的怀念_David11 小时前
第二十二夜 · 数字迷雾
java·程序人生·算法