Commit 7286f33a7fb6b58c0e0856e9eba78dda8dd9eb7c

Authored by puhui999
2 parents 60e684c4 bd5c7d57

Merge remote-tracking branch 'yudao/develop' into develop

Showing 37 changed files with 217 additions and 105 deletions
README.md
@@ -31,7 +31,7 @@ @@ -31,7 +31,7 @@
31 31
32 ![架构图](/.image/common/ruoyi-vue-pro-architecture.png) 32 ![架构图](/.image/common/ruoyi-vue-pro-architecture.png)
33 33
34 -* Java 后端:`master` 分支为 JDK 21 + Spring Boot 3.2.0,`master-jdk8` 分支为 JDK8 + Spring Boot 2.7.18 34 +* Java 后端:`master` 分支为 JDK 8 + Spring Boot 2.7.18,`master-jdk21` 分支为 JDK21 + Spring Boot 3.2.0
35 * 管理后台的电脑端:Vue3 提供 `element-plus`、`vben(ant-design-vue)` 两个版本,Vue2 提供 `element-ui` 版本 35 * 管理后台的电脑端:Vue3 提供 `element-plus`、`vben(ant-design-vue)` 两个版本,Vue2 提供 `element-ui` 版本
36 * 管理后台的移动端:采用 `uni-app` 方案,一份代码多终端适配,同时支持 APP、小程序、H5! 36 * 管理后台的移动端:采用 `uni-app` 方案,一份代码多终端适配,同时支持 APP、小程序、H5!
37 * 后端采用 Spring Boot 多模块架构、MySQL + MyBatis Plus、Redis + Redisson 37 * 后端采用 Spring Boot 多模块架构、MySQL + MyBatis Plus、Redis + Redisson
@@ -78,15 +78,19 @@ @@ -78,15 +78,19 @@
78 78
79 【完整版】包括系统功能、基础设施、会员中心、数据报表、工作流程、商城系统、微信公众号、CRM 等功能 79 【完整版】包括系统功能、基础设施、会员中心、数据报表、工作流程、商城系统、微信公众号、CRM 等功能
80 80
81 -* JDK 21 + Spring Boot 3.2.0 版本:<https://gitee.com/zhijiantianya/ruoyi-vue-pro> 的 `master` 分支  
82 -* JDK 8 + Spring Boot 2.7.18 版本:<https://gitee.com/zhijiantianya/ruoyi-vue-pro> 的 `master-jdk8` 分支 81 +* JDK 8 + Spring Boot 2.7.18 版本:<https://gitee.com/zhijiantianya/ruoyi-vue-pro> 的 `master` 分支
  82 +* JDK 21 + Spring Boot 3.2.0 版本:<https://gitee.com/zhijiantianya/ruoyi-vue-pro> 的 `master-jdk21` 分支
  83 +
  84 +两个分支的功能是一致的,可以放心使用!
