用户中心(末)

开发用户注销前后端

后端

当用户登录成功之后,我们在请求体的 session 中保存了用户的登录态,之后判断用户是否登录就是看这个 session 里有没有这个标识,判断用户是否登录。
因此用户注销也是同样的,把用户的登录态移除即可
UserService

/**
 * 用户注销
 * @param request
 * @return
 */
int userLogout(HttpServletRequest request);

UserServiceImpl

/**
 * 用户注销
 * @param request
 * @return
 */
@Override
public int userLogout(HttpServletRequest request) {
    //移除登录态
    request.getSession().removeAttribute(USER_LOGIN_STATE);
    return 1;
}

UserController

@PostMapping("/logout")
public Integer userLogout(HttpServletRequest request){
    if(request==null){
        return null;
    }
    return userService.userLogout(request);
}

前端

启动之后登录进去发现这个“退出登录”在导航栏上,因此应该是在 components 包下,是在 RightContent 包下的 AvatarDropdown.tsx 文件
image.png
image.png
修改即可
image.png

补充用户注册校验逻辑前后端

设计

仅适用于用户可信的情况

先让用户自己填:2-5位编号,自觉填
后台补充对自己编号的校验:长度校验、唯一性校验
前端补充输入框,适配后端

后期拉取星球数据,定期清理违规用户

后端

数据库增添用户星球编号属性
相应的在User, mapper.xml, UserServieIml 里的方法都加上planetCode 属性(参数)
修改 UserService、UserServiceImpl、UserController
UserService 里的多加了参数

/**
     * 用户注册
     *
     * @param userAccount   用户账户
     * @param userPassword  用户密码
     * @param checkPassword 校验密码
     * @param planetCode 星球编号
     * @return 用户id
     */
    long userRegister(String userAccount, String userPassword, String checkPassword, String planetCode);

UserServiceImpl 里多加了参数、校验,比如长度校验、唯一性校验,插入数据这里也要添加

@Override
    public long userRegister(String userAccount, String userPassword, String checkPassword, String planetCode) {
        // 星球编号长度不大于五
        if (planetCode.length() > 5) {
            return -1;
        } 
        //星球编号不能重复
        //账户不能重复
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("planetCode", planetCode);
        count = userMapper.selectCount(queryWrapper);
        if(count > 0){
            return -1;
        }
        //3.插入数据
        User user = new User();
        user.setUserAccount(userAccount);
        user.setUserPassword(encryptPassword);
        user.setPlanetCode(planetCode);
        boolean saveResult = this.save(user);
        if (!saveResult){
            return -1;
        }
        return user.getId();
    }

UserController 里主要是多加了参数

PostMapping("/register")
    public Long userRegister(@RequestBody UserRegisterRequest userRegisterRequest) {
        if (userRegisterRequest == null)
        {
            return null;
        }
        String userAccount = userRegisterRequest.getUserAccount();
        String userPassword = userRegisterRequest.getUserPassword();
        String checkPassword = userRegisterRequest.getCheckPassword();
        String planetCode = userRegisterRequest.getPlanetCode();

        if(StringUtils.isAnyBlank(userAccount,userPassword,checkPassword,planetCode)) {
            return null;
        }

        return userService.userRegister(userAccount, userPassword, checkPassword,planetCode);
    }

同时在测试类里也要改,不然会报错,同时进行测试

