『博客开发日记』之删除userType字段并修改被这个字段所影响的类和接口

本文最后更新于 2026年4月27日 晚上

删除userType字段并修改被这个字段所影响的类和接口


起因

我在开发前台系统中的时候在用户表中有一个 userType 字段用于区分用户类型的

但是在后台管理系统中使用了 role 和 user_role 表来管理用户类型

这一来就导致了 userType 字段和那两个表有冲突了

这必须要改

不能让这两个重复功能的东西

改呗删字段该功能

将用户和角色之间的绑定改用 SysRole 和 SysUserRole 来提供支持


代码修改

首先将 SysUser 里的 userType 字段删除

这里不贴代码了

然后给 CommentVo 和 SysUserInfoVo 添加角色字段列表(list roles)来给前端判断用户类型

CommentVo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* 评论VO
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "评论响应对象")
public class CommentVo {

@ApiModelProperty(value = "评论ID")
private Long id;

@ApiModelProperty(value = "评论类型(0-文章评论,1-友链评论,2-留言板评论)")
private String type;

@ApiModelProperty(value = "文章ID")
private Long articleId;

@ApiModelProperty(value = "用户ID")
private Long userId;

@ApiModelProperty(value = "用户角色列表")
private List<String> roles;

@ApiModelProperty(value = "昵称")
private String nickname;

@ApiModelProperty(value = "头像URL")
private String avatar;

@ApiModelProperty(value = "评论内容")
private String content;

@ApiModelProperty(value = "根评论ID")
private Long rootId;

@ApiModelProperty(value = "回复目标评论ID")
private Long replyToCommentId;

@ApiModelProperty(value = "回复目标评论的用户昵称")
private String replyToCommentNickname;

@ApiModelProperty(value = "回复目标评论的用户角色列表")
private List<String> replyToCommentRoles;

@ApiModelProperty(value = "点赞数")
private Integer likeCount;

@ApiModelProperty(value = "创建时间")
private Date createTime;

@ApiModelProperty(value = "子评论列表")
private List<CommentVo> children;
}

SysUserInfoVo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Data
@Accessors(chain = true)
@ApiModel(description = "前台用户信息响应对象")
public class SysUserInfoVo {

@ApiModelProperty(value = "用户ID")
private Long id;

@ApiModelProperty(value = "昵称")
private String nickname;

@ApiModelProperty(value = "头像URL")
private String avatar;

@ApiModelProperty(value = "手机号")
private String phone;

@ApiModelProperty(value = "性别(0-男,1-女,2-隐藏)")
private String sex;

@ApiModelProperty(value = "邮箱")
private String email;

@ApiModelProperty(value = "用户角色列表")
private List<String> roles;
}


然后在 SystemConstants 里添加一些用户类型常量

1
2
3
4
5
6
7
8
9
10
11
12
13
public static final String MENU_TYPE_B = "B";
/**
* 角色为超级管理员
*/
public static final String ROLE_IS_ADMIN = "admin";
/**
* 角色为用户
*/
public static final String ROLE_IS_USER = "user";
/**
* 角色为访客
*/
public static final String ROLE_IS_VISITOR = "visitor";

剩下的就有关的服务类中的接口实现方法的修改了

