一、项目介绍
这是一个基于Spring Boot + MyBaits Plus打造的一个用户管理系统
用到MySQL、knife4和Session等技术
二、需求分析
1.用户登录\注册
2.用户管理(仅对管理员可见)对用户的查询或者修改
3.用户校验
三、后端初始化
3.1 三种初始化java项目的方式:
1.Github 搜现成的代码
2.SpringBoot官方的模板生成器(https://start.spring.io/)
3.直接咋IDEA开发工具中生成(推荐)
3.2新建IDEA项目
选择项目依赖
添加数据库
pom文件引入mybits-plus和junit的依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
删除appliation.properties文件
创建appliation.yml文件并添加一下内容
#端口号
server:
port: 8080
spring:
#程序名称
application:
name: user-admin
# 数据库配置
datasource:
url: jdbc:mysql://localhost:3306/useradmin
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
3.3 设计数据库
什么是数据库? 存储数据的
数据库里有什么?数据表(可以理解为excel表格)
java操作数据库,代替人工
什么是设计数据库表?
有哪些表(模型)有哪些字段 字段的类型 数据库添加索引 表与表之间的关联
用户表
id(主键)bigint
username(昵称) varchar
useAccount 登录账号 varchar
avatarUrl 头像 varchaer
gender 性别 tinyint
password 密码 varchar
phone 电话 varchar
email 邮箱 varchar
userStatus 用户状态 int
cretaeTime 创建时间 datetime
updateTime 数据更新时间 datetime
isDelete 是否删除(逻辑删除) tinyint
创建数据表
create table user
(
username varchar(256) null comment '用户昵称',
id bigint not null AUTO_INCREMENT comment 'id' primary key,
userAccount varchar(256) null comment '账号',
avatarUrl varchar(1024) null comment '用户头像',
gender tinyint null comment '性别',
userPassword varchar(512) not null comment '密码',
phone varchar(128) null comment '电话',
email varchar(512) null comment '邮箱',
userStatus int default 0 not null comment '状态 0 - 正常',
createTime datetime defaULt CURRENT_TIMESTAMP null comment '创建时间',
updateTime datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP,
isDelete tinyint default 0 not null comment '是否删除')
comment '用户';
整合目录
创建controller mapper model service 目录 删除static目录
Spring Boot 五层目录介绍
使用MyBatisX自动生成数据对象
安装MyBatisX
file -> settings -> Plugins -> MyBatisX
使用MyBatisX生成代码
将生成的文件整合
创建一个test类
运行报错经过检查原因是MyBatis Plus 自动开启了驼峰命名的映射
我们在appliction.yml文件中添加配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: false
至此用户管理项目已经初始话完成,接下来可以完成业务逻辑
四、业务逻辑开发
4.1 用户注册
4.1.1 用户注册逻辑的分析
- 用户在前端输入账号和密码,以及校验码
- 校验用户的账号、密码、校验密码、是否符合要求
1.账号不少于4位
2.密码不少于8位
3.账号不能重复
4.账户不包含特殊字符
5.密码和校验码相同
6.判断短信验证码是否正确
- 对密码进行加密(密码千万不要以明文存储到数据库中)
- 向数据库中插入用户数据
4.1.2用户注册代码的开发
package com.yupi.usercenter.service;
import com.yupi.usercenter.model.domain.User;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.stereotype.Service;
/**
* @author 小申同学
* @description 针对表【user(用户)】的数据库操作Service
* @createDate 2025-03-09 15:39:38
*/
public interface UserService extends IService<User> {
/**
* 用户注册功能
*
* @param userAccount
* @param userPassword
* @param checkPassword
* @return
*/
// todo 后续可以添加一个验证码注册
public long userRegister(String userAccount,String userPassword,String checkPassword);
}
package com.yupi.usercenter.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.usercenter.model.domain.User;
import com.yupi.usercenter.service.UserService;
import com.yupi.usercenter.mapper.UserMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import javax.annotation.Resource;
/**
* @author 小申同学
* @description 针对表【user(用户)】的数据库操作Service实现
* @createDate 2025-03-09 15:39:38
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
implements UserService{
@Resource
private UserService userService;
@Resource
private UserMapper userMapper;
@Override
public long userRegister(String userAccount, String userPassword, String checkPassword) {
// 判断请求参数是否为空
if (StringUtils.isAnyBlank(userAccount,userPassword,checkPassword)) {
return -1;
}
// 判断用户名是否小于4位,密码是否小于8位
if (userAccount.length() < 4) {
return -1;
}
if (checkPassword.length() < 8 || checkPassword.length() < 8) {
return -1;
}
// 判断校验码是否等于密码
if (!userPassword.equals(checkPassword)) {
return -1;
}
// todo 校验账号不能有特殊的字符
// 判断账号是否重复
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("userAccount", userAccount);
// QueryWrapper查询的两种方式
long count = this.count(queryWrapper);
Long count1 = userMapper.selectCount(queryWrapper);
if (count > 0) {
return -1;
}
// 对密码进行加密
final String salt = "xiaoshen";
String encryptPassword = DigestUtils.md5DigestAsHex((salt +userPassword).getBytes());
// 构造user对象
User user = new User();
user.setUserAccount(userAccount);
user.setUserPassword(encryptPassword);
// 向数据库中插入数据
boolean result = this.save(user);
if (!result) {
return -1;
}
return user.getId();
}
}
4.1.3 注册功能的测试
在src/test/java/com/yupi/usercenter/service/UserServiceTest.java文件中添加
@Test
void userRegister() {
String userAccount = "xiaoshen";
String userPassword = "12345678";
String checkPassword = "12345678";
long result = userService.userRegister(userAccount, userPassword, checkPassword);
Assertions.assertEquals(-1,result);
}
4.2用户登录功能
4.2.1 用户登录接口分析
接受参数:用户账号,密码
请求方式:Post
请求体:JSON 格式数据
请求参数很长时不建议用get方式请求
返回值:用户脱敏后的信息
4.2.2 用户登录逻辑的分析
1.检查用户账号和密码是否合法
1.非空
2.帐号不少于4位
3.密码不少于8位
4.账号不能包含特殊字符
2.校验密码是否输入正确,要和数据库中的数据进行对比
3.我们要记录用户的登录状态(session)将其存入到服务器上(用后端SpringBoot框架封装到服务器tomact去记录)cookie
如何知道是哪个用户登录?
- 连接服务器端后,得到一个sessoin状态返回给前端
- 登录成功后,得到了登录成功的session,并给session设置一些值(比如用户信息)返回给前端一个设置cookie的命令
- 前端接收到后端的命令后,设置cookie,保存到浏览器内
- 前端再次请求后端的时候(相同的域名),在请求头带上cookie去请求
- 后端拿到前端传的cookie找到对应的session存储的变量(用户的登录信息,登录名)
4.返回用户脱敏后的信息 (隐藏敏感信息)
3.2.3 用户登录代码的开发
/**
* 用户登录态值
*/
private final static String USER_LOGIN_STATE = "userLoginState";
@Override
public User doLogin(String userAccount, String userPassword, HttpServletRequest request) {
//1. 校验请求参数是否为空
if (StringUtils.isAnyBlank(userAccount,userPassword)){
return null;
}
// 判断账号不能少于4位,密码不能少于8位
if (userAccount.length() < 4) {
return null;
}
if (userPassword.length() < 8) {
return null;
}
// 2.加密
String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
// 查询数据库密码是否于登录密码相同
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("userPassword", encryptPassword)
.eq("userAccount", userAccount);
User user = userMapper.selectOne(queryWrapper);
// 用户不存在
if (user == null) {
log.info("user login failed, userAccount cannot match userPassword");
return null;
}
// 3.返回用户脱敏信息
User safetyUser = new User();
safetyUser.setId(user.getId());
safetyUser.setUsername(user.getUsername());
safetyUser.setUserAccount(user.getUserAccount());
safetyUser.setAvatarUrl(user.getAvatarUrl());
safetyUser.setGender(user.getGender());
safetyUser.setPhone(user.getPhone());
safetyUser.setEmail(user.getEmail());
safetyUser.setUserStatus(user.getUserStatus());
safetyUser.setCreateTime(user.getCreateTime());
// 4.记录用户的登录态
request.getSession().setAttribute(USER_LOGIN_STATE,safetyUser);
return safetyUser;
}
4.3 用户注册和登录接口的开发
先创建对应的请求类
在model.domain下创建request文件夹,在文件内创建UserRegisterRequest、UserLoginRequest请求类
package com.yupi.usercenter.model.domain.request;
import lombok.Data;
import java.io.Serializable;
@Data
public class UserRegisterRequest implements Serializable {
/**
* 用户账户
*/
private String userAccount;
/**
* 用户密码
*/
private String userPassword;
/**
* 校验密码
*/
private String checkPassword;
}
package com.yupi.usercenter.model.domain.request;
import lombok.Data;
import java.io.Serializable;
@Data
public class UserLoginRequest implements Serializable {
/**
* 用户账户
*/
private String userAccount;
/**
* 用户密码
*/
private String userPassword;
}
接口的开发 在controller问渐渐中创建UserController
package com.yupi.usercenter.controller;
import com.yupi.usercenter.model.domain.User;
import com.yupi.usercenter.model.domain.request.UserLoginRequest;
import com.yupi.usercenter.model.domain.request.UserRegisterRequest;
import com.yupi.usercenter.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
/**
* 用户注册请求
* @param userRegisterRequest
* @return
*/
@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();
if (StringUtils.isAnyBlank(userAccount,userPassword,checkPassword)) {
return null;
}
return userService.userRegister(userAccount,userPassword,checkPassword) ;
}
@PostMapping("login")
public User userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {
if (userLoginRequest == null) {
return null;
}
String userAccount = userLoginRequest.getUserAccount();
String userPassword = userLoginRequest.getUserPassword();
if (StringUtils.isAnyBlank(userAccount,userPassword)) {
return null;
}
return userService.doLogin(userAccount,userPassword,request);
}
}
五、用户管理功能
!!!管理功能必须鉴权
用户删除
用户查找
5.1 用户的删除和查找
/**
* 查询用户
* @param username
* @return
*/
@PostMapping("/search")
public List<User> searchUsers(String username,HttpServletRequest request) {
if (!isAdmin(request)) {
return null;
}
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(username)) {
queryWrapper.eq("username",username);
}
List<User> userList = userService.list(queryWrapper);
return userList.stream().map(user -> userService.getSafetyUser(user)).collect(Collectors.toList());
}
/**
* 删除用户
* @param id
* @return
*/
@PostMapping("/delete")
public boolean deleteUser(@RequestBody long id,HttpServletRequest request) {
if(!isAdmin(request)) {
return false;
}
if (id <= 0) {
return false;
}
return userService.removeById(id);
}
/**
* 判断是否为管理员
* @param request
* @return
*/
public boolean isAdmin(HttpServletRequest request) {
User user = (User) request.getSession().getAttribute(USER_LOGIN_STATE);
return user == null && user.getUserRole() == ADMIN_ROLE;
}
在serviceImpl中封装一个用户信息脱敏的方法
/**
* 用户信息脱敏
* @param originUser
* @return
*/
public User getSafetyUser(User originUser) {
User user = new User();
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.setPhone(originUser.getPhone());
safetyUser.setEmail(originUser.getEmail());
safetyUser.setUserStatus(originUser.getUserStatus());
safetyUser.setUserRole(originUser.getUserRole());
safetyUser.setCreateTime(originUser.getCreateTime());
return user;
}
5.2 用户注销功能
首先在service建一个注销的方法并在serviceImpl中实现这个方法
/**
* 用户注销功能
* @param request
* @return
*/
int userLogout(HttpServletRequest request);
@Override
public int userLogout(HttpServletRequest request) {
request.getSession().removeAttribute(USER_LOGIN_STATE);
return 1;
}
六、后端代码优化
定义通用的返回对象
目的:给对象补充一些信息,告诉前端这个对象在请求业务层是成功还是失败
// 失败
{
"code" : 0 // 业务代码
"data" : null
"message" : "用户操作异常"
}
// 成功
{
"code" : 0 // 业务代码
"data" : {
"返回响应体"
}
"message" : "用户操作异常"
}
之前所有异常的返回-1,但前端接受到这个响应并不知道需要干什么,
所以需要定义错误码
返回类支持返回正常和错误
6.1封装全局异常处理对象
6.1.1自定义异常
- 定义业务异常类
-
- 相对于java的异常类,支持更多的字段
- 自定义构造函数,更灵活/快捷的设置字段
- 编写全局异常处理器
作用
1.捕获代码中的所有异常,内部消化,集中处理,让前端得到更多的业务报错/信息
2.同时屏蔽掉项目框架本身的异常(不暴露服务器内部状态)
3.集中处理,比如日志
实现方法:
spring aop 在调用方法前后进行额外的处理
3.TODO 全局请求日志和登录校验
通用的反馈对象
新建common包,在com/yupi/usercenter/common包下创建BaseResponse文件封装反馈对象
package com.yupi.usercenter.common;
import java.io.Serializable;
/**
* 封装返回对象
*/
public class BaseResponse<T> implements Serializable {
private int code;
// 返回信息使用泛型
private T data;
private String message;
public BaseResponse(int code,T data,String message) {
this.code = code;
this.data = data;
this.message = message;
}
public BaseResponse(int code,T data) {
this(code,data,"");
}
}
自定义异常及错误信息
在common包下创建ErrorCode 选择enum
package com.yupi.usercenter.common;
/**
* 错误码
*/
public enum ErrorCode {
SUCCESS(0,"success",""),
PARAMS_ERROR(4000,"请求参数错误",""),
NULL_ERROR(4001,"请求参数为空",""),
NO_LOGIN(40100,"用户未登录",""),
NO_AUTH(40101,"没有权限","");
/**
* 状态码
*/
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;
}
}
修改BaseResponse
package com.yupi.usercenter.common;
import lombok.Data;
import java.io.Serializable;
/**
* 封装返回对象
*/
@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(ErrorCode errorCode) {
this(errorCode.getCode(),null,errorCode.getMessage(),errorCode.getDescription());
}
}
由于返回值重复较多,我们新建ResultUtils封装常用返回对象
package com.yupi.usercenter.common;
/**
* 返回工具类
*/
public class ResultUtils {
/**
* 成功
* @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);
}
}
6.1.2全局异常处理
在com/yupi/usercenter包下创建exception文件 并创建BussinessException
package com.yupi.usercenter.exception;
import com.yupi.usercenter.common.ErrorCode;
/**
* 自定义异常
*/
public class BusinessException extends RuntimeException {
private final int code;
private final String description;
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;
}
}
定义全局异常处理器
在exception包下创建GlobalExceptionHandler
在ErrorCode中 新增系统内部异常状态码
在ResultUtils中新增三个构造函数
/**
* 失败
* @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(),errorCode.getMessage(),description);
}
GlobalExceptionHadler中编写具体异常处理代码
package com.yupi.usercenter.exception;
import com.yupi.usercenter.common.BaseResponse;
import com.yupi.usercenter.common.ErrorCode;
import com.yupi.usercenter.common.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 全局异常处理
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
public BaseResponse businessExceptionHandler(BusinessException e) {
log.error("runtimeException" + e.getMessage());
return ResultUtils.error(e.getCode(),e.getMessage(),e.getDescription());
}
@ExceptionHandler(RuntimeException.class)
public BaseResponse runtimeExceptionHandler(BusinessException e) {
log.error("runtimeException" + e);
return ResultUtils.error(ErrorCode.SYSTEM_ERROR,"");
}
}
修改controller
package com.yupi.usercenter.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yupi.usercenter.common.BaseResponse;
import com.yupi.usercenter.common.ErrorCode;
import com.yupi.usercenter.common.ResultUtils;
import com.yupi.usercenter.model.domain.User;
import com.yupi.usercenter.model.domain.request.UserLoginRequest;
import com.yupi.usercenter.model.domain.request.UserRegisterRequest;
import com.yupi.usercenter.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;
import static com.yupi.usercenter.constant.UserConstant.*;
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
/**
* 用户注册请求
* @param userRegisterRequest
* @return
*/
@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();
if (StringUtils.isAnyBlank(userAccount,userPassword,checkPassword)) {
return ResultUtils.error(ErrorCode.PARAMS_ERROR);
}
long result = userService.userRegister(userAccount, userPassword, checkPassword);
return ResultUtils.success(result);
}
@PostMapping("login")
public BaseResponse<User> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {
if (userLoginRequest == null) {
return ResultUtils.error(ErrorCode.PARAMS_ERROR);
}
String userAccount = userLoginRequest.getUserAccount();
String userPassword = userLoginRequest.getUserPassword();
if (StringUtils.isAnyBlank(userAccount,userPassword)) {
return ResultUtils.error(ErrorCode.PARAMS_ERROR);
}
User user = userService.doLogin(userAccount, userPassword, request);
return ResultUtils.success(user);
}
/**
* 查询用户
* @param username
* @return
*/
@PostMapping("/search")
public BaseResponse<List<User>> searchUsers(String username,HttpServletRequest request) {
if (!isAdmin(request)) {
return ResultUtils.error(ErrorCode.PARAMS_ERROR);
}
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(username)) {
queryWrapper.eq("username",username);
}
List<User> userList = userService.list(queryWrapper);
List<User> list = userList.stream().map(user -> userService.getSafetyUser(user)).collect(Collectors.toList());
return ResultUtils.success(list);
}
/**
* 删除用户
* @param id
* @return
*/
@PostMapping("/delete")
public BaseResponse<Boolean> deleteUser(@RequestBody long id,HttpServletRequest request) {
if(!isAdmin(request)) {
return ResultUtils.error(ErrorCode.NO_AUTH);
}
if (id <= 0) {
return ResultUtils.error(ErrorCode.PARAMS_ERROR);
}
boolean b = userService.removeById(id);
return ResultUtils.success(b);
}
/**
* 用户注销功能
* @param request
* @return
*/
@PostMapping("/logout")
public BaseResponse<Integer> logout(HttpServletRequest request){
if (request == null) {
return ResultUtils.error(ErrorCode.PARAMS_ERROR);
}
int i = userService.userLogout(request);
return ResultUtils.success(i);
}
/**
* 判断是否为管理员
* @param request
* @return
*/
public boolean isAdmin(HttpServletRequest request) {
User user = (User) request.getSession().getAttribute(USER_LOGIN_STATE);
return user == null && user.getUserRole() == ADMIN_ROLE;
}
}
修改serviceImpl
package com.yupi.usercenter.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.usercenter.common.ErrorCode;
import com.yupi.usercenter.common.ResultUtils;
import com.yupi.usercenter.exception.BusinessException;
import com.yupi.usercenter.model.domain.User;
import com.yupi.usercenter.service.UserService;
import com.yupi.usercenter.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import static com.yupi.usercenter.constant.UserConstant.DEFAULT_ROLE;
/**
* @author 小申同学
* @description 针对表【user(用户)】的数据库操作Service实现
* @createDate 2025-03-09 15:39:38
*/
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
implements UserService {
/**
* 盐值,用于混淆密码
*/
private final static String SALT = "xiaoshen";
/**
* 用户登录态值
*/
private final static String USER_LOGIN_STATE = "userLoginState";
@Resource
private UserMapper userMapper;
@Override
public long userRegister(String userAccount, String userPassword, String checkPassword) {
// 判断请求参数是否为空
if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword)) {
throw new BusinessException(ErrorCode.PARAMS_ERROR,"参数为空");
}
// 判断用户名是否小于4位,密码是否小于8位
if (userAccount.length() < 4) {
throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户名过短");
}
if (checkPassword.length() < 8 || checkPassword.length() < 8) {
throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度过短");
}
// 判断校验码是否等于密码
if (!userPassword.equals(checkPassword)) {
throw new BusinessException(ErrorCode.PARAMS_ERROR,"两次输入密码不一致");
}
// todo 校验账号不能有特殊的字符
// 判断账号是否重复
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("userAccount", userAccount);
// QueryWrapper查询的两种方式
long count = this.count(queryWrapper);
Long count1 = userMapper.selectCount(queryWrapper);
if (count > 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户账号重复");
}
// 对密码进行加密
String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
// 构造user对象
User user = new User();
user.setUserAccount(userAccount);
user.setUserPassword(encryptPassword);
// 向数据库中插入数据
boolean result = this.save(user);
if (!result) {
throw new BusinessException(ErrorCode.PARAMS_ERROR,"添加用户失败");
}
return user.getId();
}
@Override
public User doLogin(String userAccount, String userPassword, HttpServletRequest request) {
//1. 校验请求参数是否为空
if (StringUtils.isAnyBlank(userAccount, userPassword)) {
throw new BusinessException(ErrorCode.NULL_ERROR);
}
// 判断账号不能少于4位,密码不能少于8位
if (userAccount.length() < 4) {
throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码过短");
}
if (userPassword.length() < 8) {
throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户名过短");
}
// 2.加密
String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
// 查询数据库密码是否于登录密码相同
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("userPassword", encryptPassword)
.eq("userAccount", userAccount);
User user = userMapper.selectOne(queryWrapper);
// 用户不存在
if (user == null) {
log.info("user login failed, userAccount cannot match userPassword");
throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户名不存在");
}
// 3.返回用户脱敏信息
User safetyUser = getSafetyUser(user);
// 4.记录用户的登录态
request.getSession().setAttribute(USER_LOGIN_STATE, safetyUser);
return safetyUser;
}
/**
* 用户信息脱敏
*
* @param originUser
* @return
*/
public User getSafetyUser(User originUser) {
User user = new User();
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.setPhone(originUser.getPhone());
safetyUser.setEmail(originUser.getEmail());
safetyUser.setUserStatus(originUser.getUserStatus());
safetyUser.setUserRole(originUser.getUserRole());
safetyUser.setCreateTime(originUser.getCreateTime());
return user;
}
@Override
public int userLogout(HttpServletRequest request) {
request.getSession().removeAttribute(USER_LOGIN_STATE);
throw new BusinessException(ErrorCode.SUCCESS);
}
}
至此我们的项目厚后端已经完成
我们可以引入测试
在pom文件中引入knife4依赖
<!--knife4--v>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
在application.yml文件中添加
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
可以通过访问http://localhost:8080/doc.html#/home来进行测试