package com.nova.sankuai.service.impl;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.util.StrUtil;
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.nova.sankuai.domain.api.shantai.ShanTaiCheckVo;
|
import com.nova.sankuai.domain.api.yinsheng.enums.SignStatusEnum;
|
import com.nova.sankuai.domain.entity.Customer;
|
import com.nova.sankuai.domain.entity.ShanTaiSignRecord;
|
import com.nova.sankuai.domain.vo.huifubao.HuifubaoSignRecordVO;
|
import com.nova.sankuai.domain.entity.CustomerUser;
|
import com.nova.sankuai.domain.entity.HuifubaoSignRecord;
|
import com.nova.sankuai.domain.vo.huifubao.SignCallBackVo;
|
import com.nova.sankuai.infra.config.CommonException;
|
import com.nova.sankuai.infra.constants.ResultCode;
|
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.infra.utils.huifubao.common.*;
|
import com.nova.sankuai.infra.utils.huifubao.request.BaseRequest;
|
import com.nova.sankuai.infra.utils.huifubao.request.SignRequest;
|
import com.nova.sankuai.infra.utils.huifubao.respone.BaseResponse;
|
import com.nova.sankuai.infra.utils.huifubao.respone.SignResponse;
|
import com.nova.sankuai.security.UserDetail;
|
import com.nova.sankuai.service.ICustomerUserService;
|
import com.nova.sankuai.service.IHuifubaoSignRecordService;
|
import com.nova.sankuai.service.IHuiFuBaoSignService;
|
import lombok.SneakyThrows;
|
import org.bouncycastle.util.encoders.Base64;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.http.HttpStatus;
|
import org.springframework.http.ResponseEntity;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import javax.annotation.Resource;
|
import javax.servlet.http.HttpServletRequest;
|
import java.security.KeyFactory;
|
import java.security.PrivateKey;
|
import java.security.PublicKey;
|
import java.security.spec.PKCS8EncodedKeySpec;
|
import java.security.spec.X509EncodedKeySpec;
|
import java.text.SimpleDateFormat;
|
import java.util.*;
|
|
import static com.nova.sankuai.infra.constants.ResultCode.BAD_REQUEST;
|
|
|
@Service
|
public class HuiFuBaoSignServiceImpl implements IHuiFuBaoSignService {
|
|
private static final Logger logger = LoggerFactory.getLogger("huibaofu-sign");
|
|
private static final String SERVER_URL = "https://pay.Heepay.com/API/PageSign/Index.aspx";
|
|
private static final String METHOD = "heepay.agreement.bank.sign.page";
|
|
@Value("${huifubao.merchId}")
|
private String merchId;
|
|
@Value("${huifubao.domainUrl}")
|
private String domainUrl;
|
|
@Value("${huifubao.returnSignUrl}")
|
private String returnSignUrl;
|
|
@Resource
|
private ICustomerUserService iCustomerUserService;
|
|
@Resource
|
private IHuifubaoSignRecordService iHuiFuBaoSignRecordService;
|
|
@Resource
|
private CustomerMapper customerMapper;
|
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public ResultJson signInfo(HuifubaoSignRecordVO vo, UserDetail userDetail) {
|
if (userDetail == null){
|
userDetail = new UserDetail();
|
}
|
LambdaQueryWrapper<CustomerUser> customerUserWrapper = new LambdaQueryWrapper<>();
|
customerUserWrapper.eq(CustomerUser::getPhone, userDetail.getPhone()).eq(CustomerUser::getDeleteFlag, 0);
|
List<CustomerUser> customerUserList = iCustomerUserService.list(customerUserWrapper);
|
|
if (CollUtil.isEmpty(customerUserList)) {
|
logger.error("手机查询用户不存在,手机号:{}", userDetail.getPhone());
|
// throw new CommonException("用户不存在");
|
return ResultJson.failure(BAD_REQUEST,"");
|
}
|
CustomerUser customerUser = customerUserList.stream().min(Comparator.comparing(CustomerUser::getCreationDate)).orElse(new CustomerUser());
|
LambdaQueryWrapper<HuifubaoSignRecord> huiFuBaoSignRecordWrapper = Wrappers.lambdaQuery();
|
huiFuBaoSignRecordWrapper.eq(HuifubaoSignRecord::getCustomerUserId,customerUser.getId());
|
huiFuBaoSignRecordWrapper.eq(HuifubaoSignRecord::getSignResult,SignStatusEnum.SUCCESS.getValue());
|
List<HuifubaoSignRecord> huifubaoSignRecordList = iHuiFuBaoSignRecordService.list(huiFuBaoSignRecordWrapper);
|
if (CollUtil.isNotEmpty(huifubaoSignRecordList)){
|
HuifubaoSignRecord huifubaoSignRecord = huifubaoSignRecordList.stream().distinct().findFirst().orElse(new HuifubaoSignRecord());
|
logger.error("该用户已录入 录入用户id:{},录入信息为:{}",customerUser.getId(),JSON.toJSONString(huifubaoSignRecord));
|
throw new CommonException("该用户已录入");
|
}
|
|
if (StrUtil.isEmpty(vo.getSignIdNo()) || StrUtil.isEmpty(vo.getSignName())
|
|| StrUtil.isEmpty(vo.getSignPhone()) || StrUtil.isEmpty(vo.getSignCardNumber())){
|
logger.error("录入参数不完整,请完善信息。vo:{}",JSON.toJSONString(vo));
|
return ResultJson.failure(BAD_REQUEST,"录入参数不完整,请完善信息。");
|
}
|
|
SignRequest signRequest = new SignRequest();
|
/**
|
* 业务参数
|
*/
|
BaseRequest baseRequest = new BaseRequest();
|
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
/* 子商户号,大商户子商户模式必传
|
signRequest.setSub_merch_id("");*/
|
|
signRequest.setNotify_url(domainUrl + "/api/v2/hfb/sign/callback");
|
signRequest.setReturn_url(returnSignUrl);
|
long tenDigitTimestamp = System.currentTimeMillis() / 1000;
|
//商户签约单号,自定义
|
String outTradeNo = String.valueOf(tenDigitTimestamp);
|
signRequest.setOut_trade_no(outTradeNo);
|
Date date = new Date();
|
signRequest.setOut_trade_time(sd.format(date));
|
//商户平台用户标识,自定义保证唯一
|
signRequest.setMerch_user_id(String.valueOf(customerUser.getId()));
|
//持卡人银行卡号,若传值页面自动代入
|
signRequest.setBank_card_no(vo.getSignCardNumber());
|
//持卡人姓名,若传值页面自动代入
|
signRequest.setBank_user_name(vo.getSignName());
|
//持卡人预留银行手机号,若传值页面自动代入
|
signRequest.setMobile(vo.getSignPhone());
|
//持卡人证据号码
|
signRequest.setCert_no(vo.getSignIdNo());
|
|
/**
|
** 公共请求参数
|
*/
|
CertRequest certRequest = new CertRequest();
|
//请求URL
|
certRequest.setServerUrl(SERVER_URL);
|
//商户编号,(汇付宝商户内码:七位整数数字)
|
certRequest.setMerchantId(merchId);
|
// certRequest.setMerchantId(signRequest.getSub_merch_id());
|
//版本号:固定值 1.0
|
certRequest.setVersion("1.0");
|
//具体业务接口名称
|
certRequest.setMethod(METHOD);
|
baseRequest.setBiz_content(JSON.toJSONString(signRequest));
|
//商户私钥
|
certRequest.setPrivateKeyStr(MyKey.privateKeystr);
|
//汇付宝公钥
|
certRequest.setPublicKeyStr(MyKey.publicKeystr);
|
baseRequest.setBiz_content(JSON.toJSONString(signRequest));
|
//请求汇付宝演
|
SignResponse response = doSignPost(baseRequest,certRequest);
|
if (!Objects.equals(response.getCode(), "10000")) {
|
String msg = response.getMsg();
|
if (StrUtil.isEmpty(msg)){
|
msg = SignStatusEnum.FAILED.getValue();
|
}
|
return ResultJson.failure(ResultCode.OPERATE_ERROR, msg);
|
}
|
//录入
|
HuifubaoSignRecord huifubaoSignRecord = new HuifubaoSignRecord();
|
BeanUtils.copyProperties(vo, huifubaoSignRecord);
|
huifubaoSignRecord.setSignOrderNo(outTradeNo);
|
huifubaoSignRecord.setCustomerUserId(customerUser.getId());
|
huifubaoSignRecord.setSignResult(SignStatusEnum.WAIT_CONFIRM.getValue());
|
huifubaoSignRecord.setCreationDate(date);
|
huifubaoSignRecord.setLastUpdatedDate(date);
|
iHuiFuBaoSignRecordService.saveOrUpdate(huifubaoSignRecord);
|
return ResultJson.ok(response);
|
}
|
|
@SneakyThrows
|
@Override
|
public ResponseEntity CallBack(SignCallBackVo vo) {
|
String outTradeNo = vo.getOut_trade_no();
|
String sign = vo.getSign();
|
String signNo = vo.getSign_no();
|
if (StrUtil.isEmpty(outTradeNo)){
|
logger.error("商户签约单号不能为空");
|
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("商户签约单号不能为空");
|
}
|
|
if (StrUtil.isEmpty(sign)){
|
logger.error("RSA签名结果不能为空");
|
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("RSA签名结果不能为空");
|
}
|
|
if (StrUtil.isEmpty(signNo)){
|
logger.error("支付授权码不能为空");
|
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("支付授权码不能为空");
|
}
|
//查询是否存在签约单
|
LambdaQueryWrapper<HuifubaoSignRecord> huifubaoSignRecordLambdaQueryWrapper = Wrappers.lambdaQuery();
|
huifubaoSignRecordLambdaQueryWrapper.eq(HuifubaoSignRecord::getSignOrderNo,outTradeNo);
|
HuifubaoSignRecord huifubaoSignRecord = iHuiFuBaoSignRecordService.getOne(huifubaoSignRecordLambdaQueryWrapper);
|
if (huifubaoSignRecord == null){
|
logger.error("系统中不存在当前商户签约单,单号:{}",outTradeNo);
|
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("系统中不存在当前商户签约单号:" + outTradeNo);
|
}
|
|
//decrypt为解密后的值
|
String decrypt = getKeyPath(signNo,0,false);
|
huifubaoSignRecord.setSignUniqueCode(decrypt);
|
huifubaoSignRecord.setLastUpdatedDate(new Date());
|
huifubaoSignRecord.setSignResult("签约成功");
|
iHuiFuBaoSignRecordService.saveOrUpdate(huifubaoSignRecord);
|
return ResponseEntity.ok("ok");
|
}
|
|
@Override
|
public ResultJson querySignStatus(HuifubaoSignRecordVO vo, HttpServletRequest request) {
|
String token = request.getHeader("Authorization");
|
UserDetail user = UserUtil.getUser(token);
|
if (Objects.isNull(user) || Objects.isNull(user.getId())) {
|
logger.error("Token无效 当前token:{}",token);
|
return ResultJson.failure(ResultCode.UNAUTHORIZED,"Token无效");
|
}
|
|
LambdaQueryWrapper<CustomerUser> customerUserWrapper = new LambdaQueryWrapper<>();
|
customerUserWrapper.eq(CustomerUser::getPhone, user.getPhone()).eq(CustomerUser::getDeleteFlag, 0);
|
List<CustomerUser> customerUserList = iCustomerUserService.list(customerUserWrapper);
|
|
if (CollUtil.isEmpty(customerUserList)) {
|
logger.error("手机查询用户不存在,手机号:{}", user.getPhone());
|
// throw new CommonException("用户不存在");
|
return ResultJson.failure(BAD_REQUEST,"");
|
}
|
CustomerUser customerUser = customerUserList.stream().min(Comparator.comparing(CustomerUser::getCreationDate)).orElse(new CustomerUser());
|
//判断是否录入系统
|
LambdaQueryWrapper<HuifubaoSignRecord> recordLambdaQueryWrapper = Wrappers.lambdaQuery();
|
recordLambdaQueryWrapper.eq(HuifubaoSignRecord::getCustomerUserId,customerUser.getId());
|
List<HuifubaoSignRecord> huifubaoSignRecordList = iHuiFuBaoSignRecordService.list(recordLambdaQueryWrapper);
|
|
if (CollUtil.isEmpty(huifubaoSignRecordList)){
|
logger.error("当前用户不存在 当前id:{}",user.getId());
|
return ResultJson.failure(ResultCode.OPERATE_ERROR,"当前用户不存在");
|
}
|
HuifubaoSignRecord huifubaoSignRecord = huifubaoSignRecordList.stream().min(Comparator.comparing(HuifubaoSignRecord::getCreationDate)).orElse(new HuifubaoSignRecord());
|
if (!Objects.equals(huifubaoSignRecord.getSignResult(), SignStatusEnum.SUCCESS.getValue())){
|
//枚举值不存在 会导致报错 抛出捕获预防参数不一致
|
logger.error("当前订单未成功签约,签约状态为:" + huifubaoSignRecord.getSignResult());
|
return ResultJson.failure(ResultCode.OPERATE_ERROR,"当前订单未成功签约,签约状态为:" + huifubaoSignRecord.getSignResult());
|
}
|
return ResultJson.ok(huifubaoSignRecord);
|
}
|
|
@Override
|
public boolean checkBeforePayment(Long id) {
|
CustomerUser customerUser = iCustomerUserService.getById(id);
|
//判断是否录入系统
|
LambdaQueryWrapper<HuifubaoSignRecord> recordLambdaQueryWrapper = Wrappers.lambdaQuery();
|
recordLambdaQueryWrapper.eq(HuifubaoSignRecord::getCustomerUserId,customerUser.getId());
|
List<HuifubaoSignRecord> huifubaoSignRecordList = iHuiFuBaoSignRecordService.list(recordLambdaQueryWrapper);
|
|
if (CollUtil.isEmpty(huifubaoSignRecordList)){
|
logger.error("当前用户不存在 当前id:{}",customerUser.getId());
|
return false;
|
}
|
HuifubaoSignRecord huifubaoSignRecord = huifubaoSignRecordList.stream().min(Comparator.comparing(HuifubaoSignRecord::getCreationDate)).orElse(new HuifubaoSignRecord());
|
if (!Objects.equals(huifubaoSignRecord.getSignResult(), SignStatusEnum.SUCCESS.getValue())){
|
//枚举值不存在 会导致报错 抛出捕获预防参数不一致
|
logger.error("当前订单未成功签约,签约状态为:" + huifubaoSignRecord.getSignResult());
|
return false;
|
}
|
return true;
|
}
|
|
@Override
|
public ShanTaiCheckVo checkProtocolSignBySt(HttpServletRequest request) {
|
String token = request.getHeader("Authorization");
|
UserDetail user = UserUtil.getUser(token);
|
if (user == null || user.getId() == null) {
|
throw new CommonException("Token无效");
|
}
|
CustomerUser customerUser = iCustomerUserService.getById(user.getId());
|
if (customerUser == null) {
|
throw new CommonException("用户不存在");
|
}
|
ShanTaiCheckVo checkVo = new ShanTaiCheckVo();
|
HuifubaoSignRecord signRecord = null;
|
List<HuifubaoSignRecord> signRecords = iHuiFuBaoSignRecordService.list(Wrappers.lambdaQuery(HuifubaoSignRecord.class).
|
eq(HuifubaoSignRecord::getCustomerUserId, customerUser.getId()).orderByDesc(HuifubaoSignRecord::getCreationDate));
|
if (!signRecords.isEmpty()) {
|
signRecord = signRecords.get(0);
|
}
|
if (signRecord != null && SignStatusEnum.SUCCESS.getValue().equals(signRecord.getSignResult())) {
|
checkVo.setSign(true);
|
checkVo.setSignCardNumber(signRecord.getSignCardNumber());
|
checkVo.setSignIdNo(signRecord.getSignIdNo());
|
checkVo.setSignName(signRecord.getSignName());
|
checkVo.setSignPhone(signRecord.getSignPhone());
|
} else {
|
checkVo.setSign(false);
|
}
|
return checkVo;
|
}
|
|
|
@SneakyThrows
|
private String getKeyPath(String value,Integer type,boolean isSign){
|
String str = "";
|
SignEncrypt signEncrypt = new SignEncrypt();
|
// 使用类名和常量名来访问常量
|
String publicKeystr = MyKey.publicKeystr;
|
String privateKeystr = MyKey.privateKeystr;
|
//密钥配置
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
byte[] publicKeyPath = Base64.decode(publicKeystr.getBytes());
|
byte[] privateKeyPath = Base64.decode(privateKeystr.getBytes());
|
PublicKey heepayPublicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyPath));
|
PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyPath));
|
//是否是签约加密
|
if (isSign){
|
str = signEncrypt.sign(value,privateKey);
|
}else if (type == 1){
|
//RSA加密
|
str = signEncrypt.encrypt(value, heepayPublicKey);
|
}else {
|
//RSA解密
|
str = signEncrypt.decrypt(value, privateKey);
|
}
|
return str;
|
}
|
|
private SignResponse doSignPost(BaseRequest baseRequest,CertRequest certRequest){
|
SignEncrypt signEncrypt = new SignEncrypt();
|
HttpUtil httpUtil = new HttpUtil();
|
// 使用类名和常量名来访问常量
|
String publicKeystr = MyKey.publicKeystr;
|
String privateKeystr = MyKey.privateKeystr;
|
PublicKey heepayPublicKey = null;
|
PrivateKey privateKey = null;
|
SignResponse signResponse = new SignResponse();
|
try {
|
baseRequest.setMerch_id(certRequest.getMerchantId());
|
baseRequest.setVersion(certRequest.getVersion());
|
baseRequest.setMethod(certRequest.getMethod());
|
//密钥配置
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
byte[] publicKeyPath = Base64.decode(publicKeystr.getBytes());
|
byte[] privateKeyPath = Base64.decode(privateKeystr.getBytes());
|
heepayPublicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyPath));
|
privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyPath));
|
|
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
baseRequest.setTimestamp(df.format(new Date()));
|
Map<String, String> map = Utils.convertBeanNoneEmpty(baseRequest);
|
String bizJson = Utils.coverMap2String(map);
|
logger.info("待签名:{}",bizJson);
|
//签名
|
String sign = signEncrypt.sign(bizJson, privateKey);
|
logger.info("签名后:{}",sign);
|
baseRequest.setSign(sign);
|
|
|
//bizContent加密
|
String content = signEncrypt.encrypt(baseRequest.getBiz_content(), heepayPublicKey);
|
logger.info("加密后:{}",content);
|
baseRequest.setBiz_content(content);
|
|
String res = httpUtil.sendJsonHttpPost(SERVER_URL, JSON.toJSONString(baseRequest));
|
logger.info("resq:{}",JSON.toJSONString(baseRequest));
|
logger.info("resp:{}",res);
|
|
//解析response 取到data并解密
|
ObjectMapper objectMapper = new ObjectMapper();
|
JsonNode jsonNode = objectMapper.readTree(res.toString());
|
String data = jsonNode.get("data").asText();
|
//decrypt为解密后的值
|
String decrypt = signEncrypt.decrypt(data, privateKey);
|
//继续解析解密后的值拿到sign_url
|
JsonNode jsonNode1 = objectMapper.readTree(decrypt.toString());
|
String sign_url = jsonNode1.get("sign_url").asText();
|
logger.info("sign_url:{}",sign_url);
|
|
if (StrUtil.isEmpty(res)) {
|
return new SignResponse();
|
}
|
BaseResponse response = JSONObject.parseObject(res, BaseResponse.class);
|
signResponse = JSON.parseObject(decrypt, SignResponse.class);
|
signResponse.setCode(response.getCode());
|
signResponse.setMsg(response.getMsg());
|
signResponse.setSub_code(response.getSub_code());
|
signResponse.setSub_msg(response.getSub_msg());
|
signResponse.setData(response.getData());
|
signResponse.setSign(response.getSign());
|
}catch (Exception e){
|
e.printStackTrace();
|
logger.error("签约状态异常,请求参数:{}",baseRequest);
|
throw new RuntimeException("签约异常");
|
}
|
return signResponse;
|
}
|
}
|