BlogLoginServiceImpl 里的 login 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@Override
public ResponseResult login(LoginDto dto)
{
// 预防编程,用户名是否为空
if (!StringUtils.hasText(dto.getUsername())) {
// 提示 必须要传用户名
throw new SystemException(AppHttpCodeEnum.REQUIRE_USERNAME);
}

// 将DTO转换为User实体
SysUser sysUser = BeanCopyUtils.copyBean(dto, SysUser.class);

UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(sysUser.getUsername(), sysUser.getPassword());
Authentication authenticate = authenticationManager.authenticate(authenticationToken);
//判断是否认证通过
if (Objects.isNull(authenticate)) {
throw new RuntimeException("用户名或密码错误!");
}
//获取userid生成token
LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
String userId = loginUser.getSysUser().getId().toString();
String jwt = JwtUtil.createJWT(userId);//传数据进去jwt加密,最终生成一个字符串类型的jwt
//把用户信息存入Redis (格式为 blogLogin:id),设置过期时间与JWT一致
redisCache.setCacheObject("blogLogin:" + userId, loginUser, JwtUtil.JWT_TTL.intValue(), TimeUnit.MILLISECONDS);

//把token和userInfo封装,返回
//把User转化成UserInfoVo
SysUser sysUser1 = loginUser.getSysUser();
SysUserInfoVo sysUserInfoVo = BeanCopyUtils.copyBean(sysUser1, SysUserInfoVo.class);

// 如果昵称为空,使用用户名代替
if (!StringUtils.hasText(sysUserInfoVo.getNickname())) {
sysUserInfoVo.setNickname(sysUser1.getUsername());
}
// 如果头像为空,根据邮箱生成头像
if (!StringUtils.hasText(sysUserInfoVo.getAvatar())) {
sysUserInfoVo.setAvatar(GravatarUtils.getGravatarUrl(sysUser1.getEmail()));
}

// 查询用户角色
List<String> roles = sysRoleMapper.selectRoleCodeByUserId(sysUser1.getId());
if (roles == null || roles.isEmpty()) {
// 如果没有角色,设置为空列表
roles = Collections.emptyList();
}
sysUserInfoVo.setRoles(roles);

BlogUserLoginVo vo = new BlogUserLoginVo(jwt, sysUserInfoVo);
return ResponseResult.okResult(vo);
}

BlogLoginServiceImpl 里的 generateLoginResponse 私有方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//生成登录响应(token和用户信息)
private ResponseResult generateLoginResponse(SysUser sysUser)
{
// 创建LoginUser对象
LoginUser loginUser = new LoginUser(sysUser);

// 生成JWT token
String userId = sysUser.getId().toString();
String jwt = JwtUtil.createJWT(userId);

// 把用户信息存入Redis,设置过期时间与JWT一致
redisCache.setCacheObject("blogLogin:" + userId, loginUser, JwtUtil.JWT_TTL.intValue(), TimeUnit.MILLISECONDS);

// 封装返回数据
SysUserInfoVo sysUserInfoVo = BeanCopyUtils.copyBean(sysUser, SysUserInfoVo.class);

// 如果昵称为空,使用用户名代替
if (!StringUtils.hasText(sysUserInfoVo.getNickname())) {
sysUserInfoVo.setNickname(sysUser.getUsername());
}
// 如果头像为空,根据邮箱生成头像
if (!StringUtils.hasText(sysUserInfoVo.getAvatar())) {
sysUserInfoVo.setAvatar(GravatarUtils.getGravatarUrl(sysUser.getEmail()));
}

// 查询用户角色
List<String> roles = sysRoleMapper.selectRoleCodeByUserId(sysUser.getId());
if (roles == null || roles.isEmpty()) {
// 如果没有角色,设置为空列表
roles = Collections.emptyList();
}
sysUserInfoVo.setRoles(roles);

BlogUserLoginVo vo = new BlogUserLoginVo(jwt, sysUserInfoVo);
return ResponseResult.okResult(vo);
}

CommentServiceImpl 里的 addComment 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//添加评论
@Override
public ResponseResult addComment(AddCommentDto addCommentDto)
{
//校验评论内容
if (!StringUtils.hasText(addCommentDto.getContent())) {
return ResponseResult.errorResult(AppHttpCodeEnum.CONTENT_NOT_NULL);
}

String type = addCommentDto.getType();

//如果是文章评论,需要校验文章是否允许评论
if (SystemConstants.COMMENT_TYPE_ARTICLE.equals(type)) {
Long articleId = addCommentDto.getArticleId();
if (articleId == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(), "文章ID不能为空");
}

//查询文章信息
Article article = articleService.getById(articleId);
if (article == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(), "文章不存在");
}