@Test
    void userRegister() {
        //  a. 非空
        String userAccount = "yupi";
        String userPassword = "";
        String checkPassword = "12345678";
        String planetCode = "1";
        long result = userService.userRegister(userAccount,userPassword,checkPassword, planetCode);
        Assertions.assertEquals(-1, result);
        //  b. 账户不小于 4 位
        userAccount = "yu";
        userPassword = "12345678";
        result = userService.userRegister(userAccount,userPassword,checkPassword, planetCode);
        Assertions.assertEquals(-1, result);

        //  c. 密码不小于 8 位
        userAccount = "yupi";
        userPassword = "123";
        result = userService.userRegister(userAccount,userPassword,checkPassword, planetCode);
        Assertions.assertEquals(-1, result);

        //  d. 账户不能重复
        userAccount = "123456";
        userPassword = "12345678";
        result = userService.userRegister(userAccount,userPassword,checkPassword, planetCode);
        Assertions.assertEquals(-1, result);
        //  e. 账户不包含特殊字符
        userAccount = "yu pi";
        result = userService.userRegister(userAccount,userPassword,checkPassword, planetCode);
        Assertions.assertEquals(-1, result);

        //  f. 校验密码和密码相同
        userAccount = "yupi";
        userPassword = "12345678";
        checkPassword = "12345678";
        result = userService.userRegister(userAccount,userPassword,checkPassword, planetCode);
        Assertions.assertTrue(result > 0);
    }

前端

注册页面添加输入框,填入星球编号
image.png
添加星球编号字段

type CurrentUser = {
    id: number,
    username: string,
    userAccount: string,
    avatarUrl?: string,
    gender: number,
    phone: string,
    email: string,
    planetCode:string,
    userStatus: number,
    userRole: number,
    createTime: Date;
  };
type RegisterParams = {
  userAccount?: string;
  userPassword?: string;
  checkPassword?: string;
  planetCode?: string;
  type?: string;
};

在管理页面加上星球编号列
image.png

后端代码优化

封装通用返回对象

  • 目的:给对象补充一些信息,告诉前端这个请求在业务层面上是成功还是失败
}//成功
{
  "code": 0 //业务状态码
  "data": {
    "name": "yupi"
  },
  "message": "ok"
}

//错误
{
  "code": 50001 //业务状态码
  "data": null
  "message": "用户操作异常、..."
  "description": 
}

创建一个包 common,创建通用返回类 BaseResponse,我们用泛型定义返回结果,这样就能返回任意类型的结果
image.png

package com.ivy.usercenter.common;

import java.io.Serializable;

/**
 * 通用返回类
 * @author ivy
 * @date 2024/4/15 17:13
 */
@Data
public class BaseResponse<T> implements Serializable {
    private int code;
    private T data;
    private String message;
    private String description;

    public BaseResponse(int code, T data, String message, String description) {
        this.code = code;
        this.data = data;
        this.message = message;
        this.description=description;
    }

    public BaseResponse(int code, T data, String message) {
        this(code,data,message,"");
    }

    public BaseResponse(int code, T data) {
        this(code,data,"","");
    }

    public BaseResponse(ErrorCode errorCode){
        this(errorCode.getCode(),null,errorCode.getMessage(),errorCode.getDescription());
    }
}

自定义错误码

package com.ivy.usercenter.common;

/**
 * 自定义错误码
 * @author ivy
 * @date 2024/4/15 17:19
 */
public enum ErrorCode {
    SUCCESS(0,"success",""),
    PARAMS_ERROR(40000,"请求参数错误",""),
    NULL_ERROR(40001,"请求数据为空",""),
    NO_AUTH_ERROR(40101,"无权限",""),
    NOT_LOGIN_ERROR(40100,"未登录",""),
    SYSTEM_ERROR(50000,"系统内部异常","");

    private final int code;
    /**
     * 状态码信息
     */
    private final String message;
    /**
     * 状态码描述(详情)
     */
    private final String description;

    ErrorCode(int code, String message, String description) {
        this.code = code;
        this.message = message;
        this.description = description;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    public String getDescription() {
        return description;
    }
}

返回结果统一封装,避免代码容易出错,创建个返回工具类 ResultUtils

package com.ivy.usercenter.common;

import java.io.Serializable;

/**
 * @author ivy
 * @date 2024/4/15 17:17
 */
public class ResultUtils implements Serializable {
    /**
     * 成功
     * @param data
     * @return
     * @param <T>
     */
    public static <T> BaseResponse<T> success(T data){
        return new BaseResponse<>(0,data,"success","");
    }

