大事件后端注册登录搭建笔记

一、创建Springboot项目

1.工具类:

Result

package com.spring.pojo;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

//统一响应结果
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Result<T> {
    private Integer code;//业务状态码  0-成功  1-失败
    private String message;//提示信息
    private T data;//响应数据

    //快速返回操作成功响应结果(带响应数据)
    public static <E> Result<E> success(E data) {
        return new Result<>(0, "操作成功", data);
    }

    //快速返回操作成功响应结果
    public static Result success() {
        return new Result(0, "操作成功", null);
    }

    public static Result error(String message) {
        return new Result(1, message, null);
    }
}

ThreadLocalUtil

package com.spring.utils;

import java.util.HashMap;
import java.util.Map;

/**
 * ThreadLocal 工具类
 */
@SuppressWarnings("all")
public class ThreadLocalUtil {
    //提供ThreadLocal对象,
    private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();

    //根据键获取值
    public static <T> T get(){
        return (T) THREAD_LOCAL.get();
    }
	
    //存储键值对
    public static void set(Object value){
        THREAD_LOCAL.set(value);
    }


    //清除ThreadLocal 防止内存泄漏
    public static void remove(){
        THREAD_LOCAL.remove();
    }
}

2.启动类和yaml配置

Springboot启动类

@SpringBootApplication
public class bigEventApplication {
    public static void main(String[] args) {
        SpringApplication.run(bigEventApplication.class,args);
    }
}

application.yaml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/big_event
    username: root
    password: 123456
  servlet:
    multipart:
      max-file-size: 5MB
      max-request-size: 5MB
  data:
    redis:
      host: localhost
      port: 6379

mybatis:
  configuration:
    map-underscore-to-camel-case: true # 开启驼峰命名法

3.Maven配置

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.3</version>
    </parent>

    <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>

        <!--mysql驱动-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--Validation-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

        <!--java-jwt-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.4.0</version>
        </dependency>

        <!--单元测试坐标-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <!--分页查询-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <!--阿里云SDK-->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.15.1</version>
        </dependency>
        <!-- 处理Java 9及以上版本的JAXB问题: -->
        <dependency>
            <groupId>jakarta.xml.bind</groupId>
            <artifactId>jakarta.xml.bind-api</artifactId>
            <version>3.0.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>4.0.5</version>
        </dependency>

        <!--redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>3.2.4</version>
            </plugin>
        </plugins>
    </build>

二、后端登录注册部分

(一)、后端注册和登录类:

UserController

/**
 * @author OceanStar
 * @create 2024-04-23 22:25
 */
@RestController
@RequestMapping("user")
@Validated
/*TODO
    1.引入Spring Validation 起步依赖
    2.在参数前面添加@Pattern注解
    3.在Controller类上添加@Validated注解
 */
