package com.nova.sankuai.service.impl; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.IdUtil; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.fasterxml.jackson.databind.ObjectMapper; import com.nova.sankuai.domain.api.externalInterface.*; import com.nova.sankuai.domain.dto.LoginUserDto; import com.nova.sankuai.domain.entity.*; import com.nova.sankuai.domain.enums.vipservice.VipCardTypeEnum; import com.nova.sankuai.domain.vo.VipEffectiveTimeVo; import com.nova.sankuai.domain.vo.auth.AutoLoginVo; import com.nova.sankuai.infra.config.CommonException; import com.nova.sankuai.infra.constants.ResultCode; import com.nova.sankuai.infra.mapper.*; import com.nova.sankuai.infra.utils.RsaSecretUtils; import com.nova.sankuai.infra.utils.UserUtil; import com.nova.sankuai.security.JwtUtils; import com.nova.sankuai.security.UserDetail; import com.nova.sankuai.security.UserDetailUtil; import com.nova.sankuai.service.IChannelInfoService; import com.nova.sankuai.service.ICustomerUserService; import com.nova.sankuai.service.IVipCardOrderLogService; import com.nova.sankuai.service.UnionloginChannelService; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.DigestUtils; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; import java.util.Objects; import java.util.Random; /** * @author weikangdi * @create 2021/11/8 */ @Service @AllArgsConstructor @Slf4j public class CustomerUserServiceImpl extends ServiceImpl implements ICustomerUserService { private final ChannelInfoMapper channelInfoMapper; private final VipCardMapper vipCardMapper; private final RsaSecretUtils rsaSecretUtils; private final UserDetailUtil userDetailUtil; private final JwtUtils jwtUtils; private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private final IChannelInfoService channelInfoService; private final IVipCardOrderLogService vipCardOrderLogService; private static final Logger logger = LoggerFactory.getLogger("payLogger"); private final EIUtil eiUtil; private static final Logger autoLogger = LoggerFactory.getLogger("autoLogger"); private final UnionloginChannelService unionloginChannelService; private final CustomerMapper customerMapper; private final CustomerUserLoginLogMapper customerUserLoginLogMapper; @Override @Transactional(rollbackFor = Exception.class) public void registerUserByCustomer(Customer customer) { CustomerUser customerUserDb = lambdaQuery().eq(CustomerUser::getPhone, customer.getPhone()).one(); if (customerUserDb == null) { String logNumber = IdUtil.randomUUID(); autoLogger.info("日志编号" + logNumber + "通过申请记录注册新用户,用户手机号:" + customer.getPhone() + "渠道Code:" + customer.getSourceChannel()); CustomerUser customerUser = new CustomerUser(); customerUser.setName(customer.getName()); customerUser.setPhone(customer.getPhone()); customerUser.setCreationDate(new Date()); customerUser.setSourceChannel(customer.getSourceChannel()); //对姓名、手机号、身份证进行MD5加密 String phoneMd5 = DigestUtils.md5DigestAsHex(customer.getPhone().getBytes()); customerUser.setPhoneMd5(phoneMd5); String nameMd5 = DigestUtils.md5DigestAsHex(customer.getName().getBytes()); customerUser.setNameMd5(nameMd5); if (StringUtils.isNotEmpty(customer.getIdCard())) { String idCardMd5 = DigestUtils.md5DigestAsHex(customer.getIdCard().getBytes()); customerUser.setIdCardMd5(idCardMd5); } save(customerUser); autoLogger.info("日志编号" + logNumber + "通过申请记录注册新用户成功,用户Id" + customerUser.getId() + ",用户手机号" + customerUser.getPhone()); customerUserDb = customerUser; } else { checkAndUpdateUser(customerUserDb, customer); } if (customer.getCustomerUserId() == null) { customerMapper.update(null, Wrappers.lambdaUpdate() .set(Customer::getCustomerUserId, customerUserDb.getId()) .eq(Customer::getId, customer.getId())); } } /** * 根据最新申请记录更新用户注册表信息 * * @param customerUser * @param customer */ @Transactional(rollbackFor = Exception.class) @Override public void checkAndUpdateUser(CustomerUser customerUser, Customer customer) { boolean isUpdate = false; if (StringUtils.isNotEmpty(customer.getName()) && !customer.getName().equals(customerUser.getName())) { isUpdate = true; } if (!Objects.equals(customer.getIdCard(), customerUser.getIdCard())) { isUpdate = true; } if (isUpdate) { String nameMd5 = DigestUtils.md5DigestAsHex(customer.getName().getBytes()); String idCardMd5 = null; if (StringUtils.isNotEmpty(customer.getIdCard())) { idCardMd5 = DigestUtils.md5DigestAsHex(customer.getIdCard().getBytes()); } update(Wrappers.lambdaUpdate() .set(CustomerUser::getName, customer.getName()) .set(CustomerUser::getNameMd5, nameMd5) .set(CustomerUser::getIdCard, customer.getIdCard()) .set(CustomerUser::getIdCardMd5, idCardMd5) .eq(CustomerUser::getId, customerUser.getId())); } } @Override public JSONObject autodownload(String autodownload) throws Exception { autoLogger.info("加密字符串:{}", autodownload); if (org.apache.commons.lang3.StringUtils.isBlank(autodownload)) { throw new Exception("加密字符串为空"); } autodownload = URLDecoder.decode(autodownload, "UTF-8"); // 将空格全部替换为+,不然会解密失败 autodownload = autodownload.replaceAll(" ", "+"); // 将autologin Base64解码 byte[] contentBytes = rsaSecretUtils.base642Byte(autodownload); // 使用私钥解密 String content = new String(rsaSecretUtils.privateDecrypt(contentBytes), StandardCharsets.UTF_8); // 序列化对象 AutoLoginVo autoLoginVo = OBJECT_MAPPER.readValue(content, AutoLoginVo.class); // 数据校验 if (StringUtils.isEmpty(autoLoginVo.getAppId())) { throw new Exception("appId为空"); } if (StringUtils.isEmpty(autoLoginVo.getPhone())) { throw new Exception("phone为空"); } boolean channelCodeEmpty = StringUtils.isEmpty(autoLoginVo.getChannelCode()); boolean channelNameEmpty = StringUtils.isEmpty(autoLoginVo.getChannelName()); if (!channelCodeEmpty || !channelNameEmpty) { if (channelNameEmpty || channelCodeEmpty) { throw new Exception("channelName和channelName必须同时存在"); } } ChannelInfo channelInfo = channelInfoMapper.getChannelByAppId(autoLoginVo.getAppId()); if (channelInfo == null) { throw new Exception("该渠道AppId不合法"); } CustomerUser customerUser = getUserByPhone(autoLoginVo.getPhone()); String appId = autoLoginVo.getAppId(); if (!channelCodeEmpty) { appId = channelInfoService.createThirdChannel(autoLoginVo, channelInfo); } if (customerUser == null) { String logNumber = IdUtil.randomUUID(); autoLogger.info("日志编号" + logNumber + "联登下载开始注册新用户,用户手机号:" + autoLoginVo.getPhone() + "渠道AppId:" + appId); customerUser = registerInitCustomerUser(autoLoginVo.getPhone(), appId, null, autoLoginVo.getBusinessType()); autoLogger.info("日志编号" + logNumber + "联登下载注册新用户成功,用户Id" + customerUser.getId() + ",用户手机号" + customerUser.getPhone()); } ChannelInfo channelInfoUser = channelInfoService.getOne(new LambdaQueryWrapper().eq(ChannelInfo::getCode, customerUser.getSourceChannel())); if (channelInfoUser == null) { throw new Exception("用户渠道AppId不合法"); } JSONObject params = userDetailUtil.getAutoDownloadUserJson(customerUser, channelInfoUser.getAppId()); return params; } @Override public CustomerUser getCustomerUser(Long id) { return baseMapper.getCustomerUser(id); } @Override @Transactional(rollbackFor = Exception.class) public CustomerUser registerInitCustomerUser(String phone, String appId, Integer device, String businessType) { CustomerUser customerUserDb = lambdaQuery().eq(CustomerUser::getPhone, phone).one(); if (StringUtils.isNotBlank(phone) && customerUserDb == null) { ChannelInfo channelInfo = channelInfoMapper.getChannelByAppId(appId); CustomerUser customerUser = new CustomerUser(); customerUser.setPhone(phone); customerUser.setName(phone); customerUser.setCreationDate(new Date()); customerUser.setDevice(device); customerUser.setSourceChannel(channelInfo.getCode()); //对姓名和手机号进行MD5加密 String phoneMd5 = DigestUtils.md5DigestAsHex(phone.getBytes()); customerUser.setPhoneMd5(phoneMd5); customerUser.setNameMd5(phoneMd5); if (customerUser.getFirstQuota() == null) { Random random = new Random(); int nextInt = 3 + random.nextInt(8); Integer quota = nextInt * 1000; customerUser.setFirstQuota(quota); } if (!StringUtils.isEmpty(businessType)) { customerUser.setBusinessType(businessType); } save(customerUser); return customerUser; } return customerUserDb; } @Override public CustomerUser getUser(LoginUserDto userDto) { CustomerUser customerUser = getUserByPhone(userDto.getPhone()); if (customerUser == null) { String logNumber = IdUtil.randomUUID(); autoLogger.info("日志编号" + logNumber + "登录时开始注册新用户,用户手机号:" + userDto.getPhone() + "渠道AppId:" + userDto.getAppId()); customerUser = registerInitCustomerUser(userDto.getPhone(), userDto.getAppId(), userDto.getDevice(), null); autoLogger.info("日志编号" + logNumber + "登录时注册新用户成功,用户Id" + customerUser.getId() + ",用户手机号" + customerUser.getPhone()); } //日志入库 CustomerUserLoginLog customerUserLoginLog = new CustomerUserLoginLog(); customerUserLoginLog.setPhone(customerUser.getPhone()); customerUserLoginLog.setCreateTime(new Date()); customerUserLoginLogMapper.insert(customerUserLoginLog); return customerUser; } @Override public CustomerUser getUserByPhone(String phone) { return lambdaQuery().eq(CustomerUser::getPhone, phone).eq(CustomerUser::getDeleteFlag, 0).one(); } /** * 联登接口 * * @param autologin */ @Override public JSONObject autoLogin(String autologin) throws Exception { if (org.apache.commons.lang3.StringUtils.isBlank(autologin)) { throw new Exception("加密字符串为空"); } // 将空格全部替换为+,不然会解密失败 autologin = autologin.replaceAll(" ", "+"); // 将autologin Base64解码 byte[] contentBytes = rsaSecretUtils.base642Byte(autologin); // 使用私钥解密 String content = new String(rsaSecretUtils.privateDecrypt(contentBytes), StandardCharsets.UTF_8); // 序列化对象 AutoLoginVo autoLoginVo = OBJECT_MAPPER.readValue(content, AutoLoginVo.class); // 数据校验 if (StringUtils.isEmpty(autoLoginVo.getAppId())) { throw new Exception("appId为空"); } if (StringUtils.isEmpty(autoLoginVo.getPhone())) { throw new Exception("phone为空"); } boolean channelCodeEmpty = StringUtils.isEmpty(autoLoginVo.getChannelCode()); boolean channelNameEmpty = StringUtils.isEmpty(autoLoginVo.getChannelName()); if (!channelCodeEmpty || !channelNameEmpty) { if (channelNameEmpty || channelCodeEmpty) { throw new Exception("channelName和channelName必须同时存在"); } } ChannelInfo channelInfo = channelInfoMapper.getChannelByAppId(autoLoginVo.getAppId()); if (channelInfo == null) { throw new Exception("该渠道AppId不合法"); } CustomerUser customerUser = getUserByPhone(autoLoginVo.getPhone()); String appId = autoLoginVo.getAppId(); if (!channelCodeEmpty) { appId = channelInfoService.createThirdChannel(autoLoginVo, channelInfo); } if (customerUser == null) { String logNumber = IdUtil.randomUUID(); autoLogger.info("日志编号" + logNumber + "联登跳转开始注册新用户,用户手机号:" + autoLoginVo.getPhone() + "渠道AppId:" + appId); customerUser = registerInitCustomerUser(autoLoginVo.getPhone(), appId, null, autoLoginVo.getBusinessType()); autoLogger.info("日志编号" + logNumber + "联登跳转注册新用户成功,用户Id" + customerUser.getId() + ",用户手机号" + customerUser.getPhone()); } UserDetail userDetail = userDetailUtil.parseCustomer(customerUser); String token = jwtUtils.generateToken(userDetail); UserUtil.setUser(token, userDetail); JSONObject params = userDetailUtil.getUserJson(userDetail, token); return params; } @Override @Transactional(rollbackFor = Exception.class) public void updateVipEffectiveTime(VipCardOrder cardOrder, VipEffectiveTimeVo vipEffectiveTimeVo) { logger.info("开始更新会员有效日期,原始数据:" + cardOrder.toString() + vipEffectiveTimeVo.toString()); VipCard card = vipCardMapper.selectOne(Wrappers.lambdaQuery() .eq(VipCard::getCardId, cardOrder.getCardId())); // 更新用户会员到期时间 logger.info("更新用户会员到期时间 userId={}", cardOrder.getUserId()); CustomerUser user = getOne(Wrappers.lambdaQuery() .eq(CustomerUser::getId, cardOrder.getUserId())); logger.info("更新用户会员到期时间 user={}", user); if (user == null) { logger.error("更新用户会员到期时间失败,用户不存在,原始数据" + cardOrder.toString()); return; } if (vipEffectiveTimeVo == null) { logger.error("更新用户会员到期时间失败,更新的有效期为空,原始数据" + cardOrder.toString()); return; } if (VipCardTypeEnum.MEMBER_SERVICE.getCode().equals(card.getVipType())) { update(Wrappers.lambdaUpdate() .set(CustomerUser::getVipStartDate, vipEffectiveTimeVo.getVipStartDate()) .set(CustomerUser::getVipEndDate, vipEffectiveTimeVo.getVipEndDate()) .set(CustomerUser::getSeniorVipStartDate, vipEffectiveTimeVo.getVipStartDate()) .set(CustomerUser::getSeniorVipEndDate, vipEffectiveTimeVo.getVipEndDate()) .eq(CustomerUser::getId, user.getId())); } else if (VipCardTypeEnum.AUDIT_QUEUE.getCode().equals(card.getVipType())) { if (StringUtils.isNotEmpty(card.getQueueVipCode())) { user.setQueueVipCode(card.getQueueVipCode()); update(Wrappers.lambdaUpdate() .set(CustomerUser::getQueueVipCode, card.getQueueVipCode()) .eq(CustomerUser::getId, user.getId())); } } else if (VipCardTypeEnum.LOAN_MARKET_VIP.getCode().equals(card.getVipType())) { update(Wrappers.lambdaUpdate() .set(CustomerUser::getLoanVipStartDate, vipEffectiveTimeVo.getVipStartDate()) .set(CustomerUser::getLoanVipEndDate, vipEffectiveTimeVo.getVipEndDate()) .set(CustomerUser::getVipCardId, card.getCardId()) .eq(CustomerUser::getId, user.getId())); } else if (VipCardTypeEnum.SENIOR_VIP.getCode().equals(card.getVipType())) { update(Wrappers.lambdaUpdate() .set(CustomerUser::getSeniorVipStartDate, vipEffectiveTimeVo.getVipStartDate()) .set(CustomerUser::getSeniorVipEndDate, vipEffectiveTimeVo.getVipEndDate()) .set(CustomerUser::getVipStartDate, vipEffectiveTimeVo.getVipStartDate()) .set(CustomerUser::getVipEndDate, vipEffectiveTimeVo.getVipEndDate()) .eq(CustomerUser::getId, user.getId())); } vipCardOrderLogService.addOrderSuccessLog(cardOrder.getPartnerThirdOrderId(), cardOrder.getUserId()); } @Override public VipEffectiveTimeVo calculateExpiredDate(Long userId, Integer day, Date startDate, Date endDate) { logger.info("更新用户会员到期时间 userId={}", userId); CustomerUser user = getOne(Wrappers.lambdaQuery() .eq(CustomerUser::getId, userId)); Date from, to, today = new Date(); if (day != null) { if (user.getVipStartDate() != null && user.getVipEndDate() != null && user.getVipStartDate().after(today)) { // 只修改到期时间 from = user.getVipStartDate(); to = addDay(user.getVipEndDate(), day); } else { from = today; to = addDay(today, day); } return new VipEffectiveTimeVo(from, to); } else if (day == null && startDate != null && endDate != null) { from = user.getVipStartDate(); to = user.getVipEndDate(); if (from == null) { from = startDate; } if (to == null) { to = endDate; } else { int compare = DateUtil.compare(endDate, user.getVipEndDate()); if (compare > 0) { to = endDate; } } return new VipEffectiveTimeVo(from, to); } logger.error("更新用户会员到期时间失败:转换最新会员有效时间失败,原始数据:UserId=" + userId + ",会员卡期限=" + day + ",会员开始时间=" + startDate + "会员结束时间=" + endDate); throw new CommonException("更新用户会员到期时间失败"); } @Override public CustomerUser checkCustomer(String phone, String phoneMD5) { CustomerUser customerUser = null; if (!StringUtils.isEmpty(phone)) { customerUser = getOne(new LambdaQueryWrapper().eq(CustomerUser::getPhone, phone)); } else { customerUser = getOne(new LambdaQueryWrapper().eq(CustomerUser::getPhoneMd5, phoneMD5)); } return customerUser; } @Override public CheckUserResponse unionCheckUser(UserDto checkUserDto) { String uuId = IdUtil.randomUUID(); CheckUserResponse checkUserResponse = new CheckUserResponse(); ChannelInfo channelInfo = channelInfoMapper.getChannelByAppId(checkUserDto.getAppId()); if (channelInfo == null) { throw new CommonException("该渠道AppId不合法"); } if (StringUtils.isEmpty(checkUserDto.getData())) { throw new CommonException("参数data不能为空"); } autoLogger.info("日志编号:" + uuId + "渠道方撞库原始数据" + checkUserDto.getData()); CheckUserData checkUserData = eiUtil.checkUserDataParse(uuId, checkUserDto.getData()); if (checkUserData != null) { autoLogger.info("日志编号:" + uuId + "渠道方撞库原始数据data" + checkUserData.toString()); } if (checkUserData == null) { throw new CommonException("撞库解密转换失败"); } if (StringUtils.isEmpty(checkUserData.getPhoneMd5())) { throw new CommonException("手机号不能为空"); } CustomerUser customerUser = getOne(new LambdaQueryWrapper().eq(CustomerUser::getPhoneMd5, checkUserData.getPhoneMd5())); if (customerUser == null) { checkUserResponse.setCode(ResultCode.SUCCESS.getCode()); checkUserResponse.setMsg("成功"); checkUserResponse.setData(true); } else { checkUserResponse.setCode(ResultCode.SERVER_ERROR.getCode()); checkUserResponse.setMsg("失败"); checkUserResponse.setData(false); } return checkUserResponse; } @Override public RegisterResponse unionRegister(UserDto checkUserDto) { String uuId = IdUtil.randomUUID(); RegisterResponse registerResponse = new RegisterResponse(); ChannelInfo channelInfo = channelInfoMapper.getChannelByAppId(checkUserDto.getAppId()); if (channelInfo == null) { throw new CommonException("该渠道AppId不合法"); } if (StringUtils.isEmpty(checkUserDto.getData())) { throw new CommonException("参数data不能为空"); } autoLogger.info("日志编号:" + uuId + "渠道方联登原始数据" + checkUserDto.getData()); RegisterData registerData = eiUtil.rigisterDataParse(uuId, checkUserDto.getData()); if (registerData != null) { autoLogger.info("日志编号:" + uuId + "渠道方联登原始数据data" + registerData.toString()); } if (registerData == null) { throw new CommonException("联登解密转换失败失败"); } if (StringUtils.isEmpty(registerData.getPhone())) { throw new CommonException("手机号不能为空"); } CustomerUser customerUser = getOne(new LambdaQueryWrapper().eq(CustomerUser::getPhone, registerData.getPhone())); if (customerUser == null) { String logNumber = IdUtil.randomUUID(); autoLogger.info("日志编号" + logNumber + "面向渠道方联登开始注册新用户,用户手机号:" + registerData.getPhone() + "渠道AppId:" + checkUserDto.getAppId()); registerInitCustomerUser(registerData.getPhone(), checkUserDto.getAppId(), null, null); autoLogger.info("日志编号" + logNumber + "面向渠道方联登注册新用户成功,用户Id" + customerUser.getId() + ",用户手机号" + customerUser.getPhone()); } registerResponse.setCode(ResultCode.SUCCESS.getCode()); registerResponse.setMsg("成功"); UnionloginChannel unionloginChannel = unionloginChannelService.getOne(new LambdaQueryWrapper() .eq(UnionloginChannel::getAppId, checkUserDto.getAppId())); if (unionloginChannel != null && StringUtils.isNotEmpty(unionloginChannel.getReturnUrl())) { if (unionloginChannel.getReturnUrl().contains("${autologin}")) { try { JSONObject jsonObject = new JSONObject(); jsonObject.put("appId", checkUserDto.getAppId()); jsonObject.put("phone", registerData.getPhone()); byte[] bytes = rsaSecretUtils.publicEncrypt(jsonObject.toJSONString().getBytes()); String autologin = RsaSecretUtils.byte2Base64(bytes); unionloginChannel.setReturnUrl(unionloginChannel.getReturnUrl().replace("${autologin}", autologin)); } catch (Exception e) { e.printStackTrace(); } } registerResponse.setUrl(unionloginChannel.getReturnUrl()); } return registerResponse; } private Date addDay(Date before, int days) { LocalDateTime after = LocalDateTime.ofInstant(before.toInstant(), ZoneId.systemDefault()).plusDays(days); return Date.from(after.atZone(ZoneId.systemDefault()).toInstant()); } }