    /**
     * 失败
     * @param errorCode
     * @return
     */
    public static BaseResponse error(ErrorCode errorCode){
        return new BaseResponse<>(errorCode.getCode(),null,errorCode.getMessage(),errorCode.getDescription());
    }

    /**
     * 失败
     * @param code
     * @param message
     * @param description
     * @return
     */
    public static BaseResponse error(int code, String message, String description){
        return new BaseResponse<>(code,null,message,description);
    }

    /**
     * 失败
     * @param errorCode
     * @param message
     * @param description
     * @return
     */
    public static BaseResponse error(ErrorCode errorCode, String message, String description){
        return new BaseResponse<>(errorCode.getCode(),null,message,description);
    }

    /**
     * 失败
     * @param errorCode
     * @param description
     * @return
     */
    public static BaseResponse error(ErrorCode errorCode, String description){
        return new BaseResponse<>(errorCode.getCode(),null,errorCode.getMessage(),description);
    }
}

修改UserController 中的接口返回结果

package com.ivy.usercenter.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ivy.usercenter.common.BaseResponse;
import com.ivy.usercenter.common.ErrorCode;
import com.ivy.usercenter.common.ResultUtils;
import com.ivy.usercenter.model.domain.User;
import com.ivy.usercenter.model.domain.request.UserLoginrequest;
import com.ivy.usercenter.model.domain.request.UserRegisterRequest;
import com.ivy.usercenter.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;
import static com.ivy.usercenter.contant.UserConstant.ADMIN_ROLE;
import static com.ivy.usercenter.contant.UserConstant.USER_LOGIN_STATE;

/**
 * 用户控制器
 * @author ivy
 * @date 2024/4/11 17:11
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserService userService;

    @PostMapping("/register")
    public BaseResponse<Long> userRegister(@RequestBody UserRegisterRequest userRegisterRequest) {
        if (userRegisterRequest == null)
        {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR);
        }
        String userAccount = userRegisterRequest.getUserAccount();
        String userPassword = userRegisterRequest.getUserPassword();
        String checkPassword = userRegisterRequest.getCheckPassword();
        String planetCode = userRegisterRequest.getPlanetCode();

        if(StringUtils.isAnyBlank(userAccount,userPassword,checkPassword,planetCode)) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR);
        }

        long l = userService.userRegister(userAccount, userPassword, checkPassword, planetCode);
        return ResultUtils.success(l);
    }

    @PostMapping("/login")
    public BaseResponse<User> userLogin(@RequestBody UserLoginrequest userLoginrequest, HttpServletRequest request) {
        if (userLoginrequest == null)
        {
            return ResultUtils.error(ErrorCode.NULL_ERROR);
        }
        String userAccount = userLoginrequest.getUserAccount();
        String userPassword = userLoginrequest.getUserPassword();
        if(StringUtils.isAnyBlank(userAccount,userPassword)) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR);
        }

        User user = userService.userLogin(userAccount, userPassword, request);
        return ResultUtils.success(user);
    }

    @PostMapping("/logout")
    public BaseResponse<Integer> userLogout(HttpServletRequest request) {
        if (request == null)
        {
            return ResultUtils.error(ErrorCode.NULL_ERROR);
        }
        int i = userService.userLogout(request);
        return ResultUtils.success(i);
    }

    /**
     * 获取当前用户
     * @param request 前端请求
     * @return 当前用户
     */
    @GetMapping("/current")
    public BaseResponse<User> getCurrentUser(HttpServletRequest request) {
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        User currentUser = (User) userObj;
        if(currentUser == null) {
            return ResultUtils.error(ErrorCode.NOT_LOGIN_ERROR);
        }
        long id = currentUser.getId();
        // todo 校验用户是否合法
        User user = userService.getById(id);
        User safetyUser = userService.getSafetyUser(user);
        return ResultUtils.success(safetyUser);
    }