public class UserController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private UserService userService;

    @PostMapping("register")
    public Result register(@Pattern(regexp = "^\\S{5,16}$") String username,@Pattern(regexp = "^\\S{5,16}$" )String password) {
//        if (username != null && username.length() >= 5 && username.length() <= 16 &&
//                password != null && password.length() >= 6 && password.length() <= 16) {
            User u = userService.findByUserName(username);
            if (u == null) {
                //没有占用 -> 注册
                userService.register(username, password);
                return Result.success();
            } else {
                //占用
                return Result.error("用户名已被占用");

            }
//        }else {
//            return Result.error("用户名密码格式错误");
//        }
    }

    @PostMapping("login")
    public Result<String> login(@Pattern(regexp = "^\\S{5,16}$") String username,@Pattern(regexp = "^\\S{5,16}$") String password){
        //根据用户名查询用户(根据用户名查询,返回这个用户的对象)
        User loginUser = userService.findByName(username);
        //判断用户名是否存在
        if(loginUser == null){
            return Result.error("用户名错误");
        }
        //判断密码是否正确
        //判断Controller中的password进行md5加密与userService层的md5加密的密码是否一致
        if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){
            //登录成功
            Map<String,Object> claims = new HashMap<>();
            claims.put("id",loginUser.getId());
            claims.put("username",loginUser.getUsername());
            String token = JwtUtil.genToken(claims);
            //TODO:把token存储到redis中
            ValueOperations<String, String> ops = redisTemplate.opsForValue();
            ops.set(token,token,999, TimeUnit.DAYS);
            return Result.success(token);//传入到loginInterceptor里面的request请求中
        }
    return Result.error("密码错误");
    }

    @GetMapping("/userInfo")
    public Result<User> userInfo
        //1.根据请求头获取token
        (/*@RequestHeader(name="Authorization") String token*/){
        //2.解析token,获取用户名
       /* Map<String, Object> map = JwtUtil.parseToken(token);
        String username = (String) map.get("username");*/
        //3.根据用户名查询用户
        //1.从ThreadLocal中获取存储的数据。ThreadLocal是一种线程绑定的存储机制,
        //每个线程都有自己独立的副本,用于在同一线程的不同方法间共享数据。
        Map<String, Object> map = ThreadLocalUtil.get();

        // 2.从ThreadLocal存储的Map中提取用户名,以键"username"取出对应的值,并将其转换为String类型。
        String username = (String) map.get("username");

        // 3. 根据获取的用户名查询用户,这里使用了userService对象的findByName方法
        User user = userService.findByName(username);
        //4.返回用户
        return Result.success(user);
    }

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

    /**
     * 处理HTTP PATCH请求,用于更新用户头像。
     * @param avatarUrl 新的头像URL,作为请求参数传递。
     * @return 更新头像操作的结果,通常封装在自定义的Result对象中。
     * @PatchMapping 注解是更新部分内容
   (只提交需要更改的部分属性或字段,而不是整个资源的完整表示)
     */
    @PatchMapping("updateAvatar")
    public Result updateAvatar(@RequestParam @URL String avatarUrl) {
        userService.updateAvatar(avatarUrl);
        return Result.success();
    }

    @PatchMapping("updatePwd")
    public Result updatePwd(@RequestBody Map<String,String> params,@RequestHeader("Authorization") String token) {
        //1.校验参数
        String oldPwd = params.get("old_pwd");
        String newpwd = params.get("new_pwd");
        String rePwd = params.get("re_pwd");
        if(!StringUtils.hasLength(oldPwd)||!StringUtils.hasLength(newpwd)||!StringUtils.hasLength(rePwd)){
            return Result.error("缺少必要参数");
        }
        //原密码是否正确
        //调用userService根据用户名拿到密码,再old_pwd比对
        Map<String,Object> map = ThreadLocalUtil.get();
        String username = (String) map.get("username");
        User loginUser = userService.findByName(username);
        if(!loginUser.getPassword().equals(Md5Util.getMD5String(oldPwd))){
            return Result.error("原密码填写不正确");
        }
        //newPwd和rePwd是否一致
        if(!newpwd.equals(rePwd)){
           return Result.error("两次输入的新密码不一致") ;
        }
        //2.调用service实现密码更新
        userService.updatePwd(newpwd);
        //TODO:删除redis中对应的token
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        ops.getOperations().delete(token);
        return Result.success();
    }
}

  1. 包导入
    • 引入了必要的pojo、service、util类以及Spring框架的相关依赖。
  2. 类定义
    • @RestController:声明这是一个REST控制器,处理HTTP请求并返回JSON响应。
    • @RequestMapping("user"):所有处理的请求路径都以"user"作为前缀。
    • @Validated:在类级别上使用,表示类中的方法参数将进行数据验证。
  3. 依赖注入
    • @Autowired:用于自动注入依赖的StringRedisTemplateUserServiceStringRedisTemplate用于操作Redis,而UserService提供了与用户相关的业务逻辑。
  4. 工具类引用
    • JwtUtil:处理JWT(JSON Web Tokens)相关的操作,如生成和解析Token。
    • Md5Util:提供MD5加密功能,可能用于密码存储。
    • ThreadLocalUtil:一个线程局部存储工具类,可能用于存储线程相关的上下文信息,比如当前登录用户的标识。
  5. 其他导入的库和注解
    • jakarta.validation.constraints.Patternorg.hibernate.validator.constraints.URL:用于数据验证,确保输入符合特定的正则表达式或URL格式。
    • org.springframework.util.StringUtils:提供字符串操作的实用方法。
    • org.springframework.web.bind.annotation.*:用于处理HTTP请求的方法注解,如@GetMapping, @PostMapping, @PutMapping, @DeleteMapping

