package com.nova.sankuai.domain.api.zhongan; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.nova.sankuai.domain.entity.City; import com.nova.sankuai.domain.entity.Customer; import com.nova.sankuai.domain.enums.SourceTypeEnum; import com.nova.sankuai.domain.enums.customerinfo.EnterpriseInfoEnum; import com.nova.sankuai.domain.enums.customerinfo.MaritalStatusEnum; import com.nova.sankuai.infra.config.CommonException; import com.nova.sankuai.service.ICityService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DateFormatUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import javax.annotation.Resource; import java.math.BigDecimal; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; /** *

* description *

* * @author denglb 2021/11/16 */ @Component @Slf4j public class ZhongAnUtil { @Value("${rsa.local.privateKey}") private String localPrivateKey; @Value("${rsa.local.publicKey}") private String localPublicKey; @Value("${rsa.zhongan.publicKey}") private String zhonganPublicKey; @Value("${rsa.zhongan.appKey}") private String zhonganAppKey; @Value("${rsa.zhongan.creditApplyService}") private String creditApplyService; @Value("${rsa.zhongan.url}") private String zhonganUrl; @Value("${rsa.zhongan.callbackService}") private String callbackService; @Resource private ICityService cityService; private static final String API_NAME = "apiName"; private static final String CHANNEL_NO = "channelNo"; private static final String SUPPLIER_NO = "supplierNo"; private static final String REQ_DATE = "reqDate"; private static final String REQ_NO = "reqNo"; private static final String RESP_CODE = "respCode"; private static final String RESP_MSG = "respMsg"; private static final String RESP_NO = "respNo"; private static final String RESULT = "result"; private static final String THIRD_USER_NO = "thirdUserNo"; private static final String APPKEY = "appKey"; private static final String SERVICE_NAME = "serviceName"; private static final String BIZ_CONTENT = "bizContent"; private static final String TIMESTAMP = "timestamp"; private static final String FORMAT = "format"; private static final String SIGN_TYPE = "signType"; private static final String CHARSET = "charset"; private static final String VERSION = "version"; private static final String SIGN = "sign"; private static final String CERTI_NO = "certiNo"; private static final String PHONE = "phone"; private static final String IS_ALLOW_CREDIT = "isAllowCredit"; private static final String ERROR_CODE = "errorCode"; private static final String ERROR_MSG = "errorMsg"; private static final String VAL_CHANNEL_NO = "DL-ZAXD001"; private static final String VAL_CHARSET_DEFAULT = "UTF-8"; private static final String VAL_FORMAT_DEFAULT = "json"; private static final String VAL_SIGN_TYPE_DEFAULT = "RSA"; private static final String VAL_SUCCESS_CODE = "0000"; private static final String VAL_SUCCESS_MSG = ""; private static final String VAL_VERSION = "1.0.0"; public String buildAvailAmountResult(Customer customer, DuolaiRequest request) { if (customer == null) { throw new CommonException("未查询到相关信息"); } AvailAmountQuery query = queryZhonganCustomerCardNo(request); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); AvailAmountResult result = new AvailAmountResult(); result.setCreditAmount(BigDecimal.valueOf(customer.getLoanAmount())); result.setUsedAmount(BigDecimal.valueOf(0)); result.setFrozenAmount(BigDecimal.valueOf(0)); result.setAvailableAmount(BigDecimal.valueOf(customer.getLoanAmount())); result.setStartLoanAmount(BigDecimal.valueOf(customer.getLoanAmount())); String applyDate = sdf.format(customer.getApplyDate()); result.setEffectiveDate(applyDate); Calendar cal = Calendar.getInstance(); cal.setTime(customer.getApplyDate()); cal.add(Calendar.YEAR, 1); result.setExpireDate(sdf.format(cal.getTime())); result.setStatus(1); result.setMaxLoanPeriods(12); result.setSupportPeriods(Collections.singletonList(12)); Map respInner = new HashMap<>(); respInner.put(RESULT, result); respInner.put(RESP_CODE, "0000"); respInner.put(RESP_MSG, "成功"); respInner.put(RESP_NO, UUID.randomUUID().toString()); respInner.put(REQ_NO, query.getReqNo()); //使用众安的公钥加密 String bizContent = SignUtil.encryptByPublicKeyWithNoOrderForLongData(JSONObject.toJSONString(respInner), zhonganPublicKey); return bizContent; } public Map buildAvailAmountResp(String bizContent, String resultCode, String resultMsg) { Map resp = new HashMap<>(); resp.put(BIZ_CONTENT, bizContent);// 业务数据 resp.put(CHARSET, VAL_CHARSET_DEFAULT);// 字节编码 resp.put(FORMAT, VAL_FORMAT_DEFAULT);// 格式化类型 resp.put(TIMESTAMP, DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS"));// 时间戳 resp.put(SIGN_TYPE, VAL_SIGN_TYPE_DEFAULT);// 签名类型 resp.put(ERROR_CODE, resultCode == null ? "" : resultCode);// 错误码 resp.put(ERROR_MSG, resultMsg == null ? "" : resultMsg);// 错误信息 // 供应商的私钥加签 String sign = SignUtil.doSign(resp, localPrivateKey); // sign签名当成请求入参 resp.put(SIGN, sign); return resp; } public AvailAmountQuery queryZhonganCustomerCardNo(DuolaiRequest request) { Map req = buildZhonganReq(request, creditApplyService); String getSign = String.valueOf(req.get(SIGN)); // 使用众安的公钥验签 boolean verify = SignUtil.rsa256CheckContent(req, getSign, zhonganPublicKey); Assert.isTrue(verify, "验签失败"); // 使用供应商的私钥解密 String decryptBizContent = SignUtil.decryptRSAByPrivateKeyForLongData(String.valueOf(req.get(BIZ_CONTENT)), localPrivateKey); log.info("众安参数:" + decryptBizContent); AvailAmountQuery query = JSONObject.parseObject(decryptBizContent, AvailAmountQuery.class); if (query == null || StringUtils.isBlank(query.getCertiNo())) { log.error("接收参数异常:{}", query); throw new CommonException("接收参数异常"); } return query; } private DuolaiDto queryDuolaiDto(DuolaiRequest request) { if (request == null) { throw new CommonException("未接受到参数"); } Map req = buildZhonganReq(request, creditApplyService); String getSign = String.valueOf(req.get(SIGN)); // 使用众安的公钥验签 // boolean verify = SignUtil.rsa256CheckContent(req, getSign, zhonganPublicKey); // Assert.isTrue(verify, "验签失败"); // 使用供应商的私钥解密 String decryptBizContent = SignUtil.decryptRSAByPrivateKeyForLongData(String.valueOf(req.get(BIZ_CONTENT)), localPrivateKey); log.info("众安参数:" + decryptBizContent); DuolaiDto dto = JSONObject.parseObject(decryptBizContent, DuolaiDto.class); return dto; } public Customer buildZhongAnCustomer(DuolaiRequest request) { DuolaiDto dto = queryDuolaiDto(request); Customer customer = new Customer(); OcrInfoDto infoDto = dto.getOcrInfoDto(); customer.setName(infoDto.getName()); customer.setPhone(dto.getMobile()); customer.setIdCard(infoDto.getCertiNo()); OtherCreditInfo otherCreditInfo = dto.getOtherCreditInfo(); City one = cityService.getOne(new LambdaQueryWrapper().like(City::getName, otherCreditInfo.getContactCity())); if (one != null) { customer.setCity(one.getCityId()); customer.setCityName(one.getName()); } customer.setSourceChannel(SourceTypeEnum.ZhongAn.getCode()); customer.setApplyDate(dto.getCreditApplyTime()); customer.setIdCardFrontPath(dto.getCertFrontImageId()); customer.setIdCardBackPath(dto.getCertBackImageId()); if (otherCreditInfo.getContact1Relation().equals(RelationshipEnum.PARENT.getCode())) { customer.setRelationship("0"); customer.setRelationshipName(otherCreditInfo.getContact1Name()); customer.setRelationshipPhone(otherCreditInfo.getContact1Mobile()); } else if (otherCreditInfo.getContact1Relation().equals(RelationshipEnum.CHILD.getCode())) { customer.setRelationship("1"); customer.setRelationshipName(otherCreditInfo.getContact1Name()); customer.setRelationshipPhone(otherCreditInfo.getContact1Mobile()); } else { customer.setContact1Name(otherCreditInfo.getContact1Name()); customer.setContact1Phone(otherCreditInfo.getContact1Mobile()); } if (otherCreditInfo.getContact2Relation().equals(RelationshipEnum.PARENT.getCode())) { customer.setRelationship1("0"); customer.setRelationship1Name(otherCreditInfo.getContact2Name()); customer.setRelationship1Phone(otherCreditInfo.getContact2Mobile()); } else if (otherCreditInfo.getContact2Relation().equals(RelationshipEnum.CHILD.getCode())) { customer.setRelationship1("1"); customer.setRelationship1Name(otherCreditInfo.getContact2Name()); customer.setRelationship1Phone(otherCreditInfo.getContact2Mobile()); } else { customer.setContactName(otherCreditInfo.getContact2Name()); customer.setContactPhone(otherCreditInfo.getContact2Mobile()); } customer.setEducation(queryEducation(otherCreditInfo.getFilledDegree())); customer.setMaritalStatus(queryMarital(otherCreditInfo.getMarriage())); customer.setMonthlyIncome(queryInCome(otherCreditInfo.getMonthlyPay())); customer.setAddress(otherCreditInfo.getDetailedAddress()); customer.setAge(getAge(dto.getOcrInfoDto().getBirthday())); if (StringUtils.isBlank(otherCreditInfo.getCompanyName())) { customer.setEnterpriseInfo(EnterpriseInfoEnum.Enterprise_1.getCode()); } else { customer.setEnterpriseInfo(EnterpriseInfoEnum.Enterprise_2.getCode()); } customer.setLoanAmount(buildLoanAmount()); return customer; } private Double buildLoanAmount() { Random random = new Random(); int i = random.nextInt(5) + 1; return i * 10000.00; } private Integer getAge(String strDate) { if (StringUtils.isBlank(strDate)) { return null; } SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date birthDay = null; try { birthDay = sdf.parse(strDate); } catch (ParseException e) { e.printStackTrace(); } Calendar cal = Calendar.getInstance(); if (cal.before(birthDay)) { //出生日期晚于当前时间,无法计算 throw new IllegalArgumentException( "The birthDay is before Now.It's unbelievable!"); } int yearNow = cal.get(Calendar.YEAR); //当前年份 int monthNow = cal.get(Calendar.MONTH); //当前月份 int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH); //当前日期 cal.setTime(birthDay); int yearBirth = cal.get(Calendar.YEAR); int monthBirth = cal.get(Calendar.MONTH); int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH); int age = yearNow - yearBirth; //计算整岁数 if (monthNow <= monthBirth) { if (monthNow == monthBirth) { if (dayOfMonthNow < dayOfMonthBirth) { age--; }//当前日期在生日之前,年龄减一 } else { age--;//当前月份在生日之前,年龄减一1 } } return age; } private Integer queryInCome(Integer monthlyPay) { for (MonthPayEnum m : MonthPayEnum.values()) { if (m.getCode().equals(monthlyPay)) { return m.getSys(); } } return null; } private String queryMarital(Integer marriage) { for (MaritalStatusEnum maritalStatusEnum : MaritalStatusEnum.values()) { return maritalStatusEnum.getSys(); } return null; } private String queryEducation(Integer zhonganEducation) { for (ZhonganEducationEnum educationEnum : ZhonganEducationEnum.values()) { if (educationEnum.getCode().equals(zhonganEducation)) { return educationEnum.getSys(); } } return null; } private Map buildZhonganReq(DuolaiRequest request, String serviceName) { Map req = new HashMap<>(); req.put(APPKEY, zhonganAppKey);// appKey req.put(SERVICE_NAME, serviceName);// serviceName req.put(BIZ_CONTENT, request.getBizContent());// 业务数据 req.put(TIMESTAMP, DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS"));// 时间戳 req.put(FORMAT, VAL_FORMAT_DEFAULT);// 格式化类型 req.put(SIGN_TYPE, VAL_SIGN_TYPE_DEFAULT);// 签名类型 req.put(CHARSET, VAL_CHARSET_DEFAULT);// 字节编码 req.put(VERSION, VAL_VERSION);// API版本号 req.put(SIGN, request.getSign()); return req; } public Map buildZhonganResp(DuolaiRequest request, String status, String resultCode, String resultMsg) { DuolaiDto dto = queryDuolaiDto(request); CreditApplyResult result = new CreditApplyResult(); result.setOuterCreditApplyNo(result.getOuterCreditApplyNo()); result.setStatus(status); result.setResultCode(resultCode); result.setResultMsg(resultMsg); Map respInner = new HashMap<>(); respInner.put(RESULT, result); respInner.put(RESP_CODE, resultCode == null ? "0000" : resultCode); respInner.put(RESP_MSG, resultMsg); respInner.put(RESP_NO, UUID.randomUUID().toString()); respInner.put(REQ_NO, dto.getReqNo()); //使用众安的公钥加密 String bizContent = SignUtil.encryptByPublicKeyWithNoOrderForLongData(JSONObject.toJSONString(respInner), zhonganPublicKey); Map resp = new HashMap<>(); resp.put(BIZ_CONTENT, bizContent);// 业务数据 resp.put(CHARSET, VAL_CHARSET_DEFAULT);// 字节编码 resp.put(FORMAT, VAL_FORMAT_DEFAULT);// 格式化类型 resp.put(TIMESTAMP, DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS"));// 时间戳 resp.put(SIGN_TYPE, VAL_SIGN_TYPE_DEFAULT);// 签名类型 resp.put(ERROR_CODE, resultCode == null ? "" : resultCode);// 错误码 resp.put(ERROR_MSG, resultMsg == null ? "" : resultMsg);// 错误信息 // 供应商的私钥加签 String sign = SignUtil.doSign(resp, localPrivateKey); // sign签名当成请求入参 resp.put(SIGN, sign); return resp; } public void callback(DuolaiRequest request, String status, Double money) { DuolaiDto dto = queryDuolaiDto(request); Map map = new HashMap<>(); map.put(CHANNEL_NO, dto.getChannelNo()); map.put(REQ_DATE, dto.getReqDate()); map.put(REQ_NO, dto.getReqNo()); map.put(THIRD_USER_NO, dto.getThirdUserNo()); map.put("productCode", dto.getProductCode()); map.put("creditApplyNo", dto.getOuterCreditApplyNo()); map.put("status", status); map.put("creditApplyTime", DateFormatUtils.format(dto.getCreditApplyTime(), "yyyy-MM-dd HH:mm:ss")); if (ZhongAnStatus.STATUS_3.getCode().equals(status)) { map.put("creditAmount", BigDecimal.valueOf(money)); map.put("availableAmount", BigDecimal.valueOf(money)); Calendar cal = Calendar.getInstance(); cal.setTime(dto.getCreditApplyTime()); cal.add(Calendar.YEAR, 1); map.put("quotaInvalidDate", DateFormatUtils.format(cal.getTime(), "yyyy-MM-dd HH:mm:ss")); } else { map.put("resultMsg", "订单常见失败"); } //使用众安的公钥加密 String bizContent = SignUtil.encryptByPublicKeyWithNoOrderForLongData(JSONObject.toJSONString(map), zhonganPublicKey); Map req = new HashMap<>(); req.put(APPKEY, zhonganAppKey);// appKey req.put(SERVICE_NAME, callbackService);// serviceName req.put(BIZ_CONTENT, bizContent);// 业务数据 req.put(TIMESTAMP, DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS"));// 时间戳 req.put(FORMAT, VAL_FORMAT_DEFAULT);// 格式化类型 req.put(SIGN_TYPE, VAL_SIGN_TYPE_DEFAULT);// 签名类型 req.put(CHARSET, VAL_CHARSET_DEFAULT);// 字节编码 req.put(VERSION, VAL_VERSION);// API版本号 req.put(SUPPLIER_NO, request.getSupplierNo());//TODO 供应商发起请求该值必填,值为众安侧分配的编码 // 供应商的私钥加签 String sign = SignUtil.doSign(req, localPrivateKey); // sign签名当成请求入参 req.put(SIGN, sign); // HttpUtil.post(zhonganUrl, req); } }