//检查文章是否允许评论
if (!SystemConstants.ALLOW_COMMENT.equals(article.getIsComment())) {
return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(), "该文章不允许评论");
}
}

//使用 BeanCopyUtils 进行基础字段转换(自动复制 type, articleId, content, rootId, parentId, replyToCommentId, replyToUserId, nickname, email, personalWebsite)
Comment comment = BeanCopyUtils.copyBean(addCommentDto, Comment.class);

//处理 rootId 默认值
if (comment.getRootId() == null) {
comment.setRootId(-1L);
}

//根据评论类型进行权限校验和用户信息设置
if (SystemConstants.COMMENT_TYPE_ARTICLE.equals(type) || SystemConstants.COMMENT_TYPE_LINK.equals(type))
{
//文章评论和友链评论需要登录
if (!SecurityUtils.isLogin()) {
return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
}
LoginUser loginUser = SecurityUtils.getLoginUser();
SysUser sysUser = loginUser.getSysUser();
comment.setUserId(sysUser.getId());
comment.setNickname(sysUser.getNickname());
comment.setEmail(sysUser.getEmail());
//personalWebsite 已通过 BeanCopyUtils 复制
} else if (SystemConstants.COMMENT_TYPE_MESSAGE.equals(type)) {
//留言板评论可以不登录
if (SecurityUtils.isLogin()) {
//已登录用户使用登录信息
LoginUser loginUser = SecurityUtils.getLoginUser();
SysUser sysUser = loginUser.getSysUser();
comment.setUserId(sysUser.getId());
comment.setNickname(sysUser.getNickname());
comment.setEmail(sysUser.getEmail());
//personalWebsite 已通过 BeanCopyUtils 复制
} else {
//未登录用户需要填写昵称和邮箱
if (!StringUtils.hasText(addCommentDto.getNickname())) {
return ResponseResult.errorResult(AppHttpCodeEnum.NICKNAME_NOT_NULL);
}
if (!StringUtils.hasText(addCommentDto.getEmail())) {
return ResponseResult.errorResult(AppHttpCodeEnum.EMAIL_NOT_NULL);
}
//nickname, email, personalWebsite 已通过 BeanCopyUtils 复制,无需再设置
}
}

//根据用户信息获取头像
if (comment.getUserId() != null) {
//已登录用户,使用用户表中的最新头像
SysUser sysUser = sysUserMapper.selectById(comment.getUserId());
if (sysUser != null && StringUtils.hasText(sysUser.getAvatar())) {
comment.setAvatar(sysUser.getAvatar());
} else {
//用户表中没有头像,根据邮箱生成(使用评论专用头像)
comment.setAvatar(GravatarUtils.getCommentPreviewAvatarUrl(comment.getEmail()));
}
} else {
//未登录用户,根据邮箱生成(使用评论专用头像)
comment.setAvatar(GravatarUtils.getCommentPreviewAvatarUrl(comment.getEmail()));
}

//设置默认值
comment.setLikeCount(SystemConstants.DEFAULT_COMMENT_LIKES);
comment.setStatus(SystemConstants.COMMENT_STATUS_NORMAL);
comment.setDelFlag(SystemConstants.DEFAULT_NUMBER_OF_COMMENTS);
comment.setCreateTime(new Date());

save(comment);

//发送邮件通知
emailService.sendCommentNotificationByEmail(comment);

return ResponseResult.okResult();
}