    @GetMapping("/search")
    public BaseResponse<List<User>> searchUsers(String username, HttpServletRequest request) {
        if (!isAdmin(request)) {
            return ResultUtils.error(ErrorCode.NO_AUTH_ERROR);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(username)) {
            queryWrapper.like("username", username);
        }
        List<User> userList = userService.list();
        List<User> collect = userList.stream().map(user -> userService.getSafetyUser(user)).collect(Collectors.toList());
        return ResultUtils.success(collect);
    }

    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteUser(@RequestBody Long id , HttpServletRequest request) {
        if (!isAdmin(request)) {
            return ResultUtils.error(ErrorCode.NO_AUTH_ERROR);
        }
        if(id <= 0) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR);
        }
        boolean b = userService.removeById(id);
        return ResultUtils.success(b);
    }

    private boolean isAdmin(HttpServletRequest request) {
        // 鉴权,只有管理员可以查询
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        User user = (User) userObj;
        if(user == null || user.getUserRole() != ADMIN_ROLE) {
            return false;
        }
        return  true;
    }
}

我们有很多都需要在判断出错误以后就调用错误返回类(ResultUtils.error的多次使用),这样比较麻烦,因此我们就封装全局异常处理,把所有的错误都在一个地方处理

封装全局异常处理

先创建个包 exception,创建类 BusinessException
这里直接继承 RuntimeException 了,但还是要封装,是因为和我们的错误码的参数相比,少了 description,不能直接用 ErrorCode,因此要自己封装。

  1. 定义业务异常类
    1. 支持更多的字段
    2. 自定义构造函数也能更灵活地设置字段
package com.ivy.usercenter.exception;

import com.ivy.usercenter.common.ErrorCode;

/**
 * 自定义异常类
 * @author ivy
 * @date 2024/4/15 19:52
 */
public class BusinessException extends RuntimeException{

    //异常中的属性不需要 setter
    //这里就相当于给原来的 RuntimeException 扩充了这两个属性
    private static final long serialVersionUID = -6937582848772423714L;
    private final int code;
    private final String description;

    //并且创建了几个构造函数,让他能够使用 ErrorCode
    public BusinessException(String message, int code, String description) {
        super(message);
        this.code = code;
        this.description = description;
    }

    public BusinessException(ErrorCode errorCode) {
        super(errorCode.getMessage());
        this.code = errorCode.getCode();
        this.description = errorCode.getDescription();
    }

    public BusinessException(ErrorCode errorCode, String description) {
        super(errorCode.getMessage());
        this.code = errorCode.getCode();
        this.description = description;
    }

    public int getCode() {
        return code;
    }

    public String getDescription() {
        return description;
    }
}

  1. 编写全局异常处理器
    1. 捕获代码中所有的异常,内部消化,集中处理,让前端得到更详细的业务报错/信息
    2. 同时屏蔽掉项目框架本身的异常(不暴露服务器内部状态)
    3. 集中处理,比如记录日志
    4. 方式:通过 SpringAOP:在调用方法前后进行额外的处理
package com.ivy.usercenter.exception;

import com.ivy.usercenter.common.BaseResponse;
import com.ivy.usercenter.common.ErrorCode;
import com.ivy.usercenter.common.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理器
 * @author ivy
 * @date 2024/4/15 20:26
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(BusinessException.class)
    public BaseResponse businessExceptionHandler(BusinessException e){
        log.error("businessException"+e.getMessage(),e);
        return ResultUtils.error(e.getCode(),e.getMessage(),e.getDescription());
    }

    @ExceptionHandler(RuntimeException.class)
    public BaseResponse runtimeExceptionHandler(RuntimeException e){
        log.error("runtimeException",e);
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR,e.getMessage(),"");
    }
}

UserController

