diff --git a/.vscode/settings.json b/.vscode/settings.json index b0b2909..c4f2897 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx2G -Xms100m -Xlog:disable" + "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx2G -Xms100m -Xlog:disable", + "java.compile.nullAnalysis.mode": "automatic" } \ No newline at end of file diff --git a/agileboot-api/src/main/java/com/agileboot/api/controller/WxController.java b/agileboot-api/src/main/java/com/agileboot/api/controller/WxController.java index 13b6db3..10f0e87 100644 --- a/agileboot-api/src/main/java/com/agileboot/api/controller/WxController.java +++ b/agileboot-api/src/main/java/com/agileboot/api/controller/WxController.java @@ -6,11 +6,15 @@ import com.agileboot.common.core.dto.ResponseDTO; import com.agileboot.common.exception.ApiException; import com.agileboot.common.exception.error.ErrorCode; import com.agileboot.domain.wx.WxService; +import com.agileboot.domain.wx.user.WxUserApplicationService; +import com.agileboot.domain.wx.user.dto.WxUserDTO; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestClientException; @@ -25,6 +29,8 @@ import java.util.Map; public class WxController { private final WxService wxService; + private final WxUserApplicationService wxUserApplicationService; + /** * 获取小程序用户OpenID * @param code 微信授权码 @@ -32,14 +38,40 @@ public class WxController { * @throws ApiException 当code无效或微信接口调用失败时抛出 */ @GetMapping("/mpCodeToOpenId") - public ResponseDTO mpCodeToOpenId(String code) { + public ResponseDTO mpCodeToOpenId(String code) { try { String openid = wxService.getSmallOpenid(code); + // 校验openid是否为空 + if (StringUtils.isBlank(openid)) { + throw new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "根据code获取openid失败"); + } - return ResponseDTO.ok(openid); + return ResponseDTO.ok(wxUserApplicationService.getOrCreateUserByOpenid(openid)); } catch (Exception e) { log.error("获取openid失败", e); return ResponseDTO.fail(new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, e.getMessage())); } } + + /** + * 根据openid获取微信用户信息 + * @param openid 微信用户openid + * @return 微信用户信息 + * @throws ApiException 当openid无效或用户不存在时抛出 + */ + @GetMapping("/getWxUserByOpenid") + public ResponseDTO getWxUserByOpenid(@RequestParam("openid") String openid) { + try { + WxUserDTO wxUserDTO = wxUserApplicationService.getUserDetailByOpenid(openid); + + if (wxUserDTO == null) { + return ResponseDTO.fail(new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "用户不存在")); + } + + return ResponseDTO.ok(wxUserDTO); + } catch (Exception e) { + log.error("获取微信用户信息失败", e); + return ResponseDTO.fail(new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, e.getMessage())); + } + } } diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/wx/user/WxUserApplicationService.java b/agileboot-domain/src/main/java/com/agileboot/domain/wx/user/WxUserApplicationService.java index ef33afd..88feb0e 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/wx/user/WxUserApplicationService.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/wx/user/WxUserApplicationService.java @@ -2,6 +2,7 @@ package com.agileboot.domain.wx.user; import com.agileboot.common.core.page.PageDTO; import com.agileboot.domain.common.command.BulkOperationCommand; +import com.agileboot.domain.wx.utils.WxNicknameGenerator; import com.agileboot.domain.wx.user.command.AddWxUserCommand; import com.agileboot.domain.wx.user.command.UpdateWxUserCommand; import com.agileboot.domain.wx.user.db.SearchWxUserDO; @@ -166,4 +167,39 @@ public class WxUserApplicationService { // 更新 model.updateById(); } + + /** + * 根据openid获取或创建微信用户 + * 如果openid对应数据不存在,则创建一条新数据到数据库 + * + * @param openid 微信openid + * @return 微信用户信息 + */ + @Transactional(rollbackFor = Exception.class) + public WxUserDTO getOrCreateUserByOpenid(String openid) { + // 先尝试查询用户 + WxUserDTO userDTO = getUserDetailByOpenid(openid); + + // 如果用户不存在,则创建新用户 + if (userDTO == null) { + AddWxUserCommand command = new AddWxUserCommand(); + command.setOpenid(openid); + command.setNickName(WxNicknameGenerator.generateRandomNickname()); // 使用昵称生成器生成随机昵称 + + // 保存新用户 + WxUserModel model = modelFactory.create(); + model.loadAddWxUserCommand(command); + + // 业务校验(只校验openid唯一性,因为是新用户,其他字段有默认值) + model.checkOpenidIsUnique(); + + // 保存 + model.insert(); + + // 返回新创建的用户信息 + userDTO = getUserDetailByOpenid(openid); + } + + return userDTO; + } } diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/wx/utils/WxNicknameGenerator.java b/agileboot-domain/src/main/java/com/agileboot/domain/wx/utils/WxNicknameGenerator.java new file mode 100644 index 0000000..a9a68bd --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/wx/utils/WxNicknameGenerator.java @@ -0,0 +1,53 @@ +package com.agileboot.domain.wx.utils; + +import java.security.SecureRandom; + +/** + * 微信昵称生成器 + * 生成格式:固定前缀_随机6位大小写字母数字 + * + * @author your-name + * @since 2025-01-01 + */ +public class WxNicknameGenerator { + + private static final String PREFIX = "微信用户"; + private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static final int RANDOM_LENGTH = 6; + private static final SecureRandom random = new SecureRandom(); + + /** + * 生成随机昵称 + * 格式:微信用户_XXXXXX(其中XXXXXX为6位随机大小写字母数字) + * + * @return 生成的昵称 + */ + public static String generateRandomNickname() { + StringBuilder randomPart = new StringBuilder(RANDOM_LENGTH); + + for (int i = 0; i < RANDOM_LENGTH; i++) { + int index = random.nextInt(CHARACTERS.length()); + randomPart.append(CHARACTERS.charAt(index)); + } + + return PREFIX + "_" + randomPart.toString(); + } + + /** + * 生成指定前缀的随机昵称 + * 格式:{前缀}_XXXXXX(其中XXXXXX为6位随机大小写字母数字) + * + * @param prefix 自定义前缀 + * @return 生成的昵称 + */ + public static String generateRandomNickname(String prefix) { + StringBuilder randomPart = new StringBuilder(RANDOM_LENGTH); + + for (int i = 0; i < RANDOM_LENGTH; i++) { + int index = random.nextInt(CHARACTERS.length()); + randomPart.append(CHARACTERS.charAt(index)); + } + + return prefix + "_" + randomPart.toString(); + } +} \ No newline at end of file