CommentServiceImpl 里的 toCommentVoList 私有方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//转换为CommentVo列表,并设置回复目标昵称和用户角色
private List<CommentVo> toCommentVoList(List<Comment> comments)
{
List<CommentVo> voList = BeanCopyUtils.copyBeanList(comments, CommentVo.class);
for (int i = 0; i < voList.size(); i++) {
CommentVo vo = voList.get(i);
Comment original = comments.get(i);

// 只有评论时已登录(有user_id)的评论才实时获取最新头像、昵称和角色
if (original.getUserId() != null) {
SysUser sysUser = sysUserMapper.selectById(original.getUserId());
if (sysUser != null) {
// 使用用户表中的最新头像和昵称
vo.setAvatar(sysUser.getAvatar());
vo.setNickname(sysUser.getNickname());
// 查询用户角色
List<String> roles = sysRoleMapper.selectRoleCodeByUserId(sysUser.getId());
vo.setRoles(roles != null && !roles.isEmpty() ? roles : Collections.emptyList());
} else {
// 用户不存在,使用评论表中的数据
vo.setAvatar(original.getAvatar());
vo.setRoles(Collections.emptyList());
}
} else {
// 未登录时的评论,使用评论表中保存的头像
vo.setAvatar(original.getAvatar());
// 优先通过邮箱判断是否为博主,未登录时也可识别
if (StringUtils.hasText(original.getEmail())
&& original.getEmail().equalsIgnoreCase(SystemConstants.BLOGGER_EMAIL)) {
// 博主标识 - 设置为admin角色
vo.setRoles(Collections.singletonList(SystemConstants.ROLE_IS_ADMIN));
} else {
// 普通用户 - 空角色列表
vo.setRoles(Collections.emptyList());
}
}

// 设置回复目标昵称和用户角色
if (vo.getReplyToCommentId() != null && vo.getReplyToCommentId() > 0)
{
Comment replyTo = getById(vo.getReplyToCommentId());
if (replyTo != null)
{
// 如果被回复的评论是登录后发布的,获取最新昵称和角色
if (replyTo.getUserId() != null)
{
SysUser replyToSysUser = sysUserMapper.selectById(replyTo.getUserId());
if (replyToSysUser != null) {
vo.setReplyToCommentNickname(replyToSysUser.getNickname());
// 查询被回复用户的角色
List<String> replyToRoles = sysRoleMapper.selectRoleCodeByUserId(replyToSysUser.getId());
vo.setReplyToCommentRoles(replyToRoles != null && !replyToRoles.isEmpty() ? replyToRoles : Collections.emptyList());
} else {
vo.setReplyToCommentNickname(replyTo.getNickname());
vo.setReplyToCommentRoles(Collections.emptyList());
}
} else {
// 被回复的评论是匿名评论,使用评论表中的昵称
vo.setReplyToCommentNickname(replyTo.getNickname());
// 判断被回复者是否为博主
if (StringUtils.hasText(replyTo.getEmail())
&& replyTo.getEmail().equalsIgnoreCase(SystemConstants.BLOGGER_EMAIL)) {
// 博主或者管理员 - 设置为admin角色
vo.setReplyToCommentRoles(Collections.singletonList(SystemConstants.ROLE_IS_ADMIN));
} else {
// 普通用户 - 空角色列表
vo.setReplyToCommentRoles(Collections.singletonList(SystemConstants.ROLE_IS_VISITOR));
}
}
}
}
}
return voList;
}

SysUserServiceImpl 里的 userInfo 方法

这里避免方法体里有过多的代码,将查询用户信息的代码提取出来封装成一个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//查询用户信息
@Override
public ResponseResult userInfo()
{
//获取当前用户id
Long userId = SecurityUtils.getUserId();
//根据用户id查询用户信息
SysUser byId = getById(userId);
//封装成UserInfo
SysUserInfoVo vo = BeanCopyUtils.copyBean(byId, SysUserInfoVo.class);

//查询用户的角色信息
List<String> roles = getUserRoles(userId);
vo.setRoles(roles);

return ResponseResult.okResult(vo);
}

