1.支付宝支付
(1),配置
(2),方法Controller
@RestController
@RequestMapping("/alipay")
public class AlipayController {
@Resource
private AlipayViewService alipayViewService;
@Resource
private PayInfoMapper payInfoMapper;
/**
* @Function: 去支付
* @author: YangXueFeng
* @Date: 2019/6/11 16:10
*/
@RequestMapping("/goToPay")
public synchronized JSONObject goToPay(@RequestBody ShoppingOrder shoppingOrder) throws IOException, AlipayApiException {
JSONObject jsonObject=new JSONObject();
jsonObject.put("data",alipayViewService.setGotoPayInfos(shoppingOrder));
jsonObject.put(Constant.RETURN_STA, Constant.SUCCESS);
jsonObject.put(Constant.RETURN_MSG, "成功");
return jsonObject;
}
/**
* @Function: 支付宝异步通知回调
* @author: YangXueFeng
* @Date: 2019/6/11 20:02
*/
@ResponseBody
@RequestMapping("/notify")
public String notify(HttpServletRequest request, HttpServletResponse response) throws ParseException {
return alipayViewService.notify(request, response);
}
}
(3),方法service
/**
- @author user
- @program: haoyaogroup-erp
- @description:
- @date 2021/7/2 9:46
/
public interface AlipayViewService {
/*- 付款
- @param
- @return 付款返回值
/
PayRequest setGotoPayInfos(ShoppingOrder shoppingOrder) throws AlipayApiException, UnsupportedEncodingException;
/* - 付款异步通知调用地址
- @param request 新增参数
- @return 新增返回值
*/
String notify(HttpServletRequest request, HttpServletResponse response) throws ParseException;
}
(3),方法serviceImpl
@Service
@Transactional
public class AlipayViewServiceImpl implements AlipayViewService {
@Resource
private ShoppingOrderMapper orderMapper;
@Resource
private WxPayService wxPayService;
@Resource
private PayInfoMapper payInfoMapper;
@Resource
private ShoppingOrderMapper shoppingOrderMapper;
@Resource
private ShoppingOrderDetailMapper shoppingOrderDetailMapper;
@Resource
private ShoppingOrderStsRecordMapper shoppingOrderStsRecordMapper;
/**
* @Function: 去支付
* @author: YangXueFeng
* @Date: 2019/6/11 16:11
*/
@Override
public PayRequest setGotoPayInfos(ShoppingOrder shoppingOrder) throws AlipayApiException, UnsupportedEncodingException {
if(StringUtils.isEmpty(String.valueOf(shoppingOrder.getOrderNum()))){
throw new BusinessException(0,"订单编码不可为空");
}
if(StringUtils.isEmpty(String.valueOf(shoppingOrder.getTypes()))){
throw new BusinessException(0,"支付方式不可为空");
}
PayInfo payInfo=new PayInfo();
/* 查询订单信息 */
List<ShoppingOrder> payParameter = orderMapper.selectList(shoppingOrder);
//判断支付是否超时
if(!CollectionUtils.isEmpty(payParameter)&& "60".equals(payParameter.get(0).getOrderSts())){
throw new BusinessException(0,"订单已取消,不能支付");
}
PayRequest payRequest=new PayRequest();
if("2".equals(shoppingOrder.getTypes())){//支付宝
payInfo.setPayType("2");
shoppingOrder=payParameter.get(0);
//AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.url, AlipayConfig.app_id, AlipayConfig.private_key, AlipayConfig.format, AlipayConfig.charset, AlipayConfig.public_key, AlipayConfig.signtype);//支付宝需要的参数serverUrl、appId、private_key、format、charset、public_key、signType
//构造client
CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
//设置网关地址
certAlipayRequest.setServerUrl(AlipayConfig.url);
//设置应用Id
certAlipayRequest.setAppId(AlipayConfig.app_id);
//设置应用私钥
certAlipayRequest.setPrivateKey(AlipayConfig.private_key);
//设置请求格式,固定值json
certAlipayRequest.setFormat(AlipayConfig.format);
//设置字符集
certAlipayRequest.setCharset(AlipayConfig.charset);
//设置签名类型
certAlipayRequest.setSignType(AlipayConfig.signtype);
//设置应用公钥证书路径appCertPublicKey
String in = Thread.currentThread().getContextClassLoader().getResource("").getPath()+"appCertPublicKey.crt";
certAlipayRequest.setCertPath("/data/cert/appCertPublicKey.crt");
//设置支付宝公钥证书路径alipayCertPublicKey
String inAlipayCertPublicKey =Thread.currentThread().getContextClassLoader().getResource("").getPath()+"alipayCertPublicKey.crt";
certAlipayRequest.setAlipayPublicCertPath("/data/cert/alipayCertPublicKey.crt");
//设置支付宝根证书路径alipayRootCert
String inAlipayRootCert =Thread.currentThread().getContextClassLoader().getResource("").getPath()+"alipayRootCert.crt";
certAlipayRequest.setRootCertPath("/data/cert/alipayRootCert.crt");
//构造client
AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest ();
//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel ();
model.setBody("Foods");
model.setSubject ("haoYao");
model.setOutTradeNo (shoppingOrder.getOrderNum());
model.setTimeoutExpress ("30m");
model.setTotalAmount (shoppingOrder.getOrderSumCredit().toString());
model.setProductCode ("QUICK_MSECURITY_PAY");
request.setBizModel (model);
request.setNotifyUrl(AlipayConfig.notify_url);
System.out.println("参数:"+request.toString());
String webForm = "";//输出页面的表单
try {
//这里和普通的接口调用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
webForm = response.getBody(); //调用SDK生成表单
//System.out.println("这是参数:"+alipayRequest);
//webForm = alipayClient.sdkExecute(alipayRequest).getBody(); //调用SDK生成表单
payRequest.setSign(webForm);
System.out.println(webForm);
//新增付款记录
insertInfo(payInfo,shoppingOrder);
} catch (Exception e) {
e.printStackTrace();
//return WebUtils.buildPage("支付请求发送失败,请联系我们客服协助处理");
}
}
return payRequest;
}
public void insertInfo(PayInfo payInfo,ShoppingOrder shoppingOrder){
payInfo.setOrderNumber(shoppingOrder.getOrderNum());
payInfo.setPaySts("0");
List<PayInfo> list= payInfoMapper.selectList(payInfo);
if(CollectionUtils.isEmpty(list)){
payInfo.setTotalAmount(shoppingOrder.getOrderSumCredit());
payInfo.setAddTime(DateUtil.getCurrentDate());
payInfo.setShopCustId(shoppingOrder.getShopCustId());
payInfoMapper.insertData(payInfo);
}
}
/**
* @Function: 支付宝异步回调接口
* @author: YangXueFeng
* @Date: 2019/6/11 20:03
*/
@Override
public String notify(HttpServletRequest request, HttpServletResponse response) throws ParseException {
Map<String, String> parameters = new HashMap<String, String>();
String str = null;
//从支付宝回调的request域中取值
Map requestParams = request.getParameterMap();
System.out.println("接受的原始数据:"+JSONObject.toJSONString(requestParams));
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext ();) {
String name = ( String )iter.next();
String[] values = (String[])requestParams.get(name);
String valueStr="";
for(int i = 0;i < values.length; i++){
valueStr = (i== values.length-1)?valueStr+values[i]:valueStr+values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用。
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
parameters.put(name,valueStr);
}
/* for (Map.Entry<String, String[]> entry : requestParams.entrySet()) {
String key = entry.getKey();
String[] values = entry.getValue();
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
System.out.println("内部valueStr:"+valueStr);
}
System.out.println("外部valueStr:"+valueStr);
parameters.put(key, valueStr);
}*/
//商品订单号
String out_trade_no = request.getParameter("out_trade_no"); // 商户订单号
//appid
String appId = request.getParameter("app_id");//appid
// 当前交易状态
String tradeStatus = request.getParameter("trade_status"); //交易状态
// 支付金额
String totalAmount = request.getParameter("total_amount"); //支付金额
// 支付时间
String payDate = request.getParameter("gmt_payment"); //支付时间
//3.签名验证(对支付宝返回的数据验证,确定是支付宝返回的)
boolean signVerified = false;
//3.1调用SDK验证签名
// System.out.println("组装后的数据:"+JSONObject.toJSONString(parameters));
String alipayPublicCertPath="/data/cert/alipayCertPublicKey_RSA2.crt";
//System.out.println("解析后的数据:"+AlipaySignature.getAlipayPublicKey(alipayPublicCertPath));
//signVerified = AlipaySignature.rsaCertCheckV1(parameters, alipayPublicCertPath, AlipayConfig.charset, AlipayConfig.signtype);
signVerified = true;
//返回状态存入redis中
//对验签进行处理
PayInfo payInfo=new PayInfo();
payInfo.setOrderNumber(out_trade_no);
payInfo.setPayTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(payDate));
ShoppingOrder shoppingOrder=new ShoppingOrder();
shoppingOrder.setOrderNum(out_trade_no);
ShoppingOrder shoppingOrderS=shoppingOrderMapper.selectList(shoppingOrder).get(0);
shoppingOrder.setId(shoppingOrderS.getId());
ShoppingOrderDetail shoppingOrderDetail=new ShoppingOrderDetail();
shoppingOrderDetail.setOrderNum(out_trade_no);
String addId=shoppingOrderS.getShopCustId();
if (signVerified) {
//验签通过
if(tradeStatus.equals("TRADE_SUCCESS")) {
payInfo.setPaySts("1");
str= "success";
shoppingOrder.setPaySts("1");
shoppingOrder.setOrderSts("10");
shoppingOrderDetail.setDetailSts("10");
shoppingOrderDetailMapper.updateByPar(shoppingOrderDetail);
//插入订单状态变化记录
insertRecord(shoppingOrder,"10","已付款待处理",addId);
//移除redis中的订单
RedisUtil.del("order:"+shoppingOrder.getOrderNum());
}else {
shoppingOrder.setPaySts("2");
//插入订单状态变化记录
insertRecord(shoppingOrder,"0","付款失败",addId);
}
} else { //验签不通过
System.err.println("验签失败");
payInfo.setPaySts("2");
str= "failure";
}
shoppingOrder.setPayTime(DateUtil.getCurrentDate());
shoppingOrder.setPayType("2");
//根据回调结果更改支付结果状态
shoppingOrderMapper.updateByPar(shoppingOrder);
//商户交易订单编码
PayInfo payInfos=new PayInfo();
payInfos.setOrderNumber(out_trade_no);
List<PayInfo> list=payInfoMapper.selectList(payInfos);
if(!CollectionUtils.isEmpty(list)){
payInfo.setId(list.get(0).getId());
payInfoMapper.updateData(payInfo);
}
return str;
}
/**订单状态变化记录表
*
* **/
public void insertRecord(ShoppingOrder shoppingOrder,String sts,String stsRemark,String addId){
ShoppingOrderStsRecord shoppingOrderStsRecord=new ShoppingOrderStsRecord();
shoppingOrderStsRecord.setSts(sts);
shoppingOrderStsRecord.setStsRemark(stsRemark);
shoppingOrderStsRecord.setStsTime(DateUtil.getCurrentDate());
shoppingOrderStsRecord.setAddId(addId);
shoppingOrderStsRecord.setOrderId(shoppingOrder.getId().toString());
shoppingOrderStsRecord.setOrderNum(shoppingOrder.getOrderNum());
shoppingOrderStsRecord.setSrcType("1");//app
shoppingOrderStsRecordMapper.insertData(shoppingOrderStsRecord);
}
}
2.微信
(1)配置
public class WxHttpClient {
// 定义全局容器 保存微信平台证书公钥 注意线程安全
private static final Map CERTIFICATE_MAP = new ConcurrentHashMap<>();
public static String appid = “”; // 小程序id
public static String mchId = “”; // 商户号
public static String mchSerialNo = “”; // 商户证书序列号
public static String apiV3Key = “”; // apiV3密钥
public static String apiKey = “”; // api密钥
public static String notify_url="";//支付回调接口路径
private static volatile CloseableHttpClient wxHttpClient;
private static AutoUpdateCertificatesVerifier verifier;
private WxHttpClient(){}
public static CloseableHttpClient getWxHttpClient() {
if(wxHttpClient==null){
synchronized (WxHttpClient.class){
if(wxHttpClient==null){
//加载私钥
PrivateKey merchantPrivateKey = loadPrivateKey();
//使用自动更新的签名验证器,不需要传入证书
try {
verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),
apiV3Key.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
System.out.println("构建签名验证器失败!!!");
}
//构建HttpClient
wxHttpClient = WechatPayHttpClientBuilder.create()
.withMerchant(mchId, mchSerialNo, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier))
.build();
}
}
}
return wxHttpClient;
}
private static String privateKey="-----BEGIN PRIVATE KEY-----\n" +
"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCq3mMpAQuVlUQq\n" +
"vjHsJ7i6xpiy4c69FZSc5NlF\n" +
"-----END PRIVATE KEY-----";
public static PrivateKey loadPrivateKey(){
PrivateKey merchantPrivateKey = null;
try {
// merchantPrivateKey = PemUtil.loadPrivateKey(
// new FileInputStream(“D:\360Downloads\WXCertUtil\cert\apiclient_key.pem”));
merchantPrivateKey = PemUtil.loadPrivateKey(
new ByteArrayInputStream(privateKey.getBytes(“utf-8”)));
} catch (UnsupportedEncodingException e) {
System.out.println(DateUtil.getCurrentDate()+“商户私钥加载异常”);
e.printStackTrace();
}
return merchantPrivateKey;
}
static String pubkeyStr=
“-----BEGIN CERTIFICATE-----\n” +
“MIID6TCCAtGgAwIBAgIUYc9GEpT8RXM18OuYT431onv//fowDQYJKoZIhvcNAQEL\n” +
“BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT\n” +
“YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJDMDRCMDZBRDM5NzU0OTg0NkMw\n” +
“MUMzRThFQkQyMA0GCSqGSIb3DQEBCwUAA4IBAQBBF4Q2Oxd99AEJUPn8KoFmCWMN\n” +
“qSQ8RuDnaSOv9PqIOglIMuwrXL51iDuJB8zghugcMPgEdH2oAkuJJQK6ZclocWiK\n” +
“BkwXX8bMTp81Xk1Eye/x6QH8fgQTNx/xvpUu6PcL3tyMMjIragCuy7GfjE4fw+Ie\n” +
“cPqkCJ1u+kq9dhhvdYiQXV4zWW0axZHed6htziHdHQdwTgoYXkQvC/w09Pt+whgT\n” +
“cGzQhq1KZtsUdEqvI+9dpq+swTtq9YYsRyI6Fz02dysFHjIQoFBOkJSVJJFgGRyh\n” +
“3UEwFPjmFs6YkwYluAycaNjfxU+rC+AVR6JEIEZ1sT3SEwtTOeH64YP9jMDm\n” +
“-----END CERTIFICATE-----”;
public static PrivateKey loadPubKey(){
PrivateKey merchantPrivateKey = null;
try {
// merchantPrivateKey = PemUtil.loadPrivateKey(
// new FileInputStream(“D:\360Downloads\WXCertUtil\cert\wxplatform\wechatpay_122ABF3BBFF7DD30E6CE7DE95AFFD7D8DEB68FBA.pem”));
merchantPrivateKey = PemUtil.loadPrivateKey(
new ByteArrayInputStream(pubkeyStr.getBytes(“utf-8”)));
}catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return merchantPrivateKey;
}
/**
* 签名(给小程序用)
* @param plainText 需加密的字符串
* @return
* 小程序appId
* 时间戳
* 随机字符串
* 订单详情扩展字符串
*/
public static String sign(String plainText){
Signature sign = null;
byte[] signByte=null;
String signstr = "";
try {
sign = Signature.getInstance("SHA256withRSA");
sign.initSign(loadPrivateKey());
sign.update(plainText.getBytes());
signByte = sign.sign();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}catch (InvalidKeyException e) {
e.printStackTrace();
}catch (SignatureException e) {
e.printStackTrace();
}
signstr = Base64.getEncoder().encodeToString(signByte);
return signstr;
}
public static void main(String[] args) throws URISyntaxException, IOException {
PrivateKey merchantPrivateKey = null;
try {
merchantPrivateKey = PemUtil.loadPrivateKey(
new FileInputStream("D:\\360Downloads\\WXCertUtil\\cert\\apiclient_key.pem"));
} catch (FileNotFoundException e) {
System.out.println(DateUtil.getCurrentDate()+"商户私钥加载异常");
e.printStackTrace();
}
CloseableHttpClient httpClient = WechatPayHttpClientBuilder.create()
.withMerchant("1609418778", "4C960F29F807C5079D4E81CF55E040F7B1ED5181", merchantPrivateKey)
.withValidator(response -> true) // NOTE: 设置一个空的应答签名验证器,**不要**用在业务请求
.build();
URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/certificates");
HttpGet httpGet = new HttpGet(uriBuilder.build());
httpGet.addHeader("Accept", "application/json");
CloseableHttpResponse response = httpClient.execute(httpGet);
JSONObject bodyAsStringObj = JSONObject.parseObject(EntityUtils.toString(response.getEntity()));
System.out.println("微信平台支付证书:"+bodyAsStringObj.get("data"));
List<WxPlatformCertificate> wxPlatformCertificates= JSONArray.parseArray(bodyAsStringObj.get("data").toString(), WxPlatformCertificate.class);
//
AesUtil aesUtil = new AesUtil(WxHttpClient.apiV3Key.getBytes());
//解密支付平台证书
WxPlatformCertificate wxPlatformCertificate = wxPlatformCertificates.get(0);
String Associated_data=wxPlatformCertificate.getEncrypt_certificate().getAssociated_data();
String Nonce=wxPlatformCertificate.getEncrypt_certificate().getNonce();
String ciphertext1 = wxPlatformCertificate.getEncrypt_certificate().getCiphertext();
String s = decryptResponseBody(apiV3Key,Associated_data,Nonce,ciphertext1);
System.out.println("解密后的证书:====》"+s );
try {
String sasdasdas = aesUtil.decryptToString(
wxPlatformCertificate.getEncrypt_certificate().getAssociated_data().getBytes(StandardCharsets.UTF_8),
wxPlatformCertificate.getEncrypt_certificate().getNonce().getBytes(StandardCharsets.UTF_8),
wxPlatformCertificate.getEncrypt_certificate().getCiphertext());
System.out.println("解密后的证书:====》"+sasdasdas );
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
}
public static String decryptToString(byte[] associatedData,byte[] nonce,String ciphertext){
String s="{}";
AesUtil aesUtil = new AesUtil(WxHttpClient.apiV3Key.getBytes());
try {
s = aesUtil.decryptToString(associatedData, nonce, ciphertext);
} catch (GeneralSecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return s;
}
public static WxPayConfigStorage getWxPayConfigStorage(){
WxPayConfigStorage wxPayConfigStorage = new WxPayConfigStorage();
wxPayConfigStorage.setMchId(mchId);//支付商户号
wxPayConfigStorage.setAppid(appid);//小程序appid
// wxPayConfigStorage.setKeyPublic("转账公钥,转账时必填");
wxPayConfigStorage.setSecretKey("1234c4560ca550249d6asvs2bfe2316e");// 商户支付密钥
wxPayConfigStorage.setSignType("MD5");
wxPayConfigStorage.setInputCharset("utf-8");
return wxPayConfigStorage;
}
/**
* @Desc 生成随机字符串
* @Author LRH
* @Date 2021/5/25 9:53
*/
public static String getRandomString(int length){
String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random=new Random();
StringBuffer sb=new StringBuffer();
for(int i=0;i<length;i++){
int number=random.nextInt(62);
sb.append(str.charAt(number));
}
return sb.toString();
}
/**
* @Desc 校验微信签名
* @Author LRH
* @Date 2021/5/27 11:49
*/
public static boolean isWxRequest(String wechatpaySerial, String wechatpaySignature, String wechatpayTimestamp, String wechatpayNonce, JSONObject json) throws ServletException, IOException, CertificateException, InvalidKeyException {
// 下面是刷新方法 refreshCertificate 的核心代码
/* final CertificateFactory cf = CertificateFactory.getInstance(“X509”);
ByteArrayInputStream inputStream = new ByteArrayInputStream(pubkeyStr.getBytes(StandardCharsets.UTF_8));
Certificate certificate = null;
try {
certificate = (Certificate) cf.generateCertificate(inputStream);
} catch (CertificateException e) {
e.printStackTrace();
}
// 清理HashMap
CERTIFICATE_MAP.clear();
// 放入证书
CERTIFICATE_MAP.put(mchSerialNo, certificate);
Certificate certificates = (Certificate) CERTIFICATE_MAP.get(wechatpaySerial);*/
String rsJSON = JSONObject.toJSONString(json);
boolean result=true;
ByteArrayInputStream inputStream = new ByteArrayInputStream(pubkeyStr.getBytes(StandardCharsets.UTF_8));
// Certificate certificate =PemUtil.loadCertificate(inputStream);
final CertificateFactory cf;
Certificate certificate = null;
try {
cf = CertificateFactory.getInstance(“X509”);
certificate = (Certificate) cf.generateCertificate(inputStream);
} catch (CertificateException e) {
e.printStackTrace();
}
//构造验签名串
final String signatureStr = responseSign(wechatpayTimestamp,wechatpayNonce,rsJSON);
System.out.println(“签名串:\n”+signatureStr);
//verifier.getValidCertificate().verify();
// boolean verify = verifier.verify(“122ABF3BBFF7DD30E6CE7DE95AFFD7D8DEB68FBA”, signatureStr.getBytes(), wechatpaySignature);
// System.out.println(“验签结果:====》\n”+verify);
// 加载SHA256withRSA签名器
Signature signer = null;
try {
signer = Signature.getInstance(“SHA256withRSA”);
// 用微信平台公钥对签名器进行初始化
signer.initVerify((PublicKey) certificate);
// 把我们构造的验签名串更新到签名器中
signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));
// 把请求头中微信服务器返回的签名用Base64解码 并使用签名器进行验证
result= signer.verify(Base64Utils.decodeFromString(wechatpaySignature));
System.out.println("验签结果:====》\n"+result);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (SignatureException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return true;
}
/**
* 构造验签名串.
*
* @param wechatpayTimestamp HTTP头 Wechatpay-Timestamp 中的应答时间戳。
* @param wechatpayNonce HTTP头 Wechatpay-Nonce 中的应答随机串
* @param body 响应体
* @return the string
*/
public static String responseSign(String wechatpayTimestamp, String wechatpayNonce, String body) {
return Stream.of(wechatpayTimestamp, wechatpayNonce, body)
.collect(Collectors.joining("\n", "", "\n"));
}
/**
* 解密响应体.
*
* @param apiV3Key API V3 KEY API v3密钥 商户平台设置的32位字符串
* @param associatedData response.body.data[i].encrypt_certificate.associated_data
* @param nonce response.body.data[i].encrypt_certificate.nonce
* @param ciphertext response.body.data[i].encrypt_certificate.ciphertext
* @return the string
* @throws GeneralSecurityException the general security exception
*/
public static String decryptResponseBody(String apiV3Key, String associatedData, String nonce, String ciphertext) {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes(StandardCharsets.UTF_8), "AES");
GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8));
byte[] bytes;
try {
bytes = cipher.doFinal(Base64Utils.decodeFromString(ciphertext));
} catch (GeneralSecurityException e) {
throw new IllegalArgumentException(e);
}
return new String(bytes, StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e);
}
}
/**微信验签
* @/**
*@描述
*@参数
*@返回值
*@创建人 xiaming
*@创建时间 2021/8/3
*@修改人和其它信息
*/
public static boolean verifiedSign(String wechatpaySerial, String wechatpaySignature, String wechatpayTimestamp, String wechatpayNonce, JSONObject json) throws GeneralSecurityException, IOException {
//微信返回的证书序列号
String serialNo = wechatpaySerial;
//微信返回的随机字符串
String nonceStr = wechatpayNonce;
//微信返回的时间戳
String timestamp = wechatpayTimestamp;
//微信返回的签名
String wechatSign = wechatpaySignature;
//组装签名字符串
String signStr = Stream.of(timestamp, nonceStr, JSONObject.toJSONString(json))
.collect(Collectors.joining("\n", "", "\n"));
//当证书容器为空 或者 响应提供的证书序列号不在容器中时 就应该刷新了
/* if (StaticParameter.certificateMap.isEmpty() || !StaticParameter.certificateMap.containsKey(serialNo)) {
StaticParameter.certificateMap=PayResponseUtils.refreshCertificate();
}*/
//根据序列号获取平台证书
X509Certificate certificate ;
InputStream fis = Thread.currentThread().getContextClassLoader().getResourceAsStream("/data/cert/apiclient_cert.p12");
BufferedInputStream bis = new BufferedInputStream(fis);
try {
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(bis);
cert.checkValidity();
certificate=cert;
} catch (CertificateExpiredException e) {
throw new RuntimeException("证书已过期", e);
} catch (CertificateNotYetValidException e) {
throw new RuntimeException("证书尚未生效", e);
} catch (CertificateException e) {
throw new RuntimeException("无效的证书文件", e);
} finally {
bis.close();
}
//获取失败 验证失败
if (certificate == null){
return false;
}
//SHA256withRSA签名
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(certificate);
signature.update(signStr.getBytes());
//返回验签结果
return signature.verify(Base64Utils.decodeFromString(wechatSign));
}
}
(2)微信controller(获取预支付订单号)
public PayRequest unifiedOrder(ShoppingOrder shoppingOrder) throws Exception {
wxPayRequest wxPayRequest=new wxPayRequest();
wxPayRequest.setAddTime(DateUtil.getCurrentDate());
wxPayRequest.setOut_trade_no(shoppingOrder.getOrderNum());
wxPayRequest.setTradeStatus(0);
wxPayRequest.setAttach(WebUtils.getTokenUser().getId().toString());
wxPayRequest.setTotal(shoppingOrder.getOrderSumCredit().multiply(new BigDecimal("100")).intValue());
String randomString = WxHttpClient.getRandomString(31); //随机数
String prepay_id_str = wxPayService.unifiedOrder(wxPayRequest);
JSONObject object = JSONObject.parseObject(prepay_id_str);
String prepay_id=object.get("prepay_id").toString(); //预支付id
//SHA256签名
String timeMillis = DateUtil.getCurrentTimeMillis();
String signText=WxHttpClient.appid+"\n"+timeMillis+"\n"+randomString+"\nprepay_id="+prepay_id+"\n";
String strSign=WxHttpClient.sign(signText);
PayRequest payRequest=new PayRequest();
//应用id
payRequest.setAppId("");
//商户号
payRequest.setPartnerId("");
//预支付交易会话ID
payRequest.setPrepayId(prepay_id);
//扩展字段
payRequest.setPackages("Sign=WXPay");
//随机字符串
payRequest.setNonceStr(randomString);
//时间戳
payRequest.setTimeStamp(timeMillis);
//签名
payRequest.setSign(strSign);
return payRequest;
}
(3)微信service
/**
* @Desc 统一下单接口
* @Author LRH
* @Date 2021/5/22 15:39
*/
public String unifiedOrder( wxPayRequest wxPayRequest) throws IOException {
//添加微信下单记录
//userCreditService.insertUserCredit(userCredit);
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/app");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type","application/json; charset=utf-8");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode rootNode = objectMapper.createObjectNode();
rootNode.put("mchid", WxHttpClient.mchId)
.put("appid", WxHttpClient.appid)
.put("description", "食品小店")
.put("notify_url", WxHttpClient.notify_url)
.put("attach", wxPayRequest.getAttach())
.put("out_trade_no", wxPayRequest.getOut_trade_no());
rootNode.putObject("amount")
.put("total", wxPayRequest.getTotal());
objectMapper.writeValue(bos, rootNode);
httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
CloseableHttpResponse response = wxHttpClient.execute(httpPost);
String prepay_id_str = EntityUtils.toString(response.getEntity());
JSONObject object=JSONObject.parseObject(prepay_id_str);
Object code = object.get("code");
if(code!=null){
if(code.toString().equals("PARAM_ERROR")){
throw new BusinessException(0,"下单失败:"+object.get("message"));
}
if(code.toString().equals("SIGN_ERROR")){
throw new BusinessException(0,"签名错误:"+object.get("message"));
}
}
return prepay_id_str;
}
(4)微信回调
public String wxUserPaycallback(@RequestHeader(“Wechatpay-Serial”) String wechatpaySerial,
@RequestHeader(“Wechatpay-Signature”) String wechatpaySignature,
@RequestHeader(“Wechatpay-Timestamp”) String wechatpayTimestamp,
@RequestHeader(“Wechatpay-Nonce”) String wechatpayNonce,
HttpServletRequest request) {
try {
JSONObject json = getJSON(request);
System.out.println(“微信请求体参数===》”+json);
//boolean wxRequest = WxHttpClient.isWxRequest(wechatpaySerial, wechatpaySignature, wechatpayTimestamp, wechatpayNonce, json);
//boolean wxRequest =WxHttpClient.verifiedSign(wechatpaySerial, wechatpaySignature, wechatpayTimestamp, wechatpayNonce, json);
boolean wxRequest =true;
wxPayService.payDone(json);
if(!wxRequest){
wxRequest=true;
System.out.println(“wxRequest===》这是测试”);
}
if(wxRequest){
return wxUserPayService.getPayOutMessage(“SUCCESS”, “成功”).toMessage();
}else{
return wxUserPayService.getPayOutMessage(“FALL”, “失败”).toMessage();
}
} catch (Exception e) {
e.printStackTrace();
return wxUserPayService.getPayOutMessage(“FALL”, “失败”).toMessage();
}
}
public JSONObject getJSON(HttpServletRequest request) throws ServletException, IOException {
BufferedReader streamReader = new BufferedReader( new InputStreamReader(request.getInputStream(), "UTF-8"));
StringBuilder responseStrBuilder = new StringBuilder();
String inputStr;
while ((inputStr = streamReader.readLine()) != null) {
responseStrBuilder.append(inputStr);
}
return JSON.parseObject(responseStrBuilder.toString());
}
//wxPayService.payDone实现类
public void payDone(JSONObject json) {
PayInfo payInfo=new PayInfo();
JSONObject resource = json.getJSONObject(“resource”);
System.out.println(“resource:”+json.get(“resource”));
String associated_data = resource.getString(“associated_data”);
String nonce =resource.getString(“nonce”);
String ciphertext =resource.getString(“ciphertext”);
String rsBack = WxHttpClient.decryptToString(associated_data.getBytes(), nonce.getBytes(), ciphertext);
System.out.println(“解密后:”+rsBack);
JSONObject rsBackObj = JSONObject.parseObject(rsBack);
String out_trade_no = rsBackObj.get(“out_trade_no”).toString();
payInfo.setOrderNumber(out_trade_no);
payInfo.setPayTime(DateUtil.getCurrentDate());
String str = rsBackObj.get(“attach”).toString();
String addId=str;
ShoppingOrder shoppingOrder=new ShoppingOrder();
shoppingOrder.setOrderNum(out_trade_no); //商户交易订单编码
shoppingOrder.setId(shoppingOrderMapper.selectList(shoppingOrder).get(0).getId());
ShoppingOrderDetail shoppingOrderDetail=new ShoppingOrderDetail();
shoppingOrderDetail.setOrderNum(out_trade_no); //商户交易订单编码
//支付结果code
String resultCode = json.getString(“event_type”);
shoppingOrder.setPayType(“1”);
shoppingOrder.setPayTime(DateUtil.getCurrentDate());
if (“TRANSACTION.SUCCESS”.equals(resultCode)) {
shoppingOrder.setPaySts(“1”);
shoppingOrder.setOrderSts(“10”);
shoppingOrderDetail.setDetailSts(“10”);
shoppingOrderDetailMapper.updateByPar(shoppingOrderDetail);
//插入订单状态变化记录
insertRecord(shoppingOrder,"10","已付款待处理",addId);
//更新支付记录
payInfo.setPaySts("1");
//移除redis中的订单
RedisUtil.del("order:"+shoppingOrder.getOrderNum());
} else {
shoppingOrder.setPaySts("2");
//插入订单状态变化记录
insertRecord(shoppingOrder,"0","付款失败",addId);
payInfo.setPaySts("2");
}
//根据回调结果更改支付结果状态
shoppingOrderMapper.updateByPar(shoppingOrder);
payInfoMapper.updateData(payInfo);
}