Userservice

/**
     public interface UserService {

    /**
     * 查询用户信息,根据用户名。
     *
     * @param username 用户名
     * @return 用户对象
     */
    User findById(String username);

    /**
     * 注册新用户。
     *
     * @param username 用户名
     * @param password 密码
     */
    void register(String username, String password);

    /**
     * 查询用户信息,根据用户名。
     *
     * @param username 用户名
     * @return 用户对象
     */
    User findByName(String username);

    /**
     * 更新用户信息。
     *
     * @param user 完整的用户对象,包含待更新的数据
     */
    void update(User user);

    /**
     * 更新用户头像。
     *
     * @param avatarUrl 新的头像URL
     */
    void updateAvatar(String avatarUrl);


    void updatePwd(String newpwd);
}

UserServiceImpl

package com.spring.service.Impl;

import com.spring.mapper.UserMapper;
import com.spring.pojo.User;
import com.spring.service.UserService;
import com.spring.utils.Md5Util;
import com.spring.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Map;

/**
 * @author OceanStar
 * @create 2024-04-23 22:27
 */
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public User findByUserName(String username) {
        return userMapper.findByUserName(username);
    }

    @Override
    public void register(String username, String password) {
        //TODO MD5加密
        String md5String = Md5Util.getMD5String(password);
        //添加
        userMapper.add(username,md5String);
    }

    @Override
    public User findByName(String username) {
        return userMapper.findByName(username);
    }

    @Override
    public void update(User user) {
        //更新需要更改更新时间,所以调用localDataTime.now()方法进行更新
        user.setUpdateTime(LocalDateTime.now());
        userMapper.update(user);
    }

    @Override
    public void updateAvatar(String avatarUrl) {
        Map<String,Object> map = ThreadLocalUtil.get();
        Integer id = (Integer) map.get("id");
        //更新头像
        userMapper.updateAvatar(avatarUrl,id);
    }

    @Override
    public void updatePwd(String newpwd) {
        Map<String,Object> map = ThreadLocalUtil.get();
        Integer id = (Integer) map.get("id");
        userMapper.updatePwd(Md5Util.getMD5String(newpwd),id);//需要的是加密后的密码再给mapper层
    }


}

UserMapper类

@Mapper
public interface UserMapper {
    //根据用户名添加用户
    @Select("select * from user where username = #{username} ")
    User findById(String username);
    //添加用户
    @Insert("insert into user(username,password,create_time,update_time)" +
            " values(#{username},#{md5String},now(),now())")
    void add(String username, String md5String);

    @Select("select * from user where username = #{username}")
    User findByName(String username);

    @Update("update user set nickname=#{nickname},email=#{email},update_time=#{updateTime} where id = #{id}")
    void update(User user);

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

    @Update("update user set password=#{newpwd},update_time= now() where id = #{id}")
    void updatePwd(String newpwd, Integer id);
}

User类:

package com.spring.pojo;

import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Data;

import java.time.LocalDateTime;

@Data
public class User {
    @NotNull //值不能是null
    private Integer id;//主键ID

    private String username;//用户名

    @JsonIgnore //让springmvc转换json对象时忽略password
    private String password;//密码

    @NotEmpty //值不能是null,并且内容不能为空
    private String nickname;//昵称

    @Email //满足邮箱格式
    /*@Pattern(regexp = "^\\S{1,10}$")*/
    private String email;//邮箱

    private String userPic;//用户头像地址
    private LocalDateTime createTime;//创建时间
    private LocalDateTime updateTime;//更新时间
}

