3 - 用户模块(后端)
2025-02-18 17:37
阅读 2.1k
需求分析
1、用户注册
2、用户登录PoFzH92dkfxTeZctnfcQ23EvJKA6S8P5RqYrFFpQE9Q=TqVRUbFNVZXbqk/hUxkmHLiLVxI7bDwn14nbiZDSWtc=
3、获取登录的用户信息
4、用户注销
5、用户权限控制JP6W2a+u/tK3+CtiEE3dIFH6LGArLhwCpb/rrZiHIv4=PoFzH92dkfxTeZctnfcQ23EvJKA6S8P5RqYrFFpQE9Q=
6、用户管理
库表设计
1、在根目录创建 sql/create_table_sql.sqlj/yPunylytGeRjIlPoK/Y8GFlWyG27wU5zB5N3p1+E0=TqVRUbFNVZXbqk/hUxkmHLiLVxI7bDwn14nbiZDSWtc=
▼text复制代码create database if not exists `yu_picture` default character set utf8mb4 collate utf8mb4_unicode_ci;
-- 用户表
create table if not exists user
(
id bigint auto_increment comment 'id' primary key,
userAccount varchar(256) not null comment '账号',
userPassword varchar(512) not null comment '密码',
userName varchar(256) null comment '用户昵称',
userAvatar varchar(1024) null comment '用户头像',
userProfile varchar(512) null comment '用户简介',
userRole varchar(256) default 'user' not null comment '用户角色:user/admin',
editTime datetime default CURRENT_TIMESTAMP not null comment '编辑时间',
createTime datetime default CURRENT_TIMESTAMP not null comment '创建时间',
updateTime datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
isDelete tinyint default 0 not null comment '是否删除',
UNIQUE KEY uk_userAccount (userAccount),
INDEX idx_userName (userName)
) comment '用户' collate = utf8mb4_unicode_ci;2、直接右键权限 execute

3、修改 application.yml 的
修改 url 变成 jdbc:mysql://localhost:3306/yu_picture 最后面具体参考自己定义的数据库的名称

数据访问层
1、找到右侧的 Database 对应的 user 表,右键 MybatisX-GeneratorJP6W2a+u/tK3+CtiEE3dIFH6LGArLhwCpb/rrZiHIv4=qI9xw9e7xkICTi4p8LSAdDoi8Snc4lUY3aI/FxTRelw=

2、选着好之后,点击 next

如果这个里的 module path 为空我们需要点击一下 module path 的空白位置,选着一下 module


3、

4、生成成功后的结果

5、移动代码到对应的路径下j/yPunylytGeRjIlPoK/Y8GFlWyG27wU5zB5N3p1+E0=qI9xw9e7xkICTi4p8LSAdDoi8Snc4lUY3aI/FxTRelw=
- User 移动到
com.yupi.yupicturebackend.model.entity - 移动 UserMapper 到
com.leikooo.yupicturebackend.mapper - 移动 service 整个文件夹到
com.yupi.yupicturebackend
移动直接鼠标左键选着 文件/目录 拖动到对应文件夹就可以,如果没有自己创建一下即可
一般移动会弹出一个 Move 点击 Refactor 即可
还可能出现 Refactoring Preview,点击 Do factor 即可
最后效果u7fV9dpr2/5fhmXsWxDVN16wRk39LhGC2lz8S+YEjko=ibbBLHPWrQl9roziUnu+bBZIVr+dZrBeEkWwwoLNs3I=

