用户中心(末)

news2025/1/14 18:16:07

文章目录

    • 开发用户注销前后端
      • 后端
      • 前端
    • 补充用户注册校验逻辑前后端
      • 设计
      • 后端
      • 前端
    • 后端代码优化
      • 封装通用返回对象
      • 封装全局异常处理
      • 全局请求日志和登录校验 TODO
    • 前端代码优化

开发用户注销前后端

后端

当用户登录成功之后,我们在请求体的 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1639456.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一对一WebRTC视频通话系列(一)—— 创建页面并显示摄像头画面

本系列博客主要记录WebRtc实现过程中的一些重点&#xff0c;代码全部进行了注释&#xff0c;便于理解WebRTC整体实现。 一、创建html页面 简单添加input、button、video控件的布局。 <html><head><title>WebRTC demo</title></head><h1>…

vue2(4)之scoped解决样式冲突/组件通信/非父子通信/ref和$refs/异步更新/.sync/事件总线/provide和inject

vue2 一、学习目标1.组件的三大组成部分&#xff08;结构/样式/逻辑&#xff09;2.组件通信3.综合案例&#xff1a;小黑记事本&#xff08;组件版&#xff09;4.进阶语法 二、scoped解决样式冲突**1.默认情况**&#xff1a;2.代码演示3.scoped原理4.总结 三、data必须是一个函数…

自动驾驶规划与控制技术解析

目录 1. 自动驾驶技术 2.定位location 3. 地图HD Map ​编辑 4 预测prediction 5 自动驾驶路径规划 6. 自动驾驶路径规划 7. 规划planning 8. 视频路径 1. 自动驾驶技术 2.定位location 3. 地图HD Map 4 预测prediction 5 自动驾驶路径规划 6. 自动驾驶路径规划 7.…

IDEA 2022.1版本开始,可以直接运行Markdown里的命令行

参照这种格式&#xff1a; shell mvn clean install注意idea支持的版本&#xff1a;是从 2022.1版本开始的。 ps&#xff1a;之前有人写过了&#xff0c;感觉很实用但是蛮多开发者不一定会知道的功能。 参考资料&#xff1a; https://www.cnblogs.com/didispace/p/16144107.h…

2.4Java全栈开发前端+后端(全栈工程师进阶之路)-前端框架VUE3-基础-Vue组件

初识Vue组件 Vue中的组件是页面中的一部分&#xff0c;通过层层拼装&#xff0c;最终形成了一个完整的组件。这也是目前前端最流行的开发方 式。下面是Vue3官方给出的一张图&#xff0c;通过图片能清楚的了解到什么是Vue中的组件。 图的左边是一个网页&#xff0c;网页分为了…

革新DNA存储:DNA-QLC编码方案高效可靠,多媒体图像存储新时代启航

在数字信息爆炸的时代&#xff0c;传统存储介质正面临容量、持久性和能耗的极限挑战。为此&#xff0c;大连理工大学计算机科学与技术学院的研究团队在《BMC基因组学》发表了一篇开创性论文&#xff0c;介绍了一种名为DNA-QLC的创新编码方案&#xff0c;为DNA存储系统的高效性和…

基于免疫粒子群算法的考虑负荷需求相应的热电联供系统优化调度(MATLAB实现)

1.研究背景 随着“双碳”战略的提出&#xff0c;各种分布式能源的开发和利用收到越来越多的重视。冷热电联供(Combined Cooling Heating and Power, CCHP)系统在发电的同时可以将燃气轮机产生的废热用于制热或制冷&#xff0c;实现能量的梯级利用&#xff0c;并减少系统的污染气…

【热门话题】PostCSS:现代前端开发中的CSS增强工具

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 PostCSS&#xff1a;现代前端开发中的CSS增强工具一、引言二、PostCSS简介2.1 核…

前端工程化04-VsCode插件设置总结(持续更)

1、输出语句log设置 log输出、平常你输出log,还必须得打一个console然后再.log()非常不方便&#xff0c;当然我们可以直接输入一个log,但是提示有两个&#xff0c;我们还得上下选择 所以我们直接采用插件的提示 一个clg就可以了 2、括号包裹提示 找到VsCode的settings.js文…