1.register方法

接口定义:
  • 接口路径:/user/register
  • 请求方法:POST
  • 功能描述:处理用户的注册请求,验证并创建新用户。
请求参数:
  • username:用户输入的用户名,通过正则表达式^\\S{5,16}$验证,确保5到16个非空白字符。
  • password:用户输入的密码,同样遵循上述正则规则,保证安全性和一致性。
@PostMapping("register")
    public Result register(@Pattern(regexp = "^\\S{5,16}$") String username,@Pattern(regexp = "^\\S{5,16}$" )String password) {
            User u = userService.findByUserName(username);//用username去查找数据库是否存在用户名
            //判断当前用户是否注册
            if (u == null) {
                //没有占用 -> 注册
                userService.register(username, password);
                return Result.success();
            } else {
                //占用
                return Result.error("用户名已被占用");

            }
    }
service层:
  • findById:根据用户名查询用户对象,如果存在返回用户信息,否则返回null
  • register:接收用户名和密码,执行实际的注册操作,如创建新用户记录。
 /**
     * 查询用户信息,根据用户名。
     *
     * @param username 用户名
     * @return 用户对象
     */
    User findByUserName(String username);

    /**
     * 注册新用户。
     *
     * @param username 用户名
     * @param password 密码
     */
    void register(String username, String password);
serviceImpl层:
  • 当用户注册时,输入的明文密码通过Md5Util.getMD5String(password)方法转换成MD5哈希值。这个哈希值随后被存储到数据库中,而不是原始密码。
  • 当用户登录时,输入的密码同样会被转换成MD5哈希值,然后与数据库中对应用户名的密码哈希值进行比较,如果两者匹配,则密码验证成功。
  • 这样,即使数据库数据泄露,攻击者也无法直接知道用户的明文密码,增加了破解的难度,提高了系统的安全性。
@Override
    public User findByUserName(String username) {
        return userMapper.findByUserName(username);
    }

    @Override
    public void register(String username, String password) {
        //TODO MD5加密
        String md5String = Md5Util.getMD5String(password);
        //添加
        userMapper.add(username,md5String);
    }
mapper层:
  • findById:使用MyBatis的@Select注解执行SQL查询,查找用户名对应的用户记录。
  • add:使用@Insert注解执行SQL插入,创建新的用户记录。注意这里密码可能已经进行了加密处理(如MD5),以提高安全性。
//根据用户名添加用户
@Select("select * from user where username = #{username} ")
User findByUserName(String username);
//添加用户
@Insert("insert into user(username,password,create_time,update_time)" +
       "values(#{username},#{md5String},now(),now())")
void add(String username, String md5String);
业务逻辑:
  • 用户名检查:调用userService.findById(username)查询数据库中是否存在相同用户名的用户。
  • 如果查询结果u为空,说明用户名未被占用,执行userService.register(username, password)进行注册。
  • 注册成功后,返回Result.success(),表示注册完成。
  • 如果u非空,说明用户名已被占用,返回Result.error("用户名已被占用"),提示前端错误信息

2.login方法

接口定义
  • 接口路径/user/login
  • 请求方法POST
  • 功能描述:处理用户的登录请求,验证用户名和密码,返回JWT令牌用于身份验证。
请求参数
  • username:用户输入的用户名,遵循正则表达式^\\S{5,16}$,确保为5至16个字符的非空白字符串。
  • password:用户输入的密码,同样遵循^\\S{5,16}$正则规则,保证输入安全。
@PostMapping("login")
    public Result<String> login(@Pattern(regexp = "^\\S{5,16}$") String username,@Pattern(regexp = "^\\S{5,16}$") String password){
        //根据用户名查询用户(根据用户名查询,返回这个用户的对象)
        User loginUser = userService.findByName(username);
        //判断用户名是否存在
        if(loginUser == null){
            return Result.error("用户名错误");
        }
        //判断密码是否正确
        //判断Controller中的password进行md5加密与userService层的md5加密的密码是否一致
        if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){
            //登录成功
            Map<String,Object> claims = new HashMap<>();
            claims.put("id",loginUser.getId());
            claims.put("username",loginUser.getUsername());
            String token = JwtUtil.genToken(claims);
            //TODO:把token存储到redis中
            ValueOperations<String, String> ops = redisTemplate.opsForValue();
            ops.set(token,token,999, TimeUnit.DAYS);
            return Result.success(token);//传入到loginInterceptor里面的request请求中
        }
    return Result.error("密码错误");
    }