package com.ivy.usercenter.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ivy.usercenter.common.BaseResponse;
import com.ivy.usercenter.common.ErrorCode;
import com.ivy.usercenter.common.ResultUtils;
import com.ivy.usercenter.exception.BusinessException;
import com.ivy.usercenter.model.domain.User;
import com.ivy.usercenter.model.domain.request.UserLoginrequest;
import com.ivy.usercenter.model.domain.request.UserRegisterRequest;
import com.ivy.usercenter.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

import static com.ivy.usercenter.contant.UserConstant.ADMIN_ROLE;
import static com.ivy.usercenter.contant.UserConstant.USER_LOGIN_STATE;

/**
 * 用户控制器
 * @author ivy
 * @date 2024/4/11 17:11
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserService userService;

    @PostMapping("/register")
    public BaseResponse<Long> userRegister(@RequestBody UserRegisterRequest userRegisterRequest) {
        if (userRegisterRequest == null)
        {
            //return ResultUtils.error(ErrorCode.PARAMS_ERROR);
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        String userAccount = userRegisterRequest.getUserAccount();
        String userPassword = userRegisterRequest.getUserPassword();
        String checkPassword = userRegisterRequest.getCheckPassword();
        String planetCode = userRegisterRequest.getPlanetCode();

        if(StringUtils.isAnyBlank(userAccount,userPassword,checkPassword,planetCode)) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR);
        }

        long l = userService.userRegister(userAccount, userPassword, checkPassword, planetCode);
        return ResultUtils.success(l);
    }

    @PostMapping("/login")
    public BaseResponse<User> userLogin(@RequestBody UserLoginrequest userLoginrequest, HttpServletRequest request) {
        if (userLoginrequest == null)
        {
            return ResultUtils.error(ErrorCode.NULL_ERROR);
        }
        String userAccount = userLoginrequest.getUserAccount();
        String userPassword = userLoginrequest.getUserPassword();
        if(StringUtils.isAnyBlank(userAccount,userPassword)) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR);
        }

        User user = userService.userLogin(userAccount, userPassword, request);
        return ResultUtils.success(user);
    }

    @PostMapping("/logout")
    public BaseResponse<Integer> userLogout(HttpServletRequest request) {
        if (request == null)
        {
            return ResultUtils.error(ErrorCode.NULL_ERROR);
        }
        int i = userService.userLogout(request);
        return ResultUtils.success(i);
    }

    /**
     * 获取当前用户
     * @param request 前端请求
     * @return 当前用户
     */
    @GetMapping("/current")
    public BaseResponse<User> getCurrentUser(HttpServletRequest request) {
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        User currentUser = (User) userObj;
        if(currentUser == null) {
            return ResultUtils.error(ErrorCode.NOT_LOGIN_ERROR);
        }
        long id = currentUser.getId();
        // todo 校验用户是否合法
        User user = userService.getById(id);
        User safetyUser = userService.getSafetyUser(user);
        return ResultUtils.success(safetyUser);
    }


    @GetMapping("/search")
    public BaseResponse<List<User>> searchUsers(String username, HttpServletRequest request) {
        if (!isAdmin(request)) {
            return ResultUtils.error(ErrorCode.NO_AUTH_ERROR);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(username)) {
            queryWrapper.like("username", username);
        }
        List<User> userList = userService.list();
        List<User> collect = userList.stream().map(user -> userService.getSafetyUser(user)).collect(Collectors.toList());
        return ResultUtils.success(collect);
    }

    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteUser(@RequestBody Long id , HttpServletRequest request) {
        if (!isAdmin(request)) {
            return ResultUtils.error(ErrorCode.NO_AUTH_ERROR);
        }
        if(id <= 0) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR);
        }
        boolean b = userService.removeById(id);
        return ResultUtils.success(b);
    }

    private boolean isAdmin(HttpServletRequest request) {
        // 鉴权,只有管理员可以查询
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        User user = (User) userObj;
        if(user == null || user.getUserRole() != ADMIN_ROLE) {
            return false;
        }
        return  true;
    }
}