//查询用户的角色列表功能方法
private List<String> getUserRoles(Long userId)
{
//通过用户ID查询用户角色关联表
LambdaQueryWrapper<SysUserRole> userRoleWrapper = new LambdaQueryWrapper<>();
userRoleWrapper.eq(SysUserRole::getUserId, userId);
List<SysUserRole> userRoles = sysUserRoleMapper.selectList(userRoleWrapper);

//如果用户没有角色,返回空列表
if (userRoles == null || userRoles.isEmpty()) {
return new ArrayList<>();
}

//获取角色ID列表
List<Long> roleIds = userRoles.stream()
.map(SysUserRole::getRoleId)
.collect(Collectors.toList());

//查询角色信息
List<SysRole> sysRoles = sysRoleMapper.selectBatchIds(roleIds);

//返回角色代码列表
return sysRoles.stream()
.map(SysRole::getRoleCode)
.collect(Collectors.toList());
}

//为新注册用户分配默认角色功能方法
private void assignDefaultRole(Long userId)
{
try {
//查询"普通用户"角色(role_code = "user")
LambdaQueryWrapper<SysRole> roleQueryWrapper = new LambdaQueryWrapper<>();
roleQueryWrapper.eq(SysRole::getRoleCode, SystemConstants.ROLE_IS_USER)
.last("LIMIT 1");
SysRole userRole = sysRoleMapper.selectOne(roleQueryWrapper);

if (userRole != null) {
//创建用户角色关联记录
SysUserRole sysUserRole = new SysUserRole();
sysUserRole.setUserId(userId);
sysUserRole.setRoleId(userRole.getId());
sysUserRoleMapper.insert(sysUserRole);
log.info("为用户 {} 分配默认角色 {} 成功", userId, userRole.getName());
} else {
log.warn("未找到默认角色(role_code='user'),用户 {} 未分配角色", userId);
}
} catch (Exception e) {
log.error("为用户 {} 分配默认角色失败: {}", userId, e.getMessage(), e);
}
}

SysUserServiceImpl 里的 getBloggerInfo 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//获取博主信息
@Override
public ResponseResult getBloggerInfo()
{
// 通过角色查询博主(查询拥有admin角色的用户)
// 首先查询admin角色的ID
LambdaQueryWrapper<SysRole> roleQueryWrapper = new LambdaQueryWrapper<>();
roleQueryWrapper.eq(SysRole::getRoleCode, SystemConstants.ROLE_IS_ADMIN)
.last("LIMIT 1");
SysRole adminRole = sysRoleMapper.selectOne(roleQueryWrapper);

if (adminRole == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.SELECT_ERROR, "未找到管理员角色");
}

// 查询拥有该角色的用户
LambdaQueryWrapper<SysUserRole> userRoleQueryWrapper = new LambdaQueryWrapper<>();
userRoleQueryWrapper.eq(SysUserRole::getRoleId, adminRole.getId())
.last("LIMIT 1");
SysUserRole userRole = sysUserRoleMapper.selectOne(userRoleQueryWrapper);

if (userRole == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.SELECT_ERROR, "未找到博主信息");
}

// 查询用户信息
SysUser blogger = sysUserMapper.selectById(userRole.getUserId());

if (blogger == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.SELECT_ERROR, "未找到博主信息");
}

// 封装成 BloggerInfoVo
BloggerInfoVo vo = new BloggerInfoVo(
blogger.getNickname(),
blogger.getAvatar()
);

return ResponseResult.okResult(vo);
}

用户注册时也给用户设置默认的角色



这样这个问题就修好了

又是一个数据表导致的问题


PS:该系列只做为作者学习开发项目做的笔记用

不一定符合读者来学习,仅供参考


预告

后续会记录博客的开发过程

每次学习会做一份笔记来进行发表

“一花一世界,一叶一菩提”


版权所有 © 2026 云梦泽
欢迎访问我的个人网站:https://hgt12.github.io/


『博客开发日记』之删除userType字段并修改被这个字段所影响的类和接口
http://example.com/2026/04/26/『博客开发日记』之删除userType字段并修改被这个字段所影响的类和接口/
作者
云梦泽
发布于
2026年4月26日
更新于
2026年4月27日
许可协议