Commit 7286f33a7fb6b58c0e0856e9eba78dda8dd9eb7c
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 | 31 | |
| 32 | 32 |  |
| 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 | 35 | * 管理后台的电脑端:Vue3 提供 `element-plus`、`vben(ant-design-vue)` 两个版本,Vue2 提供 `element-ui` 版本 |
| 36 | 36 | * 管理后台的移动端:采用 `uni-app` 方案,一份代码多终端适配,同时支持 APP、小程序、H5! |
| 37 | 37 | * 后端采用 Spring Boot 多模块架构、MySQL + MyBatis Plus、Redis + Redisson |
| ... | ... | @@ -78,15 +78,19 @@ |
| 78 | 78 | |
| 79 | 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 | 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
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java
| ... | ... | @@ -88,8 +88,6 @@ public class ServletUtils { |
| 88 | 88 | return JakartaServletUtil.getClientIP(request); |
| 89 | 89 | } |
| 90 | 90 | |
| 91 | - // TODO @疯狂:terminal 还是从 ServletUtils 里拿,更容易全局治理; | |
| 92 | - | |
| 93 | 91 | public static boolean isJsonRequest(ServletRequest request) { |
| 94 | 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 | 1 | package cn.iocoder.yudao.framework.web.core.util; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.NumberUtil; |
| 4 | +import cn.hutool.extra.servlet.ServletUtil; | |
| 5 | +import cn.iocoder.yudao.framework.common.enums.TerminalEnum; | |
| 4 | 6 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 5 | 7 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 8 | +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; | |
| 6 | 9 | import cn.iocoder.yudao.framework.web.config.WebProperties; |
| 7 | 10 | import org.springframework.web.context.request.RequestAttributes; |
| 8 | 11 | import org.springframework.web.context.request.RequestContextHolder; |
| ... | ... | @@ -25,6 +28,13 @@ public class WebFrameworkUtils { |
| 25 | 28 | |
| 26 | 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 | 38 | private static WebProperties properties; |
| 29 | 39 | |
| 30 | 40 | public WebFrameworkUtils(WebProperties webProperties) { |
| ... | ... | @@ -107,6 +117,15 @@ public class WebFrameworkUtils { |
| 107 | 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 | 129 | public static void setCommonResult(ServletRequest request, CommonResult<?> result) { |
| 111 | 130 | request.setAttribute(REQUEST_ATTRIBUTE_COMMON_RESULT, result); |
| 112 | 131 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-websocket/pom.xml
| ... | ... | @@ -38,17 +38,6 @@ |
| 38 | 38 | <artifactId>spring-boot-starter-websocket</artifactId> |
| 39 | 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 | 42 | <dependency> |
| 54 | 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 | 82 | return success(DiyTemplateConvert.INSTANCE.convertPage(pageResult)); |
| 83 | 83 | } |
| 84 | 84 | |
| 85 | + // TODO @疯狂:这个要不和 getDiyTemplate 合并,然后 DiyTemplateRespVO 里面直接把 DiyPagePropertyRespVO 也加上。减少 VO 好了,管理后台 get 多返回点数据,也问题不大的。目的,还是想尽可能降低大家的理解成本哈; | |
| 85 | 86 | @GetMapping("/get-property") |
| 86 | 87 | @Operation(summary = "获得装修模板属性") |
| 87 | 88 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| ... | ... | @@ -92,6 +93,7 @@ public class DiyTemplateController { |
| 92 | 93 | return success(DiyTemplateConvert.INSTANCE.convertPropertyVo(diyTemplate, pages)); |
| 93 | 94 | } |
| 94 | 95 | |
| 96 | + // TODO @疯狂:这个接口,要不和 useDiyTemplate 合并成一个,然后 VO 改成我们新的 VO 规范。不改的字段,就不传递。 | |
| 95 | 97 | @PutMapping("/update-property") |
| 96 | 98 | @Operation(summary = "更新装修模板属性") |
| 97 | 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
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 | 33 | @Resource |
| 34 | 34 | private DiyPageService diyPageService; |
| 35 | 35 | |
| 36 | + // TODO @疯狂:要不要把 used 和 get 接口合并哈;不传递 id,直接拿默认; | |
| 36 | 37 | @GetMapping("/used") |
| 37 | 38 | @Operation(summary = "使用中的装修模板") |
| 38 | 39 | public CommonResult<AppDiyTemplatePropertyRespVO> getUsedDiyTemplate() { |
| ... | ... | @@ -54,6 +55,7 @@ public class AppDiyTemplateController { |
| 54 | 55 | } |
| 55 | 56 | // 查询模板下的页面 |
| 56 | 57 | List<DiyPageDO> pages = diyPageService.getDiyPageByTemplateId(diyTemplate.getId()); |
| 58 | + // TODO @疯狂:首页、我的,要不枚举到 DiyPageDO 例如说 NAME_USER,NAME_HOME 类似这种哈; | |
| 57 | 59 | String home = findFirst(pages, page -> "首页".equals(page.getName()), DiyPageDO::getProperty); |
| 58 | 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
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 | 50 | * 备注 |
| 51 | 51 | */ |
| 52 | 52 | private String remark; |
| 53 | + // TODO @疯狂:这个字段要不改成 previewPicUrls,和别的模块一样用 pic 作为图片哇? | |
| 53 | 54 | /** |
| 54 | 55 | * 预览图 |
| 55 | 56 | */ |
| 56 | 57 | @TableField(typeHandler = StringListTypeHandler.class) |
| 57 | 58 | private List<String> previewImageUrls; |
| 58 | 59 | /** |
| 59 | - * 底部导航属性,JSON 格式 | |
| 60 | + * uni-app 底部导航属性,JSON 格式 | |
| 60 | 61 | */ |
| 61 | 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 | 61 | @PostMapping("/create") |
| 62 | 62 | @Operation(summary = "创建订单") |
| 63 | 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 | 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 | 69 | @Mapping(source = "calculateRespBO.price.vipPrice", target = "vipPrice"), |
| 70 | 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 | 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 | 36 | * 【会员】创建交易订单 |
| 37 | 37 | * |
| 38 | 38 | * @param userId 登录用户 |
| 39 | - * @param userIp 用户 IP 地址 | |
| 40 | 39 | * @param createReqVO 创建交易订单请求模型 |
| 41 | - * @param terminal 终端 {@link TerminalEnum} | |
| 42 | 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 | 64 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 65 | 65 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 66 | 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 | 69 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; |
| 68 | 70 | |
| 69 | 71 | /** |
| ... | ... | @@ -158,11 +160,11 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 158 | 160 | @Override |
| 159 | 161 | @Transactional(rollbackFor = Exception.class) |
| 160 | 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 | 164 | // 1.1 价格计算 |
| 163 | 165 | TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO); |
| 164 | 166 | // 1.2 构建订单 |
| 165 | - TradeOrderDO order = buildTradeOrder(userId, userIp, createReqVO, calculateRespBO, terminal); | |
| 167 | + TradeOrderDO order = buildTradeOrder(userId, createReqVO, calculateRespBO); | |
| 166 | 168 | List<TradeOrderItemDO> orderItems = buildTradeOrderItems(order, calculateRespBO); |
| 167 | 169 | |
| 168 | 170 | // 2. 订单创建前的逻辑 |
| ... | ... | @@ -178,15 +180,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 178 | 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 | 186 | order.setType(calculateRespBO.getType()); |
| 185 | 187 | order.setNo(tradeNoRedisDAO.generate(TradeNoRedisDAO.TRADE_ORDER_NO_PREFIX)); |
| 186 | 188 | order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); |
| 187 | 189 | order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); |
| 188 | 190 | order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); |
| 189 | - order.setTerminal(terminal); | |
| 191 | + order.setUserIp(getClientIP()).setTerminal(getTerminal()); | |
| 190 | 192 | // 支付 + 退款信息 |
| 191 | 193 | order.setAdjustPrice(0).setPayStatus(false); |
| 192 | 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 | 18 | // ========== AUTH 模块 1-004-003-000 ========== |
| 19 | 19 | ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1_004_003_000, "登录失败,账号密码不正确"); |
| 20 | 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 | 22 | ErrorCode AUTH_MOBILE_USED = new ErrorCode(1_004_003_007, "手机号已经被使用"); |
| 23 | 23 | |
| 24 | 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 | 73 | |
| 74 | 74 | @PostMapping("/sms-login") |
| 75 | 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 | 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 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 5 | 6 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; |
| 6 | 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 | 9 | import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserUnbindReqVO; |
| 8 | -import cn.iocoder.yudao.module.member.convert.social.SocialUserConvert; | |
| 9 | 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 | 15 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 11 | 16 | import io.swagger.v3.oas.annotations.Operation; |
| 12 | 17 | import org.springframework.validation.annotation.Validated; |
| ... | ... | @@ -15,11 +20,12 @@ import org.springframework.web.bind.annotation.*; |
| 15 | 20 | import jakarta.annotation.Resource; |
| 16 | 21 | import jakarta.validation.Valid; |
| 17 | 22 | |
| 23 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 18 | 24 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 19 | 25 | |
| 20 | 26 | @Tag(name = "用户 App - 社交用户") |
| 21 | 27 | @RestController |
| 22 | -@RequestMapping("/system/social-user") | |
| 28 | +@RequestMapping("/member/social-user") | |
| 23 | 29 | @Validated |
| 24 | 30 | public class AppSocialUserController { |
| 25 | 31 | |
| ... | ... | @@ -28,17 +34,30 @@ public class AppSocialUserController { |
| 28 | 34 | |
| 29 | 35 | @PostMapping("/bind") |
| 30 | 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 | 44 | @DeleteMapping("/unbind") |
| 37 | 45 | @Operation(summary = "取消社交绑定") |
| 38 | 46 | @PreAuthenticated |
| 39 | 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 | 13 | |
| 14 | 14 | @Schema(description = "用户 APP - 社交绑定 Request VO,使用 code 授权码") |
| 15 | 15 | @Data |
| 16 | -@NoArgsConstructor | |
| 17 | -@AllArgsConstructor | |
| 18 | -@Builder | |
| 19 | 16 | public class AppSocialUserBindReqVO { |
| 20 | 17 | |
| 21 | 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 | 13 | |
| 14 | 14 | @Schema(description = "用户 APP - 取消社交绑定 Request VO") |
| 15 | 15 | @Data |
| 16 | -@NoArgsConstructor | |
| 17 | -@AllArgsConstructor | |
| 18 | -@Builder | |
| 19 | 16 | public class AppSocialUserUnbindReqVO { |
| 20 | 17 | |
| 21 | 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 | 1 | package cn.iocoder.yudao.module.member.service.auth; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.framework.common.enums.TerminalEnum; | |
| 4 | 3 | import cn.iocoder.yudao.module.member.controller.app.auth.vo.*; |
| 5 | 4 | |
| 6 | 5 | import jakarta.validation.Valid; |
| ... | ... | @@ -33,10 +32,9 @@ public interface MemberAuthService { |
| 33 | 32 | * 手机 + 验证码登陆 |
| 34 | 33 | * |
| 35 | 34 | * @param reqVO 登陆信息 |
| 36 | - * @param terminal 终端 {@link TerminalEnum} | |
| 37 | 35 | * @return 登录结果 |
| 38 | 36 | */ |
| 39 | - AppAuthLoginRespVO smsLogin(@Valid AppAuthSmsLoginReqVO reqVO, Integer terminal); | |
| 37 | + AppAuthLoginRespVO smsLogin(@Valid AppAuthSmsLoginReqVO reqVO); | |
| 40 | 38 | |
| 41 | 39 | /** |
| 42 | 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 | 36 | |
| 37 | 37 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 38 | 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 | 40 | import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*; |
| 40 | 41 | |
| 41 | 42 | /** |
| ... | ... | @@ -78,13 +79,13 @@ public class MemberAuthServiceImpl implements MemberAuthService { |
| 78 | 79 | |
| 79 | 80 | @Override |
| 80 | 81 | @Transactional |
| 81 | - public AppAuthLoginRespVO smsLogin(AppAuthSmsLoginReqVO reqVO, Integer terminal) { | |
| 82 | + public AppAuthLoginRespVO smsLogin(AppAuthSmsLoginReqVO reqVO) { | |
| 82 | 83 | // 校验验证码 |
| 83 | 84 | String userIp = getClientIP(); |
| 84 | 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 | 89 | Assert.notNull(user, "获取用户失败,结果为空"); |
| 89 | 90 | |
| 90 | 91 | // 如果 socialType 非空,说明需要绑定社交用户 |
| ... | ... | @@ -99,16 +100,25 @@ public class MemberAuthServiceImpl implements MemberAuthService { |
| 99 | 100 | } |
| 100 | 101 | |
| 101 | 102 | @Override |
| 103 | + @Transactional | |
| 102 | 104 | public AppAuthLoginRespVO socialLogin(AppAuthSocialLoginReqVO reqVO) { |
| 103 | 105 | // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 |
| 104 | - SocialUserRespDTO socialUser = socialUserApi.getSocialUser(UserTypeEnum.MEMBER.getValue(), reqVO.getType(), | |
| 106 | + SocialUserRespDTO socialUser = socialUserApi.getSocialUserByCode(UserTypeEnum.MEMBER.getValue(), reqVO.getType(), | |
| 105 | 107 | reqVO.getCode(), reqVO.getState()); |
| 106 | 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 | 122 | if (user == null) { |
| 113 | 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 | 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 | 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 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 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 | 6 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 9 | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 10 | 8 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| ... | ... | @@ -81,10 +79,17 @@ public class MemberUserServiceImpl implements MemberUserService { |
| 81 | 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 | 94 | String password = IdUtil.fastSimpleUUID(); |
| 90 | 95 | // 插入用户 |
| ... | ... | @@ -92,8 +97,12 @@ public class MemberUserServiceImpl implements MemberUserService { |
| 92 | 97 | user.setMobile(mobile); |
| 93 | 98 | user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启 |
| 94 | 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 | 106 | memberUserMapper.insert(user); |
| 98 | 107 | |
| 99 | 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<PayWalletRechargeDO |
| 24 | 24 | default PageResult<PayWalletRechargeDO> selectPage(PageParam pageReqVO, Long walletId, Boolean payStatus) { |
| 25 | 25 | return selectPage(pageReqVO, new LambdaQueryWrapperX<PayWalletRechargeDO>() |
| 26 | 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 | 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 | 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 | 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 | 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 | 45 | * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 |
| ... | ... | @@ -40,7 +50,6 @@ public interface SocialUserApi { |
| 40 | 50 | * @param state state |
| 41 | 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 | 15 | public class SocialUserRespDTO { |
| 16 | 16 | |
| 17 | 17 | /** |
| 18 | - * 社交用户 openid | |
| 18 | + * 社交用户的 openid | |
| 19 | 19 | */ |
| 20 | 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 | 3 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.validation.InEnum; |
| 5 | 5 | import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; |
| 6 | +import lombok.AllArgsConstructor; | |
| 6 | 7 | import lombok.Data; |
| 7 | 8 | |
| 8 | 9 | import jakarta.validation.constraints.NotEmpty; |
| 9 | 10 | import jakarta.validation.constraints.NotNull; |
| 11 | +import lombok.NoArgsConstructor; | |
| 10 | 12 | |
| 11 | 13 | /** |
| 12 | 14 | * 社交绑定 Request DTO,使用 code 授权码 |
| ... | ... | @@ -14,6 +16,8 @@ import jakarta.validation.constraints.NotNull; |
| 14 | 16 | * @author 芋道源码 |
| 15 | 17 | */ |
| 16 | 18 | @Data |
| 19 | +@AllArgsConstructor | |
| 20 | +@NoArgsConstructor | |
| 17 | 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 | 33 | } |
| 34 | 34 | |
| 35 | 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<SocialUserBindDO> { |
| 34 | 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 | 156 | @Override |
| 157 | 157 | public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) { |
| 158 | 158 | // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 |
| 159 | - SocialUserRespDTO socialUser = socialUserService.getSocialUser(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), | |
| 159 | + SocialUserRespDTO socialUser = socialUserService.getSocialUserByCode(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), | |
| 160 | 160 | reqVO.getCode(), reqVO.getState()); |
| 161 | - if (socialUser == null) { | |
| 161 | + if (socialUser == null || socialUser.getUserId() == null) { | |
| 162 | 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 | 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 | 61 | * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 |
| ... | ... | @@ -56,7 +66,7 @@ public interface SocialUserService { |
| 56 | 66 | * @param state state |
| 57 | 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 | 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 | 26 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 27 | 27 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 28 | 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 | 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 | 93 | } |
| 95 | 94 | |
| 96 | 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 | 112 | SocialUserDO socialUser = authSocialUser(socialType, userType, code, state); |
| 100 | 113 | Assert.notNull(socialUser, "社交用户不能为空"); |
| 101 | 114 | |
| 102 | - // 如果未绑定的社交用户,则无法自动登录,进行报错 | |
| 115 | + // 获得绑定用户 | |
| 103 | 116 | SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserTypeAndSocialUserId(userType, |
| 104 | 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 | 236 | AuthSocialLoginReqVO reqVO = randomPojo(AuthSocialLoginReqVO.class); |
| 237 | 237 | // mock 方法(绑定的用户编号) |
| 238 | 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 | 240 | eq(reqVO.getCode()), eq(reqVO.getState()))).thenReturn(new SocialUserRespDTO(randomString(), userId)); |
| 241 | 241 | // mock(用户) |
| 242 | 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 | 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 | 152 | assertEquals(userId, socialUser.getUserId()); |
| 153 | 153 | assertEquals(socialUserDO.getOpenid(), socialUser.getOpenid()); | ... | ... |