service层:
  • findByName:根据用户名查询用户对象,如果存在返回用户信息,否则返回null
  • validateLogin:执行登录验证逻辑,包括用户名存在性和密码正确性。
 /**
     * 查询用户信息,根据用户名。
     *
     * @param username 用户名
     * @return 用户对象
     */
    User findByName(String username);
serviceImpl层:
 @Override
    public User findByName(String username) {
        return userMapper.findByName(username);
    }
mapper层:
  • findByName:使用MyBatis的@Select注解执行SQL查询,查找用户名对应的用户记录。
  • getPasswordByUsername:如果需要单独查询密码,可以添加一个方法来获取特定用户名的密码。
 //根据用户名,查询用户信息
 @Select("select * from user where username = #{username}")
    User findByName(String username);
业务逻辑
  1. 用户名验证
    • 调用userService.findByName(username)查询数据库中是否存在该用户名的用户。
  2. 密码验证
    • 如果查询结果loginUser非空,进行密码验证。
    • 使用Md5Util.getMD5String(password)对用户输入的密码进行MD5加密。
    • 比较加密后的密码与数据库中用户对象的密码(loginUser.getPassword()),如果匹配,密码验证通过。
  3. 登录成功处理
    • 如果密码验证通过,构建JWT令牌的载荷信息,如用户ID和用户名。
    • 使用JwtUtil.genToken(claims)生成JWT字符串。
    • 存储JWT令牌到Redis,设置一个合适的过期时间,如ops.set(token, token, tokenExpireTime, TimeUnit.SECONDS)
    • 返回登录成功的结果,携带JWT令牌,供客户端后续请求使用。
  4. 错误处理
    • 如果用户名不存在,返回Result.error("用户名不存在")
    • 如果密码验证失败,返回Result.error("密码错误")

3.userInfo方法

接口定义
  • 接口路径/userInfo
  • 请求方法GET
  • 功能描述:根据请求中的用户标识(通过ThreadLocal存储的用户名)获取并返回用户的详细信息。
@GetMapping("/userInfo")
    public Result<User> userInfo(){
        //1.根据请求头获取token
        //(@RequestHeader(name="Authorization") String token){
        //2.解析token,获取用户名
       /* Map<String, Object> map = JwtUtil.parseToken(token);
        String username = (String) map.get("username");*/
        //3.根据用户名查询用户
        //User user = userService.findByName(username);
               
        //1.从ThreadLocal中获取存储的数据。ThreadLocal是一种线程绑定的存储机制,
        //每个线程都有自己独立的副本,用于在同一线程的不同方法间共享数据。
        Map<String, Object> map = ThreadLocalUtil.get();

        // 2.从ThreadLocal存储的Map中提取用户名,以键"username"取出对应的值,并将其转换为String类型。
        String username = (String) map.get("username");

        // 3. 根据获取的用户名查询用户,这里使用了userService对象的findByName方法
        User user = userService.findByName(username);
        
        //4.返回用户信息
        return Result.success(user);
    }

service层:
 /**
     * 查询用户信息,根据用户名。
     *
     * @param username 用户名
     * @return 用户对象
     */
    User findByName(String username);
serviceImpl层:
 @Override
    public User findByName(String username) {
        return userMapper.findByName(username);
    }
mapper层:
  • findByName:使用MyBatis的@Select注解执行SQL查询,查找用户名对应的用户记录。
   @Select("select * from user where username = #{username}")
    User findByName(String username);
