开发用户注销前后端
后端
当用户登录成功之后,我们在请求体的 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 文件
修改即可
补充用户注册校验逻辑前后端
设计
仅适用于用户可信的情况
先让用户自己填: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);
}
前端
注册页面添加输入框,填入星球编号
添加星球编号字段
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;
};
在管理页面加上星球编号列
后端代码优化
封装通用返回对象
- 目的:给对象补充一些信息,告诉前端这个请求在业务层面上是成功还是失败
}
↓
//成功
{
"code": 0 //业务状态码
"data": {
"name": "yupi"
},
"message": "ok"
}
//错误
{
"code": 50001 //业务状态码
"data": null
"message": "用户操作异常、..."
"description":
}
创建一个包 common,创建通用返回类 BaseResponse,我们用泛型定义返回结果,这样就能返回任意类型的结果
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,因此要自己封装。
- 定义业务异常类
- 支持更多的字段
- 自定义构造函数也能更灵活地设置字段
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;
}
}
- 编写全局异常处理器
- 捕获代码中所有的异常,内部消化,集中处理,让前端得到更详细的业务报错/信息
- 同时屏蔽掉项目框架本身的异常(不暴露服务器内部状态)
- 集中处理,比如记录日志
- 方式:通过 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报错
、包括全局异常处理时一直出现这样的报错
在SpringBoot的项目中,在于前端进行数据交互的同时,都是JSON形式进行传递的,而在我封装的统一返回对象中需要有getter和setter方法,才能保证对象在进行传递的时候才能转换成json形式,可见上面我写的对象忘记写getter和setter方法了,加上就可以解决了!!!所以我选择使用lombok进行将对象进行处理一下
这样前端就正常出现处理后的异常提示
全局请求日志和登录校验 TODO
前端代码优化
- 对接后端的返回值,取 data
- 全局响应处理:
- 应用场景:我们需要对接口的通用响应进行统一处理,比如从 response 中取出 data ,或者根据 code 去集中处理错误,比如用户未登录、无权限之类的
- 优势:不用在每个接口请求中都去写相同的逻辑
- 实现:参考你用的请求封装工具的官方文档,比如 umi-request
在 typings.d.ts 里写个通用返回类,跟后端是对应的
然后在 api.ts 里修改(用到的接口都要修改)
然后在注册页面也修改一下
在 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文件里记得引用
在.gitignore添加上.umi,让这个编辑器帮我们识别出来,它就是项目自动生成的文件