package com.nova.sankuai.infra.utils.ryh; import cn.hutool.core.util.IdUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.nova.sankuai.domain.api.ryh.RyhCallback; import com.nova.sankuai.domain.api.ryh.RyhResponse; import com.nova.sankuai.domain.dto.ryh.RyhCallbackRequestDTO; import com.nova.sankuai.domain.entity.*; import com.nova.sankuai.domain.enums.capitalInfo.CapitalInfoStatusEnum; import com.nova.sankuai.domain.enums.capitalInfo.CapitalInfoTypeCodeEnum; import com.nova.sankuai.domain.vo.capitalresult.LvdiPushResultVo; import com.nova.sankuai.infra.config.CommonException; import com.nova.sankuai.infra.mapper.CustomerCapitalResultMapper; import com.nova.sankuai.infra.mapper.CustomerMapper; import com.nova.sankuai.infra.utils.ResultJson; import com.nova.sankuai.infra.utils.UserUtil; import com.nova.sankuai.security.HttpClientUtil; import com.nova.sankuai.security.UserDetail; import com.nova.sankuai.service.ICustomerScyIncomeService; import com.nova.sankuai.service.ICustomerUserService; import com.nova.sankuai.service.IPlatformCapitalService; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.DigestUtils; import sun.misc.BASE64Decoder; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import javax.servlet.http.HttpServletRequest; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Objects; import java.util.UUID; import static com.baomidou.mybatisplus.core.toolkit.Constants.AES; /** * 任意花对接 */ @Component @RequiredArgsConstructor public class RyhUtil { private static final Logger log = LoggerFactory.getLogger("capitalLogger"); // 任意花在capital_info数据库中的ID private static final Long capitalId = 10L; @Value("${ryh.zkUrl}") private String zkUrl; @Value("${ryh.jkUrl}") private String jkUrl; @Value("${ryh.cps73ChannelId}") private String channelId; @Value("${ryh.cps73Key}") private String secretKey; @Value("${ryh.h5Protocolurl}") private String protocolUrl; private final CustomerMapper customerMapper; private final CustomerCapitalResultMapper capitalResultMapper; private final ICustomerUserService customerUserService; private final CustomerCapitalResultMapper customerCapitalResultMapper; private final ICustomerScyIncomeService customerZcyIncomeService; private JSONObject getParam(Customer customer) { JSONObject param = new JSONObject(); /* age String 是 25 年龄(25-55之间)*/ Integer age = customer.getAge(); param.put("age", Objects.isNull(age) ? 25 : age); /* sex int 是 1 性别 1-男 2-女 */ String sex = customer.getSex(); param.put("sex", "男".equals(sex) ? 1 : 0); param.put("city", customer.getCityName()); String cityCode = customer.getCity(); /*用户所在城市区划代码 */ param.put("cityCode", StringUtils.isNotBlank(cityCode) ? cityCode.substring(0, 6) : "440100"); /* sesame Integer 是 4 芝麻分 1:无芝麻分 4:700分以上 5:650分以下 6:650-700分 芝麻分(1:无芝麻分,2:600分以下,3:600-650分,4:650-700分,5:700分以上) * */ Integer customerSesame = customer.getSesame(); int cus = Objects.isNull(customerSesame) ? 1 : customerSesame.intValue(); int sesame = 1;// 默认 1 无 if (cus == 2) { sesame = 3; } else if (cus == 3) { sesame = 4; } else if (cus == 4) { sesame = 5; } param.put("zhiMa", sesame); /* accumulation int 1 公积金(1-无;2-有)*/ Integer accumulation = customer.getProvidentFund(); int at = Objects.isNull(accumulation) ? 0 : accumulation.intValue(); int accu= 1; if (at > 0) accu = 2; param.put("fund", accu); /* social int 否 1 社保(1-无;2-有)*/ Integer social = customer.getSocialSecurity(); int soc = Objects.isNull(social) ? 0 : social.intValue(); int soci = 1; if (soc > 0) { soci = 2; } param.put("social", soci); /* insurance string 否 1 保单(1-无;2-有)*/ Integer insurancePolicy = customer.getInsurancePolicy(); int ipy = Objects.isNull(insurancePolicy) ? 0 : insurancePolicy.intValue(); int hasPolicy = 1; if (ipy > 0) { hasPolicy = 2; } param.put("insurance", hasPolicy); /* house int 否 1 房屋信息(1-无;2-有)*/ Integer houseStatus = customer.getHouseStatus(); int hs = Objects.isNull(houseStatus) ? 0 : houseStatus.intValue(); int house = 1; if (hs > 0) { house = 2; } param.put("house", house); /* car int 否 1车辆信息(1-无;2-有) */ Integer carStatus = customer.getCarStatus(); int cs = Objects.isNull(carStatus) ? 0 : carStatus.intValue(); int car = 1; if (cs > 0) { car = 2; } param.put("car", car); if (car == 2) { /*(有车必填)车辆抵押状态 1-未抵押 2-有抵押*/ param.put("vehicleStatus", 1); /*(有车必填)车龄 1-十年以下 2-十年以上*/ param.put("vehicleAge", 1); /*(有车必填)车辆当前价值 1- 10W以内 2- 10W-30W 3- 30W-50W 4- 50W以上*/ param.put("vehicleValue", 1); /*(有车必填)车牌户籍地*/ param.put("vehicleArea", 1); } /*借款金额 */ param.put("loanAmount", Objects.isNull(customer.getLoanAmount()) ? 0 : customer.getLoanAmount().intValue()); /* 职业身份 1-上班族 2-公务员/事业单位 3-私营业主 4-个体户 5-其他 */ Integer pi = customer.getProfessionInfo(); int professionInfo = 1;// 默认自由职业 int job = 1; if (!Objects.isNull(pi)) { professionInfo = pi.intValue(); } if (professionInfo == 0) { job = 5; } else if (professionInfo == 1) { job = 2; } else if (professionInfo == 2) { job = 3; } else if (professionInfo == 3) { job = 4; } else if (professionInfo == 4) { job = 2; } param.put("professional", String.valueOf(job)); /* ip string 是 127.0.0.1 用户ip */ param.put("ip", !StringUtils.isEmpty(customer.getClientIp()) ? customer.getClientIp() : "127.0.0.1"); /* platform int 是 1 设备标识(0 安卓 1苹果) */ String os = customer.getOs(); Integer platform = "ios".equals(os) ? 2 : 1; param.put("platform", platform); return param; } public RyhResponse callback(RyhCallbackRequestDTO body) { String logNumber = IdUtil.randomUUID(); RyhResponse resp = new RyhResponse(); try { if (body == null) { resp.setCode(400); resp.setMsg("请求体为空"); log.error("日志编号:{}【任意花】资方回调请求体为空", logNumber); return resp; } String signs = body.getData(); String requestNo = body.getRequestNo(); if (StringUtils.isBlank(requestNo) || StringUtils.isBlank(signs)) { resp.setCode(400); resp.setMsg("请求体为空"); log.error("日志编号:{}【任意花】资方回调请求体为空", logNumber); return resp; } String signsRes = aesDecrypt(signs);// 解密 if (StringUtils.isBlank(signsRes)) { resp.setCode(400); resp.setMsg("请求体data解析失败!"); log.error("日志编号:{}【任意花】回调请求体data解析失败,signs:{}", logNumber, signs); return resp; } RyhCallback callback = JSON.parseObject(signsRes, RyhCallback.class); String mobileMd5 = callback.getPhoneMd5(); String orderId = callback.getOrderId(); if (StringUtils.isBlank(orderId)) {// 申请订单号不能为空 resp.setCode(400); resp.setMsg("申请订单号不能为空"); log.error("日志编号:{}【任意花】资方回调返回申请订单号不能为空,data:{}", logNumber, signs); return resp; } if (StringUtils.isBlank(mobileMd5)) {// 手机号为空 resp.setCode(400); resp.setMsg("手机号不能为空"); log.error("日志编号:{}【任意花】资方回调返回手机号为空,data:{}", logNumber, signs); return resp; } PlatformCapital platformCapital = platformCapitalService.getOne(new LambdaQueryWrapper().eq(PlatformCapital::getOrderId, orderId)); if (platformCapital == null) { resp.setCode(400); resp.setMsg("申请的数据不存在"); log.error("日志编号:{}【任意花】资方申请的数据不存在,data:{}", logNumber, signs); return resp; } LambdaQueryWrapper wrc = new LambdaQueryWrapper<>(); wrc.eq(Customer::getId, platformCapital.getCustomerId()) .last(" limit 1 "); Customer customer = customerMapper.selectOne(wrc); if (customer == null) { resp.setCode(500); resp.setMsg("该用户已注销"); log.error("日志编号:{}【任意花】资方返回的用户已注销,data:{}", logNumber, signs); return resp; } String phoneMd5 = DigestUtils.md5DigestAsHex(customer.getPhone().getBytes()); if (! phoneMd5.equals(mobileMd5)) { resp.setCode(500); resp.setMsg("该用户已注销"); log.error("日志编号:{}【任意花】资方返回的用户已注销,data:{}", logNumber, signs); return resp; } CustomerUser customerUser = customerUserService.getOne(new LambdaQueryWrapper().eq(CustomerUser::getPhone, customer.getPhone())); if (customerUser == null) { resp.setCode(500); resp.setMsg("该用户已注销"); log.error("日志编号:{}【任意花】资方返回的用户已注销,data:{}", logNumber, signs); return resp; } LambdaQueryWrapper wr = new LambdaQueryWrapper<>(); wr.eq(CustomerCapitalResult::getCustomerUserId, customerUser.getId()) .eq(CustomerCapitalResult::getCustomerRecordId, customer.getId()) .eq(CustomerCapitalResult::getCapitalInfoCode, CapitalInfoTypeCodeEnum.RYH.getCode()) .last(" limit 1 "); CustomerCapitalResult capitalResult = customerCapitalResultMapper.selectOne(wr); if (capitalResult == null) { resp.setCode(500); resp.setMsg("该数据不存在"); log.error("日志编号:{} 【任意花】资方回调返回的用户不存在,data:{}", logNumber, signs); return resp; } Integer status = CapitalInfoStatusEnum.APPLY_PASS.getCode(); LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate(CustomerCapitalResult.class); updateWrapper.eq(CustomerCapitalResult::getId, capitalResult.getId()). set(CustomerCapitalResult::getStatus, status); customerCapitalResultMapper.update(null,updateWrapper); resp.setCode(200); resp.setMsg("成功接收数据"); log.info("日志编号:{}【任意花】资方回调返回数据入库成功:{}", logNumber, body); return resp; } catch (Exception e) { resp.setCode(500); resp.setMsg(e.getMessage()); log.error("日志编号:{}【任意花】资方回调返回数据入库失败:{} 错误原因:{}", logNumber, body, e); return resp; } } /** * 中诚易数据推送到任意花操作 */ public boolean zcyPushToRyh(Customer customer, String logNumber) { boolean isSucc = false; log.info("日志编号:" + logNumber + ",手机号:{},中诚易数据推送到任意花流程开始", customer.getPhone()); try { JSONObject param = getParam(customer); isSucc = push(customer, param, logNumber); Integer ryh = 0; if (!isSucc) { log.error("日志编号:" + logNumber + ",手机号:{},中诚易数据推送到任意花失败", customer.getPhone()); } else { ryh = 1; } saveStatus(customer, ryh); } catch (Exception ex) { log.error("日志编号:" + logNumber + ",手机号:{},中诚易数据推送到任意花失败", customer.getPhone()); } return isSucc; } /** * 推送操作 */ public LvdiPushResultVo ryhPush(CustomerUser customerUser, String channelCode) { String logNumber = IdUtil.randomUUID(); log.info("日志编号:" + logNumber + "【任意花】 channelCode:" + channelCode + " 推送流程开始"); Customer customer = customerMapper.getLatestCustomerRecord(customerUser.getPhone()); CustomerCapitalResult capitalResult = capitalResultMapper.selectOne(new LambdaQueryWrapper() .eq(CustomerCapitalResult::getCustomerUserId, customerUser.getId()) .eq(CustomerCapitalResult::getCustomerRecordId, customer.getId()) .eq(CustomerCapitalResult::getCapitalInfoCode, CapitalInfoTypeCodeEnum.RYH.getCode())); if (capitalResult == null) { log.info("日志编号:" + logNumber + " 手机号:" + customerUser.getPhone() + "【任意花】数据库结果不存在, customerUser id:" + customerUser.getId() + " customer id:" + customer.getId()); throw new CommonException("资方对接结果不存在"); } JSONObject param = getParam(customer); boolean isSucc = push(customer, param, logNumber); if (!isSucc) { return null; } // 开始进件操作 // 转成 LvdiPushResultVo LvdiPushResultVo result = new LvdiPushResultVo(); result.setCheckResult(true); result.setUrlType("1");// APP下载链接 return result; } private final IPlatformCapitalService platformCapitalService; /** * 中诚易进件数据给任意花操作 */ public void zcyIncomeToRyh(Customer customer, String logNumber) { log.info("日志编号:" + logNumber + ",手机号:{},中诚易数据进件到任意花流程开始", customer.getPhone()); try { Integer syh = 3; ResultJson rs = getPushResult(logNumber, customer); if (rs == null) { log.error("日志编号:" + logNumber + ",手机号:{},中诚易数据进件到任意花失败", customer.getPhone()); } else { syh = 4; log.info("日志编号:" + logNumber + ",手机号:{},中诚易数据进件到任意花成功", customer.getPhone()); } saveStatus(customer, syh); } catch (Exception ex) { log.error("日志编号:" + logNumber + ",手机号:{},中诚易数据进件到任意花失败", customer.getPhone()); } } private void saveStatus(Customer customer, Integer ryh) { // 录入或更新到customer_scy_income表 LambdaQueryWrapper wr = new LambdaQueryWrapper<>(); wr.eq(CustomerScyIncome::getCustomerZcyId, customer.getId()); wr.last(" limit 1 "); CustomerScyIncome csi = customerZcyIncomeService.getOne(wr); if (Objects.isNull(csi)) { csi = new CustomerScyIncome(); } csi.setCustomerZcyId(customer.getId()); csi.setRyh(ryh); customerZcyIncomeService.saveOrUpdate(csi); } private boolean push(Customer customer, JSONObject body, String logNumber) { /*姓名MD5*/ body.put("nameMd5", DigestUtils.md5DigestAsHex(customer.getName().getBytes())); /* 手机号md5(32位小写)*/ body.put("phoneMd5", DigestUtils.md5DigestAsHex(customer.getPhone().getBytes())); // 转参 String contentStr = body.toJSONString(); String contentStrAes = encryptByAES(contentStr); log.info("日志编号:" + logNumber + " 手机号为:{},【任意花】参数:: {}, data加密 {}", customer.getPhone(), body, contentStrAes); JSONObject jsonData = new JSONObject(); jsonData.put("requestNo", UUID.randomUUID().toString().replace("-", "")); jsonData.put("channelId", channelId); jsonData.put("data", contentStrAes); log.info("日志编号:" + logNumber + " 开始推送手机号:" + customer.getPhone() + "的资料给资方【任意花】"); String result = null; try { result = HttpClientUtil.getInstance().postJsonData(zkUrl, jsonData.toJSONString()); log.info("日志编号:" + logNumber + " 手机号为:" + customer.getPhone() + ",【任意花】推送原始返回参数:{}", result); } catch (Exception ex) { log.error("日志编号:" + logNumber + " 手机号为:{},【任意花】推送失败,传参:{} ex:{}", customer.getPhone(), jsonData , ex); } if (StringUtils.isBlank(result)) { log.error("日志编号:" + logNumber + " 手机号为:{},【任意花】推送原始返回数据为空,传参:{} ", customer.getPhone(), jsonData); } try { RyhResponse res = JSON.parseObject(result, RyhResponse.class); if (res.getCode().intValue() == 200) { log.info("日志编号:" + logNumber + " 手机号为:" + customer.getPhone() + ",【任意花】推送成功"); String signsResult = JSON.toJSONString(res.getData()); PlatformCapital platformCapital = JSON.parseObject(signsResult, PlatformCapital.class); // 删除同一资方的同一用户数据 LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(PlatformCapital::getCustomerId, customer.getId()); wrapper.eq(PlatformCapital::getCapitalId, capitalId); platformCapitalService.remove(wrapper); // 录入到数据库 platformCapital.setCustomerId(customer.getId()); platformCapital.setCapitalId(capitalId); platformCapitalService.save(platformCapital); return true; } else { log.error("日志编号:" + logNumber + " 手机号为:{},【任意花】推送失败:{},jsonData:{}", customer.getPhone(), res.getMsg(),jsonData); } } catch (Exception ex) { log.error("日志编号:" + logNumber + " 手机号为:{},【任意花】推送原始返回参数转换失败,jsonData:{} ex:{}", customer.getPhone(), jsonData , ex); } return false; } /** * 进件操作 */ public ResultJson income(HttpServletRequest request) { String logNumber = IdUtil.randomUUID(); log.info("日志编号:" + logNumber + " 【任意花】进件流程开始"); String token = request.getHeader("Authorization"); UserDetail user = UserUtil.getUser(token); if (user == null) { log.info("日志编号:" + logNumber + " 【任意花】进件失败,原因:用户Token无效"); throw new CommonException("用户Token无效"); } Customer customer = customerMapper.getLatestCustomerRecord(user.getPhone()); LambdaQueryWrapper wr = new LambdaQueryWrapper<>(); wr.eq(CustomerUser::getPhone, user.getPhone()); wr.eq(CustomerUser::getDeleteFlag, 0); wr.last(" limit 1 "); CustomerUser customerUser = customerUserService.getOne(wr); if (customerUser == null) { log.info("日志编号:" + logNumber + " 手机号:" + user.getPhone() + "【任意花】进件失败,原因:用户不存在"); throw new CommonException("用户不存在"); } CustomerCapitalResult capitalResult = capitalResultMapper.selectOne(new LambdaQueryWrapper() .eq(CustomerCapitalResult::getCustomerUserId, customerUser.getId()) .eq(CustomerCapitalResult::getCustomerRecordId, customer.getId()) .eq(CustomerCapitalResult::getCapitalInfoCode, CapitalInfoTypeCodeEnum.RYH.getCode())); if (capitalResult == null) { log.info("日志编号:" + logNumber + " 手机号:" + customerUser.getPhone() + "进件失败,原因:【任意花】数据库结果不存在, customerUser id:" + customerUser.getId() + " customer id:" + customer.getId()); throw new CommonException("资方对接结果不存在"); } return getPushResult(logNumber, customer); } @Nullable private ResultJson getPushResult(String logNumber, Customer customer) { // 判断是否数据库中是否有数据,有过数据就不推送了 LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(PlatformCapital::getCustomerId, customer.getId()); wrapper.eq(PlatformCapital::getCapitalId, capitalId); wrapper.last(" limit 1 "); PlatformCapital platformCapital = platformCapitalService.getOne(wrapper); if (Objects.isNull(platformCapital)) {// 若没有数据 log.info("日志编号:" + logNumber + " 手机号:" + customer.getPhone() + "进件失败,原因:【任意花】推送结果不存在, customer id:" + customer.getId()); throw new CommonException("资方推送结果不存在"); } if (platformCapital.getIncomeStatus() == 1) {// 已进件成功 log.info("日志编号:" + logNumber + " 手机号:" + customer.getPhone() + "进件失败,原因:【任意花】已经进件成功过,不再进件, customer id:" + customer.getId()); return null; } JSONObject param = getParam(customer); param.put("orderId", platformCapital.getOrderId()); param.put("phone", customer.getPhone()); param.put("name", customer.getName()); param.put("protocolUrl", protocolUrl); JSONObject jsonData = new JSONObject(); jsonData.put("requestNo", UUID.randomUUID().toString().replace("-", "")); jsonData.put("channelId", channelId); jsonData.put("data", encryptByAES(param.toJSONString())); log.info("日志编号:" + logNumber + " 手机号:" + customer.getPhone() + "开始进件给资方【任意花】,参数:{}", jsonData); String result = null; try { result = HttpClientUtil.getInstance().postJsonData(jkUrl, jsonData.toJSONString()); log.info("日志编号:" + logNumber + " 手机号为:" + customer.getPhone() + ",【任意花】进件原始返回参数:{}", result); } catch (Exception ex) { log.error("日志编号:" + logNumber + " 手机号为:{},【任意花】进件失败,传参:{} ex:{}", customer.getPhone(), jsonData , ex); } if (StringUtils.isBlank(result)) { log.error("日志编号:" + logNumber + " 手机号为:{},【任意花】进件返回数据为空,传参:{} ", customer.getPhone(), jsonData); } try { RyhResponse res = JSON.parseObject(result, RyhResponse.class); if (res.getCode().intValue() == 200) { log.info("日志编号:" + logNumber + " 手机号为:" + customer.getPhone() + ",【任意花】进件成功"); // 更新数据库 platformCapital.setIncomeStatus(1); platformCapitalService.updateById(platformCapital); LvdiPushResultVo rs = new LvdiPushResultVo(); rs.setCheckResult(true); rs.setUrlType("1");// APP下载链接 return ResultJson.ok(rs); } else { log.error("日志编号:" + logNumber + " 手机号为:{},【任意花】进件失败:{},jsonData:{}", customer.getPhone(), res.getMsg(),jsonData); } } catch (Exception ex) { log.error("日志编号:" + logNumber + " 手机号为:{},【任意花】进件原始返回参数转换失败,jsonData:{} ex:{}", customer.getPhone(), jsonData , ex); } return null; } /** * AES加密 */ public String encryptByAES(String contentStr) { try { if(StringUtils.isEmpty(contentStr)) { return null; } byte[] raw = secretKey.getBytes(StandardCharsets.UTF_8); SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(contentStr.getBytes(StandardCharsets.UTF_8)); Base64.Encoder encoder = Base64.getEncoder(); return encoder.encodeToString(encrypted); } catch(Exception e) { e.printStackTrace(); return null; } } /** * AES解密 */ public String aesDecrypt(String sSrc) { try { byte[] raw = secretKey.getBytes(StandardCharsets.UTF_8); SecretKeySpec skeySpec = new SecretKeySpec(raw, AES); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, skeySpec); byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);//先用base64解密 try { byte[] original = cipher.doFinal(encrypted1); String originalString = new String(original, StandardCharsets.UTF_8); return originalString; } catch (Exception e) { e.printStackTrace(); return null; } } catch (Exception ex) { ex.printStackTrace(); return null; } } }