From fa3612648b8c4951d6f8a5888c5e8d0cd792f1a9 Mon Sep 17 00:00:00 2001 From: chen-xin-zhi <3588068430@qq.com> Date: Wed, 7 May 2025 00:27:51 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/aop/PermissionCheck.java | 10 +- .../promotion/constant/SystemConstant.java | 10 ++ .../fileInfo/FileInfoController.java | 1 - .../controller/user/UserInfoController.java | 120 ++++++++++++-- .../dto/fileInfo/FileInfoAddRequest.java | 3 - .../model/dto/user/UserInfoAddRequest.java | 3 + .../UserInfoMiniPasswordLoginRequest.java | 36 +++++ .../UserInfoMiniVerifyCodeLoginRequest.java | 36 +++++ .../dto/user/UserInfoRegisterRequest.java | 57 +++++++ .../model/dto/user/UserInfoResetRequest.java | 53 ++++++ .../promotion/model/entity/FileInfo.java | 7 + .../promotion/model/entity/UserInfo.java | 4 + .../file/impl/FileInfoServiceImpl.java | 3 +- .../service/user/UserInfoService.java | 34 +++- .../user/impl/UserInfoServiceImpl.java | 152 +++++++++++++++++- .../promotion/utils/SendSmsUtil.java | 73 +++++++++ .../promotion/utils/codec/sendsms.java | 3 +- 17 files changed, 574 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/greenorange/promotion/constant/SystemConstant.java create mode 100644 src/main/java/com/greenorange/promotion/model/dto/user/UserInfoMiniPasswordLoginRequest.java create mode 100644 src/main/java/com/greenorange/promotion/model/dto/user/UserInfoMiniVerifyCodeLoginRequest.java create mode 100644 src/main/java/com/greenorange/promotion/model/dto/user/UserInfoRegisterRequest.java create mode 100644 src/main/java/com/greenorange/promotion/model/dto/user/UserInfoResetRequest.java create mode 100644 src/main/java/com/greenorange/promotion/utils/SendSmsUtil.java diff --git a/src/main/java/com/greenorange/promotion/aop/PermissionCheck.java b/src/main/java/com/greenorange/promotion/aop/PermissionCheck.java index 5e80869..57b5949 100644 --- a/src/main/java/com/greenorange/promotion/aop/PermissionCheck.java +++ b/src/main/java/com/greenorange/promotion/aop/PermissionCheck.java @@ -57,8 +57,8 @@ public class PermissionCheck { // 接口的权限 String mustRole = requiresPermission.mustRole(); // 获取接口权限的枚举类 - UserRoleEnum mustUserRoleEnum = UserRoleEnum.getEnumByValue(mustRole); - ThrowUtils.throwIf(mustUserRoleEnum == null, ErrorCode.NO_AUTH_ERROR); + UserRoleEnum interfaceRoleEnum = UserRoleEnum.getEnumByValue(mustRole); + ThrowUtils.throwIf(interfaceRoleEnum == null, ErrorCode.NO_AUTH_ERROR); // 获取用户权限 String token = request.getHeader("Authorization"); ThrowUtils.throwIf(StringUtils.isBlank(token), ErrorCode.NO_AUTH_ERROR, "JWT为空"); @@ -81,11 +81,11 @@ public class PermissionCheck { String userRole = userInfo.getUserRole(); UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(userRole); - // 接口权限只能是 ADMIN 或者 BOSS,用户权限是 ADMIN 或者 BOSS,USER,BAN + // 接口权限只能是 USER,ADMIN,BOSS,用户权限是 ADMIN,BOSS,USER,BAN // 校验角色 - ThrowUtils.throwIf(UserRoleEnum.USER.equals(userRoleEnum), ErrorCode.NO_AUTH_ERROR); + ThrowUtils.throwIf(UserRoleEnum.USER.equals(userRoleEnum) && !UserRoleEnum.USER.equals(interfaceRoleEnum), ErrorCode.NO_AUTH_ERROR); ThrowUtils.throwIf(UserRoleEnum.BAN.equals(userRoleEnum), ErrorCode.NO_AUTH_ERROR, "用户已被封禁"); - ThrowUtils.throwIf(UserRoleEnum.ADMIN.equals(userRoleEnum) && UserRoleEnum.BOSS.equals(mustUserRoleEnum), ErrorCode.NO_AUTH_ERROR); + ThrowUtils.throwIf(UserRoleEnum.ADMIN.equals(userRoleEnum) && UserRoleEnum.BOSS.equals(interfaceRoleEnum), ErrorCode.NO_AUTH_ERROR); return joinPoint.proceed(); } diff --git a/src/main/java/com/greenorange/promotion/constant/SystemConstant.java b/src/main/java/com/greenorange/promotion/constant/SystemConstant.java new file mode 100644 index 0000000..49b1d77 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/constant/SystemConstant.java @@ -0,0 +1,10 @@ +package com.greenorange.promotion.constant; + +public interface SystemConstant { + + /** + * 验证码 + */ + String VERIFICATION_CODE = "verificationCode"; + +} diff --git a/src/main/java/com/greenorange/promotion/controller/fileInfo/FileInfoController.java b/src/main/java/com/greenorange/promotion/controller/fileInfo/FileInfoController.java index f01029b..beca360 100644 --- a/src/main/java/com/greenorange/promotion/controller/fileInfo/FileInfoController.java +++ b/src/main/java/com/greenorange/promotion/controller/fileInfo/FileInfoController.java @@ -62,7 +62,6 @@ public class FileInfoController { */ @PostMapping("upload") @Operation(summary = "Web端文件上传(服务器)", description = "参数:文件添加请求体,权限:管理员,方法名:addFileInfo") - @SysLog(title = "文件管理", content = "Web端文件上传(服务器)") public BaseResponse uploadFile(@RequestPart("file") MultipartFile multipartFile, UploadFileRequest uploadFileRequest) throws IOException{ // 校验文件 fileInfoService.validFile(multipartFile, uploadFileRequest); diff --git a/src/main/java/com/greenorange/promotion/controller/user/UserInfoController.java b/src/main/java/com/greenorange/promotion/controller/user/UserInfoController.java index 95d1f43..f5e15f1 100644 --- a/src/main/java/com/greenorange/promotion/controller/user/UserInfoController.java +++ b/src/main/java/com/greenorange/promotion/controller/user/UserInfoController.java @@ -8,24 +8,25 @@ import com.greenorange.promotion.annotation.SysLog; import com.greenorange.promotion.common.BaseResponse; import com.greenorange.promotion.common.ErrorCode; import com.greenorange.promotion.common.ResultUtils; +import com.greenorange.promotion.constant.SystemConstant; import com.greenorange.promotion.constant.UserConstant; import com.greenorange.promotion.exception.ThrowUtils; import com.greenorange.promotion.model.dto.CommonBatchRequest; import com.greenorange.promotion.model.dto.CommonRequest; -import com.greenorange.promotion.model.dto.user.UserInfoAddRequest; -import com.greenorange.promotion.model.dto.user.UserInfoLoginRequest; -import com.greenorange.promotion.model.dto.user.UserInfoQueryRequest; -import com.greenorange.promotion.model.dto.user.UserInfoUpdateRequest; +import com.greenorange.promotion.model.dto.CommonStringRequest; +import com.greenorange.promotion.model.dto.user.*; import com.greenorange.promotion.model.entity.UserInfo; import com.greenorange.promotion.model.vo.user.UserInfoVO; import com.greenorange.promotion.service.common.CommonService; import com.greenorange.promotion.service.user.UserInfoService; import com.greenorange.promotion.utils.JWTUtils; +import com.greenorange.promotion.utils.RegexUtils; +import com.greenorange.promotion.utils.SendSmsUtil; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.*; @@ -59,30 +60,121 @@ public class UserInfoController { private JWTUtils jwtUtils; + /** + * 小程序端用户获取验证码 + * @param commonStringRequest 手机号 + * @return 验证码 + */ + @PostMapping("code") + @Operation(summary = "小程序端用户获取验证码", description = "参数:手机号,权限:管理员(boss, admin),方法名:getVerificationCode") + @SysLog(title = "用户管理", content = "小程序端用户获取验证码") + public BaseResponse getVerificationCode(@Valid @RequestBody CommonStringRequest commonStringRequest) { + String phoneNumber = commonStringRequest.getTemplateString(); + String verificationCode = userInfoService.getVerificationCode(phoneNumber); + return ResultUtils.success(verificationCode); + } + + + + /** + * 小程序端用户注册 + * @param userInfoRegisterRequest 小程序用户注册请求体 + * @return 是否注册成功 + */ + @PostMapping("register") + @Operation(summary = "小程序端用户注册", description = "参数:小程序用户注册请求体,权限:管理员(boss, admin),方法名:userInfoMiniRegister") + @SysLog(title = "用户管理", content = "小程序端用户注册") + public BaseResponse userInfoMiniRegister(@Valid @RequestBody UserInfoRegisterRequest userInfoRegisterRequest) { + userInfoService.userInfoMiniRegister(userInfoRegisterRequest); + return ResultUtils.success(true); + } + + + + /** + * 小程序端用户密码登录 + * @param userInfoMiniPasswordLoginRequest 小程序用户密码登录请求体 + * @return token + */ + @PostMapping("mini/pwd/login") + @Operation(summary = "小程序端用户密码登录", description = "参数:小程序用户密码登录请求体,权限:管理员(boss, admin),方法名:userInfoMiniLogin") + @SysLog(title = "用户管理", content = "小程序端用户密码登录") + public BaseResponse userInfoMiniLoginByPwd(@Valid @RequestBody UserInfoMiniPasswordLoginRequest userInfoMiniPasswordLoginRequest) { + String token = userInfoService.userInfoMiniLoginByPwd(userInfoMiniPasswordLoginRequest); + return ResultUtils.success(token); + } + + + /** + * 小程序端用户验证码登录 + * @param userInfoMiniVerifyCodeLoginRequest 小程序用户验证码登录请求体 + * @return token + */ + @PostMapping("mini/vcd/login") + @Operation(summary = "小程序端用户验证码登录", description = "参数:小程序用户验证码登录请求体,权限:管理员(boss, admin),方法名:userInfoMiniLoginByVcd") + @SysLog(title = "用户管理", content = "小程序端用户验证码登录") + public BaseResponse userInfoMiniLoginByVcd(@Valid @RequestBody UserInfoMiniVerifyCodeLoginRequest userInfoMiniVerifyCodeLoginRequest) { + String token = userInfoService.userInfoMiniLoginByVcd(userInfoMiniVerifyCodeLoginRequest); + return ResultUtils.success(token); + } + + + /** + * 小程序用户重置密码 + * @param userInfoResetRequest 小程序用户密码重置请求体 + * @return 是否重置成功 + */ + @PostMapping("mini/reset/pwd") + @Operation(summary = "小程序用户重置密码", description = "参数:小程序用户密码重置请求体,权限:管理员(boss, admin),方法名:userInfoMiniResetPwd") + @SysLog(title = "用户管理", content = "小程序端用户重置密码") + public BaseResponse userInfoMiniResetPwd(@Valid @RequestBody UserInfoResetRequest userInfoResetRequest) { + userInfoService.userInfoMiniResetPwd(userInfoResetRequest); + return ResultUtils.success(true); + } + + + + + /** + * 小程序端用户退出登录(用户退出时将 token 加入 Redis 黑名单) + * @return 是否退出登录成功 + */ + @GetMapping("mini/logout") + @Operation(summary = "小程序端用户退出登录", description = "参数:JWT,权限:管理员(boss, admin),方法名:userInfoMiniLogout") + @RequiresPermission(mustRole = UserConstant.DEFAULT_ROLE) + @SysLog(title = "用户管理", content = "小程序端用户退出登录") + public BaseResponse userInfoMiniLogout(@RequestHeader("Authorization") String token) { + // 获取token的过期时间 + DecodedJWT decodedJWT = jwtUtils.verify(token); + long expirationTime = decodedJWT.getExpiresAt().getTime() - System.currentTimeMillis(); + // 将token存入Redis黑名单,并设置过期时间与token一致 + redisTemplate.opsForValue().set(token, token, expirationTime, TimeUnit.MILLISECONDS); + return ResultUtils.success(true); + } + /** * web端管理员登录 - * @param userInfoLoginRequest 用户登录请求体 + * @param userInfoLoginRequest web用户登录请求体 * @return 是否登录成功 */ @PostMapping("login") - @Operation(summary = "web端管理员登录", description = "参数:用户登录请求体,权限:管理员(boss, admin),方法名:userInfoLogin") + @Operation(summary = "web端管理员登录", description = "参数:web用户登录请求体,权限:管理员(boss, admin),方法名:userInfoLogin") @SysLog(title = "用户管理", content = "web端管理员登录") - public BaseResponse userInfoLogin(@Valid @RequestBody UserInfoLoginRequest userInfoLoginRequest, HttpServletRequest request) { - String userAccount = userInfoLoginRequest.getUserAccount(); - String userPassword = userInfoLoginRequest.getUserPassword(); - String token = userInfoService.userInfoLogin(userAccount, userPassword, request); + public BaseResponse userInfoLogin(@Valid @RequestBody UserInfoLoginRequest userInfoLoginRequest) { + String token = userInfoService.userInfoLogin(userInfoLoginRequest); return ResultUtils.success(token); } + /** * web端管理员退出登录(用户退出时将 token 加入 Redis 黑名单) * @return 是否退出登录成功 */ - @PostMapping("logout") + @GetMapping("logout") @Operation(summary = "web端管理员退出登录", description = "参数:JWT,权限:管理员(boss, admin),方法名:userInfoLogout") @RequiresPermission(mustRole = UserConstant.ADMIN_ROLE) @SysLog(title = "用户管理", content = "web端管理员退出登录") @@ -98,6 +190,8 @@ public class UserInfoController { + + /** * web端管理员添加用户表 * @param userInfoAddRequest 用户表添加请求体 @@ -105,6 +199,8 @@ public class UserInfoController { */ @PostMapping("add") @Operation(summary = "web端管理员添加用户", description = "参数:用户表添加请求体,权限:管理员(boss, admin),方法名:addUserInfo") + @RequiresPermission(mustRole = UserConstant.ADMIN_ROLE) + @SysLog(title = "用户管理", content = "web端管理员添加用户") public BaseResponse addUserInfo(@Valid @RequestBody UserInfoAddRequest userInfoAddRequest) { UserInfo userInfo = commonService.copyProperties(userInfoAddRequest, UserInfo.class); userInfoService.save(userInfo); diff --git a/src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoAddRequest.java b/src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoAddRequest.java index 91c3396..63dee49 100644 --- a/src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoAddRequest.java +++ b/src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoAddRequest.java @@ -16,9 +16,6 @@ import java.io.Serializable; * 文件添加请求体 */ @Data -@NoArgsConstructor -@AllArgsConstructor -@Builder @Schema(description = "文件添加请求体", requiredProperties = { "name", "type", diff --git a/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoAddRequest.java b/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoAddRequest.java index 58d64ce..9a5a718 100644 --- a/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoAddRequest.java +++ b/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoAddRequest.java @@ -5,7 +5,10 @@ import com.greenorange.promotion.model.enums.UserRoleEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import java.io.Serial; import java.io.Serializable; diff --git a/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoMiniPasswordLoginRequest.java b/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoMiniPasswordLoginRequest.java new file mode 100644 index 0000000..0fe0b9f --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoMiniPasswordLoginRequest.java @@ -0,0 +1,36 @@ +package com.greenorange.promotion.model.dto.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 小程序用户密码登录请求体 + */ +@Data +@Schema(description = "小程序用户密码登录请求体", requiredProperties = {"phoneNumber", "userPassword"}) +public class UserInfoMiniPasswordLoginRequest implements Serializable { + + /** + * 账号 + */ + @NotBlank(message = "手机号不能为空") + @Schema(description = "手机号", example = "15888610253") + private String phoneNumber; + + /** + * 密码 + */ + @NotBlank(message = "密码不能为空") + @Size(min = 6, max = 10, message = "密码长度在 6 到 10 个字符") + @Schema(description = "密码(建议加密存储)", example = "qingcheng") + private String userPassword; + + @Serial + private static final long serialVersionUID = 1L; + +} diff --git a/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoMiniVerifyCodeLoginRequest.java b/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoMiniVerifyCodeLoginRequest.java new file mode 100644 index 0000000..978abe0 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoMiniVerifyCodeLoginRequest.java @@ -0,0 +1,36 @@ +package com.greenorange.promotion.model.dto.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 小程序用户验证码登录请求体 + */ +@Data +@Schema(description = "小程序用户验证码登录请求体", requiredProperties = {"phoneNumber", "verificationCode"}) +public class UserInfoMiniVerifyCodeLoginRequest implements Serializable { + + /** + * 账号 + */ + @NotBlank(message = "手机号不能为空") + @Schema(description = "手机号", example = "15888610253") + private String phoneNumber; + + /** + * 验证码 + */ + @NotBlank(message = "验证码不能为空") + @Schema(description = "验证码", example = "666999") + private String verificationCode; + + + @Serial + private static final long serialVersionUID = 1L; + +} diff --git a/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoRegisterRequest.java b/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoRegisterRequest.java new file mode 100644 index 0000000..2fe908b --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoRegisterRequest.java @@ -0,0 +1,57 @@ +package com.greenorange.promotion.model.dto.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 小程序用户注册请求体 + */ +@Data +@Schema(description = "小程序用户注册请求体", requiredProperties = {"nickName", "phoneNumber", +"verificationCode", "invitationCode", "userPassword"}) +public class UserInfoRegisterRequest implements Serializable { + + /** + * 用户昵称 + */ + @NotBlank(message = "用户昵称不能为空") + @Schema(description = "用户昵称", example = "chenxinzhi") + private String nickName; + + /** + * 手机号 + */ + @NotBlank(message = "手机号不能为空") + @Schema(description = "手机号", example = "15888610253") + private String phoneNumber; + + /** + * 验证码 + */ + @NotBlank(message = "验证码不能为空") + @Schema(description = "验证码", example = "666999") + private String verificationCode; + + /** + * 邀请码 + */ + @Schema(description = "邀请码", example = "666999") + private String invitationCode; + + /** + * 密码 + */ + @NotBlank(message = "密码不能为空") + @Size(min = 6, max = 10, message = "密码长度在 6 到 10 个字符") + @Schema(description = "密码(建议加密存储)", example = "qingcheng") + private String userPassword; + + + @Serial + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoResetRequest.java b/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoResetRequest.java new file mode 100644 index 0000000..56eeb20 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/dto/user/UserInfoResetRequest.java @@ -0,0 +1,53 @@ +package com.greenorange.promotion.model.dto.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 用户信息重置请求体 + */ +@Data +@Schema(description = "小程序用户信息重置请求体", requiredProperties = +{"phoneNumber", "verificationCode", "userPassword", "userConfirmPassword"}) +public class UserInfoResetRequest implements Serializable { + + /** + * 手机号 + */ + @NotBlank(message = "手机号不能为空") + @Schema(description = "手机号", example = "15888610253") + private String phoneNumber; + + /** + * 验证码 + */ + @NotBlank(message = "验证码不能为空") + @Schema(description = "验证码", example = "666999") + private String verificationCode; + + /** + * 密码 + */ + @NotBlank(message = "密码不能为空") + @Size(min = 6, max = 10, message = "密码长度在 6 到 10 个字符") + @Schema(description = "密码(建议加密存储)", example = "qingcheng") + private String userPassword; + + + /** + * 确认密码 + */ + @NotBlank(message = "确认密码不能为空") + @Size(min = 6, max = 10, message = "密码长度在 6 到 10 个字符") + @Schema(description = "确认密码(建议加密存储)", example = "qingcheng") + private String userConfirmPassword; + + + @Serial + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/com/greenorange/promotion/model/entity/FileInfo.java b/src/main/java/com/greenorange/promotion/model/entity/FileInfo.java index fe73edb..dbfbd05 100644 --- a/src/main/java/com/greenorange/promotion/model/entity/FileInfo.java +++ b/src/main/java/com/greenorange/promotion/model/entity/FileInfo.java @@ -6,7 +6,11 @@ import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; import java.util.Date; + +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; /** * 文件上传列表 @@ -14,6 +18,9 @@ import lombok.Data; */ @TableName(value ="file_info") @Data +@NoArgsConstructor +@AllArgsConstructor +@Builder public class FileInfo implements Serializable { /** * 文件ID diff --git a/src/main/java/com/greenorange/promotion/model/entity/UserInfo.java b/src/main/java/com/greenorange/promotion/model/entity/UserInfo.java index 681deda..478367a 100644 --- a/src/main/java/com/greenorange/promotion/model/entity/UserInfo.java +++ b/src/main/java/com/greenorange/promotion/model/entity/UserInfo.java @@ -6,7 +6,11 @@ import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; import java.util.Date; + +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; /** * 用户基本信息表 diff --git a/src/main/java/com/greenorange/promotion/service/file/impl/FileInfoServiceImpl.java b/src/main/java/com/greenorange/promotion/service/file/impl/FileInfoServiceImpl.java index 3af2af1..859a532 100644 --- a/src/main/java/com/greenorange/promotion/service/file/impl/FileInfoServiceImpl.java +++ b/src/main/java/com/greenorange/promotion/service/file/impl/FileInfoServiceImpl.java @@ -96,7 +96,7 @@ public class FileInfoServiceImpl extends ServiceImpl FileInfo fileInfo = this.getOne(lambdaQueryWrapper); if (fileInfo != null) return fileInfo.getFileView(); // 保存文件 - FileInfoAddRequest fileInfoAddRequest = FileInfoAddRequest.builder() + fileInfo = FileInfo.builder() .name(fileName) .type(fileType) .path(filePath) @@ -105,7 +105,6 @@ public class FileInfoServiceImpl extends ServiceImpl .biz(biz) .hashValue(hashValue) .build(); - fileInfo = commonService.copyProperties(fileInfoAddRequest, FileInfo.class); this.save(fileInfo); // 创建上传目录,如果不存在 File file = new File(UPLOAD_DIR + filePath); diff --git a/src/main/java/com/greenorange/promotion/service/user/UserInfoService.java b/src/main/java/com/greenorange/promotion/service/user/UserInfoService.java index 4393fd3..2766679 100644 --- a/src/main/java/com/greenorange/promotion/service/user/UserInfoService.java +++ b/src/main/java/com/greenorange/promotion/service/user/UserInfoService.java @@ -1,7 +1,7 @@ package com.greenorange.promotion.service.user; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.greenorange.promotion.model.dto.user.UserInfoQueryRequest; +import com.greenorange.promotion.model.dto.user.*; import com.greenorange.promotion.model.entity.UserInfo; import com.baomidou.mybatisplus.extension.service.IService; import jakarta.servlet.http.HttpServletRequest; @@ -23,5 +23,35 @@ public interface UserInfoService extends IService { /** * web端用户登录 */ - String userInfoLogin(String userAccount, String userPassword, HttpServletRequest request); + String userInfoLogin(UserInfoLoginRequest userInfoLoginRequest); + + + /** + * 小程序用户注册 + */ + void userInfoMiniRegister(UserInfoRegisterRequest userInfoRegisterRequest); + + + /** + * 小程序端用户密码登录 + */ + String userInfoMiniLoginByPwd(UserInfoMiniPasswordLoginRequest userInfoMiniPasswordLoginRequest); + + + /** + * 小程序用户验证码登录 + */ + String userInfoMiniLoginByVcd(UserInfoMiniVerifyCodeLoginRequest userInfoMiniVerifyCodeLoginRequest); + + + /** + * 小程序用户重置密码 + */ + void userInfoMiniResetPwd(UserInfoResetRequest userInfoResetRequest); + + + /** + * 小程序用户获取验证码 + */ + String getVerificationCode(String phoneNumber); } diff --git a/src/main/java/com/greenorange/promotion/service/user/impl/UserInfoServiceImpl.java b/src/main/java/com/greenorange/promotion/service/user/impl/UserInfoServiceImpl.java index c8490c5..32022b3 100644 --- a/src/main/java/com/greenorange/promotion/service/user/impl/UserInfoServiceImpl.java +++ b/src/main/java/com/greenorange/promotion/service/user/impl/UserInfoServiceImpl.java @@ -1,26 +1,34 @@ package com.greenorange.promotion.service.user.impl; +import cn.hutool.core.util.RandomUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.greenorange.promotion.annotation.RequiresPermission; import com.greenorange.promotion.common.ErrorCode; import com.greenorange.promotion.constant.CommonConstant; +import com.greenorange.promotion.constant.SystemConstant; +import com.greenorange.promotion.constant.UserConstant; import com.greenorange.promotion.exception.ThrowUtils; import com.greenorange.promotion.mapper.UserInfoMapper; -import com.greenorange.promotion.model.dto.user.UserInfoQueryRequest; +import com.greenorange.promotion.model.dto.user.*; import com.greenorange.promotion.model.entity.UserInfo; +import com.greenorange.promotion.service.common.CommonService; import com.greenorange.promotion.service.user.UserInfoService; import com.greenorange.promotion.utils.JWTUtils; +import com.greenorange.promotion.utils.RegexUtils; +import com.greenorange.promotion.utils.SendSmsUtil; import com.greenorange.promotion.utils.SqlUtils; import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; /** * @author 35880 @@ -35,6 +43,14 @@ public class UserInfoServiceImpl extends ServiceImpl private JWTUtils jwtUtils; + @Resource + private CommonService commonService; + + + @Resource + private RedisTemplate redisTemplate; + + /** * 获取查询条件 */ @@ -56,7 +72,9 @@ public class UserInfoServiceImpl extends ServiceImpl * web端用户登录 */ @Override - public String userInfoLogin(String userAccount, String userPassword, HttpServletRequest request) { + public String userInfoLogin(UserInfoLoginRequest userInfoLoginRequest) { + String userAccount = userInfoLoginRequest.getUserAccount(); + String userPassword = userInfoLoginRequest.getUserPassword(); LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(UserInfo::getUserAccount, userAccount).eq(UserInfo::getUserPassword, userPassword); UserInfo userInfo = this.getOne(lambdaQueryWrapper); @@ -66,6 +84,132 @@ public class UserInfoServiceImpl extends ServiceImpl payload.put("userPassword", userPassword); return jwtUtils.generateToken(payload); } + + + /** + * 小程序用户注册 + */ + @Override + public void userInfoMiniRegister(UserInfoRegisterRequest userInfoRegisterRequest) { + String phoneNumber = userInfoRegisterRequest.getPhoneNumber(); + ThrowUtils.throwIf(RegexUtils.isPhoneInvalid(phoneNumber), ErrorCode.PARAMS_ERROR, "手机号格式无效"); + LambdaQueryWrapper phoneNumberLambdaQueryWrapper = new LambdaQueryWrapper<>(); + phoneNumberLambdaQueryWrapper.eq(UserInfo::getPhoneNumber, phoneNumber); + UserInfo userInfo = this.getOne(phoneNumberLambdaQueryWrapper); + ThrowUtils.throwIf(userInfo != null, ErrorCode.OPERATION_ERROR, "手机号已注册"); + + String verificationCode = userInfoRegisterRequest.getVerificationCode(); + String code = redisTemplate.opsForValue().get(SystemConstant.VERIFICATION_CODE + ":" + verificationCode); + ThrowUtils.throwIf(code == null, ErrorCode.OPERATION_ERROR, "验证码已失效"); + + // 移除验证码 + redisTemplate.delete(SystemConstant.VERIFICATION_CODE + ":" + verificationCode); + + String invitationCode = userInfoRegisterRequest.getInvitationCode(); + LambdaQueryWrapper invitedLambdaQueryWrapper = new LambdaQueryWrapper<>(); + invitedLambdaQueryWrapper.eq(UserInfo::getInvitationCode, invitationCode); + UserInfo parentUserInfo = this.getOne(invitedLambdaQueryWrapper); + ThrowUtils.throwIf(parentUserInfo == null, ErrorCode.OPERATION_ERROR, "邀请码错误"); + + UserInfo myUserInfo = commonService.copyProperties(userInfoRegisterRequest, UserInfo.class); + userInfo.setParentUserId(parentUserInfo.getId()); + userInfo.setInvitationCode(RandomUtil.randomNumbers(6)); + userInfo.setUserAccount(RandomUtil.randomNumbers(8)); + userInfo.setUserRole(UserConstant.DEFAULT_ROLE); + userInfo.setUserAvatar(UserConstant.USER_DEFAULT_AVATAR); + userInfo.setSuperUserList(parentUserInfo.getSuperUserList() + "," + parentUserInfo.getId()); + this.save(myUserInfo); + } + + + + /** + * 小程序端用户密码登录 + */ + @Override + public String userInfoMiniLoginByPwd(UserInfoMiniPasswordLoginRequest userInfoMiniPasswordLoginRequest) { + String phoneNumber = userInfoMiniPasswordLoginRequest.getPhoneNumber(); + ThrowUtils.throwIf(RegexUtils.isPhoneInvalid(phoneNumber), ErrorCode.PARAMS_ERROR, "手机号格式无效"); + String userPassword = userInfoMiniPasswordLoginRequest.getUserPassword(); + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(UserInfo::getPhoneNumber, phoneNumber).eq(UserInfo::getUserPassword, userPassword); + UserInfo userInfo = this.getOne(lambdaQueryWrapper); + ThrowUtils.throwIf(userInfo == null, ErrorCode.OPERATION_ERROR, "手机号未注册"); + + Map payload = new HashMap<>(); + payload.put("phoneNumber", phoneNumber); + payload.put("userPassword", userPassword); + return jwtUtils.generateToken(payload); + } + + + + + /** + * 小程序用户验证码登录 + */ + @Override + public String userInfoMiniLoginByVcd(UserInfoMiniVerifyCodeLoginRequest userInfoMiniVerifyCodeLoginRequest) { + String phoneNumber = userInfoMiniVerifyCodeLoginRequest.getPhoneNumber(); + ThrowUtils.throwIf(RegexUtils.isPhoneInvalid(phoneNumber), ErrorCode.PARAMS_ERROR, "手机号格式无效"); + + String verificationCode = userInfoMiniVerifyCodeLoginRequest.getVerificationCode(); + String code = redisTemplate.opsForValue().get(SystemConstant.VERIFICATION_CODE + ":" + verificationCode); + ThrowUtils.throwIf(code == null, ErrorCode.OPERATION_ERROR, "验证码已失效"); + + // 移除验证码 + redisTemplate.delete(SystemConstant.VERIFICATION_CODE + ":" + verificationCode); + + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(UserInfo::getPhoneNumber, phoneNumber); + UserInfo userInfo = this.getOne(lambdaQueryWrapper); + String userPassword = userInfo.getUserPassword(); + + Map payload = new HashMap<>(); + payload.put("phoneNumber", phoneNumber); + payload.put("userPassword", userPassword); + return jwtUtils.generateToken(payload); + } + + + + /** + * 小程序用户重置密码 + */ + @Override + public void userInfoMiniResetPwd(UserInfoResetRequest userInfoResetRequest) { + String phoneNumber = userInfoResetRequest.getPhoneNumber(); + ThrowUtils.throwIf(RegexUtils.isPhoneInvalid(phoneNumber), ErrorCode.PARAMS_ERROR, "手机号格式无效"); + + String verificationCode = userInfoResetRequest.getVerificationCode(); + String code = redisTemplate.opsForValue().get(SystemConstant.VERIFICATION_CODE + ":" + verificationCode); + ThrowUtils.throwIf(code == null, ErrorCode.OPERATION_ERROR, "验证码已失效"); + + // 移除验证码 + redisTemplate.delete(SystemConstant.VERIFICATION_CODE + ":" + verificationCode); + + String userPassword = userInfoResetRequest.getUserPassword(); + String userConfirmPassword = userInfoResetRequest.getUserConfirmPassword(); + ThrowUtils.throwIf(!userPassword.equals(userConfirmPassword), ErrorCode.OPERATION_ERROR, "两次密码不一致"); + + // 更新用户密码 + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper<>(); + lambdaUpdateWrapper.eq(UserInfo::getPhoneNumber, phoneNumber).set(UserInfo::getUserPassword, userPassword); + this.update(lambdaUpdateWrapper); + } + + + /** + * 小程序用户获取验证码 + */ + @Override + public String getVerificationCode(String phoneNumber) { + ThrowUtils.throwIf(RegexUtils.isPhoneInvalid(phoneNumber), ErrorCode.PARAMS_ERROR, "手机号格式错误"); + String verificationCode = SendSmsUtil.getVerificationCode(phoneNumber); + ThrowUtils.throwIf(verificationCode == null, ErrorCode.OPERATION_ERROR, "验证码获取失败"); + redisTemplate.opsForValue().set(SystemConstant.VERIFICATION_CODE + ":" + verificationCode, verificationCode, 5, TimeUnit.MINUTES); + return verificationCode; + } } diff --git a/src/main/java/com/greenorange/promotion/utils/SendSmsUtil.java b/src/main/java/com/greenorange/promotion/utils/SendSmsUtil.java new file mode 100644 index 0000000..571d8ab --- /dev/null +++ b/src/main/java/com/greenorange/promotion/utils/SendSmsUtil.java @@ -0,0 +1,73 @@ +package com.greenorange.promotion.utils; + +import org.apache.http.HttpEntity; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.dom4j.Document; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; + +import java.util.ArrayList; +import java.util.List; + +public class SendSmsUtil { + + + private static String Url = "http://106.ihuyi.com/webservice/sms.php?method=Submit"; + + public static String getVerificationCode(String phoneNumber) { + // 创建 HttpClient + try (CloseableHttpClient client = HttpClients.createDefault()) { + // 创建 POST 请求 + HttpPost post = new HttpPost(Url); + post.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=GBK"); + + // 生成验证码 + int mobile_code = (int) ((Math.random() * 9 + 1) * 100000); + String content = "您的验证码是:" + mobile_code + "。请不要把验证码泄露给其他人。"; + + // 设置请求参数 + List data = new ArrayList<>(); + data.add(new BasicNameValuePair("account", "C08121984")); + data.add(new BasicNameValuePair("password", "84a27a879413ec629bf26c5d84a25271")); + data.add(new BasicNameValuePair("mobile", phoneNumber)); + data.add(new BasicNameValuePair("content", content)); + + // 设置请求体 + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(data, "GBK"); + post.setEntity(entity); + + // 执行请求 + String response = client.execute(post, httpResponse -> { + HttpEntity entity1 = httpResponse.getEntity(); + return EntityUtils.toString(entity1, "GBK"); + }); + + // 解析返回的 XML 响应 + Document doc = DocumentHelper.parseText(response); + Element root = doc.getRootElement(); + + String code = root.elementText("code"); + String msg = root.elementText("msg"); + String smsid = root.elementText("smsid"); + + System.out.println(code); + System.out.println(msg); + System.out.println(smsid); + + if ("2".equals(code)) { + System.out.println("短信提交成功"); + return String.valueOf(mobile_code); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + +} diff --git a/src/main/java/com/greenorange/promotion/utils/codec/sendsms.java b/src/main/java/com/greenorange/promotion/utils/codec/sendsms.java index 17ef394..e17ba3c 100644 --- a/src/main/java/com/greenorange/promotion/utils/codec/sendsms.java +++ b/src/main/java/com/greenorange/promotion/utils/codec/sendsms.java @@ -28,8 +28,7 @@ public class sendsms { post.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=GBK"); // 生成验证码 -// int mobile_code = (int) ((Math.random() * 9 + 1) * 100000); - int mobile_code = 114514; + int mobile_code = (int) ((Math.random() * 9 + 1) * 100000); String content = "您的验证码是:" + mobile_code + "。请不要把验证码泄露给其他人。"; // 设置请求参数