UserServiceImpl

package com.ivy.usercenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ivy.usercenter.common.ErrorCode;
import com.ivy.usercenter.exception.BusinessException;
import com.ivy.usercenter.mapper.UserMapper;
import com.ivy.usercenter.model.domain.User;
import com.ivy.usercenter.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.ivy.usercenter.contant.UserConstant.USER_LOGIN_STATE;

/**
* @author ivy
* @description 针对表【user(用户表)】的数据库操作Service实现
* @createDate 2024-04-10 16:57:51
*/
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{

    @Autowired
    private UserMapper userMapper;

    /**
     * 盐值, 混淆密码
     */
    private static final String SALT = "yupi";


    @Override
    public long userRegister(String userAccount, String userPassword, String checkPassword, String planetCode) {
        //1.校验
        if(StringUtils.isAnyBlank(userAccount, userPassword, checkPassword)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"数据为空");
        }
        //账户不小于4位
        if(userAccount.length() < 4){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号多短");
        }
        //密码不小于 8 位
        if(userPassword.length() < 8){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码过短");
        }
        // 星球编号长度不大于五
        if (planetCode.length() > 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "星球编号过长");
        }
        //账户不包含特殊字符
        String validPattern = "[`~!@#$%^&*()+=|{}':;',\\\\\\\\[\\\\\\\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?\\s]";
        Matcher matcher = Pattern.compile(validPattern).matcher(userAccount);
        if(matcher.find()){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号包含特殊字符");
        }
        //校验密码和密码相同
        if(!userPassword.equals(checkPassword)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次输入密码不一致");
        }
        //账户不能重复
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userAccount", userAccount);
        long count = userMapper.selectCount(queryWrapper);
        if(count > 0){
            throw new BusinessException(ErrorCode.USER_DUPLICATE_ERROR);
        }
        //星球编号不能重复
        //账户不能重复
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("planetCode", planetCode);
        count = userMapper.selectCount(queryWrapper);
        if(count > 0){
            throw new BusinessException(ErrorCode.USER_DUPLICATE_ERROR);
        }
        //2.加密
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());

        //3.插入数据
        User user = new User();
        user.setUserAccount(userAccount);
        user.setUserPassword(encryptPassword);
        user.setPlanetCode(planetCode);
        boolean saveResult = this.save(user);
        if (!saveResult){
            throw new BusinessException(ErrorCode.SAVE_USER_ERROR);
        }
        return user.getId();
    }

    @Override
    public User userLogin(String userAccount, String userPassword, HttpServletRequest request) {
        //1.校验
        if(StringUtils.isAnyBlank(userAccount, userPassword)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"数据为空");
        }
        //账户不小于4位
        if(userAccount.length() < 4){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号多短");
        }
        //密码不小于 8 位
        if(userPassword.length() < 8){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码过短");
        }
        //账户不包含特殊字符
        String validPattern = "[`~!@#$%^&*()+=|{}':;',\\\\\\\\[\\\\\\\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?\\s]";
        Matcher matcher = Pattern.compile(validPattern).matcher(userAccount);
        if(matcher.find()){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号包含特殊字符");
        }
        //2.加密
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());

        //查询用户是否存在
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userAccount", userAccount);
        queryWrapper.eq("userPassword", encryptPassword);
        User user = userMapper.selectOne(queryWrapper);
        // 用户不存在
        if(user == null) {
            log.info("user login failed, userAccount cannot match userPassword");
            throw new BusinessException(ErrorCode.USER_NOT_FOUND);
        }
        //3. 用户脱敏
        User safetyUser = getSafetyUser(user);
        //4. 记录用户的登录态
        request.getSession().setAttribute(USER_LOGIN_STATE, safetyUser);

        return safetyUser;
    }

    /**
     * 用户脱敏
     * @param originUser 起始用户
     * @return 安全用户
     */
    @Override
    public User getSafetyUser(User originUser) {
        // 判空
        if (originUser == null) {
            throw new BusinessException(ErrorCode.USER_NOT_FOUND);
        }
        User safetyUser = new User();
        safetyUser.setId(originUser.getId());
        safetyUser.setUsername(originUser.getUsername());
        safetyUser.setUserAccount(originUser.getUserAccount());
        safetyUser.setAvatarUrl(originUser.getAvatarUrl());
        safetyUser.setGender(originUser.getGender());
        safetyUser.setEmail(originUser.getEmail());
        safetyUser.setUserRole(originUser.getUserRole());
        safetyUser.setUserStatus(originUser.getUserStatus());
        safetyUser.setPhone(originUser.getPhone());
        safetyUser.setPlanetCode(originUser.getPlanetCode());
        safetyUser.setCreateTime(originUser.getCreateTime());
        return safetyUser;
    }

    @Override
    public int userLogout(HttpServletRequest request) {
        if (request == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        request.getSession().removeAttribute(USER_LOGIN_STATE);
        return  1;
    }
}

