package com.jsowell.service; import cn.hutool.core.util.PageUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.TypeReference; import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayClient; import com.alipay.api.request.AlipaySystemOauthTokenRequest; import com.alipay.api.response.AlipaySystemOauthTokenResponse; import com.alipay.easysdk.factory.Factory; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.huifu.adapay.core.exception.BaseAdaPayException; import com.huifu.adapay.model.Payment; import com.jsowell.adapay.common.CreateAdaPaymentParam; import com.jsowell.adapay.config.AbstractAdapayConfig; import com.jsowell.adapay.factory.AdapayConfigFactory; import com.jsowell.alipay.factory.AlipayClientFactory; import com.jsowell.alipay.service.AliAppletRemoteService; import com.jsowell.common.constant.CacheConstants; import com.jsowell.common.constant.Constants; import com.jsowell.common.constant.UserConstants; import com.jsowell.common.core.page.PageResponse; import com.jsowell.common.core.redis.RedisCache; import com.jsowell.common.enums.TitleTypeEnum; import com.jsowell.common.enums.adapay.AdapayPayChannelEnum; import com.jsowell.common.enums.adapay.MerchantDelayModeEnum; import com.jsowell.common.enums.uniapp.BalanceChangesEnum; import com.jsowell.common.enums.ykc.ReturnCodeEnum; import com.jsowell.common.enums.ykc.ScenarioEnum; import com.jsowell.common.exception.BusinessException; import com.jsowell.common.util.AdapayUtil; import com.jsowell.common.util.JWTUtils; import com.jsowell.common.util.StringUtils; import com.jsowell.common.util.id.IdUtils; import com.jsowell.common.util.id.SnowflakeIdWorker; import com.jsowell.pile.domain.*; import com.jsowell.pile.dto.*; import com.jsowell.pile.service.*; import com.jsowell.pile.transaction.dto.MemberTransactionDTO; import com.jsowell.pile.transaction.service.TransactionService; import com.jsowell.pile.util.MerchantUtils; import com.jsowell.pile.vo.base.MemberWalletVO; import com.jsowell.pile.vo.uniapp.customer.InvoiceTitleVO; import com.jsowell.pile.vo.uniapp.customer.MemberVO; import com.jsowell.pile.vo.uniapp.customer.MemberWalletInfoVO; import com.jsowell.pile.vo.uniapp.customer.MemberWalletLogVO; import com.jsowell.wxpay.service.WxAppletRemoteService; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.compress.utils.Lists; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cglib.beans.BeanMap; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.text.ParseException; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @Service public class MemberService { private final Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private RedisCache redisCache; @Autowired private TransactionService transactionService; @Autowired private MemberBasicInfoService memberBasicInfoService; @Autowired private PileMerchantInfoService pileMerchantInfoService; @Autowired private WxAppletRemoteService wxAppletRemoteService; @Autowired private AliAppletRemoteService aliAppletRemoteService; @Autowired private MemberPlateNumberRelationService memberPlateNumberRelationService; @Autowired private PileAuthCardService pileAuthCardService; @Autowired private MemberInvoiceTitleService memberInvoiceTitleService; @Autowired private MemberWalletInfoService memberWalletInfoService; @Autowired private PileRemoteService pileRemoteService; @Autowired private OrderBasicInfoService orderBasicInfoService; @Autowired private OrderService orderService; @Value("${adapay.jsowell.appId}") private String ADAPAY_APP_ID; @Value("${adapay.callback}") private String ADAPAY_CALLBACK_URL; @Value("${weixin.login.appid}") private String APP_ID; private final AlipayClient alipayClient; @Autowired public MemberService(AlipayClientFactory alipayClientFactory) { this.alipayClient = alipayClientFactory.getAlipayClient(); } /** * 校验短信验证码 * @param dto */ public void checkVerificationCode(MemberRegisterAndLoginDTO dto) { // 取出缓存中的验证码进行对比,如果缓存中没有,则超时 String captchaCode = redisCache.getCacheObject(CacheConstants.SMS_VERIFICATION_CODE_KEY + dto.getMobileNumber()); // if (StringUtils.isEmpty(captchaCode)) { // throw new BusinessException(ReturnCodeEnum.CODE_VERIFICATION_CODE_TIMEOUT_ERROR); // } // 获取通用验证码 String commonCaptchaCode = redisCache.getCacheObject(CacheConstants.SMS_COMMON_VERIFICATION_CODE_KEY + dto.getMobileNumber()); // 缓存中的验证码或者通用验证码, 两个都不匹配, 则抛出异常 if (!StringUtils.equals(captchaCode, dto.getVerificationCode()) && !StringUtils.equals(commonCaptchaCode, dto.getVerificationCode())) { throw new BusinessException(ReturnCodeEnum.CODE_VERIFICATION_CODE_ERROR); } // 如果缓存中有,但与实际不一致,则为验证码错误 // if (!StringUtils.equals(captchaCode, dto.getVerificationCode())) { // throw new BusinessException(ReturnCodeEnum.CODE_VERIFICATION_CODE_ERROR); // } } /** * 短信验证码登录注册 * @param dto * @return */ public String memberRegisterAndLoginBySMS(MemberRegisterAndLoginDTO dto) { // 校验短信验证码 两种情况不能通过校验,1-验证码错误;2-超时 验证码10分钟有效 checkVerificationCode(dto); return memberRegisterAndLoginV2(dto); // 短信验证码登录 } /** * 公共登录注册方法 * *
该方法已废弃,当前会员注册/登录主流程统一走 * {@link #memberRegisterAndLoginV2(MemberRegisterAndLoginDTO)}。
* *保留该方法的原因:
*1. 便于和 V2 做逻辑对照,确认重构前后行为一致。
*2. 作为短期回溯参考,降低生产切换风险。
*3. 避免在一次重构中直接删除旧实现,影响排查问题时的可读性。
* * @return token返给前端 */ @Deprecated protected String memberRegisterAndLogin(MemberRegisterAndLoginDTO dto) { String phoneNumber = dto.getMobileNumber(); String firstLevelMerchantId = dto.getFirstLevelMerchantId(); String openId = dto.getOpenId(); String buyerId = dto.getBuyerId(); log.info("公共登录注册方法, phoneNumber:{}, firstLevelMerchantId:{}, openId:{}", phoneNumber, firstLevelMerchantId, openId); if (StringUtils.isBlank(phoneNumber)) { throw new BusinessException(ReturnCodeEnum.CODE_GET_MOBILE_NUMBER_BY_CODE_ERROR); } if (StringUtils.isBlank(firstLevelMerchantId)) { throw new BusinessException(ReturnCodeEnum.CODE_GET_MERCHANT_ID_BY_APP_ID_ERROR); } // 2024年6月11日15点37分 支付宝没有openid,改为不校验openid // 2024年6月14日17点03分,请求来源为微信,校验openId if (AdapayPayChannelEnum.WX_LITE.getValue().equals(dto.getRequestSource()) && StringUtils.isBlank(openId)) { throw new BusinessException(ReturnCodeEnum.CODE_OPEN_ID_IS_NULL_ERROR); } // 锁键包含手机号和运营商ID,确保同一运营商下的同一手机号串行处理,不同运营商互不影响 String lockKey = CacheConstants.USER_APP_REGISTER + phoneNumber + ":" + firstLevelMerchantId; String requestId = IdUtils.fastUUID(); Boolean isLock = false; try { // 获取锁,防止注册创建重复账户,锁超时时间60秒(足够覆盖业务执行时间) isLock = redisCache.lock(lockKey, requestId, 60); if (!isLock) { // 获取锁失败,说明有其他请求正在处理,提示用户稍候 log.warn("获取注册锁失败,可能有并发请求正在处理, phoneNumber:{}, merchantId:{}", phoneNumber, firstLevelMerchantId); throw new BusinessException(ReturnCodeEnum.CODE_MEMBER_REGISTER_AND_LOGIN_PROCESSING); } // 查询手机号码是否注册过 MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMobileNumber(phoneNumber, firstLevelMerchantId); if (Objects.isNull(memberBasicInfo)) { // 不存在则新增数据 String memberId = generateNewMemberId(); memberBasicInfo = new MemberBasicInfo(); memberBasicInfo.setStatus(Constants.ONE); memberBasicInfo.setMemberId(memberId); memberBasicInfo.setNickName("会员" + memberId); memberBasicInfo.setMobileNumber(phoneNumber); memberBasicInfo.setMerchantId(Long.valueOf(firstLevelMerchantId)); if (AdapayPayChannelEnum.WX_LITE.getValue().equals(dto.getRequestSource()) && StringUtils.isNotBlank(openId)) { memberBasicInfo.setOpenId(openId); } if (AdapayPayChannelEnum.ALIPAY_LITE.getValue().equals(dto.getRequestSource()) && StringUtils.isNotBlank(buyerId)) { memberBasicInfo.setBuyerId(buyerId); } MemberTransactionDTO memberTransactionDTO = new MemberTransactionDTO(); memberTransactionDTO.setMemberBasicInfo(memberBasicInfo); // 首次新建会员,同时新建会员钱包 if (MerchantUtils.isXiXiaoMerchant(firstLevelMerchantId)) { MemberWalletInfo memberWalletInfo = MemberWalletInfo.builder() .memberId(memberId) .merchantId(MerchantUtils.XIXIAO_MERCHANT_ID) .walletCode(memberBasicInfoService.generateWalletCode()) .build(); memberTransactionDTO.setMemberWalletInfo(memberWalletInfo); } try { // 插入会员数据 transactionService.createMember(memberTransactionDTO); } catch (DuplicateKeyException e) { // 捕获数据库唯一索引冲突异常(极端并发情况下的兜底机制) // 说明该手机号在该运营商下已经被其他并发请求注册了,重新查询获取已存在的会员信息 log.warn("会员注册时检测到唯一索引冲突,重新查询已存在的会员, phoneNumber:{}, merchantId:{}", phoneNumber, firstLevelMerchantId); memberBasicInfo = memberBasicInfoService.selectInfoByMobileNumber(phoneNumber, firstLevelMerchantId); if (memberBasicInfo == null) { // 理论上不应该走到这里,如果走到这里说明数据被删除了,抛出异常 log.error("唯一索引冲突后重新查询会员信息为空, phoneNumber:{}, merchantId:", phoneNumber, firstLevelMerchantId); throw new BusinessException(ReturnCodeEnum.CODE_MEMBER_REGISTER_AND_LOGIN_ERROR); } } } else { boolean updateFlag = false; if (AdapayPayChannelEnum.WX_LITE.getValue().equals(dto.getRequestSource()) && !StringUtils.equals(memberBasicInfo.getOpenId(), openId)) { // openId变化就更新 memberBasicInfo.setOpenId(openId); updateFlag = true; } if (AdapayPayChannelEnum.ALIPAY_LITE.getValue().equals(dto.getRequestSource()) && !StringUtils.equals(memberBasicInfo.getBuyerId(), buyerId)) { memberBasicInfo.setBuyerId(buyerId); updateFlag = true; } if (updateFlag) { memberBasicInfoService.updateMemberBasicInfo(memberBasicInfo); } } // 服务器生成token返给前端 String memberToken = JWTUtils.createMemberToken(memberBasicInfo.getMemberId(), memberBasicInfo.getNickName()); // log.info("memToken:{}", memberToken); return memberToken; } finally { // 释放锁 if (isLock) { try { Object lockValue = redisCache.getCacheObject(lockKey); if (lockValue != null && requestId.equals(lockValue.toString())) { redisCache.unLock(lockKey); } } catch (Exception e) { log.error("释放注册锁失败, phoneNumber:{}, merchantId:{}, error:{}", phoneNumber, firstLevelMerchantId, e.getMessage()); } } } } /** * 公共登录注册方法 V2 * *该方法与 {@link #memberRegisterAndLogin(MemberRegisterAndLoginDTO)} 保持相同业务逻辑, * 但将流程拆成更清晰的几个步骤:校验请求、获取锁、查找或创建会员、同步第三方身份、生成 token。
* * @param dto 登录/注册入参 * @return 服务端生成的会员 token */ protected String memberRegisterAndLoginV2(MemberRegisterAndLoginDTO dto) { String phoneNumber = dto.getMobileNumber(); String firstLevelMerchantId = dto.getFirstLevelMerchantId(); log.info("公共登录注册方法V2, phoneNumber:{}, firstLevelMerchantId:{}, openId:{}", phoneNumber, firstLevelMerchantId, dto.getOpenId()); // 1. 先做参数校验,尽早拦截无效请求。 validateMemberRegisterAndLoginV2Request(dto); // 2. 使用“手机号 + 一级运营商”作为锁粒度,串行化同一会员的注册/登录流程。 String lockKey = buildMemberRegisterAndLoginLockKey(phoneNumber, firstLevelMerchantId); String requestId = IdUtils.fastUUID(); Boolean isLock = false; try { // 3. 获取锁,防止并发下重复注册或重复创建钱包。 isLock = acquireMemberRegisterAndLoginLock(lockKey, requestId, phoneNumber, firstLevelMerchantId); // 4. 会员不存在就静默注册,已存在则按请求来源同步 openId / buyerId。 MemberBasicInfo memberBasicInfo = findOrCreateMemberForRegisterAndLoginV2(dto); // 5. 最终统一生成会员 token 返回前端。 return JWTUtils.createMemberToken(memberBasicInfo.getMemberId(), memberBasicInfo.getNickName()); } finally { releaseMemberRegisterAndLoginLock(lockKey, requestId, phoneNumber, firstLevelMerchantId, isLock); } } /** * 校验 V2 登录/注册请求中的关键参数。 * * @param dto 登录/注册入参 */ private void validateMemberRegisterAndLoginV2Request(MemberRegisterAndLoginDTO dto) { if (StringUtils.isBlank(dto.getMobileNumber())) { throw new BusinessException(ReturnCodeEnum.CODE_GET_MOBILE_NUMBER_BY_CODE_ERROR); } if (StringUtils.isBlank(dto.getFirstLevelMerchantId())) { throw new BusinessException(ReturnCodeEnum.CODE_GET_MERCHANT_ID_BY_APP_ID_ERROR); } if (isWechatLiteRequest(dto) && StringUtils.isBlank(dto.getOpenId())) { throw new BusinessException(ReturnCodeEnum.CODE_OPEN_ID_IS_NULL_ERROR); } } /** * 生成登录/注册流程使用的分布式锁 key。 * * @param phoneNumber 手机号 * @param firstLevelMerchantId 一级运营商 ID * @return 分布式锁 key */ private String buildMemberRegisterAndLoginLockKey(String phoneNumber, String firstLevelMerchantId) { return CacheConstants.USER_APP_REGISTER + phoneNumber + ":" + firstLevelMerchantId; } /** * 获取登录/注册流程的分布式锁,避免同一会员并发注册。 * * @param lockKey 锁 key * @param requestId 当前请求唯一标识 * @param phoneNumber 手机号 * @param firstLevelMerchantId 一级运营商 ID * @return 是否成功获取锁 */ private boolean acquireMemberRegisterAndLoginLock(String lockKey, String requestId, String phoneNumber, String firstLevelMerchantId) { boolean isLock = redisCache.lock(lockKey, requestId, 60); if (!isLock) { log.warn("获取注册锁失败,可能有并发请求正在处理, phoneNumber:{}, merchantId:{}", phoneNumber, firstLevelMerchantId); throw new BusinessException(ReturnCodeEnum.CODE_MEMBER_REGISTER_AND_LOGIN_PROCESSING); } return true; } /** * 释放登录/注册流程的分布式锁。 * * @param lockKey 锁 key * @param requestId 当前请求唯一标识 * @param phoneNumber 手机号 * @param firstLevelMerchantId 一级运营商 ID * @param isLock 是否持有锁 */ private void releaseMemberRegisterAndLoginLock(String lockKey, String requestId, String phoneNumber, String firstLevelMerchantId, Boolean isLock) { if (!Boolean.TRUE.equals(isLock)) { return; } try { Object lockValue = redisCache.getCacheObject(lockKey); if (lockValue != null && requestId.equals(lockValue.toString())) { redisCache.unLock(lockKey); } } catch (Exception e) { log.error("释放注册锁失败, phoneNumber:{}, merchantId:{}, error:{}", phoneNumber, firstLevelMerchantId, e.getMessage()); } } /** * 根据手机号和运营商查询会员,不存在则静默注册,存在则同步第三方身份信息。 * * @param dto 登录/注册入参 * @return 已存在或新创建的会员信息 */ private MemberBasicInfo findOrCreateMemberForRegisterAndLoginV2(MemberRegisterAndLoginDTO dto) { MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMobileNumber(dto.getMobileNumber(), dto.getFirstLevelMerchantId()); if (Objects.isNull(memberBasicInfo)) { return registerMemberForRegisterAndLoginV2(dto); } syncMemberThirdPartyIdentityForRegisterAndLoginV2(memberBasicInfo, dto); return memberBasicInfo; } /** * 执行静默注册流程,并在唯一索引冲突时回查已创建的会员。 * * @param dto 登录/注册入参 * @return 注册完成后的会员信息 */ private MemberBasicInfo registerMemberForRegisterAndLoginV2(MemberRegisterAndLoginDTO dto) { MemberBasicInfo memberBasicInfo = buildNewMemberForRegisterAndLoginV2(dto); MemberTransactionDTO memberTransactionDTO = buildMemberTransactionForRegisterAndLoginV2(memberBasicInfo, dto.getFirstLevelMerchantId()); try { transactionService.createMember(memberTransactionDTO); return memberBasicInfo; } catch (DuplicateKeyException e) { return reloadMemberAfterDuplicateKeyForRegisterAndLoginV2(dto); } } /** * 构造一个新的会员基础信息对象。 * * @param dto 登录/注册入参 * @return 待入库的会员基础信息 */ private MemberBasicInfo buildNewMemberForRegisterAndLoginV2(MemberRegisterAndLoginDTO dto) { String memberId = generateNewMemberId(); MemberBasicInfo memberBasicInfo = new MemberBasicInfo(); memberBasicInfo.setStatus(Constants.ONE); memberBasicInfo.setMemberId(memberId); memberBasicInfo.setNickName("会员" + memberId); memberBasicInfo.setMobileNumber(dto.getMobileNumber()); memberBasicInfo.setMerchantId(Long.valueOf(dto.getFirstLevelMerchantId())); fillMemberThirdPartyIdentityForRegisterAndLoginV2(memberBasicInfo, dto); return memberBasicInfo; } /** * 组装会员注册事务对象,必要时附带创建钱包信息。 * * @param memberBasicInfo 会员基础信息 * @param firstLevelMerchantId 一级运营商 ID * @return 注册事务对象 */ private MemberTransactionDTO buildMemberTransactionForRegisterAndLoginV2(MemberBasicInfo memberBasicInfo, String firstLevelMerchantId) { MemberTransactionDTO memberTransactionDTO = new MemberTransactionDTO(); memberTransactionDTO.setMemberBasicInfo(memberBasicInfo); if (MerchantUtils.isXiXiaoMerchant(firstLevelMerchantId)) { MemberWalletInfo memberWalletInfo = MemberWalletInfo.builder() .memberId(memberBasicInfo.getMemberId()) .merchantId(MerchantUtils.XIXIAO_MERCHANT_ID) .walletCode(memberBasicInfoService.generateWalletCode()) .build(); memberTransactionDTO.setMemberWalletInfo(memberWalletInfo); } return memberTransactionDTO; } /** * 在注册发生唯一索引冲突时,回查已经被并发请求创建好的会员。 * * @param dto 登录/注册入参 * @return 已存在的会员信息 */ private MemberBasicInfo reloadMemberAfterDuplicateKeyForRegisterAndLoginV2(MemberRegisterAndLoginDTO dto) { log.warn("会员注册时检测到唯一索引冲突,重新查询已存在的会员, phoneNumber:{}, merchantId:{}", dto.getMobileNumber(), dto.getFirstLevelMerchantId()); MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMobileNumber(dto.getMobileNumber(), dto.getFirstLevelMerchantId()); if (memberBasicInfo == null) { log.error("唯一索引冲突后重新查询会员信息为空, phoneNumber:{}, merchantId:{}", dto.getMobileNumber(), dto.getFirstLevelMerchantId()); throw new BusinessException(ReturnCodeEnum.CODE_MEMBER_REGISTER_AND_LOGIN_ERROR); } return memberBasicInfo; } /** * 同步已有会员的第三方身份标识。 * * @param memberBasicInfo 已存在会员 * @param dto 登录/注册入参 */ private void syncMemberThirdPartyIdentityForRegisterAndLoginV2(MemberBasicInfo memberBasicInfo, MemberRegisterAndLoginDTO dto) { boolean needUpdate = false; if (isWechatLiteRequest(dto) && !StringUtils.equals(memberBasicInfo.getOpenId(), dto.getOpenId())) { memberBasicInfo.setOpenId(dto.getOpenId()); needUpdate = true; } if (isAlipayLiteRequest(dto) && !StringUtils.equals(memberBasicInfo.getBuyerId(), dto.getBuyerId())) { memberBasicInfo.setBuyerId(dto.getBuyerId()); needUpdate = true; } if (needUpdate) { memberBasicInfoService.updateMemberBasicInfo(memberBasicInfo); } } /** * 在新建会员时,根据请求来源写入第三方身份标识。 * * @param memberBasicInfo 待入库会员 * @param dto 登录/注册入参 */ private void fillMemberThirdPartyIdentityForRegisterAndLoginV2(MemberBasicInfo memberBasicInfo, MemberRegisterAndLoginDTO dto) { if (isWechatLiteRequest(dto) && StringUtils.isNotBlank(dto.getOpenId())) { memberBasicInfo.setOpenId(dto.getOpenId()); } if (isAlipayLiteRequest(dto) && StringUtils.isNotBlank(dto.getBuyerId())) { memberBasicInfo.setBuyerId(dto.getBuyerId()); } } /** * 判断当前请求是否来自微信小程序。 * * @param dto 登录/注册入参 * @return 是否为微信小程序请求 */ private boolean isWechatLiteRequest(MemberRegisterAndLoginDTO dto) { return AdapayPayChannelEnum.WX_LITE.getValue().equals(dto.getRequestSource()); } /** * 判断当前请求是否来自支付宝小程序。 * * @param dto 登录/注册入参 * @return 是否为支付宝小程序请求 */ private boolean isAlipayLiteRequest(MemberRegisterAndLoginDTO dto) { return AdapayPayChannelEnum.ALIPAY_LITE.getValue().equals(dto.getRequestSource()); } private String generateNewMemberId() { while (true) { String memberId = IdUtils.getMemberId(); // 通过memberId查询是否已经存在 MemberVO memberVO = memberBasicInfoService.queryMemberInfoByMemberId(memberId); if (memberVO == null) { return memberId; } } } /** * 微信一键登录 * @param dto */ public String wechatLogin(WechatLoginDTO dto) { // 通过微信传的code获取手机号码 String mobileNumber = wxAppletRemoteService.getMobileNumberByCode(dto.getCode()); if (StringUtils.isBlank(mobileNumber)) { throw new BusinessException(ReturnCodeEnum.CODE_GET_MOBILE_NUMBER_BY_CODE_ERROR); } // 通过code获取openId String openId = ""; try { openId = wxAppletRemoteService.getOpenIdByCode(dto.getOpenIdCode()); } catch (Exception e) { log.error("getOpenIdByCode发生异常", e); } // 根据appid查询merchantId String firstLevelMerchantId = pileMerchantInfoService.getFirstLevelMerchantIdByWxAppId(dto.getAppId()); // 通过手机号获取openid MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMobileNumber(mobileNumber, firstLevelMerchantId); if (memberBasicInfo != null && StringUtils.isBlank(openId)) { openId = memberBasicInfo.getOpenId(); } // 查询手机号码是否注册过 MemberRegisterAndLoginDTO loginDTO = MemberRegisterAndLoginDTO.builder() .openId(openId) .firstLevelMerchantId(firstLevelMerchantId) .mobileNumber(mobileNumber) .requestSource(dto.getRequestSource()) .build(); return memberRegisterAndLoginV2(loginDTO); // 微信小程序一键登录 } /** * 支付宝 通过密文解密 获取手机号码 */ // private String decryptMobileNumberCiphertext(String mobileNumberCiphertext) throws Exception { // String decrypt = Factory.Util.AES().decrypt(mobileNumberCiphertext); // String mobileNumber = JSON.parseObject(decrypt).getString("mobile"); // return mobileNumber; // } /** * 支付宝 通过密文解密 获取手机号码 */ private void decryptMobileNumberCiphertext(AlipayLoginDTO dto) throws Exception { String decrypt = Factory.Util.AES().decrypt(dto.getMobileNumberCiphertext()); String mobileNumber = JSON.parseObject(decrypt).getString("mobile"); dto.setMobileNumber(mobileNumber); } public String alipayLogin(AlipayLoginDTO dto) throws Exception { // 获取AccessToken getAccessToken(dto); // 解密手机号 decryptMobileNumberCiphertext(dto); // 获取buyer_id // AlipayUserInfoShareRequest request = new AlipayUserInfoShareRequest(); // AlipayUserInfoShareResponse response = alipayClient.execute(request, dto.getAccessToken()); // if(response.isSuccess()){ // log.info("调用成功:" + JSON.toJSONString(response)); // } else { // log.info("调用失败:" + JSON.toJSONString(response)); // } // String userId = response.getOpenId(); // String mobile = response.getMobile(); // 根据appid查询merchantId String firstLevelMerchantId = pileMerchantInfoService.getFirstLevelMerchantIdByAliAppId(dto.getAppId()); log.info("支付宝登录,手机号:{}, openId:{}", dto.getMobileNumber(), dto.getOpenId()); // 查询手机号码是否注册过 MemberRegisterAndLoginDTO loginDTO = MemberRegisterAndLoginDTO.builder() .requestSource(dto.getRequestSource()) .firstLevelMerchantId(firstLevelMerchantId) .mobileNumber(dto.getMobileNumber()) .buyerId(dto.getUserId()) .build(); return memberRegisterAndLoginV2(loginDTO); // 支付宝小程序一键登录 } /** * 获取 auth_code(用户授权码)后应尽快调用 alipay.system.oauth.token(换取授权访问令牌接口)换取 access_token(访问令牌) */ private void getAccessToken(AlipayLoginDTO dto) throws AlipayApiException { if (StringUtils.isBlank(dto.getAuthCode())) { log.info("换取授权访问令牌接口, authCode为空"); } AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest(); // 设置授权码 request.setCode(dto.getAuthCode()); // 设置授权方式 request.setGrantType("authorization_code"); AlipaySystemOauthTokenResponse response = alipayClient.execute(request); if (!response.isSuccess()) { throw new BusinessException(ReturnCodeEnum.CODE_ALIPAY_ACCESS_TOKEN_ERROR); } log.info("支付宝getAccessToken:{}", JSON.toJSONString(response)); dto.setAccessToken(response.getAccessToken()); dto.setOpenId(response.getOpenId()); dto.setUserId(response.getUserId()); } /** * 获取openId * @param code * @return */ // public String getOpenIdByCode(String code) { // return wxAppletRemoteService.getOpenIdByCode(code); // } /** * 处理用户信息 * * @param memberId * @param dto 用户个人信息 */ public void handleUserInfo(String memberId, MemberRegisterDTO dto) { // 通过用户手机号查询数据库,如果数据库中存在,则更新 // MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMobileNumber(dto.getMobileNumber()); MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMemberId(memberId); if (Objects.nonNull(memberBasicInfo)) { if (StringUtils.isNotBlank(dto.getAvatarUrl())) { memberBasicInfo.setAvatarUrl(dto.getAvatarUrl()); } if (StringUtils.isNotBlank(dto.getMobileNumber())) { memberBasicInfo.setMobileNumber(dto.getMobileNumber()); } if (StringUtils.isNotBlank(dto.getNickName())) { memberBasicInfo.setNickName(dto.getNickName()); } memberBasicInfoService.updateMemberBasicInfo(memberBasicInfo); } } /** * 通过memberToken获取用户账户信息 * * @param memberId * @return */ public MemberVO getMemberInfoByMemberId(String memberId) { MemberVO memberVO = memberBasicInfoService.queryMemberInfoByMemberId(memberId); return memberVO; } public MemberVO getMemberInfoByMemberId(String memberId, String merchantId) { MemberVO memberVO = memberBasicInfoService.queryMemberInfoByMemberId(memberId, merchantId); return memberVO; } /** * 查询用户账户余额变动信息 * * @param dto */ public PageResponse getMemberBalanceChanges(UniAppQueryMemberBalanceDTO dto) { // 获取分页信息以及memberId int pageNum = dto.getPageNum() == 0 ? 1 : dto.getPageNum(); int pageSize = dto.getPageSize() == 0 ? 10 : dto.getPageSize(); String memberId = dto.getMemberId(); String type = dto.getType(); if (!StringUtils.equals("1", type) && !StringUtils.equals("2", type)) { type = ""; } // 分页 PageHelper.startPage(pageNum, pageSize); List