请求处理
  1. 用户标识提取:
    • 本例中,用户标识(用户名)不是直接从请求头中的Authorization字段获取,而是利用了ThreadLocal存储的上下文信息。在之前的登录流程中,登录成功后将用户名等信息存储到了ThreadLocal中,以便后续请求在同一线程内无需再次传递Token。
  2. 解析标识:
    • 直接从ThreadLocalUtil.get()获取到的Map中提取之前存储的用户名,作为查询数据库的依据。
  3. 查询用户信息:
    • 调用userService.findByName(username),根据从ThreadLocal中获取的用户名查询数据库,获取用户详细信息。
  4. 响应处理:
    • 查询到用户信息后,通过Result.success(user)封装用户对象,并作为响应体返回,表示操作成功。

4.update方法

权限验证:在实际应用中,应确保只有登录用户才能更新自己的信息,需要验证请求中的用户ID与`ThreadLocal`中存储的用户ID一致。
接口定义
  • 接口路径/update
  • 请求方法PUT
  • 功能描述:根据请求中携带的用户对象更新用户信息,该对象应包含用户ID,以及其他待更新的属性。
请求参数
  • 用户对象 (User):包含了待更新的用户信息,如nickname, email等。用户ID是必需的,以确定要更新的用户记录。
  @PutMapping("/update")
    public Result update (@RequestBody @Validated User user){
        userService.update(user);
        return Result.success();
    }
service层:
/**
     * 更新用户信息。
     *
     * @param user 完整的用户对象,包含待更新的数据
     */
    void update(User user);
serviceImpl层:
 @Override
    public void update(User user) {
        //更新需要更改更新时间,所以调用localDataTime.now()方法进行更新
        user.setUpdateTime(LocalDateTime.now());
        userMapper.update(user);
    }
mapper层:
  • update方法使用MyBatis的@Update注解,执行更新用户信息的SQL,只列出更改的字段,如nickname, email等,并设置update_time
   @Update("update user set nickname=#{nickname},email=#{email},update_time=#{updateTime} where id = #{id}")
    void update(User user);
请求处理
  1. 数据校验
    • 请求体中的User对象通过@RequestBody@Validated注解进行数据校验,确保必填项完整且格式正确。
  2. 更新用户信息
    • 将完整的用户对象传递给userService.update(user),执行更新操作。
  3. 更新逻辑
    • serviceImpl层,首先设置updateTime为当前时间,确保每次更新都有新的更新时间戳。
    • 然后调用userMapper.update(user),使用MyBatis的@Update注解执行SQL,更新指定ID的用户记录。
  4. 响应处理
    • 更新成功后,返回Result.success(),表示操作成功。由于更新操作不返回具体的数据对象,因此响应中没有封装用户对象。

5.updateAvatar方法

接口定义
  • 接口路径/update/avatar
  • 请求方法PATCH
  • 功能描述:更新用户的头像URL,请求参数中包含新的头像链接。
请求参数
  • avatarUrl:用户上传的新头像URL,通过@RequestParam注解接收,使用@URL进行URL格式的校验。
  /**
     * 处理HTTP PATCH请求,用于更新用户头像。
     * @param avatarUrl 新的头像URL,作为请求参数传递。
     * @return 更新头像操作的结果,通常封装在自定义的Result对象中。
     * @PatchMapping 注解是更新部分内容
   (只提交需要更改的部分属性或字段,而不是整个资源的完整表示)
     */
    @PatchMapping("updateAvatar")
    public Result updateAvatar(@RequestParam @URL String avatarUrl) {
        userService.updateAvatar(avatarUrl);
        return Result.success();
    }
service层:
 /**
     * 更新用户头像。
     *
     * @param avatarUrl 新的头像URL
     */
    void updateAvatar(String avatarUrl);
serviceImpl层:
@Override
    public void updateAvatar(String avatarUrl) {
        Map<String,Object> map = ThreadLocalUtil.get();
        Integer id = (Integer) map.get("id");
        //更新头像
        userMapper.updateAvatar(avatarUrl,id);
    }
