当前位置: 首页 > article >正文

BigEvent项目后端学习笔记(一)用户管理模块 | 注册登录与用户信息全流程解析(含优化)

📖 模块概述

  • 用户管理模块是系统的核心基础模块,包含 注册、登录、用户信息维护 等功能。本模块涉及 JWT Token认证、密码加密存储、文件上传 等关键技术点,是理解前后端分离架构中安全与数据交互的典型实践。
  • 本篇对于原项目进行了代码优化,将原先写在 Controller 层的业务逻辑代码迁移至了 Service 层,并且额外定义了全局异常处理类中的参数校验异常处理方法。

🛠️ 技术实现要点

  • 前端:Vue3
  • 后端:SpringBoot3 + MyBatis + JWT
  • 安全:Token身份验证
  • 存储:用户头像上传至OSS(或本地目录)

⚙️ 各层职责与代码规范

🔗 Controller 层

⭐️ 核心职责:

  • 接收HTTP请求参数(@RequestBody/@RequestParam)
  • 调用Service层方法
  • 返回统一响应格式(如Result对象)
@RestController
@RequestMapping("/user")
@Validated
@RequiredArgsConstructor
public class UserController {
	...
}

💡 注意事项:

  • 禁止在Controller中编写业务逻辑
  • 使用DTO对象接收参数,而非直接传递Entity
  • 统一异常处理(通过@ControllerAdvice)

🔗 Service 层

⭐️ 核心职责:

  • 实现具体业务逻辑(如数据校验、事务管理)
  • 组合多个Mapper操作
  • 处理异常并抛出自定义业务异常
public interface UserService {
	...
}
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
	...
}

💡 最佳实践:

  • 接口与实现分离(UserService + UserServiceImpl)
  • 方法需明确事务边界(@Transactional注解)
  • 避免“上帝Service”(按业务拆分多个Service)

🔗 Mapper 层

⭐️ 核心职责:

  • 定义数据库操作方法(SQL映射)
  • 基于MyBatis/MyBatis-Plus实现CRUD
@Mapper
public interface UserMapper {
	...
}
<!-- 动态 SQL -->
<select id="getArticleList" resultType="com.itheima.pojo.Article">
    select * from article
    <where>
        <if test="categoryId != null">
            category_id = #{categoryId}
        </if>
        <if test="state != null">
            and state = #{state}
        </if>
        and create_user = #{userId}
    </where>
</select>

💡 规范建议:

  • 优先使用MyBatis原生方法
  • 定义数据库操作方法(SQL映射)
  • 基于MyBatis/MyBatis-Plus实现CRUD

🔗 层间交互与依赖注入

推荐使用构造函数注入:

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;
    // Lombok自动生成构造函数
}
@RestController
@RequestMapping("/user")
@Validated
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;
    // Lombok自动生成构造函数
}
层级对象类型说明
ControllerDTO(请求/响应对象)屏蔽Entity细节,保证接口安全
ServiceEntity、DTO、VO内部处理使用Entity,返回VO
MapperEntity、Query对象直接与数据库表结构对应

🔍 功能实现详解

🎯 注册

🧩 Controller 层

请求路径:/user/register
请求方式:POST
接口描述:该接口用于注册新用户

@PostMapping("/register")
public Result register(@Validated RegisterOrLoginDTO dto) {
    return userService.register(dto.getUsername(), dto.getPassword());
}

🧩 Service 层

  • 接口
// 根据用户名查询用户
User findByUsername(String username);
    
// 注册
Result register(String username, String password);
  • 实现
/**
 * 根据用户名查询用户
 * 
 * @param username 需要查询的用户名
 * @return 查询到的用户对象
 */
@Override
public User findByUsername(String username) {
    return userMapper.findByUsername(username);
}
/**
 * 注册
 * 
 * @param username 需要注册的用户名
 * @param password 需要注册的密码
 * @return 注册结果
 */
 @Override
 public Result register(String username, String password) {
     User user = findByUsername(username);
     if (user != null) {
         return Result.error("用户名已被占用");
     }
     userMapper.add(username, Md5Util.getMD5String(password));
     return Result.success();
 }

🧩 Mapper 层

// 根据用户名查询用户
@Select("select * from user where username = #{username}")
User findByUsername(String username);

🎯 登录

🧩 Controller 层

请求路径:/user/login
请求方式:POST
接口描述:该接口用于登录

@PostMapping("/login")
public Result login(@Validated RegisterOrLoginDTO dto) {
    return userService.authenticateUser(dto.getUsername(), dto.getPassword());
}

🧩 Service 层

  • 接口
// 登录验证
Result authenticateUser(String username, String password);
  • 实现
/**
 * 登录
 *
 * @param username 用户名
 * @param password 密码
 * @return 登录结果
 */
@Override
public Result authenticateUser(String username, String password) {
    User user = findByUsername(username);
    if (user == null) {
        return Result.error("用户不存在");
    }
    if (Md5Util.getMD5String(password).equals(user.getPassword())) {
        // 登录成功
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", user.getId());
        claims.put("username", user.getUsername());
        String token = JwtUtil.genToken(claims);
        return Result.success(token);
    }
    return Result.error("密码错误!");
}

🧩 Mapper 层

// 无

🎯 获取用户详细信息

🧩 Controller 层

请求路径:/user/userInfo
请求方式:GET
接口描述:该接口用于获取当前已登录用户的详细信息

@GetMapping("/userInfo")
public Result<User> getUserInfo() {
    return userService.getUserInfo();
}