修改 User 表
1、增加 TableLogicibbBLHPWrQl9roziUnu+bBZIVr+dZrBeEkWwwoLNs3I=u7fV9dpr2/5fhmXsWxDVN16wRk39LhGC2lz8S+YEjko=
2、修改组件 ID 生成策略具体 官方文档
▼java复制代码@TableName(value ="user")
@Data
public class User implements Serializable {
/**
* id
*/
@TableId(type = IdType.ASSIGN_ID)
private Long id;
/**
* 账号
*/
private String userAccount;
/**
* 密码
*/
private String userPassword;
/**
* 用户昵称
*/
private String userName;
/**
* 用户头像
*/
private String userAvatar;
/**
* 用户简介
*/
private String userProfile;
/**
* 用户角色:user/admin
*/
private String userRole;
/**
* 编辑时间
*/
private Date editTime;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 是否删除
*/
@TableLogic
private Integer isDelete;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}创建 Enum
1、方便维护
2、使用方便,不容易出现低级错误
▼text复制代码/**
* @author <a href="https://github.com/lieeew">leikooo</a>
* @date 2024/12/12
* @description
*/
@Getter
public enum UserRoleEnum {
USER("用户", "user"),
ADMIN("管理员", "admin");
private final String text;
private final String value;
UserRoleEnum(String text, String value) {
this.text = text;
this.value = value;
}
public static UserRoleEnum getEnumByValue(String value) {
if (StringUtils.isBlank(value)) {
return null;
}
Map<String, UserRoleEnum> userRoleEnumMap = Arrays.stream(UserRoleEnum.values()).
collect(Collectors.toMap(UserRoleEnum::getValue, userRoleEnum -> userRoleEnum));
return userRoleEnumMap.getOrDefault(value, null);
}
}接口开发
用户注册
DTO、VO ... 之间的区别可以看这篇博客
1、创建接收请求的参数 UserRegisterRequest 路径是 model.dto.user
▼JAVA复制代码@Data
public class UserRegisterRequest implements Serializable {
private static final long serialVersionUID = 3191241716373120793L;
/**
* 账号
*/
private String userAccount;
/**
* 密码
*/
private String userPassword;
/**
* 确认密码
*/
private String checkPassword;
}2、服务端开发u7fV9dpr2/5fhmXsWxDVN16wRk39LhGC2lz8S+YEjko=TqVRUbFNVZXbqk/hUxkmHLiLVxI7bDwn14nbiZDSWtc=
在 service 包下的 UserService 增加一个方法
PS 接口这里一定要写注释!具体实现可以不写,如果不写的话还要跳到具体实现去看逻辑
▼text复制代码public interface UserService extends IService<User> {
/**
* 用户注册
*
* @param userAccount 用户账户
* @param userPassword 用户密码
* @param checkPassword 校验密码
* @return 新用户 id
*/
long userRegister(String userAccount, String userPassword, String checkPassword);
/**
* 获取加密后的密码
*
* @param userPassword 原始密码
* @return 加密后的密码
*/
String getEncryptPassword(String userPassword);
}写好之后会出现爆红,因为咱们的实现类 UserServiceImpl 没有实现 userRegister 这个方法
快捷实现方法直接在对应方法上面 Alt +Enter 选择 implement method 'userRegister'

快捷实现

getEncryptPassword 方法同理,快捷实现即可gTP20X3DfLM35oP9bfNArxR6UuHDEamYTd38MBTsrBM=j/yPunylytGeRjIlPoK/Y8GFlWyG27wU5zB5N3p1+E0=
3、补充校验逻辑
▼text复制代码@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
implements UserService{
@Override
public long userRegister(String userAccount, String userPassword, String checkPassword) {
// 1. 校验
if (StringUtils.isAllBlank(userAccount, userPassword, checkPassword)) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
}
if (userAccount.length() < 4) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过短");
}
if (userPassword.length() < 8 || checkPassword.length() < 8) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码过短");
}
if (!userPassword.equals(checkPassword)) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次输入的密码不一致");
}
// 2. 检查是否重复
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("userAccount", userAccount);
long count = this.baseMapper.selectCount(queryWrapper);
if (count > 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
}
// 3. 加密
String encryptPassword = getEncryptPassword(userPassword);
// 4. 插入数据
User user = new User();
user.setUserAccount(userAccount);
user.setUserPassword(encryptPassword);
user.setUserName("无名");
user.setUserRole(UserRoleEnum.USER.getValue());
boolean saveResult = this.save(user);
if (!saveResult) {
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "注册失败,数据库错误");
}
return user.getId();
}
@Override
public String getEncryptPassword(String userPassword) {
// 盐值,混淆密码
final String SALT = "yupi";
return DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
}
}PS 我使用的 StringUtils 不是 hutool 包里面的,是下面的
xml▼xml复制代码 <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency>
4、编写 Controller 层级的逻辑
在 controller 创建 UserController
1、@RestController
@Controller和@ResponseBody的组合,表示该控制器类中的所有方法都返回 JSON 数据2、@RequestMapping("/user") 指定了该控制器类或方法处理
/user路径下的所有 HTTP 请求3、@PostMapping("/register") 处理 POST 请求且路径是
/api/user/register路径下的请求
▼java复制代码@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
/**
* 用户注册
*/
@PostMapping("/register")
public BaseResponse<Long> userRegister(@RequestBody UserRegisterRequest userRegisterRequest) {
ThrowUtils.throwIf(userRegisterRequest == null, ErrorCode.PARAMS_ERROR);
String userAccount = userRegisterRequest.getUserAccount();
String userPassword = userRegisterRequest.getUserPassword();
String checkPassword = userRegisterRequest.getCheckPassword();
long result = userService.userRegister(userAccount, userPassword, checkPassword);
return ResultUtils.success(result);
}
}5、测试逻辑是否正确