遇到的问题
这里没有加@Data注解也没有写getter/setter 方法于是乎就出现406报错
image.png
029eac13e73b180e8eb414987f61637.png、包括全局异常处理时一直出现这样的报错
68b3f9d490a1523b7e7698814435ce2.png
在SpringBoot的项目中,在于前端进行数据交互的同时,都是JSON形式进行传递的,而在我封装的统一返回对象中需要有getter和setter方法,才能保证对象在进行传递的时候才能转换成json形式,可见上面我写的对象忘记写getter和setter方法了,加上就可以解决了!!!所以我选择使用lombok进行将对象进行处理一下
image.png
这样前端就正常出现处理后的异常提示
image.png

全局请求日志和登录校验 TODO

前端代码优化

  1. 对接后端的返回值,取 data
  2. 全局响应处理:
    1. 应用场景:我们需要对接口的通用响应进行统一处理,比如从 response 中取出 data ,或者根据 code 去集中处理错误,比如用户未登录、无权限之类的
    2. 优势:不用在每个接口请求中都去写相同的逻辑
    3. 实现:参考你用的请求封装工具的官方文档,比如 umi-request

在 typings.d.ts 里写个通用返回类,跟后端是对应的
image.png
然后在 api.ts 里修改(用到的接口都要修改)
image.png
然后在注册页面也修改一下
image.png
在 src 下创建个 plugins 包,创建 globalRequest.ts 文件
复制 https://blog.csdn.net/huantai3334/article/details/116780020 这里的代码
修改成这样

/**
 * request 网络请求工具
 * 更详细的 api 文档: https://github.com/umijs/umi-request
 */
import {extend} from 'umi-request';
import {stringify} from "querystring";
import {message} from "antd";

/**
 * 配置request请求时的默认参数
 */
const request = extend({
  credentials: 'include', // 默认请求是否带上cookie
  // requestType: 'form',
});

/**
 * 所以请求拦截器
 */
request.interceptors.request.use((url, options): any => {
  console.log(`do request url= ${url}`);
  return {
    url,
    options: {
      ...options,
      headers: {
      },
    },
  };
});

/**
 * 所有响应拦截器
 */
request.interceptors.response.use(async (response, options): Promise<any> => {
  const res = await response.clone().json();
  if(res.code===0){
    return res.data;
  }
  if(res.code === 40100){
    message.error('请求登录');
    history.replace({
      pathname: '/user/login',
      search: stringify({
        redirect: location.pathname,
      }),
    });
  }else{
    message.error(res.description);
  }
  return res.data;
});

export default request;

api.ts文件里记得引用
image.png
在.gitignore添加上.umi,让这个编辑器帮我们识别出来,它就是项目自动生成的文件
image.png

  • 16
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值