From f792ee1678c2141d46f4fe3112940bf8dcf37519 Mon Sep 17 00:00:00 2001 From: lzh Date: Tue, 17 Mar 2026 18:04:37 +0800 Subject: [PATCH] =?UTF-8?q?refactor(system):=20=E7=A4=BE=E4=BA=A4=E7=BB=91?= =?UTF-8?q?=E5=AE=9A=E5=88=97=E8=A1=A8=E9=80=BB=E8=BE=91=E4=B8=8B=E6=B2=89?= =?UTF-8?q?=E8=87=B3=20Service=20=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 SocialUserBindMapper 从 Controller 移除,数据组装逻辑移至 SocialUserService.getSocialUserBindList(),返回绑定时间字段; 修复 avatar 误用 getNickname() 的 bug Co-Authored-By: Claude Opus 4.6 --- .../admin/socail/SocialUserController.java | 161 ++++---- .../socail/vo/user/SocialUserRespVO.java | 96 ++--- .../service/social/SocialUserService.java | 179 ++++----- .../service/social/SocialUserServiceImpl.java | 362 +++++++++--------- 4 files changed, 405 insertions(+), 393 deletions(-) diff --git a/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/controller/admin/socail/SocialUserController.java b/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/controller/admin/socail/SocialUserController.java index ceeff21..6031188 100644 --- a/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/controller/admin/socail/SocialUserController.java +++ b/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/controller/admin/socail/SocialUserController.java @@ -1,82 +1,79 @@ -package com.viewsh.module.system.controller.admin.socail; - -import com.viewsh.framework.common.enums.UserTypeEnum; -import com.viewsh.framework.common.pojo.CommonResult; -import com.viewsh.framework.common.pojo.PageResult; -import com.viewsh.framework.common.util.object.BeanUtils; -import com.viewsh.module.system.api.social.dto.SocialUserBindReqDTO; -import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserBindReqVO; -import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO; -import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserRespVO; -import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserUnbindReqVO; -import com.viewsh.module.system.dal.dataobject.social.SocialUserDO; -import com.viewsh.module.system.service.social.SocialUserService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -import static com.viewsh.framework.common.pojo.CommonResult.success; -import static com.viewsh.framework.common.util.collection.CollectionUtils.convertList; -import static com.viewsh.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; - -@Tag(name = "管理后台 - 社交用户") -@RestController -@RequestMapping("/system/social-user") -@Validated -public class SocialUserController { - - @Resource - private SocialUserService socialUserService; - - @PostMapping("/bind") - @Operation(summary = "社交绑定,使用 code 授权码") - public CommonResult socialBind(@RequestBody @Valid SocialUserBindReqVO reqVO) { - socialUserService.bindSocialUser(new SocialUserBindReqDTO().setSocialType(reqVO.getType()) - .setCode(reqVO.getCode()).setState(reqVO.getState()) - .setUserId(getLoginUserId()).setUserType(UserTypeEnum.ADMIN.getValue())); - return CommonResult.success(true); - } - - @DeleteMapping("/unbind") - @Operation(summary = "取消社交绑定") - public CommonResult socialUnbind(@RequestBody SocialUserUnbindReqVO reqVO) { - socialUserService.unbindSocialUser(getLoginUserId(), UserTypeEnum.ADMIN.getValue(), reqVO.getType(), reqVO.getOpenid()); - return CommonResult.success(true); - } - - @GetMapping("/get-bind-list") - @Operation(summary = "获得绑定社交用户列表") - public CommonResult> getBindSocialUserList() { - List list = socialUserService.getSocialUserList(getLoginUserId(), UserTypeEnum.ADMIN.getValue()); - return success(convertList(list, socialUser -> new SocialUserRespVO() // 返回精简信息 - .setId(socialUser.getId()).setType(socialUser.getType()).setOpenid(socialUser.getOpenid()) - .setNickname(socialUser.getNickname()).setAvatar(socialUser.getNickname()))); - } - - // ==================== 社交用户 CRUD ==================== - - @GetMapping("/get") - @Operation(summary = "获得社交用户") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('system:social-user:query')") - public CommonResult getSocialUser(@RequestParam("id") Long id) { - SocialUserDO socialUser = socialUserService.getSocialUser(id); - return success(BeanUtils.toBean(socialUser, SocialUserRespVO.class)); - } - - @GetMapping("/page") - @Operation(summary = "获得社交用户分页") - @PreAuthorize("@ss.hasPermission('system:social-user:query')") - public CommonResult> getSocialUserPage(@Valid SocialUserPageReqVO pageVO) { - PageResult pageResult = socialUserService.getSocialUserPage(pageVO); - return success(BeanUtils.toBean(pageResult, SocialUserRespVO.class)); - } - -} +package com.viewsh.module.system.controller.admin.socail; + +import com.viewsh.framework.common.enums.UserTypeEnum; +import com.viewsh.framework.common.pojo.CommonResult; +import com.viewsh.framework.common.pojo.PageResult; +import com.viewsh.framework.common.util.object.BeanUtils; +import com.viewsh.module.system.api.social.dto.SocialUserBindReqDTO; +import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserBindReqVO; +import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserRespVO; +import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserUnbindReqVO; +import com.viewsh.module.system.dal.dataobject.social.SocialUserDO; +import com.viewsh.module.system.service.social.SocialUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static com.viewsh.framework.common.pojo.CommonResult.success; +import static com.viewsh.framework.common.util.collection.CollectionUtils.convertList; +import static com.viewsh.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - 社交用户") +@RestController +@RequestMapping("/system/social-user") +@Validated +public class SocialUserController { + + @Resource + private SocialUserService socialUserService; + + @PostMapping("/bind") + @Operation(summary = "社交绑定,使用 code 授权码") + public CommonResult socialBind(@RequestBody @Valid SocialUserBindReqVO reqVO) { + socialUserService.bindSocialUser(new SocialUserBindReqDTO().setSocialType(reqVO.getType()) + .setCode(reqVO.getCode()).setState(reqVO.getState()) + .setUserId(getLoginUserId()).setUserType(UserTypeEnum.ADMIN.getValue())); + return CommonResult.success(true); + } + + @DeleteMapping("/unbind") + @Operation(summary = "取消社交绑定") + public CommonResult socialUnbind(@RequestBody SocialUserUnbindReqVO reqVO) { + socialUserService.unbindSocialUser(getLoginUserId(), UserTypeEnum.ADMIN.getValue(), reqVO.getType(), reqVO.getOpenid()); + return CommonResult.success(true); + } + + @GetMapping("/get-bind-list") + @Operation(summary = "获得绑定社交用户列表") + public CommonResult> getBindSocialUserList() { + return success(socialUserService.getSocialUserBindList(getLoginUserId(), UserTypeEnum.ADMIN.getValue())); + } + + // ==================== 社交用户 CRUD ==================== + + @GetMapping("/get") + @Operation(summary = "获得社交用户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:social-user:query')") + public CommonResult getSocialUser(@RequestParam("id") Long id) { + SocialUserDO socialUser = socialUserService.getSocialUser(id); + return success(BeanUtils.toBean(socialUser, SocialUserRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得社交用户分页") + @PreAuthorize("@ss.hasPermission('system:social-user:query')") + public CommonResult> getSocialUserPage(@Valid SocialUserPageReqVO pageVO) { + PageResult pageResult = socialUserService.getSocialUserPage(pageVO); + return success(BeanUtils.toBean(pageResult, SocialUserRespVO.class)); + } + +} diff --git a/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/controller/admin/socail/vo/user/SocialUserRespVO.java b/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/controller/admin/socail/vo/user/SocialUserRespVO.java index 820ad2d..4ebaa1c 100644 --- a/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/controller/admin/socail/vo/user/SocialUserRespVO.java +++ b/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/controller/admin/socail/vo/user/SocialUserRespVO.java @@ -1,48 +1,48 @@ -package com.viewsh.module.system.controller.admin.socail.vo.user; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - 社交用户 Response VO") -@Data -public class SocialUserRespVO { - - @Schema(description = "主键(自增策略)", requiredMode = Schema.RequiredMode.REQUIRED, example = "14569") - private Long id; - - @Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "30") - private Integer type; - - @Schema(description = "社交 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") - private String openid; - - @Schema(description = "社交 token", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") - private String token; - - @Schema(description = "原始 Token 数据,一般是 JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") - private String rawTokenInfo; - - @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") - private String nickname; - - @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") - private String avatar; - - @Schema(description = "原始用户数据,一般是 JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") - private String rawUserInfo; - - @Schema(description = "最后一次的认证 code", requiredMode = Schema.RequiredMode.REQUIRED, example = "666666") - private String code; - - @Schema(description = "最后一次的认证 state", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") - private String state; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime createTime; - - @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime updateTime; - -} +package com.viewsh.module.system.controller.admin.socail.vo.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 社交用户 Response VO") +@Data +public class SocialUserRespVO { + + @Schema(description = "主键(自增策略)", requiredMode = Schema.RequiredMode.REQUIRED, example = "14569") + private Long id; + + @Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "30") + private Integer type; + + @Schema(description = "社交 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private String openid; + + @Schema(description = "社交 token", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") + private String token; + + @Schema(description = "原始 Token 数据,一般是 JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") + private String rawTokenInfo; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String nickname; + + @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") + private String avatar; + + @Schema(description = "原始用户数据,一般是 JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") + private String rawUserInfo; + + @Schema(description = "最后一次的认证 code", requiredMode = Schema.RequiredMode.REQUIRED, example = "666666") + private String code; + + @Schema(description = "最后一次的认证 state", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + private String state; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime updateTime; + +} diff --git a/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/service/social/SocialUserService.java b/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/service/social/SocialUserService.java index 63eee6f..d3a940a 100644 --- a/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/service/social/SocialUserService.java +++ b/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/service/social/SocialUserService.java @@ -1,89 +1,90 @@ -package com.viewsh.module.system.service.social; - -import com.viewsh.framework.common.exception.ServiceException; -import com.viewsh.framework.common.pojo.PageResult; -import com.viewsh.module.system.api.social.dto.SocialUserBindReqDTO; -import com.viewsh.module.system.api.social.dto.SocialUserRespDTO; -import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO; -import com.viewsh.module.system.dal.dataobject.social.SocialUserDO; -import com.viewsh.module.system.enums.social.SocialTypeEnum; -import jakarta.validation.Valid; - -import java.util.List; - -/** - * 社交用户 Service 接口,例如说社交平台的授权登录 - * - * @author 芋道源码 - */ -public interface SocialUserService { - - /** - * 获得指定用户的社交用户列表 - * - * @param userId 用户编号 - * @param userType 用户类型 - * @return 社交用户列表 - */ - List getSocialUserList(Long userId, Integer userType); - - /** - * 绑定社交用户 - * - * @param reqDTO 绑定信息 - * @return 社交用户 openid - */ - String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); - - /** - * 取消绑定社交用户 - * - * @param userId 用户编号 - * @param userType 全局用户类型 - * @param socialType 社交平台的类型 {@link SocialTypeEnum} - * @param openid 社交平台的 openid - */ - void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid); - - /** - * 获得社交用户,基于 userId - * - * @param userType 用户类型 - * @param userId 用户编号 - * @param socialType 社交平台的类型 - * @return 社交用户 - */ - SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType); - - /** - * 获得社交用户 - * - * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 - * - * @param userType 用户类型 - * @param socialType 社交平台的类型 - * @param code 授权码 - * @param state state - * @return 社交用户 - */ - SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state); - - // ==================== 社交用户 CRUD ==================== - - /** - * 获得社交用户 - * - * @param id 编号 - * @return 社交用户 - */ - SocialUserDO getSocialUser(Long id); - - /** - * 获得社交用户分页 - * - * @param pageReqVO 分页查询 - * @return 社交用户分页 - */ - PageResult getSocialUserPage(SocialUserPageReqVO pageReqVO); - -} +package com.viewsh.module.system.service.social; + +import com.viewsh.framework.common.exception.ServiceException; +import com.viewsh.framework.common.pojo.PageResult; +import com.viewsh.module.system.api.social.dto.SocialUserBindReqDTO; +import com.viewsh.module.system.api.social.dto.SocialUserRespDTO; +import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserRespVO; +import com.viewsh.module.system.dal.dataobject.social.SocialUserDO; +import com.viewsh.module.system.enums.social.SocialTypeEnum; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * 社交用户 Service 接口,例如说社交平台的授权登录 + * + * @author 芋道源码 + */ +public interface SocialUserService { + + /** + * 获得指定用户的社交用户列表(含绑定时间) + * + * @param userId 用户编号 + * @param userType 用户类型 + * @return 社交用户列表 + */ + List getSocialUserBindList(Long userId, Integer userType); + + /** + * 绑定社交用户 + * + * @param reqDTO 绑定信息 + * @return 社交用户 openid + */ + String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); + + /** + * 取消绑定社交用户 + * + * @param userId 用户编号 + * @param userType 全局用户类型 + * @param socialType 社交平台的类型 {@link SocialTypeEnum} + * @param openid 社交平台的 openid + */ + void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid); + + /** + * 获得社交用户,基于 userId + * + * @param userType 用户类型 + * @param userId 用户编号 + * @param socialType 社交平台的类型 + * @return 社交用户 + */ + SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType); + + /** + * 获得社交用户 + * + * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 + * + * @param userType 用户类型 + * @param socialType 社交平台的类型 + * @param code 授权码 + * @param state state + * @return 社交用户 + */ + SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state); + + // ==================== 社交用户 CRUD ==================== + + /** + * 获得社交用户 + * + * @param id 编号 + * @return 社交用户 + */ + SocialUserDO getSocialUser(Long id); + + /** + * 获得社交用户分页 + * + * @param pageReqVO 分页查询 + * @return 社交用户分页 + */ + PageResult getSocialUserPage(SocialUserPageReqVO pageReqVO); + +} diff --git a/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/service/social/SocialUserServiceImpl.java b/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/service/social/SocialUserServiceImpl.java index 3fe66cc..af7c5e0 100644 --- a/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/service/social/SocialUserServiceImpl.java +++ b/viewsh-module-system/viewsh-module-system-server/src/main/java/com/viewsh/module/system/service/social/SocialUserServiceImpl.java @@ -1,174 +1,188 @@ -package com.viewsh.module.system.service.social; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Assert; -import com.viewsh.framework.common.exception.ServiceException; -import com.viewsh.framework.common.pojo.PageResult; -import com.viewsh.module.system.api.social.dto.SocialUserBindReqDTO; -import com.viewsh.module.system.api.social.dto.SocialUserRespDTO; -import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO; -import com.viewsh.module.system.dal.dataobject.social.SocialUserBindDO; -import com.viewsh.module.system.dal.dataobject.social.SocialUserDO; -import com.viewsh.module.system.dal.mysql.social.SocialUserBindMapper; -import com.viewsh.module.system.dal.mysql.social.SocialUserMapper; -import com.viewsh.module.system.enums.social.SocialTypeEnum; -import jakarta.annotation.Resource; -import jakarta.validation.constraints.NotNull; -import lombok.extern.slf4j.Slf4j; -import me.zhyd.oauth.model.AuthUser; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import java.util.Collections; -import java.util.List; - -import static com.viewsh.framework.common.exception.util.ServiceExceptionUtil.exception; -import static com.viewsh.framework.common.util.collection.CollectionUtils.convertSet; -import static com.viewsh.framework.common.util.json.JsonUtils.toJsonString; -import static com.viewsh.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND; - -/** - * 社交用户 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -@Slf4j -public class SocialUserServiceImpl implements SocialUserService { - - @Resource - private SocialUserBindMapper socialUserBindMapper; - @Resource - private SocialUserMapper socialUserMapper; - - @Resource - private SocialClientService socialClientService; - - @Override - public List getSocialUserList(Long userId, Integer userType) { - // 获得绑定 - List socialUserBinds = socialUserBindMapper.selectListByUserIdAndUserType(userId, userType); - if (CollUtil.isEmpty(socialUserBinds)) { - return Collections.emptyList(); - } - // 获得社交用户 - return socialUserMapper.selectByIds(convertSet(socialUserBinds, SocialUserBindDO::getSocialUserId)); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public String bindSocialUser(SocialUserBindReqDTO reqDTO) { - // 获得社交用户 - SocialUserDO socialUser = authSocialUser(reqDTO.getSocialType(), reqDTO.getUserType(), - reqDTO.getCode(), reqDTO.getState()); - Assert.notNull(socialUser, "社交用户不能为空"); - - // 社交用户可能之前绑定过别的用户,需要进行解绑 - socialUserBindMapper.deleteByUserTypeAndSocialUserId(reqDTO.getUserType(), socialUser.getId()); - - // 用户可能之前已经绑定过该社交类型,需要进行解绑 - socialUserBindMapper.deleteByUserTypeAndUserIdAndSocialType(reqDTO.getUserType(), reqDTO.getUserId(), - socialUser.getType()); - - // 绑定当前登录的社交用户 - SocialUserBindDO socialUserBind = SocialUserBindDO.builder() - .userId(reqDTO.getUserId()).userType(reqDTO.getUserType()) - .socialUserId(socialUser.getId()).socialType(socialUser.getType()).build(); - socialUserBindMapper.insert(socialUserBind); - return socialUser.getOpenid(); - } - - @Override - public void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid) { - // 获得 openid 对应的 SocialUserDO 社交用户 - SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, openid); - if (socialUser == null) { - throw exception(SOCIAL_USER_NOT_FOUND); - } - - // 获得对应的社交绑定关系 - socialUserBindMapper.deleteByUserTypeAndUserIdAndSocialType(userType, userId, socialUser.getType()); - } - - @Override - public SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType) { - // 获得绑定用户 - SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserIdAndUserTypeAndSocialType(userId, userType, socialType); - if (socialUserBind == null) { - return null; - } - // 获得社交用户 - SocialUserDO socialUser = socialUserMapper.selectById(socialUserBind.getSocialUserId()); - Assert.notNull(socialUser, "社交用户不能为空"); - return new SocialUserRespDTO(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getAvatar(), - socialUserBind.getUserId()); - } - - @Override - public SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state) { - // 获得社交用户 - SocialUserDO socialUser = authSocialUser(socialType, userType, code, state); - Assert.notNull(socialUser, "社交用户不能为空"); - - // 获得绑定用户 - SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserTypeAndSocialUserId(userType, - socialUser.getId()); - return new SocialUserRespDTO(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getAvatar(), - socialUserBind != null ? socialUserBind.getUserId() : null); - } - - /** - * 授权获得对应的社交用户 - * 如果授权失败,则会抛出 {@link ServiceException} 异常 - * - * @param socialType 社交平台的类型 {@link SocialTypeEnum} - * @param userType 用户类型 - * @param code 授权码 - * @param state state - * @return 授权用户 - */ - @NotNull - public SocialUserDO authSocialUser(Integer socialType, Integer userType, String code, String state) { - // 优先从 DB 中获取,因为 code 有且可以使用一次。 - // 在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次 - SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(socialType, code, state); - if (socialUser != null) { - return socialUser; - } - - // 请求获取 - AuthUser authUser = socialClientService.getAuthUser(socialType, userType, code, state); - Assert.notNull(authUser, "三方用户不能为空"); - - // 保存到 DB 中 - socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, authUser.getUuid()); - if (socialUser == null) { - socialUser = new SocialUserDO(); - } - socialUser.setType(socialType).setCode(code).setState(state) // 需要保存 code + state 字段,保证后续可查询 - .setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()).setRawTokenInfo((toJsonString(authUser.getToken()))) - .setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()).setRawUserInfo(toJsonString(authUser.getRawUserInfo())); - if (socialUser.getId() == null) { - socialUserMapper.insert(socialUser); - } else { - socialUser.clean(); // 避免 updateTime 不更新:https://gitee.com/viewshcode/viewsh-boot-mini/issues/ID7FUL - socialUserMapper.updateById(socialUser); - } - return socialUser; - } - - // ==================== 社交用户 CRUD ==================== - - @Override - public SocialUserDO getSocialUser(Long id) { - return socialUserMapper.selectById(id); - } - - @Override - public PageResult getSocialUserPage(SocialUserPageReqVO pageReqVO) { - return socialUserMapper.selectPage(pageReqVO); - } - -} +package com.viewsh.module.system.service.social; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import com.viewsh.framework.common.exception.ServiceException; +import com.viewsh.framework.common.pojo.PageResult; +import com.viewsh.module.system.api.social.dto.SocialUserBindReqDTO; +import com.viewsh.module.system.api.social.dto.SocialUserRespDTO; +import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO; +import com.viewsh.module.system.controller.admin.socail.vo.user.SocialUserRespVO; +import com.viewsh.module.system.dal.dataobject.social.SocialUserBindDO; +import com.viewsh.module.system.dal.dataobject.social.SocialUserDO; +import com.viewsh.module.system.dal.mysql.social.SocialUserBindMapper; +import com.viewsh.module.system.dal.mysql.social.SocialUserMapper; +import com.viewsh.module.system.enums.social.SocialTypeEnum; +import jakarta.annotation.Resource; +import jakarta.validation.constraints.NotNull; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthUser; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static com.viewsh.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.viewsh.framework.common.util.collection.CollectionUtils.convertList; +import static com.viewsh.framework.common.util.collection.CollectionUtils.convertMap; +import static com.viewsh.framework.common.util.collection.CollectionUtils.convertSet; +import static com.viewsh.framework.common.util.json.JsonUtils.toJsonString; +import static com.viewsh.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND; + +/** + * 社交用户 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class SocialUserServiceImpl implements SocialUserService { + + @Resource + private SocialUserBindMapper socialUserBindMapper; + @Resource + private SocialUserMapper socialUserMapper; + + @Resource + private SocialClientService socialClientService; + + @Override + public List getSocialUserBindList(Long userId, Integer userType) { + // 获得绑定关系 + List socialUserBinds = socialUserBindMapper.selectListByUserIdAndUserType(userId, userType); + if (CollUtil.isEmpty(socialUserBinds)) { + return Collections.emptyList(); + } + // 获得社交用户 + List socialUsers = socialUserMapper.selectByIds(convertSet(socialUserBinds, SocialUserBindDO::getSocialUserId)); + Map bindMap = convertMap(socialUserBinds, SocialUserBindDO::getSocialUserId); + // 组装返回 + return convertList(socialUsers, socialUser -> { + SocialUserBindDO bind = bindMap.get(socialUser.getId()); + return new SocialUserRespVO() + .setId(socialUser.getId()).setType(socialUser.getType()).setOpenid(socialUser.getOpenid()) + .setNickname(socialUser.getNickname()).setAvatar(socialUser.getAvatar()) + .setCreateTime(bind != null ? bind.getCreateTime() : null) + .setUpdateTime(bind != null ? bind.getUpdateTime() : null); + }); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public String bindSocialUser(SocialUserBindReqDTO reqDTO) { + // 获得社交用户 + SocialUserDO socialUser = authSocialUser(reqDTO.getSocialType(), reqDTO.getUserType(), + reqDTO.getCode(), reqDTO.getState()); + Assert.notNull(socialUser, "社交用户不能为空"); + + // 社交用户可能之前绑定过别的用户,需要进行解绑 + socialUserBindMapper.deleteByUserTypeAndSocialUserId(reqDTO.getUserType(), socialUser.getId()); + + // 用户可能之前已经绑定过该社交类型,需要进行解绑 + socialUserBindMapper.deleteByUserTypeAndUserIdAndSocialType(reqDTO.getUserType(), reqDTO.getUserId(), + socialUser.getType()); + + // 绑定当前登录的社交用户 + SocialUserBindDO socialUserBind = SocialUserBindDO.builder() + .userId(reqDTO.getUserId()).userType(reqDTO.getUserType()) + .socialUserId(socialUser.getId()).socialType(socialUser.getType()).build(); + socialUserBindMapper.insert(socialUserBind); + return socialUser.getOpenid(); + } + + @Override + public void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid) { + // 获得 openid 对应的 SocialUserDO 社交用户 + SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, openid); + if (socialUser == null) { + throw exception(SOCIAL_USER_NOT_FOUND); + } + + // 获得对应的社交绑定关系 + socialUserBindMapper.deleteByUserTypeAndUserIdAndSocialType(userType, userId, socialUser.getType()); + } + + @Override + public SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType) { + // 获得绑定用户 + SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserIdAndUserTypeAndSocialType(userId, userType, socialType); + if (socialUserBind == null) { + return null; + } + // 获得社交用户 + SocialUserDO socialUser = socialUserMapper.selectById(socialUserBind.getSocialUserId()); + Assert.notNull(socialUser, "社交用户不能为空"); + return new SocialUserRespDTO(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getAvatar(), + socialUserBind.getUserId()); + } + + @Override + public SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state) { + // 获得社交用户 + SocialUserDO socialUser = authSocialUser(socialType, userType, code, state); + Assert.notNull(socialUser, "社交用户不能为空"); + + // 获得绑定用户 + SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserTypeAndSocialUserId(userType, + socialUser.getId()); + return new SocialUserRespDTO(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getAvatar(), + socialUserBind != null ? socialUserBind.getUserId() : null); + } + + /** + * 授权获得对应的社交用户 + * 如果授权失败,则会抛出 {@link ServiceException} 异常 + * + * @param socialType 社交平台的类型 {@link SocialTypeEnum} + * @param userType 用户类型 + * @param code 授权码 + * @param state state + * @return 授权用户 + */ + @NotNull + public SocialUserDO authSocialUser(Integer socialType, Integer userType, String code, String state) { + // 优先从 DB 中获取,因为 code 有且可以使用一次。 + // 在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次 + SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(socialType, code, state); + if (socialUser != null) { + return socialUser; + } + + // 请求获取 + AuthUser authUser = socialClientService.getAuthUser(socialType, userType, code, state); + Assert.notNull(authUser, "三方用户不能为空"); + + // 保存到 DB 中 + socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, authUser.getUuid()); + if (socialUser == null) { + socialUser = new SocialUserDO(); + } + socialUser.setType(socialType).setCode(code).setState(state) // 需要保存 code + state 字段,保证后续可查询 + .setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()).setRawTokenInfo((toJsonString(authUser.getToken()))) + .setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()).setRawUserInfo(toJsonString(authUser.getRawUserInfo())); + if (socialUser.getId() == null) { + socialUserMapper.insert(socialUser); + } else { + socialUser.clean(); // 避免 updateTime 不更新:https://gitee.com/viewshcode/viewsh-boot-mini/issues/ID7FUL + socialUserMapper.updateById(socialUser); + } + return socialUser; + } + + // ==================== 社交用户 CRUD ==================== + + @Override + public SocialUserDO getSocialUser(Long id) { + return socialUserMapper.selectById(id); + } + + @Override + public PageResult getSocialUserPage(SocialUserPageReqVO pageReqVO) { + return socialUserMapper.selectPage(pageReqVO); + } + +}