学习java的继承

1.什么是继承 java中提供了一个关键字&#xff0c;extends&#xff0c;可以让一个类与另一个类建立起父子关系。 例如 public class B extends A { --- } 在这里&#xff0c;我们称A类为父类&#xff08;也被称为基类或者超类&#xff09;B类称为子类&#xff08;或者是派生…

汉王科技亮相世界数字健康论坛:以AI定义第四代血压计

作为科技行业的年度盛会&#xff0c;2024年中关村论坛年会于近日在北京揭幕。 作为中关村知名的人工智能企业&#xff0c;汉王科技携大模型的最新垂直应用、柯氏音法电子血压计等创新成果&#xff0c;在4月29日中关村论坛平行论坛“2024世界数字健康论坛”上亮相。 在《AI赋能血…

C语言/数据结构——每日一题(反转链表)

一.前言 大家好&#xff01;今天又是每日一题环节。今天我为大家分享了一道单链表题——反转链表。 废话不多说&#xff0c;让我们直接进入正题吧。 二.正文 1.1题目信息 这是一道leetCode上面的一道题&#xff1a;https://leetcode.cn/problems/reverse-linked-list 1.2解…

[技术小技巧] 可视化分析:在jupyter中使用d3可视化树形结构

首先在python中定义一个字符串&#xff0c;记录d3.js绘制属性图的js脚本代码模版。其中{{data}}就是将来要被替换的内容。 d3_code_template """ // 创建树状结构数据 var treeData {{data}};// 创建d3树布局 var margin { top: 20, right: 90, bottom: 30,…

云原生Kubernetes: K8S 1.29版本 部署Harbor

目录 一、实验 1.环境 2.Linux 部署docker compose 3.证书秘钥配置 4.K8S 1.29版本 部署Harbor 5.K8S 1.29版本 使用Harbor 二、问题 1.docker 登录harbor失败 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构版本IP备注masterK8S master节点1.2…

使用CNN或resnet,分别在flower5,flower17,flower102数据集上实现花朵识别分类-附源码-免费

前言 使用cnn和resnet实现了对flower5&#xff0c;flower17&#xff0c;flower102数据集上实现花朵识别分类。也就是6份代码&#xff0c;全部在Gitee仓库里&#xff0c;记得点个start支持谢谢。 本文给出flower17在cnn网络实现&#xff0c;flower102在resnet网络实现的代码。…

BJFUOJ-C++程序设计-实验3-继承和虚函数

A TableTennisPlayer 答案&#xff1a; #include<iostream> #include<cstring> using namespace std;class TableTennisPlayer{ private:string firstname;string lastname;bool hasTable;public:TableTennisPlayer(const string &, const string &, bool…

VULHUB复现log4j反序列化漏洞-CVE-2021-44228

本地下载vulhub复现就完了&#xff0c;环境搭建不讲&#xff0c;网上其他文章很好。 访问该环境&#xff1a; POC 构造&#xff08;任选其一&#xff09;&#xff1a; ${jndi:ldap://${sys:java.version}.xxx.dnslog.cn} ${jndi:rmi://${sys:java.version}.xxx.dnslog.cn}我是…

docker 指定根目录 迁移根目录

docker 指定根目录 1、问题描述2、问题分析3、解决方法3.1、启动docker程序前就手动指定docker根目录为一个大的分区(支持动态扩容)&#xff0c;事前就根本上解决根目录空间不够问题3.1.0、方法思路3.1.1、docker官网安装文档3.1.2、下载docker安装包3.1.3、安装docker 26.1.03…

JavaEE >> Spring MVC(2)

接上文 本文介绍如何使用 Spring Boot/MVC 项目将程序执行业务逻辑之后的结果返回给用户&#xff0c;以及一些相关内容进行分析解释。 返回静态页面 要返回一个静态页面&#xff0c;首先需要在 resource 中的 static 目录下面创建一个静态页面&#xff0c;下面将创建一个静态…

[1673]jsp在线考试管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 在线考试管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…