PS 要做充足的测试哦!
用户登录
1、创建接收请求的 UserLoginRequest 还是在 model.dto.user 路径下
▼text复制代码@Data
public class UserLoginRequest implements Serializable {
private static final long serialVersionUID = 3191241716373120793L;
/**
* 账号
*/
private String userAccount;
/**
* 密码
*/
private String userPassword;
}创建 umodel.vo 包,然后创建 LoginUserVO
▼java复制代码@Data
public class LoginUserVO implements Serializable {
/**
* 用户 id
*/
private Long id;
/**
* 账号
*/
private String userAccount;
/**
* 用户昵称
*/
private String userName;
/**
* 用户头像
*/
private String userAvatar;
/**
* 用户简介
*/
private String userProfile;
/**
* 用户角色:user/admin
*/
private String userRole;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
private static final long serialVersionUID = 1L;
}为什么需要 LoginUserVO 我们不是有 User 吗?
1)脱敏,有些信息不需要返回给前端
2)方便组合信息,扩展性更强。如果我们后面加字段也相对容易
我们设置到 session 里面的值,我们是需要频繁的读取的,为了防止我们出现低级错误 + 方便维护,我们需要创建一个 constant
在 model.constant 包下面创建 UserConstant
▼java复制代码public interface UserConstant {
/**
* 用户登录态键
*/
String USER_LOGIN_STATE = "user_login";
// region 权限
/**
* 默认角色
*/
String DEFAULT_ROLE = "user";
/**
* 管理员角色
*/
String ADMIN_ROLE = "admin";
}2、服务开发
在 service 包下面增加 方法声明
▼java复制代码/**
* 用户登录
*
* @param userAccount 用户账户
* @param userPassword 用户密码
* @param request httpRequest 请求方便设置 cookie
* @return 脱敏后的用户信息
*/
LoginUserVO userLogin(String userAccount, String userPassword, HttpServletRequest request);实现对应方法
▼java复制代码 @Override
public LoginUserVO userLogin(String userAccount, String userPassword, HttpServletRequest request) {
// 1. 校验
if (StringUtils.isAllBlank(userAccount, userPassword)) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
}
if (userAccount.length() < 4) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号错误");
}
if (userPassword.length() < 8) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");
}
// 2. 加密
String encryptPassword = getEncryptPassword(userPassword);
// 查询用户是否存在
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("userAccount", userAccount);
queryWrapper.eq("userPassword", encryptPassword);
User user = this.baseMapper.selectOne(queryWrapper);
// 用户不存在
if (user == null) {
log.info("user login failed, userAccount cannot match userPassword");
throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或密码错误");
}
// 3. 记录用户的登录态
request.getSession().setAttribute(USER_LOGIN_STATE, user);
return this.getLoginUserVO(user);
}KrryZFef4D1pctURMTqry3GjQ44W/xjmnRorDc4l6E8=gTP20X3DfLM35oP9bfNArxR6UuHDEamYTd38MBTsrBM=FkrlmFJI3Kac/KaAi63U8xt3PYKjkMMqpk/g3iv6PsE=
1、获取脱敏的已登录用户信息
2、方便后面其他方法使用
▼java复制代码/**
* 获取脱敏的已登录用户信息
*
* @return 脱敏的已登录用户信息
*/
LoginUserVO getLoginUserVO(User user);实现
▼java复制代码@Override
public LoginUserVO getLoginUserVO(User user) {
if (user == null) {
return null;
}
LoginUserVO loginUserVO = new LoginUserVO();
BeanUtils.copyProperties(user, loginUserVO);
return loginUserVO;
}3、controller 开发qI9xw9e7xkICTi4p8LSAdDoi8Snc4lUY3aI/FxTRelw=KrryZFef4D1pctURMTqry3GjQ44W/xjmnRorDc4l6E8=
▼java复制代码@PostMapping("/login")
public BaseResponse<LoginUserVO> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {
ThrowUtils.throwIf(userLoginRequest == null, ErrorCode.PARAMS_ERROR);
String userAccount = userLoginRequest.getUserAccount();
String userPassword = userLoginRequest.getUserPassword();
LoginUserVO loginUserVO = userService.userLogin(userAccount, userPassword, request);
return ResultUtils.success(loginUserVO);
}获取当前用户
1、不需要其他的请求类gTP20X3DfLM35oP9bfNArxR6UuHDEamYTd38MBTsrBM=TqVRUbFNVZXbqk/hUxkmHLiLVxI7bDwn14nbiZDSWtc=
2、接口开发
在 service 下的 UserService
▼java复制代码 /**
* 获取当前登录用户
*
* @param request request
* @return 当前登录用户
*/
User getLoginUser(HttpServletRequest request);实现
▼java复制代码@Override
public User getLoginUser(HttpServletRequest request) {
// 先判断是否已登录
Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
User currentUser = (User) userObj;
if (currentUser == null || currentUser.getId() == null) {
throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
}
// 从数据库查询(追求性能的话可以注释,直接返回上述结果)
long userId = currentUser.getId();
currentUser = this.getById(userId);
if (currentUser == null) {
throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
}
return currentUser;
}3、controller 代码JP6W2a+u/tK3+CtiEE3dIFH6LGArLhwCpb/rrZiHIv4=FkrlmFJI3Kac/KaAi63U8xt3PYKjkMMqpk/g3iv6PsE=
▼text复制代码@GetMapping("/get/login")
public BaseResponse<LoginUserVO> getLoginUser(HttpServletRequest request) {
User user = userService.getLoginUser(request);
return ResultUtils.success(userService.getLoginUserVO(user));
}用户注销
1、用户注销不需要请求参数PoFzH92dkfxTeZctnfcQ23EvJKA6S8P5RqYrFFpQE9Q=JP6W2a+u/tK3+CtiEE3dIFH6LGArLhwCpb/rrZiHIv4=
那怎么知道是谁要注销呢?其实是通过前端携带的 cookie 读取到登录用户的 id
2、service 包下面的 UserService 增加对应的代码
▼java复制代码/**
* 用户注销
*
* @param request request
* @return 注销结果
*/
boolean userLogout(HttpServletRequest request);实现
▼java复制代码@Override
public boolean userLogout(HttpServletRequest request) {
// 先判断是否已登录
Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
if (userObj == null) {
throw new BusinessException(ErrorCode.OPERATION_ERROR, "未登录");
}
// 移除登录态
request.getSession().removeAttribute(USER_LOGIN_STATE);
return true;
}3、controller 开发j/yPunylytGeRjIlPoK/Y8GFlWyG27wU5zB5N3p1+E0=JP6W2a+u/tK3+CtiEE3dIFH6LGArLhwCpb/rrZiHIv4=
▼java复制代码@PostMapping("/logout")
public BaseResponse<Boolean> userLogout(HttpServletRequest request) {
ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
boolean result = userService.userLogout(request);
return ResultUtils.success(result);
}权限控制注解
原理:通过 SpringAOP 切面 + 自定义注解实现PoFzH92dkfxTeZctnfcQ23EvJKA6S8P5RqYrFFpQE9Q=j/yPunylytGeRjIlPoK/Y8GFlWyG27wU5zB5N3p1+E0=
校验注解
在和 controller 同级目录下创建 annotation