83 85
84 ### ➡️️ 精简版 86 ### ➡️️ 精简版
85 87
86 【精简版】只包括系统功能、基础设施功能,不包括会员中心、数据报表、工作流程、商城系统、微信公众号、CRM 等功能 88 【精简版】只包括系统功能、基础设施功能,不包括会员中心、数据报表、工作流程、商城系统、微信公众号、CRM 等功能
87 89
88 -* JDK 21 + Spring Boot 3.2.0 版本:<https://gitee.com/yudaocode/yudao-boot-mini> 的 `master` 分支  
89 -* JDK 8 + Spring Boot 2.7.18 版本:<https://gitee.com/yudaocode/yudao-boot-mini> 的 `master-jdk8` 分支 90 +* JDK 8 + Spring Boot 2.7.18 版本:<https://gitee.com/yudaocode/yudao-boot-mini> 的 `master` 分支
  91 +* JDK 21 + Spring Boot 3.2.0 版本:<https://gitee.com/yudaocode/yudao-boot-mini> 的 `master-jdk21` 分支
  92 +
  93 +如果你想把【完整版】的功能,迁移到【精简版】,可以参考 [《迁移功能到精简版》](https://doc.iocoder.cn/migrate-module/) 文档。
90 94
91 ## 😎 开源协议 95 ## 😎 开源协议
92 96
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/TerminalEnum.java
@@ -15,6 +15,7 @@ import java.util.Arrays; @@ -15,6 +15,7 @@ import java.util.Arrays;
15 @Getter 15 @Getter
16 public enum TerminalEnum implements IntArrayValuable { 16 public enum TerminalEnum implements IntArrayValuable {
17 17
  18 + UNKNOWN(0, "未知"), // 目的:在无法解析到 terminal 时,使用它
18 WECHAT_MINI_PROGRAM(10, "微信小程序"), 19 WECHAT_MINI_PROGRAM(10, "微信小程序"),
19 WECHAT_WAP(11, "微信公众号"), 20 WECHAT_WAP(11, "微信公众号"),
20 H5(20, "H5 网页"), 21 H5(20, "H5 网页"),
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java
@@ -88,8 +88,6 @@ public class ServletUtils { @@ -88,8 +88,6 @@ public class ServletUtils {
88 return JakartaServletUtil.getClientIP(request); 88 return JakartaServletUtil.getClientIP(request);
89 } 89 }
90 90
91 - // TODO @疯狂:terminal 还是从 ServletUtils 里拿,更容易全局治理;  
92 -  
93 public static boolean isJsonRequest(ServletRequest request) { 91 public static boolean isJsonRequest(ServletRequest request) {
94 return StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE); 92 return StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE);
95 } 93 }
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java
1 package cn.iocoder.yudao.framework.web.core.util; 1 package cn.iocoder.yudao.framework.web.core.util;
2 2
3 import cn.hutool.core.util.NumberUtil; 3 import cn.hutool.core.util.NumberUtil;
  4 +import cn.hutool.extra.servlet.ServletUtil;
  5 +import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
4 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 6 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
5 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 7 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  8 +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
6 import cn.iocoder.yudao.framework.web.config.WebProperties; 9 import cn.iocoder.yudao.framework.web.config.WebProperties;
7 import org.springframework.web.context.request.RequestAttributes; 10 import org.springframework.web.context.request.RequestAttributes;
8 import org.springframework.web.context.request.RequestContextHolder; 11 import org.springframework.web.context.request.RequestContextHolder;
@@ -25,6 +28,13 @@ public class WebFrameworkUtils { @@ -25,6 +28,13 @@ public class WebFrameworkUtils {
25 28
26 public static final String HEADER_TENANT_ID = "tenant-id"; 29 public static final String HEADER_TENANT_ID = "tenant-id";
27 30
  31 + /**
  32 + * 终端的 Header
  33 + *
  34 + * @see cn.iocoder.yudao.framework.common.enums.TerminalEnum
  35 + */
  36 + public static final String HEADER_TERMINAL = "terminal";
  37 +
28 private static WebProperties properties; 38 private static WebProperties properties;
29 39
30 public WebFrameworkUtils(WebProperties webProperties) { 40 public WebFrameworkUtils(WebProperties webProperties) {
@@ -107,6 +117,15 @@ public class WebFrameworkUtils { @@ -107,6 +117,15 @@ public class WebFrameworkUtils {
107 return getLoginUserId(request); 117 return getLoginUserId(request);
108 } 118 }
109 119
  120 + public static Integer getTerminal() {
  121 + HttpServletRequest request = getRequest();
  122 + if (request == null) {
  123 + return TerminalEnum.UNKNOWN.getTerminal();
  124 + }
  125 + String terminalValue = request.getHeader(HEADER_TERMINAL);
  126 + return NumberUtil.parseInt(terminalValue, TerminalEnum.UNKNOWN.getTerminal());
  127 + }
  128 +
110 public static void setCommonResult(ServletRequest request, CommonResult<?> result) { 129 public static void setCommonResult(ServletRequest request, CommonResult<?> result) {
111 request.setAttribute(REQUEST_ATTRIBUTE_COMMON_RESULT, result); 130 request.setAttribute(REQUEST_ATTRIBUTE_COMMON_RESULT, result);
112 } 131 }
yudao-framework/yudao-spring-boot-starter-websocket/pom.xml
@@ -38,17 +38,6 @@ @@ -38,17 +38,6 @@
38 <artifactId>spring-boot-starter-websocket</artifactId> 38 <artifactId>spring-boot-starter-websocket</artifactId>
39 </dependency> 39 </dependency>
40 40
41 - <!-- Web 相关 -->  
42 - <dependency>  
43 - <!-- 为什么是 websocket 依赖 security 呢?而不是 security 拓展 websocket 呢?  
44 - 因为 websocket 和 LoginUser 当前登录的用户有一定的相关性,具体可见 WebSocketSessionManagerImpl 逻辑。  
45 - 如果让 security 拓展 websocket 的话,会导致 websocket 组件的封装很散,进而增大理解成本。  
46 - -->  
47 - <groupId>cn.iocoder.boot</groupId>  
48 - <artifactId>yudao-spring-boot-starter-security</artifactId>  
49 - <scope>provided</scope>  
50 - </dependency>  
51 -  
52 <!-- 消息队列相关 --> 41 <!-- 消息队列相关 -->
53 <dependency> 42 <dependency>
54 <groupId>cn.iocoder.boot</groupId> 43 <groupId>cn.iocoder.boot</groupId>
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/DiyTemplateController.java
@@ -82,6 +82,7 @@ public class DiyTemplateController { @@ -82,6 +82,7 @@ public class DiyTemplateController {
82 return success(DiyTemplateConvert.INSTANCE.convertPage(pageResult)); 82 return success(DiyTemplateConvert.INSTANCE.convertPage(pageResult));
83 } 83 }
84 84
  85 + // TODO @疯狂:这个要不和 getDiyTemplate 合并,然后 DiyTemplateRespVO 里面直接把 DiyPagePropertyRespVO 也加上。减少 VO 好了,管理后台 get 多返回点数据,也问题不大的。目的,还是想尽可能降低大家的理解成本哈;
85 @GetMapping("/get-property") 86 @GetMapping("/get-property")
86 @Operation(summary = "获得装修模板属性") 87 @Operation(summary = "获得装修模板属性")
87 @Parameter(name = "id", description = "编号", required = true, example = "1024") 88 @Parameter(name = "id", description = "编号", required = true, example = "1024")
@@ -92,6 +93,7 @@ public class DiyTemplateController { @@ -92,6 +93,7 @@ public class DiyTemplateController {
92 return success(DiyTemplateConvert.INSTANCE.convertPropertyVo(diyTemplate, pages)); 93 return success(DiyTemplateConvert.INSTANCE.convertPropertyVo(diyTemplate, pages));
93 } 94 }
94 95
  96 + // TODO @疯狂:这个接口,要不和 useDiyTemplate 合并成一个,然后 VO 改成我们新的 VO 规范。不改的字段,就不传递。
95 @PutMapping("/update-property") 97 @PutMapping("/update-property")
96 @Operation(summary = "更新装修模板属性") 98 @Operation(summary = "更新装修模板属性")
97 @PreAuthorize("@ss.hasPermission('promotion:diy-template:update')") 99 @PreAuthorize("@ss.hasPermission('promotion:diy-template:update')")
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/decorate/AppDecorateController.java
@@ -25,6 +25,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -25,6 +25,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
25 @RestController 25 @RestController
26 @RequestMapping("/promotion/decorate") 26 @RequestMapping("/promotion/decorate")
27 @Validated 27 @Validated
  28 +@Deprecated // 废弃
28 public class AppDecorateController { 29 public class AppDecorateController {
29 30
30 @Resource 31 @Resource
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/diy/AppDiyTemplateController.java
@@ -33,6 +33,7 @@ public class AppDiyTemplateController { @@ -33,6 +33,7 @@ public class AppDiyTemplateController {
33 @Resource 33 @Resource
34 private DiyPageService diyPageService; 34 private DiyPageService diyPageService;
35 35
  36 + // TODO @疯狂:要不要把 used 和 get 接口合并哈;不传递 id,直接拿默认;
36 @GetMapping("/used") 37 @GetMapping("/used")
37 @Operation(summary = "使用中的装修模板") 38 @Operation(summary = "使用中的装修模板")
38 public CommonResult<AppDiyTemplatePropertyRespVO> getUsedDiyTemplate() { 39 public CommonResult<AppDiyTemplatePropertyRespVO> getUsedDiyTemplate() {
@@ -54,6 +55,7 @@ public class AppDiyTemplateController { @@ -54,6 +55,7 @@ public class AppDiyTemplateController {
54 } 55 }
55 // 查询模板下的页面 56 // 查询模板下的页面
56 List<DiyPageDO> pages = diyPageService.getDiyPageByTemplateId(diyTemplate.getId()); 57 List<DiyPageDO> pages = diyPageService.getDiyPageByTemplateId(diyTemplate.getId());
  58 + // TODO @疯狂:首页、我的,要不枚举到 DiyPageDO 例如说 NAME_USER,NAME_HOME 类似这种哈;
57 String home = findFirst(pages, page -> "首页".equals(page.getName()), DiyPageDO::getProperty); 59 String home = findFirst(pages, page -> "首页".equals(page.getName()), DiyPageDO::getProperty);
58 String user = findFirst(pages, page -> "我的".equals(page.getName()), DiyPageDO::getProperty); 60 String user = findFirst(pages, page -> "我的".equals(page.getName()), DiyPageDO::getProperty);
59 // 拼接返回 61 // 拼接返回
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyPageDO.java
@@ -44,6 +44,7 @@ public class DiyPageDO extends BaseDO { @@ -44,6 +44,7 @@ public class DiyPageDO extends BaseDO {
44 * 备注 44 * 备注
45 */ 45 */
46 private String remark; 46 private String remark;
  47 + // TODO @疯狂:这个字段要不改成 previewPicUrls,和别的模块一样用 pic 作为图片哇?
47 /** 48 /**
48 * 预览图,多个逗号分隔 49 * 预览图,多个逗号分隔
49 */ 50 */
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyTemplateDO.java
@@ -50,13 +50,14 @@ public class DiyTemplateDO extends BaseDO { @@ -50,13 +50,14 @@ public class DiyTemplateDO extends BaseDO {
50 * 备注 50 * 备注
51 */ 51 */
52 private String remark; 52 private String remark;
  53 + // TODO @疯狂:这个字段要不改成 previewPicUrls,和别的模块一样用 pic 作为图片哇?
53 /** 54 /**
54 * 预览图 55 * 预览图
55 */ 56 */
56 @TableField(typeHandler = StringListTypeHandler.class) 57 @TableField(typeHandler = StringListTypeHandler.class)
57 private List<String> previewImageUrls; 58 private List<String> previewImageUrls;
58 /** 59 /**
59 - * 底部导航属性,JSON 格式 60 + * uni-app 底部导航属性,JSON 格式
60 */ 61 */
61 private String property; 62 private String property;
62 63
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
@@ -61,9 +61,8 @@ public class AppTradeOrderController { @@ -61,9 +61,8 @@ public class AppTradeOrderController {
61 @PostMapping("/create") 61 @PostMapping("/create")
62 @Operation(summary = "创建订单") 62 @Operation(summary = "创建订单")
63 @PreAuthenticated 63 @PreAuthenticated
64 - public CommonResult<AppTradeOrderCreateRespVO> createOrder(@Valid @RequestBody AppTradeOrderCreateReqVO createReqVO,  
65 - @RequestHeader Integer terminal) {  
66 - TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), getClientIP(), createReqVO, terminal); 64 + public CommonResult<AppTradeOrderCreateRespVO> createOrder(@Valid @RequestBody AppTradeOrderCreateReqVO createReqVO) {
  65 + TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), createReqVO);
67 return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId())); 66 return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId()));
68 } 67 }
69 68
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
@@ -69,8 +69,7 @@ public interface TradeOrderConvert { @@ -69,8 +69,7 @@ public interface TradeOrderConvert {
69 @Mapping(source = "calculateRespBO.price.vipPrice", target = "vipPrice"), 69 @Mapping(source = "calculateRespBO.price.vipPrice", target = "vipPrice"),
70 @Mapping(source = "calculateRespBO.price.payPrice", target = "payPrice") 70 @Mapping(source = "calculateRespBO.price.payPrice", target = "payPrice")
71 }) 71 })
72 - TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO,  
73 - TradePriceCalculateRespBO calculateRespBO); 72 + TradeOrderDO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradePriceCalculateRespBO calculateRespBO);
74 73
75 TradeOrderRespDTO convert(TradeOrderDO orderDO); 74 TradeOrderRespDTO convert(TradeOrderDO orderDO);
76 75
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java
@@ -36,12 +36,10 @@ public interface TradeOrderUpdateService { @@ -36,12 +36,10 @@ public interface TradeOrderUpdateService {
36 * 【会员】创建交易订单 36 * 【会员】创建交易订单
37 * 37 *
38 * @param userId 登录用户 38 * @param userId 登录用户
39 - * @param userIp 用户 IP 地址  
40 * @param createReqVO 创建交易订单请求模型 39 * @param createReqVO 创建交易订单请求模型
41 - * @param terminal 终端 {@link TerminalEnum}  
42 * @return 交易订单的 40 * @return 交易订单的
43 */ 41 */
44 - TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO, Integer terminal); 42 + TradeOrderDO createOrder(Long userId, AppTradeOrderCreateReqVO createReqVO);
45 43
46 /** 44 /**
47 * 更新交易订单已支付 45 * 更新交易订单已支付
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
@@ -64,6 +64,8 @@ import java.util.Set; @@ -64,6 +64,8 @@ import java.util.Set;
64 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 64 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
65 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 65 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
66 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.minusTime; 66 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.minusTime;
  67 +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
  68 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getTerminal;
67 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; 69 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
68 70
69 /** 71 /**
@@ -158,11 +160,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -158,11 +160,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
158 @Override 160 @Override
159 @Transactional(rollbackFor = Exception.class) 161 @Transactional(rollbackFor = Exception.class)
160 @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CREATE) 162 @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CREATE)
161 - public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO, Integer terminal) { 163 + public TradeOrderDO createOrder(Long userId, AppTradeOrderCreateReqVO createReqVO) {
162 // 1.1 价格计算 164 // 1.1 价格计算
163 TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO); 165 TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO);
164 // 1.2 构建订单 166 // 1.2 构建订单
165 - TradeOrderDO order = buildTradeOrder(userId, userIp, createReqVO, calculateRespBO, terminal); 167 + TradeOrderDO order = buildTradeOrder(userId, createReqVO, calculateRespBO);
166 List<TradeOrderItemDO> orderItems = buildTradeOrderItems(order, calculateRespBO); 168 List<TradeOrderItemDO> orderItems = buildTradeOrderItems(order, calculateRespBO);
167 169
168 // 2. 订单创建前的逻辑 170 // 2. 订单创建前的逻辑
@@ -178,15 +180,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -178,15 +180,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
178 return order; 180 return order;
179 } 181 }
180 182
181 - private TradeOrderDO buildTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO,  
182 - TradePriceCalculateRespBO calculateRespBO, Integer terminal) {  
183 - TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO); 183 + private TradeOrderDO buildTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
  184 + TradePriceCalculateRespBO calculateRespBO) {
  185 + TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, createReqVO, calculateRespBO);
184 order.setType(calculateRespBO.getType()); 186 order.setType(calculateRespBO.getType());
185 order.setNo(tradeNoRedisDAO.generate(TradeNoRedisDAO.TRADE_ORDER_NO_PREFIX)); 187 order.setNo(tradeNoRedisDAO.generate(TradeNoRedisDAO.TRADE_ORDER_NO_PREFIX));
186 order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); 188 order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
187 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); 189 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
188 order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); 190 order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
189 - order.setTerminal(terminal); 191 + order.setUserIp(getClientIP()).setTerminal(getTerminal());
190 // 支付 + 退款信息 192 // 支付 + 退款信息
191 order.setAdjustPrice(0).setPayStatus(false); 193 order.setAdjustPrice(0).setPayStatus(false);
192 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); 194 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
@@ -18,7 +18,7 @@ public interface ErrorCodeConstants { @@ -18,7 +18,7 @@ public interface ErrorCodeConstants {
18 // ========== AUTH 模块 1-004-003-000 ========== 18 // ========== AUTH 模块 1-004-003-000 ==========
19 ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1_004_003_000, "登录失败,账号密码不正确"); 19 ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1_004_003_000, "登录失败,账号密码不正确");
20 ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1_004_003_001, "登录失败,账号被禁用"); 20 ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1_004_003_001, "登录失败,账号被禁用");
21 - ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1_004_003_005, "未绑定账号,需要进行绑定"); 21 + ErrorCode AUTH_SOCIAL_USER_NOT_FOUND = new ErrorCode(1_004_003_005, "登录失败,解析不到三方登录信息");
22 ErrorCode AUTH_MOBILE_USED = new ErrorCode(1_004_003_007, "手机号已经被使用"); 22 ErrorCode AUTH_MOBILE_USED = new ErrorCode(1_004_003_007, "手机号已经被使用");
23 23
24 // ========== 用户收件地址 1-004-004-000 ========== 24 // ========== 用户收件地址 1-004-004-000 ==========
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java
@@ -73,9 +73,8 @@ public class AppAuthController { @@ -73,9 +73,8 @@ public class AppAuthController {
73 73
74 @PostMapping("/sms-login") 74 @PostMapping("/sms-login")
75 @Operation(summary = "使用手机 + 验证码登录") 75 @Operation(summary = "使用手机 + 验证码登录")
76 - public CommonResult<AppAuthLoginRespVO> smsLogin(@RequestBody @Valid AppAuthSmsLoginReqVO reqVO,  
77 - @RequestHeader Integer terminal) {  
78 - return success(authService.smsLogin(reqVO, terminal)); 76 + public CommonResult<AppAuthLoginRespVO> smsLogin(@RequestBody @Valid AppAuthSmsLoginReqVO reqVO) {
  77 + return success(authService.smsLogin(reqVO));
79 } 78 }
80 79
81 @PostMapping("/send-sms-code") 80 @PostMapping("/send-sms-code")
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/AppSocialUserController.java
@@ -2,11 +2,16 @@ package cn.iocoder.yudao.module.member.controller.app.social; @@ -2,11 +2,16 @@ package cn.iocoder.yudao.module.member.controller.app.social;
2 2
3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; 6 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
6 import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserBindReqVO; 7 import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserBindReqVO;
  8 +import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserRespVO;
7 import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserUnbindReqVO; 9 import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserUnbindReqVO;
8 -import cn.iocoder.yudao.module.member.convert.social.SocialUserConvert;  
9 import cn.iocoder.yudao.module.system.api.social.SocialUserApi; 10 import cn.iocoder.yudao.module.system.api.social.SocialUserApi;
  11 +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
  12 +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
  13 +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO;
  14 +import io.swagger.v3.oas.annotations.Parameter;
10 import io.swagger.v3.oas.annotations.tags.Tag; 15 import io.swagger.v3.oas.annotations.tags.Tag;
11 import io.swagger.v3.oas.annotations.Operation; 16 import io.swagger.v3.oas.annotations.Operation;
12 import org.springframework.validation.annotation.Validated; 17 import org.springframework.validation.annotation.Validated;
@@ -15,11 +20,12 @@ import org.springframework.web.bind.annotation.*; @@ -15,11 +20,12 @@ import org.springframework.web.bind.annotation.*;
15 import jakarta.annotation.Resource; 20 import jakarta.annotation.Resource;
16 import jakarta.validation.Valid; 21 import jakarta.validation.Valid;
17 22
  23 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
18 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; 24 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
19 25
20 @Tag(name = "用户 App - 社交用户") 26 @Tag(name = "用户 App - 社交用户")
21 @RestController 27 @RestController
22 -@RequestMapping("/system/social-user") 28 +@RequestMapping("/member/social-user")
23 @Validated 29 @Validated
24 public class AppSocialUserController { 30 public class AppSocialUserController {
25 31
@@ -28,17 +34,30 @@ public class AppSocialUserController { @@ -28,17 +34,30 @@ public class AppSocialUserController {
28 34
29 @PostMapping("/bind") 35 @PostMapping("/bind")
30 @Operation(summary = "社交绑定,使用 code 授权码") 36 @Operation(summary = "社交绑定,使用 code 授权码")
31 - public CommonResult<Boolean> socialBind(@RequestBody @Valid AppSocialUserBindReqVO reqVO) {  
32 - socialUserApi.bindSocialUser(SocialUserConvert.INSTANCE.convert(getLoginUserId(), UserTypeEnum.MEMBER.getValue(), reqVO));  
33 - return CommonResult.success(true); 37 + public CommonResult<String> socialBind(@RequestBody @Valid AppSocialUserBindReqVO reqVO) {
  38 + SocialUserBindReqDTO reqDTO = new SocialUserBindReqDTO(getLoginUserId(), UserTypeEnum.MEMBER.getValue(),
  39 + reqVO.getType(), reqVO.getCode(), reqVO.getState());
  40 + String openid = socialUserApi.bindSocialUser(reqDTO);
  41 + return success(openid);
34 } 42 }
35 43
36 @DeleteMapping("/unbind") 44 @DeleteMapping("/unbind")
37 @Operation(summary = "取消社交绑定") 45 @Operation(summary = "取消社交绑定")
38 @PreAuthenticated 46 @PreAuthenticated
39 public CommonResult<Boolean> socialUnbind(@RequestBody AppSocialUserUnbindReqVO reqVO) { 47 public CommonResult<Boolean> socialUnbind(@RequestBody AppSocialUserUnbindReqVO reqVO) {
40 - socialUserApi.unbindSocialUser(SocialUserConvert.INSTANCE.convert(getLoginUserId(), UserTypeEnum.MEMBER.getValue(), reqVO));  
41 - return CommonResult.success(true); 48 + SocialUserUnbindReqDTO reqDTO = new SocialUserUnbindReqDTO(getLoginUserId(), UserTypeEnum.MEMBER.getValue(),
  49 + reqVO.getType(), reqVO.getOpenid());
  50 + socialUserApi.unbindSocialUser(reqDTO);
  51 + return success(true);
  52 + }
  53 +
  54 + @GetMapping("/get")
  55 + @Operation(summary = "获得社交用户")
  56 + @Parameter(name = "type", description = "社交平台的类型,参见 SocialTypeEnum 枚举值", required = true, example = "10")
  57 + @PreAuthenticated
  58 + public CommonResult<AppSocialUserRespVO> getSocialUser(@RequestParam("type") Integer type) {
  59 + SocialUserRespDTO socialUser = socialUserApi.getSocialUserByUserId(UserTypeEnum.MEMBER.getValue(), getLoginUserId(), type);
  60 + return success(BeanUtils.toBean(socialUser, AppSocialUserRespVO.class));
42 } 61 }
43 62
44 } 63 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialUserBindReqVO.java
@@ -13,9 +13,6 @@ import jakarta.validation.constraints.NotNull; @@ -13,9 +13,6 @@ import jakarta.validation.constraints.NotNull;
13 13
14 @Schema(description = "用户 APP - 社交绑定 Request VO,使用 code 授权码") 14 @Schema(description = "用户 APP - 社交绑定 Request VO,使用 code 授权码")
15 @Data 15 @Data
16 -@NoArgsConstructor  
17 -@AllArgsConstructor  
18 -@Builder  
19 public class AppSocialUserBindReqVO { 16 public class AppSocialUserBindReqVO {
20 17
21 @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") 18 @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialUserRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.controller.app.social.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "用户 APP - 社交用户 Response VO")
  7 +@Data
  8 +public class AppSocialUserRespVO {
  9 +
  10 + @Schema(description = "社交用户的 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "IPRmJ0wvBptiPIlGEZiPewGwiEiE")
  11 + private String openid;
  12 +
  13 + @Schema(description = "社交用户的昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
  14 + private String nickname;
  15 +
  16 + @Schema(description = "社交用户的头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  17 + private String avatar;
  18 +
  19 +}
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialUserUnbindReqVO.java
@@ -13,9 +13,6 @@ import jakarta.validation.constraints.NotNull; @@ -13,9 +13,6 @@ import jakarta.validation.constraints.NotNull;
13 13
14 @Schema(description = "用户 APP - 取消社交绑定 Request VO") 14 @Schema(description = "用户 APP - 取消社交绑定 Request VO")
15 @Data 15 @Data
16 -@NoArgsConstructor  
17 -@AllArgsConstructor  
18 -@Builder  
19 public class AppSocialUserUnbindReqVO { 16 public class AppSocialUserUnbindReqVO {
20 17
21 @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") 18 @Schema(description = "社交平台的类型,参见 SocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/social/SocialUserConvert.java deleted
1 -package cn.iocoder.yudao.module.member.convert.social;  
2 -  
3 -import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserBindReqVO;  
4 -import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserUnbindReqVO;  
5 -import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;  
6 -import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO;  
7 -import org.mapstruct.Mapper;  
8 -import org.mapstruct.factory.Mappers;  
9 -  
10 -@Mapper  
11 -public interface SocialUserConvert {  
12 -  
13 - SocialUserConvert INSTANCE = Mappers.getMapper(SocialUserConvert.class);  
14 -  
15 - SocialUserBindReqDTO convert(Long userId, Integer userType, AppSocialUserBindReqVO reqVO);  
16 -  
17 - SocialUserUnbindReqDTO convert(Long userId, Integer userType, AppSocialUserUnbindReqVO reqVO);  
18 -  
19 -}  
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java
1 package cn.iocoder.yudao.module.member.service.auth; 1 package cn.iocoder.yudao.module.member.service.auth;
2 2
3 -import cn.iocoder.yudao.framework.common.enums.TerminalEnum;  
4 import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; 3 import cn.iocoder.yudao.module.member.controller.app.auth.vo.*;
5 4
6 import jakarta.validation.Valid; 5 import jakarta.validation.Valid;
@@ -33,10 +32,9 @@ public interface MemberAuthService { @@ -33,10 +32,9 @@ public interface MemberAuthService {
33 * 手机 + 验证码登陆 32 * 手机 + 验证码登陆
34 * 33 *
35 * @param reqVO 登陆信息 34 * @param reqVO 登陆信息
36 - * @param terminal 终端 {@link TerminalEnum}  
37 * @return 登录结果 35 * @return 登录结果
38 */ 36 */
39 - AppAuthLoginRespVO smsLogin(@Valid AppAuthSmsLoginReqVO reqVO, Integer terminal); 37 + AppAuthLoginRespVO smsLogin(@Valid AppAuthSmsLoginReqVO reqVO);
40 38
41 /** 39 /**
42 * 社交登录,使用 code 授权码 40 * 社交登录,使用 code 授权码
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java
@@ -36,6 +36,7 @@ import java.util.Objects; @@ -36,6 +36,7 @@ import java.util.Objects;
36 36
37 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 37 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
38 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; 38 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
  39 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getTerminal;
39 import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*; 40 import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;
40 41
41 /** 42 /**
@@ -78,13 +79,13 @@ public class MemberAuthServiceImpl implements MemberAuthService { @@ -78,13 +79,13 @@ public class MemberAuthServiceImpl implements MemberAuthService {
78 79
79 @Override 80 @Override
80 @Transactional 81 @Transactional
81 - public AppAuthLoginRespVO smsLogin(AppAuthSmsLoginReqVO reqVO, Integer terminal) { 82 + public AppAuthLoginRespVO smsLogin(AppAuthSmsLoginReqVO reqVO) {
82 // 校验验证码 83 // 校验验证码
83 String userIp = getClientIP(); 84 String userIp = getClientIP();
84 smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_LOGIN.getScene(), userIp)); 85 smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_LOGIN.getScene(), userIp));
85 86
86 // 获得获得注册用户 87 // 获得获得注册用户
87 - MemberUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp, terminal); 88 + MemberUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp, getTerminal());
88 Assert.notNull(user, "获取用户失败,结果为空"); 89 Assert.notNull(user, "获取用户失败,结果为空");
89 90
90 // 如果 socialType 非空,说明需要绑定社交用户 91 // 如果 socialType 非空,说明需要绑定社交用户
@@ -99,16 +100,25 @@ public class MemberAuthServiceImpl implements MemberAuthService { @@ -99,16 +100,25 @@ public class MemberAuthServiceImpl implements MemberAuthService {
99 } 100 }
100 101
101 @Override 102 @Override
  103 + @Transactional
102 public AppAuthLoginRespVO socialLogin(AppAuthSocialLoginReqVO reqVO) { 104 public AppAuthLoginRespVO socialLogin(AppAuthSocialLoginReqVO reqVO) {
103 // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 105 // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号
104 - SocialUserRespDTO socialUser = socialUserApi.getSocialUser(UserTypeEnum.MEMBER.getValue(), reqVO.getType(), 106 + SocialUserRespDTO socialUser = socialUserApi.getSocialUserByCode(UserTypeEnum.MEMBER.getValue(), reqVO.getType(),
105 reqVO.getCode(), reqVO.getState()); 107 reqVO.getCode(), reqVO.getState());
106 if (socialUser == null) { 108 if (socialUser == null) {
107 - throw exception(AUTH_THIRD_LOGIN_NOT_BIND); 109 + throw exception(AUTH_SOCIAL_USER_NOT_FOUND);
108 } 110 }
109 111
110 - // 自动登录  
111 - MemberUserDO user = userService.getUser(socialUser.getUserId()); 112 + // 情况一:已绑定,直接读取用户信息
  113 + MemberUserDO user;
  114 + if (socialUser.getUserId() != null) {
  115 + user = userService.getUser(socialUser.getUserId());
  116 + // 情况二:未绑定,注册用户 + 绑定用户
  117 + } else {
  118 + user = userService.createUser(socialUser.getNickname(), socialUser.getAvatar(), getClientIP(), getTerminal());
  119 + socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
  120 + reqVO.getType(), reqVO.getCode(), reqVO.getState()));
  121 + }
112 if (user == null) { 122 if (user == null) {
113 throw exception(USER_NOT_EXISTS); 123 throw exception(USER_NOT_EXISTS);
114 } 124 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java
@@ -50,6 +50,18 @@ public interface MemberUserService { @@ -50,6 +50,18 @@ public interface MemberUserService {
50 MemberUserDO createUserIfAbsent(@Mobile String mobile, String registerIp, Integer terminal); 50 MemberUserDO createUserIfAbsent(@Mobile String mobile, String registerIp, Integer terminal);
51 51
52 /** 52 /**
  53 + * 创建用户
  54 + * 目的:三方登录时,如果未绑定用户时,自动创建对应用户
  55 + *
  56 + * @param nickname 昵称
  57 + * @param avtar 头像
  58 + * @param registerIp 注册 IP
  59 + * @param terminal 终端 {@link TerminalEnum}
  60 + * @return 用户对象
  61 + */
  62 + MemberUserDO createUser(String nickname, String avtar, String registerIp, Integer terminal);
  63 +
  64 + /**
53 * 更新用户的最后登陆信息 65 * 更新用户的最后登陆信息
54 * 66 *
55 * @param id 用户编号 67 * @param id 用户编号
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java
@@ -2,9 +2,7 @@ package cn.iocoder.yudao.module.member.service.user; @@ -2,9 +2,7 @@ package cn.iocoder.yudao.module.member.service.user;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.collection.ListUtil; 4 import cn.hutool.core.collection.ListUtil;
5 -import cn.hutool.core.util.IdUtil;  
6 -import cn.hutool.core.util.ObjectUtil;  
7 -import cn.hutool.core.util.StrUtil; 5 +import cn.hutool.core.util.*;
8 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
9 import cn.iocoder.yudao.framework.common.pojo.PageResult; 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 8 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@@ -81,10 +79,17 @@ public class MemberUserServiceImpl implements MemberUserService { @@ -81,10 +79,17 @@ public class MemberUserServiceImpl implements MemberUserService {
81 return user; 79 return user;
82 } 80 }
83 // 用户不存在,则进行创建 81 // 用户不存在,则进行创建
84 - return createUser(mobile, registerIp, terminal); 82 + return createUser(mobile, null, null, registerIp, terminal);
85 } 83 }
86 84
87 - private MemberUserDO createUser(String mobile, String registerIp, Integer terminal) { 85 + @Override
  86 + @Transactional(rollbackFor = Exception.class)
  87 + public MemberUserDO createUser(String nickname, String avtar, String registerIp, Integer terminal) {
  88 + return createUser(null, nickname, avtar, registerIp, terminal);
  89 + }
  90 +
  91 + private MemberUserDO createUser(String mobile, String nickname, String avtar,
  92 + String registerIp, Integer terminal) {
88 // 生成密码 93 // 生成密码
89 String password = IdUtil.fastSimpleUUID(); 94 String password = IdUtil.fastSimpleUUID();
90 // 插入用户 95 // 插入用户
@@ -92,8 +97,12 @@ public class MemberUserServiceImpl implements MemberUserService { @@ -92,8 +97,12 @@ public class MemberUserServiceImpl implements MemberUserService {
92 user.setMobile(mobile); 97 user.setMobile(mobile);
93 user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启 98 user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
94 user.setPassword(encodePassword(password)); // 加密密码 99 user.setPassword(encodePassword(password)); // 加密密码
95 - user.setRegisterIp(registerIp);  
96 - user.setRegisterTerminal(terminal); 100 + user.setRegisterIp(registerIp).setRegisterTerminal(terminal);
  101 + user.setNickname(nickname).setAvatar(avtar); // 基础信息
  102 + if (StrUtil.isEmpty(nickname)) {
  103 + // 昵称为空时,随机一个名字,避免一些依赖 nickname 的逻辑报错,或者有点丑。例如说,短信发送有昵称时~
  104 + user.setNickname("用户" + RandomUtil.randomNumbers(6));
  105 + }
97 memberUserMapper.insert(user); 106 memberUserMapper.insert(user);
98 107
99 // 发送 MQ 消息:用户创建 108 // 发送 MQ 消息:用户创建
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletRechargeMapper.java
@@ -24,7 +24,8 @@ public interface PayWalletRechargeMapper extends BaseMapperX&lt;PayWalletRechargeDO @@ -24,7 +24,8 @@ public interface PayWalletRechargeMapper extends BaseMapperX&lt;PayWalletRechargeDO
24 default PageResult<PayWalletRechargeDO> selectPage(PageParam pageReqVO, Long walletId, Boolean payStatus) { 24 default PageResult<PayWalletRechargeDO> selectPage(PageParam pageReqVO, Long walletId, Boolean payStatus) {
25 return selectPage(pageReqVO, new LambdaQueryWrapperX<PayWalletRechargeDO>() 25 return selectPage(pageReqVO, new LambdaQueryWrapperX<PayWalletRechargeDO>()
26 .eq(PayWalletRechargeDO::getWalletId, walletId) 26 .eq(PayWalletRechargeDO::getWalletId, walletId)
27 - .eq(PayWalletRechargeDO::getPayStatus, payStatus)); 27 + .eq(PayWalletRechargeDO::getPayStatus, payStatus)
  28 + .orderByDesc(PayWalletRechargeDO::getId));
28 } 29 }
29 30
30 } 31 }
31 \ No newline at end of file 32 \ No newline at end of file
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/LoginLogCreateReqDTO.java
@@ -36,9 +36,9 @@ public class LoginLogCreateReqDTO { @@ -36,9 +36,9 @@ public class LoginLogCreateReqDTO {
36 private Integer userType; 36 private Integer userType;
37 /** 37 /**
38 * 用户账号 38 * 用户账号
  39 + *
  40 + * 不再强制校验 username 非空,因为 Member 社交登录时,此时暂时没有 username(mobile)!
39 */ 41 */
40 - @NotBlank(message = "用户账号不能为空")  
41 - @Size(max = 30, message = "用户账号长度不能超过30个字符")  
42 private String username; 42 private String username;
43 43
44 /** 44 /**
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApi.java
@@ -30,6 +30,16 @@ public interface SocialUserApi { @@ -30,6 +30,16 @@ public interface SocialUserApi {
30 void unbindSocialUser(@Valid SocialUserUnbindReqDTO reqDTO); 30 void unbindSocialUser(@Valid SocialUserUnbindReqDTO reqDTO);
31 31
32 /** 32 /**
  33 + * 获得社交用户,基于 userId
  34 + *
  35 + * @param userType 用户类型
  36 + * @param userId 用户编号
  37 + * @param socialType 社交平台的类型
  38 + * @return 社交用户
  39 + */
  40 + SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType);
  41 +
  42 + /**
33 * 获得社交用户 43 * 获得社交用户
34 * 44 *
35 * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 45 * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常
@@ -40,7 +50,6 @@ public interface SocialUserApi { @@ -40,7 +50,6 @@ public interface SocialUserApi {
40 * @param state state 50 * @param state state
41 * @return 社交用户 51 * @return 社交用户
42 */ 52 */
43 - SocialUserRespDTO getSocialUser(Integer userType, Integer socialType,  
44 - String code, String state); 53 + SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state);
45 54
46 } 55 }
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserRespDTO.java
@@ -15,9 +15,17 @@ import lombok.NoArgsConstructor; @@ -15,9 +15,17 @@ import lombok.NoArgsConstructor;
15 public class SocialUserRespDTO { 15 public class SocialUserRespDTO {
16 16
17 /** 17 /**
18 - * 社交用户 openid 18 + * 社交用户的 openid
19 */ 19 */
20 private String openid; 20 private String openid;
  21 + /**
  22 + * 社交用户的昵称
  23 + */
  24 + private String nickname;
  25 + /**
  26 + * 社交用户的头像
  27 + */
  28 + private String avatar;
21 29
22 /** 30 /**
23 * 关联的用户编号 31 * 关联的用户编号
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserUnbindReqDTO.java
@@ -3,10 +3,12 @@ package cn.iocoder.yudao.module.system.api.social.dto; @@ -3,10 +3,12 @@ package cn.iocoder.yudao.module.system.api.social.dto;
3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4 import cn.iocoder.yudao.framework.common.validation.InEnum; 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
5 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; 5 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
  6 +import lombok.AllArgsConstructor;
6 import lombok.Data; 7 import lombok.Data;
7 8
8 import jakarta.validation.constraints.NotEmpty; 9 import jakarta.validation.constraints.NotEmpty;
9 import jakarta.validation.constraints.NotNull; 10 import jakarta.validation.constraints.NotNull;
  11 +import lombok.NoArgsConstructor;
10 12
11 /** 13 /**
12 * 社交绑定 Request DTO,使用 code 授权码 14 * 社交绑定 Request DTO,使用 code 授权码
@@ -14,6 +16,8 @@ import jakarta.validation.constraints.NotNull; @@ -14,6 +16,8 @@ import jakarta.validation.constraints.NotNull;
14 * @author 芋道源码 16 * @author 芋道源码
15 */ 17 */
16 @Data 18 @Data
  19 +@AllArgsConstructor
  20 +@NoArgsConstructor
17 public class SocialUserUnbindReqDTO { 21 public class SocialUserUnbindReqDTO {
18 22
19 /** 23 /**
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApiImpl.java
@@ -33,8 +33,13 @@ public class SocialUserApiImpl implements SocialUserApi { @@ -33,8 +33,13 @@ public class SocialUserApiImpl implements SocialUserApi {
33 } 33 }
34 34
35 @Override 35 @Override
36 - public SocialUserRespDTO getSocialUser(Integer userType, Integer socialType, String code, String state) {  
37 - return socialUserService.getSocialUser(userType, socialType, code, state); 36 + public SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType) {
  37 + return socialUserService.getSocialUserByUserId(userType, userId, socialType);
  38 + }
  39 +
  40 + @Override
  41 + public SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state) {
  42 + return socialUserService.getSocialUserByCode(userType, socialType, code, state);
38 } 43 }
39 44
40 } 45 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/social/SocialUserBindMapper.java
@@ -34,4 +34,11 @@ public interface SocialUserBindMapper extends BaseMapperX&lt;SocialUserBindDO&gt; { @@ -34,4 +34,11 @@ public interface SocialUserBindMapper extends BaseMapperX&lt;SocialUserBindDO&gt; {
34 .eq(SocialUserBindDO::getUserType, userType)); 34 .eq(SocialUserBindDO::getUserType, userType));
35 } 35 }
36 36
  37 + default SocialUserBindDO selectByUserIdAndUserTypeAndSocialType(Long userId, Integer userType, Integer socialType) {
  38 + return selectOne(new LambdaQueryWrapperX<SocialUserBindDO>()
  39 + .eq(SocialUserBindDO::getUserId, userId)
  40 + .eq(SocialUserBindDO::getUserType, userType)
  41 + .eq(SocialUserBindDO::getSocialType, socialType));
  42 + }
  43 +
37 } 44 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
@@ -156,9 +156,9 @@ public class AdminAuthServiceImpl implements AdminAuthService { @@ -156,9 +156,9 @@ public class AdminAuthServiceImpl implements AdminAuthService {
156 @Override 156 @Override
157 public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) { 157 public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) {
158 // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 158 // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号
159 - SocialUserRespDTO socialUser = socialUserService.getSocialUser(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), 159 + SocialUserRespDTO socialUser = socialUserService.getSocialUserByCode(UserTypeEnum.ADMIN.getValue(), reqVO.getType(),
160 reqVO.getCode(), reqVO.getState()); 160 reqVO.getCode(), reqVO.getState());
161 - if (socialUser == null) { 161 + if (socialUser == null || socialUser.getUserId() == null) {
162 throw exception(AUTH_THIRD_LOGIN_NOT_BIND); 162 throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
163 } 163 }
164 164
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserService.java
@@ -46,6 +46,16 @@ public interface SocialUserService { @@ -46,6 +46,16 @@ public interface SocialUserService {
46 void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid); 46 void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid);
47 47
48 /** 48 /**
  49 + * 获得社交用户,基于 userId
  50 + *
  51 + * @param userType 用户类型
  52 + * @param userId 用户编号
  53 + * @param socialType 社交平台的类型
  54 + * @return 社交用户
  55 + */
  56 + SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType);
  57 +
  58 + /**
49 * 获得社交用户 59 * 获得社交用户
50 * 60 *
51 * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 61 * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常
@@ -56,7 +66,7 @@ public interface SocialUserService { @@ -56,7 +66,7 @@ public interface SocialUserService {
56 * @param state state 66 * @param state state
57 * @return 社交用户 67 * @return 社交用户
58 */ 68 */
59 - SocialUserRespDTO getSocialUser(Integer userType, Integer socialType, String code, String state); 69 + SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state);
60 70
61 // ==================== 社交用户 CRUD ==================== 71 // ==================== 社交用户 CRUD ====================
62 72
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java
@@ -26,7 +26,6 @@ import java.util.List; @@ -26,7 +26,6 @@ import java.util.List;
26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
27 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 27 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
28 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 28 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
29 -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.AUTH_THIRD_LOGIN_NOT_BIND;  
30 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND; 29 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND;
31 30
32 /** 31 /**
@@ -94,18 +93,30 @@ public class SocialUserServiceImpl implements SocialUserService { @@ -94,18 +93,30 @@ public class SocialUserServiceImpl implements SocialUserService {
94 } 93 }
95 94
96 @Override 95 @Override
97 - public SocialUserRespDTO getSocialUser(Integer userType, Integer socialType, String code, String state) { 96 + public SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType) {
  97 + // 获得绑定用户
  98 + SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserIdAndUserTypeAndSocialType(userId, userType, socialType);
  99 + if (socialUserBind == null) {
  100 + return null;
  101 + }
  102 + // 获得社交用户
  103 + SocialUserDO socialUser = socialUserMapper.selectById(socialUserBind.getSocialUserId());
  104 + Assert.notNull(socialUser, "社交用户不能为空");
  105 + return new SocialUserRespDTO(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getAvatar(),
  106 + socialUserBind.getUserId());
  107 + }
  108 +
  109 + @Override
  110 + public SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state) {
98 // 获得社交用户 111 // 获得社交用户
99 SocialUserDO socialUser = authSocialUser(socialType, userType, code, state); 112 SocialUserDO socialUser = authSocialUser(socialType, userType, code, state);
100 Assert.notNull(socialUser, "社交用户不能为空"); 113 Assert.notNull(socialUser, "社交用户不能为空");
101 114
102 - // 如果未绑定的社交用户,则无法自动登录,进行报错 115 + // 获得绑定用户
103 SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserTypeAndSocialUserId(userType, 116 SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserTypeAndSocialUserId(userType,
104 socialUser.getId()); 117 socialUser.getId());
105 - if (socialUserBind == null) {  
106 - throw exception(AUTH_THIRD_LOGIN_NOT_BIND);  
107 - }  
108 - return new SocialUserRespDTO(socialUser.getOpenid(), socialUserBind.getUserId()); 118 + return new SocialUserRespDTO(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getAvatar(),
  119 + socialUserBind != null ? socialUserBind.getUserId() : null);
109 } 120 }
110 121
111 /** 122 /**
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java
@@ -236,7 +236,7 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { @@ -236,7 +236,7 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest {
236 AuthSocialLoginReqVO reqVO = randomPojo(AuthSocialLoginReqVO.class); 236 AuthSocialLoginReqVO reqVO = randomPojo(AuthSocialLoginReqVO.class);
237 // mock 方法(绑定的用户编号) 237 // mock 方法(绑定的用户编号)
238 Long userId = 1L; 238 Long userId = 1L;
239 - when(socialUserService.getSocialUser(eq(UserTypeEnum.ADMIN.getValue()), eq(reqVO.getType()), 239 + when(socialUserService.getSocialUserByCode(eq(UserTypeEnum.ADMIN.getValue()), eq(reqVO.getType()),
240 eq(reqVO.getCode()), eq(reqVO.getState()))).thenReturn(new SocialUserRespDTO(randomString(), userId)); 240 eq(reqVO.getCode()), eq(reqVO.getState()))).thenReturn(new SocialUserRespDTO(randomString(), userId));
241 // mock(用户) 241 // mock(用户)
242 AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(userId)); 242 AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(userId));
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImplTest.java
@@ -147,7 +147,7 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest { @@ -147,7 +147,7 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest {
147 socialUserBindMapper.insert(socialUserBind); 147 socialUserBindMapper.insert(socialUserBind);
148 148
149 // 调用 149 // 调用
150 - SocialUserRespDTO socialUser = socialUserService.getSocialUser(userType, type, code, state); 150 + SocialUserRespDTO socialUser = socialUserService.getSocialUserByCode(userType, type, code, state);
151 // 断言 151 // 断言
152 assertEquals(userId, socialUser.getUserId()); 152 assertEquals(userId, socialUser.getUserId());
153 assertEquals(socialUserDO.getOpenid(), socialUser.getOpenid()); 153 assertEquals(socialUserDO.getOpenid(), socialUser.getOpenid());