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 customerUserWrapper = new LambdaQueryWrapper<>(); customerUserWrapper.eq(CustomerUser::getPhone, userDetail.getPhone()).eq(CustomerUser::getDeleteFlag, 0); List 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 huiFuBaoSignRecordWrapper = Wrappers.lambdaQuery(); huiFuBaoSignRecordWrapper.eq(HuifubaoSignRecord::getCustomerUserId,customerUser.getId()); huiFuBaoSignRecordWrapper.eq(HuifubaoSignRecord::getSignResult,SignStatusEnum.SUCCESS.getValue()); List 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 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 customerUserWrapper = new LambdaQueryWrapper<>(); customerUserWrapper.eq(CustomerUser::getPhone, user.getPhone()).eq(CustomerUser::getDeleteFlag, 0); List 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 recordLambdaQueryWrapper = Wrappers.lambdaQuery(); recordLambdaQueryWrapper.eq(HuifubaoSignRecord::getCustomerUserId,customerUser.getId()); List 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 recordLambdaQueryWrapper = Wrappers.lambdaQuery(); recordLambdaQueryWrapper.eq(HuifubaoSignRecord::getCustomerUserId,customerUser.getId()); List 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 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 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; } }