▼java复制代码@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthCheck {
/**
* 必须有某个角色
*/
String mustRole() default "";
}@Target(ElementType.METHOD)指定该注解只能应用于方法。@Retention(RetentionPolicy.RUNTIME)表示该注解将被保留在编译后的类文件中,并且可以在运行时通过反射访问。- 这两个都是
元注解指定注解可以在上面上面使用,指定注解被保存的时间
权限校验切面
放到和 controller 同级目录下的 aop 包
▼java复制代码@Aspect
@Component
public class AuthInterceptor {
@Resource
private UserService userService;
/**
* 执行拦截
*
* @param joinPoint 切入点
* @param authCheck 权限校验注解
*/
@Around("@annotation(authCheck)")
public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {
String mustRole = authCheck.mustRole();
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
// 当前登录用户
User loginUser = userService.getLoginUser(request);
UserRoleEnum mustRoleEnum = UserRoleEnum.getEnumByValue(mustRole);
// 不需要权限,放行
if (mustRoleEnum == null) {
return joinPoint.proceed();
}
// 以下为:必须有该权限才通过
// 获取当前用户具有的权限
UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(loginUser.getUserRole());
// 没有权限,拒绝
if (userRoleEnum == null) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
}
// 要求必须有管理员权限,但用户没有管理员权限,拒绝
if (UserRoleEnum.ADMIN.equals(mustRoleEnum) && !UserRoleEnum.ADMIN.equals(userRoleEnum)) {
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
}
// 通过权限校验,放行
return joinPoint.proceed();
}
}- 需要使用 @Aspect 注解标识
- 常见的切面注解
@Around:环绕通知可以在目标方法执行前后执行一些逻辑。@Before:在目标方法执行前执行的通知@After:在目标方法执行后执行的通知@AfterReturning:在目标方法执行后,返回结果后执行的通知@AfterThrowing:在目标方法执行后,抛出异常后执行的通知
使用切面注解
只需要在对应 controller 方法,上面标识即可
比如 health 方法,只允许管理员使用gTP20X3DfLM35oP9bfNArxR6UuHDEamYTd38MBTsrBM=j/yPunylytGeRjIlPoK/Y8GFlWyG27wU5zB5N3p1+E0=
▼text复制代码@GetMapping("/health")
@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<String> health() {
return ResultUtils.success("ok");
}用户管理
1、数据模型qI9xw9e7xkICTi4p8LSAdDoi8Snc4lUY3aI/FxTRelw=ibbBLHPWrQl9roziUnu+bBZIVr+dZrBeEkWwwoLNs3I=
都放到 model.dto.user 下使用
1)增加用户的请求类
▼java复制代码@Data
public class UserAddRequest implements Serializable {
/**
* 用户昵称
*/
private String userName;
/**
* 账号
*/
private String userAccount;
/**
* 用户头像
*/
private String userAvatar;
/**
* 用户简介
*/
private String userProfile;
/**
* 用户角色: user, admin
*/
private String userRole;
private static final long serialVersionUID = 1L;
}2)更新用户的请求类
▼java复制代码@Data
public class UserUpdateRequest implements Serializable {
/**
* id
*/
private Long id;
/**
* 用户昵称
*/
private String userName;
/**
* 用户头像
*/
private String userAvatar;
/**
* 简介
*/
private String userProfile;
/**
* 用户角色:user/admin
*/
private String userRole;
private static final long serialVersionUID = 1L;
}3)查询用户的请求类,支持分页查询JP6W2a+u/tK3+CtiEE3dIFH6LGArLhwCpb/rrZiHIv4=ibbBLHPWrQl9roziUnu+bBZIVr+dZrBeEkWwwoLNs3I=
▼java复制代码@EqualsAndHashCode(callSuper = true)
@Data
public class UserQueryRequest extends PageRequest implements Serializable {
/**
* id
*/
private Long id;
/**
* 用户昵称
*/
private String userName;
/**
* 账号
*/
private String userAccount;
/**
* 简介
*/
private String userProfile;
/**
* 用户角色:user/admin/ban
*/
private String userRole;
private static final long serialVersionUID = 1L;
}4)脱敏的 User 信息类 UserVO 放到 model.vo 下
▼java复制代码@Data
public class UserVO implements Serializable {
/**
* id
*/
private Long id;
/**
* 账号
*/
private String userAccount;
/**
* 用户昵称
*/
private String userName;
/**
* 用户头像
*/
private String userAvatar;
/**
* 用户简介
*/
private String userProfile;
/**
* 用户角色:user/admin
*/
private String userRole;
/**
* 创建时间
*/
private Date createTime;
private static final long serialVersionUID = 1L;
}2、service 包下的 UserService
▼java复制代码 /**
* 获取用户脱敏信息
* @param user 脱敏前的信息
* @return 脱敏后的信息
*/
UserVO getUserVO(User user);
/**
* 批量获取用户脱敏信息
* @param userList 脱敏前的信息
* @return 脱敏后的 List 列表
*/
List<UserVO> getUserVOList(List<User> userList);
/**
* 获取查询条件
*
* @param userQueryRequest 查询条件
* @return 查询条件
*/
QueryWrapper<User> getQueryWrapper(UserQueryRequest userQueryRequest);实现PoFzH92dkfxTeZctnfcQ23EvJKA6S8P5RqYrFFpQE9Q=gTP20X3DfLM35oP9bfNArxR6UuHDEamYTd38MBTsrBM=
▼java复制代码 @Override
public UserVO getUserVO(User user) {
if (user == null) {
return null;
}
UserVO userVO = new UserVO();
BeanUtils.copyProperties(user, userVO);
return userVO;
}
@Override
public List<UserVO> getUserVOList(List<User> userList) {
if (CollectionUtils.isEmpty(userList)) {
return new ArrayList<>();
}
return userList.stream().map(this::getUserVO).collect(Collectors.toList());
}
@Override
public QueryWrapper<User> getQueryWrapper(UserQueryRequest userQueryRequest) {
if (userQueryRequest == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数为空");
}
Long id = userQueryRequest.getId();
String userAccount = userQueryRequest.getUserAccount();
String userName = userQueryRequest.getUserName();
String userProfile = userQueryRequest.getUserProfile();
String userRole = userQueryRequest.getUserRole();
String sortField = userQueryRequest.getSortField();
String sortOrder = userQueryRequest.getSortOrder();
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(Objects.nonNull(id), "id", id);
queryWrapper.eq(StrUtil.isNotBlank(userRole), "userRole", userRole);
queryWrapper.like(StrUtil.isNotBlank(userAccount), "userAccount", userAccount);
queryWrapper.like(StrUtil.isNotBlank(userName), "userName", userName);
queryWrapper.like(StrUtil.isNotBlank(userProfile), "userProfile", userProfile);
queryWrapper.orderBy(StringUtils.isNoneBlank(sortField), sortOrder.equals("ascend"), sortField);
return queryWrapper;
}3、接口开发
▼java复制代码/**
* 创建用户
*/
@PostMapping("/add")
@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<Long> addUser(@RequestBody UserAddRequest userAddRequest) {
ThrowUtils.throwIf(userAddRequest == null, ErrorCode.PARAMS_ERROR);
User user = new User();
BeanUtils.copyProperties(userAddRequest, user);
// 默认密码 12345678
final String DEFAULT_PASSWORD = "12345678";
String encryptPassword = userService.getEncryptPassword(DEFAULT_PASSWORD);
user.setUserPassword(encryptPassword);
boolean result = userService.save(user);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
return ResultUtils.success(user.getId());
}
/**
* 根据 id 获取用户(仅管理员)
*/
@GetMapping("/get")
@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<User> getUserById(long id) {
ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
User user = userService.getById(id);
ThrowUtils.throwIf(user == null, ErrorCode.NOT_FOUND_ERROR);
return ResultUtils.success(user);
}
/**
* 根据 id 获取包装类
*/
@GetMapping("/get/vo")
public BaseResponse<UserVO> getUserVOById(long id) {
BaseResponse<User> response = getUserById(id);
User user = response.getData();
return ResultUtils.success(userService.getUserVO(user));
}
/**
* 删除用户
*/
@PostMapping("/delete")
@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<Boolean> deleteUser(@RequestBody DeleteRequest deleteRequest) {
if (deleteRequest == null || deleteRequest.getId() <= 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
boolean b = userService.removeById(deleteRequest.getId());
return ResultUtils.success(b);
}
/**
* 更新用户
*/
@PostMapping("/update")
@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<Boolean> updateUser(@RequestBody UserUpdateRequest userUpdateRequest) {
if (userUpdateRequest == null || userUpdateRequest.getId() == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
User user = new User();
BeanUtils.copyProperties(userUpdateRequest, user);
boolean result = userService.updateById(user);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
return ResultUtils.success(true);
}
/**
* 分页获取用户封装列表(仅管理员)
*
* @param userQueryRequest 查询请求参数
*/
@PostMapping("/list/page/vo")
@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
public BaseResponse<Page<UserVO>> listUserVOByPage(@RequestBody UserQueryRequest userQueryRequest) {
ThrowUtils.throwIf(userQueryRequest == null, ErrorCode.PARAMS_ERROR);
long current = userQueryRequest.getCurrent();
long pageSize = userQueryRequest.getPageSize();
Page<User> userPage = userService.page(new Page<>(current, pageSize),
userService.getQueryWrapper(userQueryRequest));
Page<UserVO> userVOPage = new Page<>(current, pageSize, userPage.getTotal());
List<UserVO> userVOList = userService.getUserVOList(userPage.getRecords());
userVOPage.setRecords(userVOList);
return ResultUtils.success(userVOPage);
}分页功能修复

当我们分页查询的时候,指定的 pageSize 没有生效,解决办法:
1、安装依赖
▼text复制代码<!-- MyBatis Plus 分页插件 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-jsqlparser-4.9</artifactId>
</dependency>
▼text复制代码<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-bom</artifactId>
<version>3.5.9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>2、在 config 目录下添加 MyBatisPlusConfig
在 config 包添加一下代码PoFzH92dkfxTeZctnfcQ23EvJKA6S8P5RqYrFFpQE9Q=JP6W2a+u/tK3+CtiEE3dIFH6LGArLhwCpb/rrZiHIv4=
▼text复制代码@Configuration
// todo 注意这个 mapper 改成自己的
@MapperScan("com.yupi.yupicturebackend.mapper")
public class MyBatisPlusConfig {
/**
* 拦截器配置
*
* @return {@link MybatisPlusInterceptor}
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}3、测试一下效果

数据精度修复
由于 Long 类型的 id 超过了前端 number 的最大值导致的问题,把返回的数据类型改成 String 即可
解决办法:修改该 SpringMVC 结合返回值,把 Long 用 String 返回FkrlmFJI3Kac/KaAi63U8xt3PYKjkMMqpk/g3iv6PsE=TqVRUbFNVZXbqk/hUxkmHLiLVxI7bDwn14nbiZDSWtc=
在 config 包下面添加
▼java复制代码/**
* Spring MVC Json 配置
*/
@JsonComponent
public class JsonConfig {
/**
* 添加 Long 转 json 精度丢失的配置
*/
@Bean
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
SimpleModule module = new SimpleModule();
module.addSerializer(Long.class, ToStringSerializer.instance);
module.addSerializer(Long.TYPE, ToStringSerializer.instance);
objectMapper.registerModule(module);
return objectMapper;
}
}