Commit e44011754c583ad7d6b397a53382e6b511f26a7c

Authored by YunaiV
1 parent fe4a774c

feat(member): 会员增加 email 字段

yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java
... ... @@ -36,6 +36,10 @@ public class MemberUserRespDTO {
36 36 */
37 37 private String mobile;
38 38 /**
  39 + * 邮箱
  40 + */
  41 + private String email;
  42 + /**
39 43 * 创建时间(注册时间)
40 44 */
41 45 private LocalDateTime createTime;
... ...
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserBaseVO.java
... ... @@ -5,7 +5,9 @@ import lombok.Data;
5 5 import org.hibernate.validator.constraints.URL;
6 6 import org.springframework.format.annotation.DateTimeFormat;
7 7  
  8 +import jakarta.validation.constraints.Email;
8 9 import jakarta.validation.constraints.NotNull;
  10 +import jakarta.validation.constraints.Size;
9 11 import java.time.LocalDateTime;
10 12 import java.util.List;
11 13  
... ... @@ -26,6 +28,11 @@ public class MemberUserBaseVO {
26 28 @NotNull(message = "状态不能为空")
27 29 private Byte status;
28 30  
  31 + @Schema(description = "邮箱", example = "member@iocoder.cn")
  32 + @Email(message = "邮箱格式不正确")
  33 + @Size(max = 50, message = "邮箱长度不能超过 50 个字符")
  34 + private String email;
  35 +
29 36 @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
30 37 @NotNull(message = "用户昵称不能为空")
31 38 private String nickname;
... ...
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserPageReqVO.java
... ... @@ -21,6 +21,9 @@ public class MemberUserPageReqVO extends PageParam {
21 21 @Schema(description = "手机号", example = "15601691300")
22 22 private String mobile;
23 23  
  24 + @Schema(description = "邮箱", example = "member@iocoder.cn")
  25 + private String email;
  26 +
24 27 @Schema(description = "用户昵称", example = "李四")
25 28 private String nickname;
26 29  
... ...
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserInfoRespVO.java
... ... @@ -23,6 +23,9 @@ public class AppMemberUserInfoRespVO {
23 23 @Schema(description = "用户手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300")
24 24 private String mobile;
25 25  
  26 + @Schema(description = "邮箱", example = "member@iocoder.cn")
  27 + private String email;
  28 +
26 29 @Schema(description = "用户性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
27 30 private Integer sex;
28 31  
... ...
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateReqVO.java
1 1 package cn.iocoder.yudao.module.member.controller.app.user.vo;
2 2  
3   -import cn.iocoder.yudao.framework.common.validation.InEnum;
4   -import cn.iocoder.yudao.module.system.enums.common.SexEnum;
5 3 import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.Email;
  5 +import jakarta.validation.constraints.Size;
6 6 import lombok.Data;
7 7 import org.hibernate.validator.constraints.URL;
8 8  
... ... @@ -17,6 +17,11 @@ public class AppMemberUserUpdateReqVO {
17 17 @URL(message = "头像必须是 URL 格式")
18 18 private String avatar;
19 19  
  20 + @Schema(description = "邮箱", example = "member@iocoder.cn")
  21 + @Email(message = "邮箱格式不正确")
  22 + @Size(max = 50, message = "邮箱长度不能超过 50 个字符")
  23 + private String email;
  24 +
20 25 @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
21 26 private Integer sex;
22 27  
... ...
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java
... ... @@ -46,6 +46,10 @@ public class MemberUserDO extends TenantBaseDO {
46 46 */
47 47 private String mobile;
48 48 /**
  49 + * 邮箱
  50 + */
  51 + private String email;
  52 + /**
49 53 * 加密后的密码
50 54 *
51 55 * 因为目前使用 {@link BCryptPasswordEncoder} 加密器,所以无需自己处理 salt 盐
... ...
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java
... ... @@ -26,6 +26,10 @@ public interface MemberUserMapper extends BaseMapperX<MemberUserDO> {
26 26 return selectOne(MemberUserDO::getMobile, mobile);
27 27 }
28 28  
  29 + default MemberUserDO selectByEmail(String email) {
  30 + return selectOne(MemberUserDO::getEmail, email);
  31 + }
  32 +
29 33 default List<MemberUserDO> selectListByNicknameLike(String nickname) {
30 34 return selectList(new LambdaQueryWrapperX<MemberUserDO>()
31 35 .likeIfPresent(MemberUserDO::getNickname, nickname));
... ... @@ -42,6 +46,7 @@ public interface MemberUserMapper extends BaseMapperX&lt;MemberUserDO&gt; {
42 46 // 分页查询
43 47 return selectPage(reqVO, new LambdaQueryWrapperX<MemberUserDO>()
44 48 .likeIfPresent(MemberUserDO::getMobile, reqVO.getMobile())
  49 + .likeIfPresent(MemberUserDO::getEmail, reqVO.getEmail())
45 50 .betweenIfPresent(MemberUserDO::getLoginDate, reqVO.getLoginDate())
46 51 .likeIfPresent(MemberUserDO::getNickname, reqVO.getNickname())
47 52 .betweenIfPresent(MemberUserDO::getCreateTime, reqVO.getCreateTime())
... ...
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
... ... @@ -14,6 +14,7 @@ public interface ErrorCodeConstants {
14 14 ErrorCode USER_MOBILE_NOT_EXISTS = new ErrorCode(1_004_001_001, "手机号未注册用户");
15 15 ErrorCode USER_MOBILE_USED = new ErrorCode(1_004_001_002, "修改手机失败,该手机号({})已经被使用");
16 16 ErrorCode USER_POINT_NOT_ENOUGH = new ErrorCode(1_004_001_003, "用户积分余额不足");
  17 + ErrorCode USER_EMAIL_USED = new ErrorCode(1_004_001_004, "修改邮箱失败,该邮箱({})已经被使用");
17 18  
18 19 // ========== AUTH 模块 1-004-003-000 ==========
19 20 ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1_004_003_000, "登录失败,账号密码不正确");
... ...
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java
... ... @@ -142,6 +142,12 @@ public class MemberUserServiceImpl implements MemberUserService {
142 142  
143 143 @Override
144 144 public void updateUser(Long userId, AppMemberUserUpdateReqVO reqVO) {
  145 + // 1.1 检测用户是否存在
  146 + validateUserExists(userId);
  147 + // 1.2 校验手机是否已经被绑定
  148 + validateEmailUnique(userId, reqVO.getEmail());
  149 +
  150 + // 2. 更新用户
145 151 MemberUserDO updateObj = BeanUtils.toBean(reqVO, MemberUserDO.class).setId(userId);
146 152 memberUserMapper.updateById(updateObj);
147 153 }
... ... @@ -238,6 +244,8 @@ public class MemberUserServiceImpl implements MemberUserService {
238 244 validateUserExists(updateReqVO.getId());
239 245 // 校验手机唯一
240 246 validateMobileUnique(updateReqVO.getId(), updateReqVO.getMobile());
  247 + // 校验邮箱唯一
  248 + validateEmailUnique(updateReqVO.getId(), updateReqVO.getEmail());
241 249  
242 250 // 更新
243 251 MemberUserDO updateObj = MemberUserConvert.INSTANCE.convert(updateReqVO);
... ... @@ -274,6 +282,24 @@ public class MemberUserServiceImpl implements MemberUserService {
274 282 }
275 283 }
276 284  
  285 + @VisibleForTesting
  286 + void validateEmailUnique(Long id, String email) {
  287 + if (StrUtil.isBlank(email)) {
  288 + return;
  289 + }
  290 + MemberUserDO user = memberUserMapper.selectByEmail(email);
  291 + if (user == null) {
  292 + return;
  293 + }
  294 + // 如果 id 为空,说明不用比较是否为相同 id 的用户
  295 + if (id == null) {
  296 + throw exception(USER_EMAIL_USED, email);
  297 + }
  298 + if (!user.getId().equals(id)) {
  299 + throw exception(USER_EMAIL_USED, email);
  300 + }
  301 + }
  302 +
277 303 @Override
278 304 public PageResult<MemberUserDO> getUserPage(MemberUserPageReqVO pageReqVO) {
279 305 return memberUserMapper.selectPage(pageReqVO);
... ...
yudao-module-member/src/test/resources/sql/create_tables.sql
... ... @@ -11,6 +11,7 @@ CREATE TABLE IF NOT EXISTS &quot;member_user&quot;
11 11 "avatar" varchar(255) NOT NULL DEFAULT '' COMMENT '头像',
12 12 "status" tinyint NOT NULL COMMENT '状态',
13 13 "mobile" varchar(11) NOT NULL COMMENT '手机号',
  14 + "email" varchar(50) NULL COMMENT '邮箱',
14 15 "password" varchar(100) NOT NULL DEFAULT '' COMMENT '密码',
15 16 "register_ip" varchar(32) NOT NULL COMMENT '注册 IP',
16 17 "login_ip" varchar(50) NULL DEFAULT '' COMMENT '最后登录IP',
... ...