mapper层:
  • update方法使用MyBatis的@Update注解,执行更新用户头像信息的SQL,通过id条件更改头像信息
 @Update("update user set user_pic=#{avatarUrl},update_time= now() where id = #{id}")
    void updateAvatar(String avatarUrl, Integer id);
请求处理
  1. 权限验证
    • 在实际应用中,应验证请求中的用户ID与ThreadLocal中存储的用户ID一致,确保只有登录用户才能更新自己的头像。
  2. 更新头像
    • ThreadLocalUtil.get()中获取当前登录用户的ID。
    • 调用userService.updateAvatar(avatarUrl),传入新的头像URL,执行头像更新操作。
  3. 响应处理
    • 头像更新成功后,返回Result.success(),表示操作成功。响应中不包含具体的数据对象。

6.updateAvatar方法

接口定义
  • 接口路径/update/pwd
  • 请求方法PATCH
  • 功能描述:更新用户密码,请求参数中包含旧密码、新密码和确认新密码。
请求参数
  • old_pwd:当前用户的旧密码。
  • new_pwd:用户设定的新密码。
  • re_pwd:用户确认的新密码,用于校验输入一致性。
  • Authorization:请求头中的Token,用于验证用户身份。
 @PatchMapping("updatePwd")
    public Result updatePwd(@RequestBody Map<String,String> params,@RequestHeader("Authorization") String token) {
        //1.校验参数
        String oldPwd = params.get("old_pwd");
        String newpwd = params.get("new_pwd");
        String rePwd = params.get("re_pwd");
        if(!StringUtils.hasLength(oldPwd)||!StringUtils.hasLength(newpwd)||!StringUtils.hasLength(rePwd)){
            return Result.error("缺少必要参数");
        }
        //原密码是否正确
        //调用userService根据用户名拿到密码,再old_pwd比对
        Map<String,Object> map = ThreadLocalUtil.get();
        String username = (String) map.get("username");
        User loginUser = userService.findByName(username);
        if(!loginUser.getPassword().equals(Md5Util.getMD5String(oldPwd))){
            return Result.error("原密码填写不正确");
        }
        //newPwd和rePwd是否一致
        if(!newpwd.equals(rePwd)){
           return Result.error("两次输入的新密码不一致") ;
        }
        //2.调用service实现密码更新
        userService.updatePwd(newpwd);
        //TODO:删除redis中对应的token
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        ops.getOperations().delete(token);
        return Result.success();
    }
参数校验
  1. 检查参数完整性
    • 检查old_pwd, new_pwd, re_pwd是否存在,如果缺失则返回错误信息。
  2. 验证原密码
    • 使用ThreadLocalUtil.get()获取当前登录用户信息,然后通过用户名查询用户,对比原密码的正确性。
  3. 新密码一致性校验
    • 比较new_pwdre_pwd是否一致,不一致则返回错误信息。
service层:
 void updatePwd(String newpwd);
serviceImpl层:
安全:密码必须加密存储,这里使用了MD5加密
@Override
    public void updatePwd(String newpwd) {
        Map<String,Object> map = ThreadLocalUtil.get();
        Integer id = (Integer) map.get("id");
        userMapper.updatePwd(Md5Util.getMD5String(newpwd),id);//需要的是加密后的密码再给mapper层
    }
mapper层:
  • update方法使用MyBatis的@Update注解,执行更新用户头像信息的SQL,通过id条件更改头像信息
 @Update("update user set password=#{newpwd},update_time= now() where id = #{id}")
    void updatePwd(String newpwd, Integer id);
请求处理
  1. 权限验证
    • 验证请求头中的Token,确保用户已登录并具有修改密码的权限。
  2. 密码更新
    • 调用userService.updatePwd(newpwd),使用新密码的MD5加密版本更新数据库。
  3. 清理Token
    • 为了安全,更新密码后从Redis中删除对应的Token,强制用户重新登录。
  4. 响应处理
    • 密码更新成功后,返回Result.success(),表示操作成功。响应中不包含具体的数据对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值