package com.nova.sankuai.domain.api.doudouqian; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.nova.sankuai.domain.dto.DdqBindCardDto; import com.nova.sankuai.domain.entity.Customer; import com.nova.sankuai.domain.entity.CustomerUser; import com.nova.sankuai.infra.config.CommonException; import com.nova.sankuai.security.HttpClientUtil; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import org.apache.commons.lang.StringUtils; 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 java.util.Map; import java.util.Optional; /** *

* 豆豆钱接口调用工具类 *

* * @author Weikangdi * @since 2022/4/26 **/ @Component @ApiModel(value = "豆豆钱接口对接工具类") public class DdqUtil { @Value("${doudouqian.conf.api-url}") @ApiModelProperty(value = "请求地址") private String apiUrl; @Value("${doudouqian.conf.public_key}") @ApiModelProperty(value = "公钥") private String publicKey; @Value("${doudouqian.conf.md5_key}") @ApiModelProperty(value = "MD5秘钥") private String md5Key; @Value("${doudouqian.conf.channel_code}") @ApiModelProperty(value = "机构申请得到的渠道号") private String channelCode; @Value("${doudouqian.conf.download_url}") @ApiModelProperty(value = "下载链接地址") public String downloadUrl; @Value("${doudouqian.conf.system_public_key}") @ApiModelProperty(value = "系统内公钥") private String systemPublicKey; @Value("${doudouqian.conf.system_private_key}") @ApiModelProperty(value = "系统内私钥") private String systemPrivateKey; private static final Logger log = LoggerFactory.getLogger("capitalLogger"); /** * 撞库-API预检MD5 * * @param customer 用户信息 * @return */ public boolean apiMd5Check(Customer customer) { String url = "/foreign/api/customer/md5_check"; JSONObject params = new JSONObject(); String phoneMd5 = DigestUtils.md5DigestAsHex(customer.getPhone().getBytes()); String nameMd5 = DigestUtils.md5DigestAsHex(customer.getName().getBytes()); String idCardMd5 = DigestUtils.md5DigestAsHex(customer.getIdCard().getBytes()); params.put("mobile", phoneMd5); params.put("identityNo", nameMd5); params.put("realName", idCardMd5); try { log.info("豆豆钱对接:API预检MD5参数->:{}", params.toJSONString()); String paramStr = DdqSignUtil.buildRequest(params.toJSONString(), channelCode, publicKey, md5Key); log.info("豆豆钱对接:API预检MD5加密参数->:{}", paramStr); String result = HttpClientUtil.getInstance().postJsonData(apiUrl + url, paramStr); log.info("豆豆钱对接:API预检MD5返回参数->:{}", result); DdqResponse response = getResponse(result); if (response.isSuccess()) { ApiMd5CheckVo checkVo = JSON.parseObject(response.getData(), ApiMd5CheckVo.class); if (checkVo.isIfCanLoan()) { return true; } } else { log.error("豆豆钱对接:API预检MD5失败,错误原因" + response.getMsg()); } } catch (Exception e) { log.error("豆豆钱对接:API预检MD5接口请求错误", e); e.printStackTrace(); } return false; } /** * 用户注册 * * @param customer 用户信息 * @return */ public boolean register(Customer customer) { String url = "/foreign/api/customer/login"; JSONObject params = new JSONObject(); params.put("mobile", customer.getPhone()); params.put("identityNo", customer.getIdCard()); params.put("realName", customer.getName()); try { log.info("豆豆钱对接:用户注册参数->:{}", params.toJSONString()); String paramStr = DdqSignUtil.buildRequest(params.toJSONString(), channelCode, publicKey, md5Key); log.info("豆豆钱对接:用户注册加密参数->:{}", paramStr); String result = HttpClientUtil.getInstance().postJsonData(apiUrl + url, paramStr); log.info("豆豆钱对接:用户注册返回参数->:{}", result); DdqResponse response = getResponse(result); if (response.isSuccess()) { return true; } else { log.error("豆豆钱对接:用户注册失败,错误原因" + response.getMsg()); } } catch (Exception e) { log.error("豆豆钱对接:用户注册接口请求错误", e); e.printStackTrace(); } return false; } /** * 获取支持的银行卡列表 * * @param phone 用户手机号 * @return */ public BankListVo getBankList(String phone) { String url = "/foreign/card/banklist"; JSONObject params = new JSONObject(); params.put("mobile", phone); try { log.info("豆豆钱对接:获取支持的银行卡列表参数->:{}", params.toJSONString()); String paramStr = DdqSignUtil.buildRequest(params.toJSONString(), channelCode, publicKey, md5Key); log.info("豆豆钱对接:获取支持的银行卡列表加密参数->:{}", paramStr); String result = HttpClientUtil.getInstance().postJsonData(apiUrl + url, paramStr); log.info("豆豆钱对接:获取支持的银行卡列表返回参数->:{}", result); DdqResponse response = getResponse(result); if (response.isSuccess()) { BankListVo bankListVo = JSON.parseObject(response.getData(), BankListVo.class); return bankListVo; } else { log.error("豆豆钱对接:获取支持的银行卡失败,错误原因" + response.getMsg()); } } catch (Exception e) { log.error("豆豆钱对接:获取支持的银行卡列表接口请求错误", e); e.printStackTrace(); } return null; } /** * 获取合同链接(协议) * * @param customerUser 用户信息 * @return */ public ContractLinkVo getContractLink(CustomerUser customerUser) { String url = "/foreign/api/get/contractlink"; JSONObject params = new JSONObject(); params.put("mobile", customerUser.getPhone()); params.put("identityNo", customerUser.getIdCard()); params.put("realName", customerUser.getName()); try { log.info("豆豆钱对接:获取合同链接参数->:{}", params.toJSONString()); String paramStr = DdqSignUtil.buildRequest(params.toJSONString(), channelCode, publicKey, md5Key); log.info("豆豆钱对接:获取合同链接加密参数->:{}", paramStr); String result = HttpClientUtil.getInstance().postJsonData(apiUrl + url, paramStr); log.info("豆豆钱对接:获取合同链接返回参数->:{}", result); DdqResponse response = getResponse(result); if (response.isSuccess()) { ContractLinkVo bankListVo = JSON.parseObject(response.getData(), ContractLinkVo.class); return bankListVo; } else { log.error("豆豆钱对接:获取合同链接失败,错误原因" + response.getMsg()); } } catch (Exception e) { log.error("豆豆钱对接:获取合同链接接口请求错误", e); e.printStackTrace(); } return null; } /** * 银行卡验卡 * * @param bindCardDto 绑卡信息 * @return */ public BankCardCheckVo bankCardCheck(DdqBindCardDto bindCardDto) { String url = "/foreign/card/cardcheck"; JSONObject params = new JSONObject(); params.put("mobile", bindCardDto.getPhone()); params.put("payCardNo", bindCardDto.getCardNo()); params.put("payCardBank", bindCardDto.getBankName()); params.put("payBankCode", bindCardDto.getBankCode()); params.put("cardReseRveMobile", bindCardDto.getBankPhoneNo()); try { log.info("豆豆钱对接:银行卡验卡参数->:{}", params.toJSONString()); String paramStr = DdqSignUtil.buildRequest(params.toJSONString(), channelCode, publicKey, md5Key); log.info("豆豆钱对接:银行卡验卡加密参数->:{}", paramStr); String result = HttpClientUtil.getInstance().postJsonData(apiUrl + url, paramStr); log.info("豆豆钱对接:银行卡验卡返回参数->:{}", result); DdqResponse response = getResponse(result); if (response.isSuccess()) { BankCardCheckVo checkVo = JSON.parseObject(response.getData(), BankCardCheckVo.class); return checkVo; } else { log.error("豆豆钱对接:银行卡验卡失败,错误原因" + response.getMsg()); } } catch (Exception e) { log.error("豆豆钱对接:银行卡验卡接口请求错误", e); e.printStackTrace(); } return null; } /** * 银行卡绑卡接口(验证码绑卡) * * @param bindCardDto 绑卡信息 * @return */ public BindCardVo bindCard(DdqBindCardDto bindCardDto) { String url = "/foreign/card/bindCard"; JSONObject params = new JSONObject(); params.put("mobile", bindCardDto.getPhone()); params.put("payCardNo", bindCardDto.getCardNo()); params.put("payCardBank", bindCardDto.getBankName()); params.put("payBankCode", bindCardDto.getBankCode()); params.put("cardReseRveMobile", bindCardDto.getBankPhoneNo()); params.put("smsCode", bindCardDto.getVerifyCode()); try { log.info("豆豆钱对接:银行卡绑卡参数->:{}", params.toJSONString()); String paramStr = DdqSignUtil.buildRequest(params.toJSONString(), channelCode, publicKey, md5Key); log.info("豆豆钱对接:银行卡绑卡加密参数->:{}", paramStr); String result = HttpClientUtil.getInstance().postJsonData(apiUrl + url, paramStr); log.info("豆豆钱对接:银行卡绑卡返回参数->:{}", result); DdqResponse response = getResponse(result); if (response.isSuccess()) { BindCardVo bindCardVo = JSON.parseObject(response.getData(), BindCardVo.class); return bindCardVo; } else { log.error("豆豆钱对接:银行卡绑卡失败,错误原因" + response.getMsg()); } } catch (Exception e) { log.error("豆豆钱对接:银行卡绑卡接口请求错误", e); e.printStackTrace(); } return null; } /** * 额度信息查询接口 * * @param phone 用户注册手机号 * @return */ public CreditQueryVo creditQuery(String phone) { String url = "/foreign/api/credit/query"; JSONObject params = new JSONObject(); params.put("mobile", phone); try { log.info("豆豆钱对接:额度信息查询参数->:{}", params.toJSONString()); String paramStr = DdqSignUtil.buildRequest(params.toJSONString(), channelCode, publicKey, md5Key); log.info("豆豆钱对接:额度信息查询加密参数->:{}", paramStr); String result = HttpClientUtil.getInstance().postJsonData(apiUrl + url, paramStr); log.info("豆豆钱对接:额度信息查询返回参数->:{}", result); DdqResponse response = getResponse(result); if (response.isSuccess()) { CreditQueryVo queryVo = JSON.parseObject(response.getData(), CreditQueryVo.class); return queryVo; } else { log.error("豆豆钱对接:额度信息查询失败,错误原因" + response.getMsg()); } } catch (Exception e) { log.error("豆豆钱对接:额度信息查询接口请求错误", e); e.printStackTrace(); } return null; } /** * 订单结果查询接口 * * @param phone 用户注册手机号 * @return */ public OrderQueryVo orderQuery(String phone) { String url = "/foreign/api/order/query"; JSONObject params = new JSONObject(); params.put("mobile", phone); try { log.info("豆豆钱对接:订单结果查询参数->:{}", params.toJSONString()); String paramStr = DdqSignUtil.buildRequest(params.toJSONString(), channelCode, publicKey, md5Key); log.info("豆豆钱对接:订单结果查询加密参数->:{}", paramStr); String result = HttpClientUtil.getInstance().postJsonData(apiUrl + url, paramStr); log.info("豆豆钱对接:订单结果查询返回参数->:{}", result); DdqResponse response = getResponse(result); if (response.isSuccess()) { OrderQueryVo orderQueryVo = JSON.parseObject(response.getData(), OrderQueryVo.class); return orderQueryVo; } else { log.error("豆豆钱对接:订单结果查询失败,错误原因" + response.getMsg()); } } catch (Exception e) { log.error("豆豆钱对接:订单结果查询接口请求错误", e); e.printStackTrace(); } return null; } /** * 交单进件接口(提交用户数据) * * @param customer 用户申请记录信息 * @return */ public boolean submitOrder(Customer customer, String logPrefix) { logPrefix = Optional.ofNullable(logPrefix).orElse("DEFAULT") + ", "; String url = "/foreign/api/credit/submitorder"; JSONObject params = new JSONObject(); params.put("mobile", customer.getPhone()); params.put("realName", customer.getName()); params.put("identityNo", customer.getIdCard()); params.put("gender", customer.getSex()); params.put("nation", customer.getNation()); params.put("agency", customer.getSignOrganization()); params.put("address", customer.getIdAddress()); params.put("expireEnd", customer.getIdValidDateEnd()); params.put("expireStart", customer.getIdValidDateBegin()); params.put("degree", DdqParamParseUtil.parseDegree(customer.getEducation())); params.put("marryStatus", DdqParamParseUtil.parseMarryStatus(customer.getMaritalStatus())); params.put("faceConfidence", customer.getVerifySimilarity()); params.put("faceThresholds", "le-4-baidu"); String paramString = params.toJSONString(); params.put("front", DdqParamParseUtil.parseBase64(customer.getIdCardFrontPath())); params.put("back", DdqParamParseUtil.parseBase64(customer.getIdCardBackPath())); params.put("hand", DdqParamParseUtil.parseBase64(customer.getFacePhotoPath())); try { log.info(logPrefix + "豆豆钱对接:交单进件参数->:{}", paramString); String paramStr = DdqSignUtil.buildRequest(params.toJSONString(), channelCode, publicKey, md5Key); // log.info(logPrefix + "豆豆钱对接:交单进件加密参数->:{}", paramStr); String result = HttpClientUtil.getInstance().postJsonData(apiUrl + url, paramStr); log.info(logPrefix + "豆豆钱对接:交单进件返回参数->:{}", result); DdqResponse response = getResponse(result); if (response.isSuccess()) { return true; } else { log.error(logPrefix + "豆豆钱对接:交单进件失败,错误原因" + response.getMsg()); } } catch (Exception e) { log.error(logPrefix + "豆豆钱对接:交单进件接口请求错误", e); e.printStackTrace(); } return false; } private DdqResponse getResponse(String result) { if (StringUtils.isNotEmpty(result)) { try { DdqResponse response = JSON.parseObject(result, DdqResponse.class); if (response != null) { return response; } } catch (Exception e) { e.printStackTrace(); log.error("豆豆钱对接:转换响应返回数据失败", e); } } log.error("豆豆钱对接:请求返回结果为空"); throw new CommonException("请求失败"); } public String parseRequest(String param) throws Exception { Map paramMap = JSON.parseObject(param, Map.class); String sign = DdqSignUtil.getValue(paramMap, "sign"); // 签名 String secretKey = DdqSignUtil.getValue(paramMap, "secret_key"); // 秘钥签 String bizData = DdqSignUtil.getValue(paramMap, "biz_data"); // 业务数据 String channelCode = DdqSignUtil.getValue(paramMap, "channel_code"); // 机构申请得到的渠道号 String timestamp = DdqSignUtil.getValue(paramMap, "timestamp"); // 时间戳(秒) // 1. 验证参数 if (org.apache.commons.lang3.StringUtils.isAnyBlank(sign, secretKey, channelCode, timestamp)) { throw new CommonException("请求不正确,缺失必要参数"); } // 3. 验证MD5签名 String tempSignStr = "biz_data=" + bizData + "&channel_code=" + channelCode + "&secret_key=" + secretKey + "×tamp=" + timestamp; String md5Sign = DdqSignUtil.md5Encrypt(tempSignStr + md5Key); if (!org.apache.commons.lang3.StringUtils.equalsIgnoreCase(md5Sign, sign)) { throw new CommonException("验签不通过"); } // 4. 解码SecretKey String aesKey = DdqSignUtil.decryptByPrivateKey(secretKey, systemPrivateKey); if (org.apache.commons.lang3.StringUtils.isBlank(aesKey)) { throw new CommonException("解密失败"); } return DdqSignUtil.decrypt(bizData, aesKey); } /** * 模拟第三方请求加密参数,使用系统内公钥加密 * * @return StringEntity */ public String buildTestRequest(JSONObject param) { try { String paramStr = DdqSignUtil.buildRequest(param.toJSONString(), channelCode, systemPublicKey, md5Key); return paramStr; } catch (Exception e) { e.printStackTrace(); } return null; } }