🧩 Service 层

  • 接口
// 获取用户信息
Result<User> getUserInfo();
  • 实现
/**
 * 获取用户信息
 *
 * @return 用户信息
 */
@Override
public Result<User> getUserInfo() {
    Map<String, Object> map = ThreadLocalUtil.get();
    String username = (String) map.get("username");
    User user = findByUsername(username);
    return Result.success(user);
}

🧩 Mapper 层

// 无

🎯 更新用户基本信息

🧩 Controller 层

请求路径:/user/update
请求方式:PUT
接口描述:该接口用于更新已登录用户的基本信息(除头像和密码)

@PutMapping("/update")
public Result update(@RequestBody @Validated User user) {
    return userService.update(user);
}

🧩 Service 层

  • 接口
// 更新
Result update(User user);
  • 实现
/**
 * 更新用户昵称和邮箱
 *
 * @param user 用户对象
 */
@Override
public Result update(User user) {
    user.setUpdateTime(LocalDateTime.now());
    userMapper.update(user);
    return Result.success();
}

🧩 Mapper 层

// 修改昵称和邮箱
@Update("update user set nickname = #{nickname}, email = #{email}, update_time = #{updateTime} where id = #{id}")
void update(User user);

🎯 更新用户头像

🧩 Controller 层

请求路径:/user/updateAvatar
请求方式:PATCH
接口描述:该接口用于更新已登录用户的头像

@PatchMapping("updateAvatar")
public Result updateAvatar(@RequestParam @URL String avatarUrl) {
    return userService.updateAvatar(avatarUrl);
}

🧩 Service 层

  • 接口
// 更新头像
Result updateAvatar(String avatarUrl);
  • 实现
/**
 * 更新用户头像
 *
 * @param avatarUrl 用户头像地址
 */
@Override
public Result updateAvatar(String avatarUrl) {
    Map<String, Object> map = ThreadLocalUtil.get();
    Integer id = (Integer) map.get("id");
    userMapper.updateAvatar(avatarUrl, id);
    return Result.success();
}

🧩 Mapper 层

// 修改头像
@Update("update user set user_pic = #{avatarUrl}, update_time = now() where id = #{id}")
void updateAvatar(String avatarUrl, Integer id);

🎯 更新用户密码

🧩 Controller 层

请求路径:/user/updatePwd
请求方式:PATCH
接口描述:该接口用于更新已登录用户的密码

@PatchMapping("/updatePwd")
public Result updatePwd(@RequestBody @Validated PwdUpdateDTO dto) {
    return userService.updatePwd(dto);
}

🧩 Service 层

  • 接口
// 更新密码
Result updatePwd(PwdUpdateDTO dto);
  • 实现
/**
 * 更新用户密码
 *
 * @param dto 密码传输对象
 * @return 更新密码结果
 */
@Override
public Result updatePwd(PwdUpdateDTO dto) {
    // 1.校验参数
    if (!StringUtils.hasLength(dto.getOldPwd())
            || !StringUtils.hasLength(dto.getNewPwd())
            || !StringUtils.hasLength(dto.getRePwd())) {
        return Result.error("缺少必要的参数");
    }

    // 2.校验旧密码
    Map<String, Object> map = ThreadLocalUtil.get();
    String username = (String) map.get("username");
    User loginUser = findByUsername(username);
    if (loginUser == null) {
        return Result.error("用户不存在");
    }
    if (!loginUser.getPassword().equals(Md5Util.getMD5String(dto.getOldPwd()))) {
        return Result.error("旧密码填写错误");
    }
    if (!dto.getNewPwd().equals(dto.getRePwd())) {
        return Result.error("两次密码不一致");
    }
    if (loginUser.getPassword().equals(Md5Util.getMD5String(dto.getNewPwd()))) {
        return Result.error("新密码不能与旧密码相同");
    }

    // 3.更新密码
    userMapper.updatePwd(Md5Util.getMD5String(dto.getNewPwd()), loginUser.getId());
    return Result.success();
}

🧩 Mapper 层

// 修改密码
@Update("update user set password = #{md5String}, update_time = now() where id = #{id}")
void updatePwd(String md5String, Integer id);

http://www.kler.cn/a/589040.html

相关文章:

  • 数据增强常见问题与解决方案:提升AI模型性能的关键技巧
  • PyCharm如何有效地添加源与库?
  • CSS中固定定位
  • 错误记录: git 无法连接到github
  • Apache Pol (excel)
  • 算法——图论——关键活动
  • Python的那些事第四十五篇:继承自Nose的测试框架Nose2
  • 区间预测 | Matlab实现QRBiTCN分位数回归双向时间卷积神经网络注意力机制时序区间预测
  • Ubuntu 一站式初始化笔记
  • 【sql靶场】第13、14、17关-post提交报错注入保姆级教程
  • JVM常用概念之超态虚拟调用
  • 解析GNGGA数据,C语言单片机
  • AI是如何实现屏幕触控防水? 实测华为畅享70X
  • Redis监控:从睁眼瞎到千里眼的进化史
  • 【go语言圣经1.6】
  • 19.如何使用 pandas 处理大型 Excel 文件:并行读取工作表
  • pytorch小记(八):pytorch中有关于.detach()的浅显见解
  • PostgreSQL技术内幕26:PG聚合算子实现分析
  • 【VBA】excel获取股票实时行情(历史数据,基金数据下载)
  • 量子计算与医疗诊断的未来:超越传统的无限可能