Merge remote-tracking branch 'origin/bugfix/wechatcallback'
# Conflicts: # src/main/resources/weChatConfig.properties
This commit is contained in:
@@ -1,39 +1,30 @@
|
|||||||
package com.peanut.modules.pay.weChatPay.config;
|
package com.peanut.modules.pay.weChatPay.config;
|
||||||
|
|
||||||
import cn.hutool.core.io.resource.ClassPathResource;
|
|
||||||
import cn.hutool.core.io.resource.Resource;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|
||||||
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
|
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
|
||||||
import com.wechat.pay.contrib.apache.httpclient.auth.*;
|
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
|
||||||
|
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
|
||||||
|
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
|
||||||
|
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
|
||||||
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
|
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
|
||||||
import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException;
|
import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException;
|
||||||
import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException;
|
import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException;
|
||||||
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
|
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
|
||||||
import io.swagger.annotations.ApiOperation;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.Value;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.junit.After;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.junit.Before;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.PropertySource;
|
import org.springframework.context.annotation.PropertySource;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||||
import org.springframework.util.ResourceUtils;
|
import org.springframework.util.ResourceUtils;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.*;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.io.Serializable;
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.util.Enumeration;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,104 +34,71 @@ import java.util.Enumeration;
|
|||||||
@Configuration
|
@Configuration
|
||||||
@Data
|
@Data
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ConfigurationProperties(prefix = "wxpay") //读取wxpay节点
|
@PropertySource(value = "classpath:weChatConfig.properties") //读取配置文件
|
||||||
@PropertySource(value = "classpath:weChatConfig.properties" ) //读取配置文件
|
|
||||||
//@Component
|
|
||||||
public class WechatPayConfig implements Serializable {
|
public class WechatPayConfig implements Serializable {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* APPID
|
* APPID
|
||||||
*/
|
*/
|
||||||
|
@Value("${wxpay.appId}")
|
||||||
private String appId;
|
private String appId;
|
||||||
/**
|
/**
|
||||||
* 商户号
|
* 商户号
|
||||||
*/
|
*/
|
||||||
|
@Value("${wxpay.mchId}")
|
||||||
private String mchId;
|
private String mchId;
|
||||||
/**
|
/**
|
||||||
* 服务商商户号
|
* pay url
|
||||||
*/
|
*/
|
||||||
|
@Value("${wxpay.payUrl}")
|
||||||
private String slMchId;
|
private String payUrl;
|
||||||
/**
|
/**
|
||||||
* APIv2密钥
|
* 回调地址
|
||||||
*/
|
|
||||||
|
|
||||||
private String apiKey;
|
|
||||||
/**
|
|
||||||
* APIv3密钥
|
|
||||||
*/
|
|
||||||
|
|
||||||
private String apiV3Key;
|
|
||||||
/**
|
|
||||||
* 支付通知回调地址
|
|
||||||
*/
|
*/
|
||||||
|
@Value("${wxpay.notifyUrl}")
|
||||||
private String notifyUrl;
|
private String notifyUrl;
|
||||||
|
/**
|
||||||
|
* key
|
||||||
|
*/
|
||||||
|
@Value("${wxpay.apiV3Key}")
|
||||||
|
private String apiV3Key;
|
||||||
/**
|
/**
|
||||||
* 退款回调地址
|
* 退款回调地址
|
||||||
*/
|
*/
|
||||||
|
@Value("${wxpay.refundNotifyUrl}")
|
||||||
private String refundNotifyUrl;
|
private String refundNotifyUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API 证书中的 key.pem 商户私钥
|
* API 证书中的 key.pem 商户私钥
|
||||||
*/
|
*/
|
||||||
|
@Value("${wxpay.keyPemPath}")
|
||||||
private String keyPemPath;
|
private String keyPemPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商户序列号
|
* 商户序列号
|
||||||
*/
|
*/
|
||||||
|
@Value("${wxpay.serialNo}")
|
||||||
private String serialNo;
|
private String serialNo;
|
||||||
|
|
||||||
|
@Value("${wxpay.wechatPayCertificateUrl}")
|
||||||
|
private String wechatPayCertificateUrl;
|
||||||
|
|
||||||
|
@Value("${wxpay.privateKeyUrl}")
|
||||||
|
private String privateKeyUrl;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
|
||||||
|
return new PropertySourcesPlaceholderConfigurer();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信支付V3-url前缀
|
* 获取私钥
|
||||||
|
*
|
||||||
|
* @param keyPemPath
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private String baseUrl;
|
|
||||||
|
|
||||||
private String domain;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//获取私钥工具
|
|
||||||
public PrivateKey getPrivateKey(String keyPemPath) {
|
public PrivateKey getPrivateKey(String keyPemPath) {
|
||||||
try {
|
try {
|
||||||
/*
|
|
||||||
|
|
||||||
解决方案
|
|
||||||
1. 将私钥文件放在应用的外部,然后通过文件路径来读取。例如:
|
|
||||||
privateKeyPath = "/etc/myapp/apiclient_key.pem";
|
|
||||||
File file = new File(privateKeyPath);
|
|
||||||
return PemUtil.loadPrivateKey(new FileInputStream(file));
|
|
||||||
这样你就可以将 privateKeyPath 设置为任意位置的文件路径。
|
|
||||||
|
|
||||||
|
|
||||||
2.如果你确实需要将私钥文件打包到应用中,你可以使用 ResourceUtils.getURL(filename).openStream() 来获取文件内容,例如:
|
|
||||||
privateKeyPath = "classpath:cert/apiclient_key.pem";
|
|
||||||
return PemUtil.loadPrivateKey(ResourceUtils.getURL(privateKeyPath).openStream());
|
|
||||||
这样你就可以从应用的 classpath 中读取文件内容。
|
|
||||||
|
|
||||||
ResourceUtils.getURL(filename).openStream() 来获取资源,这是与平台无关的,所以在Windows、Linux以及其他任何支持Java的平台上都能正常使用。只要你的资源文件(在这个例子中是私钥文件)被正确的包含在了你的应用的classpath中,那么你就可以在任何平台上使用这个方法来读取资源文件的内容。
|
|
||||||
这里需要注意的是,classpath: 是一个特殊的协议前缀,它表示资源是从classpath中获取的。当你的资源文件被打包进jar或war时,它们就位于应用的classpath中,因此你可以使用 classpath: 前缀来获取这些文件。
|
|
||||||
因此,无论你的应用运行在Windows还是Linux,或者是其他任何操作系统上,使用方法2都不会有问题。只要你的资源文件被正确地打包进了应用,那么就可以使用这种方法来读取文件内容。
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// 修改后的方法
|
|
||||||
|
|
||||||
return PemUtil.loadPrivateKey(ResourceUtils.getURL(keyPemPath).openStream());
|
return PemUtil.loadPrivateKey(ResourceUtils.getURL(keyPemPath).openStream());
|
||||||
|
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
throw new RuntimeException("私钥文件不存在", e);
|
throw new RuntimeException("私钥文件不存在", e);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -149,7 +107,6 @@ public class WechatPayConfig implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取证书管理器实例 签名验证器
|
* 获取证书管理器实例 签名验证器
|
||||||
*
|
*
|
||||||
@@ -157,27 +114,16 @@ public class WechatPayConfig implements Serializable {
|
|||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public Verifier getVerifier() throws GeneralSecurityException, IOException, HttpCodeException, NotFoundException {
|
public Verifier getVerifier() throws GeneralSecurityException, IOException, HttpCodeException, NotFoundException {
|
||||||
|
|
||||||
log.info("获取证书管理器实例");
|
log.info("获取证书管理器实例");
|
||||||
|
|
||||||
//获取商户私钥
|
//获取商户私钥
|
||||||
|
|
||||||
|
|
||||||
PrivateKey privateKey = getPrivateKey(keyPemPath);
|
PrivateKey privateKey = getPrivateKey(keyPemPath);
|
||||||
|
|
||||||
//私钥签名对象
|
//私钥签名对象
|
||||||
PrivateKeySigner privateKeySigner = new PrivateKeySigner(serialNo, privateKey);
|
PrivateKeySigner privateKeySigner = new PrivateKeySigner(serialNo, privateKey);
|
||||||
|
|
||||||
//身份认证对象
|
//身份认证对象
|
||||||
WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);
|
WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);
|
||||||
|
|
||||||
// 使用定时更新的签名验证器,不需要传入证书
|
// 使用定时更新的签名验证器,不需要传入证书
|
||||||
|
|
||||||
|
|
||||||
CertificatesManager certificatesManager = CertificatesManager.getInstance();
|
CertificatesManager certificatesManager = CertificatesManager.getInstance();
|
||||||
certificatesManager.putMerchant(
|
certificatesManager.putMerchant(mchId, wechatPay2Credentials, apiV3Key.getBytes(StandardCharsets.UTF_8));
|
||||||
mchId, wechatPay2Credentials, apiV3Key.getBytes(StandardCharsets.UTF_8));
|
|
||||||
|
|
||||||
return certificatesManager.getVerifier(mchId);
|
return certificatesManager.getVerifier(mchId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,20 +139,16 @@ public class WechatPayConfig implements Serializable {
|
|||||||
log.info("获取HttpClient");
|
log.info("获取HttpClient");
|
||||||
|
|
||||||
//获取商户私钥
|
//获取商户私钥
|
||||||
|
|
||||||
PrivateKey privateKey = getPrivateKey(keyPemPath);
|
PrivateKey privateKey = getPrivateKey(keyPemPath);
|
||||||
|
|
||||||
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
|
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
|
||||||
.withMerchant(mchId, serialNo, privateKey)
|
.withMerchant(mchId, serialNo, privateKey)
|
||||||
.withValidator(new WechatPay2Validator(verifier));
|
.withValidator(new WechatPay2Validator(verifier));
|
||||||
CloseableHttpClient httpClient =builder.build();
|
CloseableHttpClient httpClient = builder.build();
|
||||||
// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
|
// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
|
||||||
return httpClient;
|
return httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取HttpClient,无需进行应答签名验证,跳过验签的流程
|
* 获取HttpClient,无需进行应答签名验证,跳过验签的流程
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -29,13 +29,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
import java.security.spec.PKCS8EncodedKeySpec;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -76,70 +69,49 @@ public class WeChatPayController {
|
|||||||
//无需应答签名
|
//无需应答签名
|
||||||
@Autowired
|
@Autowired
|
||||||
private CloseableHttpClient wxPayClient;
|
private CloseableHttpClient wxPayClient;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private WxPayUtil wxPayUtil;
|
private WxPayUtil wxPayUtil;
|
||||||
// 由微信生成的应用ID,全局唯一。
|
|
||||||
public static final String appId = "wx47134a8f15083734";
|
|
||||||
// 直连商户的商户号,由微信支付生成并下发。
|
|
||||||
public static final String mchId = "1612860909";
|
|
||||||
// 商户证书序列号 7B5676E3CDF56680D0414A009CE501C844DBE2D6 679AECB2F7AC4183033F713828892BA640E4EEE3
|
|
||||||
public static final String mchSerialNo = "679AECB2F7AC4183033F713828892BA640E4EEE3";
|
|
||||||
// 微信下单Url
|
|
||||||
public static final String payUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/app";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* App 微信下单
|
* 生成预订单
|
||||||
*
|
*
|
||||||
* @param
|
* @param dto
|
||||||
* @return
|
* @return
|
||||||
* @PathVariable
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
|
@RequestMapping(value = "/placeAnOrder/shoppingPay")
|
||||||
@RequestMapping(value = "/placeAnOrder/app")
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public R pay(@RequestBody WechatDto dto) throws Exception {
|
public R shoppingPay(@RequestBody WechatDto dto) throws Exception {
|
||||||
log.info("微信生成订单");
|
log.info("生成预订单");
|
||||||
List<BuyOrderEntity> one = this.buyOrderService.getBaseMapper().selectList(new QueryWrapper<BuyOrderEntity>().eq("order_sn", dto.getOrderSn()));
|
QueryWrapper<BuyOrderEntity> queryWrapper = new QueryWrapper<>();
|
||||||
BuyOrderEntity order = one.get(0);
|
queryWrapper.eq("order_sn", dto.getOrderSn());
|
||||||
// 获取订单
|
BuyOrderEntity order = buyOrderService.getOne(queryWrapper);
|
||||||
|
|
||||||
Map<String, Object> paramMap = new HashMap<>();
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
paramMap.put("appid", appId);
|
paramMap.put("appid", wechatPayConfig.getAppId());
|
||||||
paramMap.put("mchid", mchId);
|
paramMap.put("mchid", wechatPayConfig.getMchId());
|
||||||
paramMap.put("description", "微信充值");
|
paramMap.put("description", "微信支付");
|
||||||
// 订单编号
|
// 订单编号
|
||||||
paramMap.put("out_trade_no", order.getOrderSn());
|
paramMap.put("out_trade_no", order.getOrderSn());
|
||||||
// paramMap.put("attach",""); //自定义数据 支付完成后才能显示 在查询API和支付通知中原样返回,可作为自定义参数使用
|
// 微信回调地址
|
||||||
//paramMap.put("notify_url", wechatPayConfig.getNotifyUrl());
|
paramMap.put("notify_url", wechatPayConfig.getNotifyUrl());
|
||||||
paramMap.put("notify_url","https://testapi.nuttyreading.com/pay/payNotify");
|
BigDecimal totalAmount = dto.getTotalAmount();
|
||||||
|
// 这里 * 100 单位为 ‘分’
|
||||||
// paramMap.put("time_expire",afterString);
|
|
||||||
// 实收金额0.38乘100=38
|
|
||||||
BigDecimal realsmoney = order.getRealMoney();
|
|
||||||
BigDecimal hand = new BigDecimal("100");
|
BigDecimal hand = new BigDecimal("100");
|
||||||
realsmoney = realsmoney.multiply(hand);
|
totalAmount = totalAmount.multiply(hand);
|
||||||
|
|
||||||
Map<String, Object> amountMap = new HashMap<>();
|
Map<String, Object> amountMap = new HashMap<>();
|
||||||
amountMap.put("total", realsmoney);
|
amountMap.put("total", totalAmount);
|
||||||
amountMap.put("currency", "CNY");
|
amountMap.put("currency", "CNY");
|
||||||
|
|
||||||
|
|
||||||
BigDecimal money = order.getRealMoney();
|
|
||||||
BigDecimal han = new BigDecimal("100");
|
|
||||||
realsmoney = realsmoney.multiply(han);
|
|
||||||
Map<String, Object> amount = new HashMap<>();
|
|
||||||
amount.put("total", realsmoney);
|
|
||||||
amount.put("currency", "CNY");
|
|
||||||
|
|
||||||
if (dto.getTotalAmount() != order.getRealMoney()) {
|
|
||||||
|
|
||||||
}
|
|
||||||
paramMap.put("amount", amountMap);
|
paramMap.put("amount", amountMap);
|
||||||
|
|
||||||
JSONObject json = JSONObject.parseObject(JSON.toJSONString(paramMap));
|
JSONObject json = JSONObject.parseObject(JSON.toJSONString(paramMap));
|
||||||
log.info("请求参数" + paramMap);
|
log.info("请求参数:{}", paramMap);
|
||||||
com.alibaba.fastjson.JSONObject jsonObject1 = wxPayUtil.doPostWexinV3("https://api.mch.weixin.qq.com/v3/pay/transactions/app", json.toJSONString());
|
JSONObject responseJson = wxPayUtil.doPostWexinV3(wechatPayConfig.getPayUrl(), json.toJSONString());
|
||||||
String prepayid = jsonObject1.getString("prepay_id");
|
String prepayId = responseJson.getString("prepay_id");
|
||||||
// 传入参数 payUrl 发送post请求
|
// 传入参数 payUrl 发送post请求
|
||||||
HttpPost httpPost = new HttpPost(payUrl);
|
HttpPost httpPost = new HttpPost(wechatPayConfig.getPayUrl());
|
||||||
// 将json数据转换成字符串
|
// 将json数据转换成字符串
|
||||||
StringEntity entity = new StringEntity(json.toString(), "utf-8");
|
StringEntity entity = new StringEntity(json.toString(), "utf-8");
|
||||||
// 设置该请求的Content-Type为application/json 都是json格式
|
// 设置该请求的Content-Type为application/json 都是json格式
|
||||||
@@ -150,77 +122,48 @@ public class WeChatPayController {
|
|||||||
httpPost.setHeader("Accept", "application/json");
|
httpPost.setHeader("Accept", "application/json");
|
||||||
CloseableHttpResponse response = wxPayClient.execute(httpPost);
|
CloseableHttpResponse response = wxPayClient.execute(httpPost);
|
||||||
// 向微信支付平台发送请求,处理响应结果,并将订单信息保存到数据库中。
|
// 向微信支付平台发送请求,处理响应结果,并将订单信息保存到数据库中。
|
||||||
String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
|
String bodyAsString = EntityUtils.toString(response.getEntity());
|
||||||
// 时间戳
|
// 时间戳
|
||||||
Long timestamp = System.currentTimeMillis() / 1000;
|
long timestamp = System.currentTimeMillis() / 1000;
|
||||||
// 随机串
|
// 随机串
|
||||||
String nonceStr = UUID.randomUUID().toString().replace("-", "");
|
String nonceStr = UUID.randomUUID().toString().replace("-", "");
|
||||||
|
String sign = wxPayUtil.getSign(wechatPayConfig.getAppId(), timestamp, nonceStr, prepayId);
|
||||||
String sign = wxPayUtil.getSign(WxPayUtil.appId, timestamp, nonceStr, prepayid);
|
log.info("签名:{}", sign);
|
||||||
log.info("签名:" + sign);
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
map.put("prepayid", prepayId);
|
||||||
Map Map = new HashMap();
|
map.put("timestamp", timestamp);
|
||||||
Map.put("prepayid", prepayid);
|
map.put("noncestr", nonceStr);
|
||||||
Map.put("timestamp", timestamp + "");
|
map.put("sign", sign);
|
||||||
Map.put("noncestr", nonceStr);
|
map.put("appid", wechatPayConfig.getAppId());
|
||||||
Map.put("sign", sign);
|
map.put("package", "Sign=WXPay");
|
||||||
Map.put("appid", appId);
|
map.put("extData", "sign");
|
||||||
Map.put("package", "Sign=WXPay");
|
map.put("partnerid", wechatPayConfig.getMchId());
|
||||||
Map.put("extData", "sign");
|
|
||||||
Map.put("partnerid", mchId);
|
|
||||||
try {
|
try {
|
||||||
int statusCode = response.getStatusLine().getStatusCode(); //响应状态码
|
int statusCode = response.getStatusLine().getStatusCode();
|
||||||
if (statusCode == 200) { //处理成功
|
if (statusCode == 200) {
|
||||||
System.out.println("成功,返回结果 = " + bodyAsString); //返回响应体 EntityUtils.toString(response.getEntity())
|
log.info("返回结果:{}", bodyAsString);
|
||||||
// 添加微信支付订单信息
|
// 添加微信支付订单信息
|
||||||
PayWechatOrderEntity wechat = new PayWechatOrderEntity();
|
PayWechatOrderEntity wechat = new PayWechatOrderEntity();
|
||||||
wechat.setCustomerId(order.getUserId()); //用户id
|
wechat.setCustomerId(order.getUserId());
|
||||||
wechat.setCreateTime(new Date()); //创建订单时间
|
wechat.setCreateTime(new Date());
|
||||||
wechat.setOrderSn(order.getOrderSn()); //订单编号
|
wechat.setOrderSn(order.getOrderSn());
|
||||||
wechat.setPrepayId(prepayid); //预支付回话标识 标识为响应体EntityUtils.toString(response.getEntity())
|
wechat.setPrepayId(prepayId);
|
||||||
wechat.setTotalAmount(dto.getTotalAmount()); //支付实收金额
|
wechat.setTotalAmount(order.getRealMoney());
|
||||||
wechat.setSystemLog(response.toString()); //日志
|
wechat.setSystemLog(response.toString());
|
||||||
wechat.setPayType(order.getOrderType()); //交易类型
|
wechat.setPayType(order.getOrderType());
|
||||||
wechat.setOrderId(order.getOrderSn()); //订单号
|
wechat.setOrderId(order.getOrderSn());
|
||||||
wechat.setBuyOrderId(dto.getBuyOrderId()); //购买配置id
|
wechat.setBuyOrderId(dto.getBuyOrderId());
|
||||||
// wechat.setEndtime(after);
|
this.payWechatOrderService.save(wechat);
|
||||||
this.payWechatOrderService.save(wechat); //微信订单表拿到数据保存数据库
|
|
||||||
|
|
||||||
} else if (statusCode == 204) { //处理成功,无返回Body
|
} else if (statusCode == 204) { //处理成功,无返回Body
|
||||||
System.out.println("成功");
|
log.info("支付成功");
|
||||||
} else {
|
} else {
|
||||||
System.out.println("下单失败 = " + statusCode + ",返回结果 = " + bodyAsString);
|
log.error("下单失败,响应码为:{},返回结果:{}", statusCode, bodyAsString);
|
||||||
throw new IOException("request failed");
|
throw new IOException("request failed");
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
response.close();
|
response.close();
|
||||||
}
|
}
|
||||||
// 返回url和订单号
|
return R.ok().put("paramMap", paramMap).put("Map", map);
|
||||||
return R.ok().put("paramMap", paramMap).put("Map", Map);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取私钥。
|
|
||||||
*
|
|
||||||
* @param filename 私钥文件路径 (required)
|
|
||||||
* @return 私钥对象
|
|
||||||
*/
|
|
||||||
public static PrivateKey getPrivateKey(String filename) throws Exception {
|
|
||||||
String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");
|
|
||||||
try {
|
|
||||||
String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
|
|
||||||
.replace("-----END PRIVATE KEY-----", "")
|
|
||||||
.replaceAll("\\s+", "");
|
|
||||||
|
|
||||||
KeyFactory kf = KeyFactory.getInstance("RSA");
|
|
||||||
return kf.generatePrivate(
|
|
||||||
new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new RuntimeException("当前Java环境不支持RSA", e);
|
|
||||||
} catch (InvalidKeySpecException e) {
|
|
||||||
throw new RuntimeException("无效的密钥格式");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -256,21 +199,16 @@ public class WeChatPayController {
|
|||||||
if ("order".equals(order.getOrderType())) {
|
if ("order".equals(order.getOrderType())) {
|
||||||
BuyOrderEntity orderEntity = buyOrderService.getBaseMapper().selectOne(new QueryWrapper<BuyOrderEntity>().eq("order_sn", wechatEntity.getOrderSn()));
|
BuyOrderEntity orderEntity = buyOrderService.getBaseMapper().selectOne(new QueryWrapper<BuyOrderEntity>().eq("order_sn", wechatEntity.getOrderSn()));
|
||||||
BigDecimal realMoney = orderEntity.getRealMoney();
|
BigDecimal realMoney = orderEntity.getRealMoney();
|
||||||
System.out.println("=========== 获取到 orderSn==================" + order.getOrderSn());
|
|
||||||
// 查询订单的所有 book_id
|
// 查询订单的所有 book_id
|
||||||
List<Integer> orderBookIdList = shopProudictBookService.getOrderBookId(order.getOrderSn());
|
List<Integer> orderBookIdList = shopProudictBookService.getOrderBookId(order.getOrderSn());
|
||||||
System.out.println("=========== 获取到 orderBookIdList==========" + orderBookIdList);
|
|
||||||
// 去重
|
// 去重
|
||||||
Set<Integer> set = new HashSet<>(orderBookIdList);
|
Set<Integer> set = new HashSet<>(orderBookIdList);
|
||||||
orderBookIdList.clear();
|
orderBookIdList.clear();
|
||||||
orderBookIdList.addAll(set);
|
orderBookIdList.addAll(set);
|
||||||
// 查询用户的所有 book_id
|
// 查询用户的所有 book_id
|
||||||
System.out.println("==============去重后orderBookIdList=========" + orderBookIdList);
|
|
||||||
List<Integer> userBookIdList = userEbookBuyService.getUserBookId(order.getUserId());
|
List<Integer> userBookIdList = userEbookBuyService.getUserBookId(order.getUserId());
|
||||||
System.out.println("==============userBookIdList===============" + userBookIdList);
|
|
||||||
// 取差集
|
// 取差集
|
||||||
orderBookIdList.removeAll(userBookIdList);
|
orderBookIdList.removeAll(userBookIdList);
|
||||||
System.out.println("============== 差集========================" + orderBookIdList);
|
|
||||||
// 为用户添加书籍
|
// 为用户添加书籍
|
||||||
List<UserEbookBuyEntity> userEbookBuyEntities = new ArrayList<>();
|
List<UserEbookBuyEntity> userEbookBuyEntities = new ArrayList<>();
|
||||||
for (Integer bookId : orderBookIdList) {
|
for (Integer bookId : orderBookIdList) {
|
||||||
@@ -279,12 +217,9 @@ public class WeChatPayController {
|
|||||||
entity.setBookId(bookId);
|
entity.setBookId(bookId);
|
||||||
userEbookBuyEntities.add(entity);
|
userEbookBuyEntities.add(entity);
|
||||||
}
|
}
|
||||||
System.out.println("============userEbookBuyEntities===========" + userEbookBuyEntities);
|
|
||||||
boolean b = userEbookBuyService.saveBatch(userEbookBuyEntities);
|
boolean b = userEbookBuyService.saveBatch(userEbookBuyEntities);
|
||||||
System.out.println("============result========================" + b);
|
|
||||||
if (wechatEntity.getTotalAmount().compareTo(realMoney) == 0) {
|
if (wechatEntity.getTotalAmount().compareTo(realMoney) == 0) {
|
||||||
buyOrderService.updateOrderStatus(order.getUserId(), order.getOrderSn(), "0");
|
buyOrderService.updateOrderStatus(order.getUserId(), order.getOrderSn(), "0");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ("point".equals(order.getOrderType())) {
|
if ("point".equals(order.getOrderType())) {
|
||||||
@@ -348,88 +283,4 @@ public class WeChatPayController {
|
|||||||
}
|
}
|
||||||
return bodyMap;
|
return bodyMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@RequestMapping(value = "/placeAnOrder/shoppingpay")
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public R shoppingpay(@RequestBody WechatDto dto) throws Exception {
|
|
||||||
log.info("生成订单");
|
|
||||||
List<BuyOrderEntity> one = this.buyOrderService.getBaseMapper().selectList(new QueryWrapper<BuyOrderEntity>().eq("order_sn", dto.getOrderSn()));
|
|
||||||
BuyOrderEntity order = one.get(0);
|
|
||||||
|
|
||||||
// 获取订单
|
|
||||||
Map<String, Object> paramMap = new HashMap<>();
|
|
||||||
paramMap.put("appid", appId);
|
|
||||||
paramMap.put("mchid", mchId);
|
|
||||||
paramMap.put("description", "微信充值");
|
|
||||||
// 订单编号
|
|
||||||
paramMap.put("out_trade_no", order.getOrderSn());
|
|
||||||
paramMap.put("notify_url", wechatPayConfig.getNotifyUrl());
|
|
||||||
BigDecimal realsmoney = dto.getTotalAmount();
|
|
||||||
BigDecimal hand = new BigDecimal("100");
|
|
||||||
realsmoney = realsmoney.multiply(hand);
|
|
||||||
Map<String, Object> amountMap = new HashMap<>();
|
|
||||||
amountMap.put("total", realsmoney);
|
|
||||||
amountMap.put("currency", "CNY");
|
|
||||||
paramMap.put("amount", amountMap);
|
|
||||||
JSONObject json = JSONObject.parseObject(JSON.toJSONString(paramMap));
|
|
||||||
log.info("请求参数" + paramMap);
|
|
||||||
com.alibaba.fastjson.JSONObject jsonObject1 = wxPayUtil.doPostWexinV3("https://api.mch.weixin.qq.com/v3/pay/transactions/app", json.toJSONString());
|
|
||||||
String prepayid = jsonObject1.getString("prepay_id");
|
|
||||||
// 传入参数 payUrl 发送post请求
|
|
||||||
HttpPost httpPost = new HttpPost(payUrl);
|
|
||||||
// 将json数据转换成字符串
|
|
||||||
StringEntity entity = new StringEntity(json.toString(), "utf-8");
|
|
||||||
// 设置该请求的Content-Type为application/json 都是json格式
|
|
||||||
entity.setContentType("application/json");
|
|
||||||
// 将实体对象设置到HttpPost表示要传递该数据到服务器端。
|
|
||||||
httpPost.setEntity(entity);
|
|
||||||
// 设置请求头部的Accept属性为"application/json"表示客户端希望接收的为json。
|
|
||||||
httpPost.setHeader("Accept", "application/json");
|
|
||||||
CloseableHttpResponse response = wxPayClient.execute(httpPost);
|
|
||||||
// 向微信支付平台发送请求,处理响应结果,并将订单信息保存到数据库中。
|
|
||||||
String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
|
|
||||||
// 时间戳
|
|
||||||
long timestamp = System.currentTimeMillis() / 1000;
|
|
||||||
// 随机串
|
|
||||||
String nonceStr = UUID.randomUUID().toString().replace("-", "");
|
|
||||||
String sign = wxPayUtil.getSign(WxPayUtil.appId, timestamp, nonceStr, prepayid);
|
|
||||||
log.info("签名:" + sign);
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("prepayid", prepayid);
|
|
||||||
map.put("timestamp", timestamp + "");
|
|
||||||
map.put("noncestr", nonceStr);
|
|
||||||
map.put("sign", sign);
|
|
||||||
map.put("appid", appId);
|
|
||||||
map.put("package", "Sign=WXPay");
|
|
||||||
map.put("extData", "sign");
|
|
||||||
map.put("partnerid", mchId);
|
|
||||||
try {
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode(); //响应状态码
|
|
||||||
if (statusCode == 200) { //处理成功
|
|
||||||
System.out.println("成功,返回结果 = " + bodyAsString); //返回响应体 EntityUtils.toString(response.getEntity())
|
|
||||||
// 添加微信支付订单信息
|
|
||||||
PayWechatOrderEntity wechat = new PayWechatOrderEntity();
|
|
||||||
wechat.setCustomerId(order.getUserId()); //用户id
|
|
||||||
wechat.setCreateTime(new Date()); //创建订单时间
|
|
||||||
wechat.setOrderSn(order.getOrderSn()); //订单编号
|
|
||||||
wechat.setPrepayId(prepayid); //预支付回话标识 标识为响应体EntityUtils.toString(response.getEntity())
|
|
||||||
wechat.setTotalAmount(order.getRealMoney()); //支付实收金额
|
|
||||||
wechat.setSystemLog(response.toString()); //日志
|
|
||||||
wechat.setPayType(order.getOrderType()); //交易类型
|
|
||||||
wechat.setOrderId(order.getOrderSn()); //订单号
|
|
||||||
wechat.setBuyOrderId(dto.getBuyOrderId()); //购买配置id
|
|
||||||
this.payWechatOrderService.save(wechat); //微信订单表拿到数据保存数据库
|
|
||||||
} else if (statusCode == 204) { //处理成功,无返回Body
|
|
||||||
System.out.println("成功");
|
|
||||||
} else {
|
|
||||||
System.out.println("下单失败 = " + statusCode + ",返回结果 = " + bodyAsString);
|
|
||||||
throw new IOException("request failed");
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
|
||||||
// 返回url和订单号
|
|
||||||
return R.ok().put("paramMap", paramMap).put("Map", map);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +1,23 @@
|
|||||||
package com.peanut.modules.pay.weChatPay.dto;
|
package com.peanut.modules.pay.weChatPay.dto;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class WechatDto implements Serializable {
|
public class WechatDto implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
//totalAmount: payItem.realMoney,
|
* 订单号
|
||||||
// customerId:
|
*/
|
||||||
|
|
||||||
private String orderSn;
|
private String orderSn;
|
||||||
|
/**
|
||||||
|
* 订单 ID
|
||||||
|
*/
|
||||||
private Integer buyOrderId;
|
private Integer buyOrderId;
|
||||||
|
/**
|
||||||
|
* 总金额
|
||||||
|
*/
|
||||||
private BigDecimal totalAmount;
|
private BigDecimal totalAmount;
|
||||||
|
|
||||||
public BigDecimal getTotalAmount() {
|
|
||||||
return totalAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTotalAmount(BigDecimal totalAmount) {
|
|
||||||
this.totalAmount = totalAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOrderSn() {
|
|
||||||
return orderSn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOrderSn(String orderSn) {
|
|
||||||
this.orderSn = orderSn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getBuyOrderId() {
|
|
||||||
return buyOrderId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBuyOrderId(Integer buyOrderId) {
|
|
||||||
this.buyOrderId = buyOrderId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.peanut.modules.pay.weChatPay.util;
|
package com.peanut.modules.pay.weChatPay.util;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.peanut.modules.pay.weChatPay.config.WechatPayConfig;
|
||||||
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
|
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
|
||||||
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
|
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -11,6 +12,7 @@ import org.apache.http.entity.StringEntity;
|
|||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.apache.http.util.EntityUtils;
|
import org.apache.http.util.EntityUtils;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@@ -21,127 +23,116 @@ import java.security.cert.X509Certificate;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Data
|
@Data
|
||||||
public class WxPayUtil {
|
public class WxPayUtil {
|
||||||
|
|
||||||
public static final String mchId = "1612860909"; // 商户号
|
@Autowired
|
||||||
|
WechatPayConfig wechatPayConfig;
|
||||||
|
|
||||||
public static final String appId = "wx47134a8f15083734"; // appId
|
private CloseableHttpClient httpClient;
|
||||||
|
|
||||||
public static final String apiV3Key = "4aYFklzaULeGlr7oJPZ6rHWKcxjihZUF"; // apiV3秘钥
|
public void setup() {
|
||||||
//商户私钥路径
|
PrivateKey merchantPrivateKey = null;
|
||||||
//public static final String privateKeyUrl = "/usr/local/hs/peanut_book/target/classes/cent/apiclient_key.pem";
|
X509Certificate wechatPayCertificate = null;
|
||||||
public static final String privateKeyUrl = "C:/Users/Cauchy/IdeaProjects/nuttyreading-java/src/main/resources/cent/apiclient_key.pem";
|
|
||||||
|
|
||||||
//平台证书路径
|
try {
|
||||||
//public static final String wechatPayCertificateUrl = "/usr/local/hs/peanut_book/target/classes/cent/wechatpay_7B5676E3CDF56680D0414A009CE501C844DBE2D6.pem";
|
merchantPrivateKey = PemUtil.loadPrivateKey(
|
||||||
public static final String wechatPayCertificateUrl = "C:/Users/Cauchy/IdeaProjects/nuttyreading-java/src/main/resources/cent/wechatpay_7B5676E3CDF56680D0414A009CE501C844DBE2D6.pem";
|
new FileInputStream(wechatPayConfig.getPrivateKeyUrl()));
|
||||||
//第一步申请完证书后,在API证书哪里点击管理证书就能看到
|
wechatPayCertificate = PemUtil.loadCertificate(
|
||||||
public static final String mchSerialNo = "679AECB2F7AC4183033F713828892BA640E4EEE3"; // 商户证书序列号
|
new FileInputStream(wechatPayConfig.getWechatPayCertificateUrl()));
|
||||||
|
|
||||||
private CloseableHttpClient httpClient;
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
public void setup() {
|
|
||||||
PrivateKey merchantPrivateKey = null;
|
|
||||||
X509Certificate wechatPayCertificate = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
merchantPrivateKey = PemUtil.loadPrivateKey(
|
|
||||||
new FileInputStream(privateKeyUrl));
|
|
||||||
wechatPayCertificate = PemUtil.loadCertificate(
|
|
||||||
new FileInputStream(wechatPayCertificateUrl));
|
|
||||||
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList<X509Certificate> listCertificates = new ArrayList<>();
|
|
||||||
listCertificates.add(wechatPayCertificate);
|
|
||||||
|
|
||||||
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
|
|
||||||
.withMerchant(mchId, mchSerialNo, merchantPrivateKey)
|
|
||||||
.withWechatPay(listCertificates);
|
|
||||||
httpClient = builder.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
ArrayList<X509Certificate> listCertificates = new ArrayList<>();
|
||||||
* wxMchid商户号
|
listCertificates.add(wechatPayCertificate);
|
||||||
* wxCertno证书编号
|
|
||||||
* wxCertPath证书地址
|
|
||||||
* wxPaternerKey v3秘钥
|
|
||||||
* url 下单地址
|
|
||||||
* body 构造好的消息体
|
|
||||||
*/
|
|
||||||
public JSONObject doPostWexinV3(String url, String body) {
|
|
||||||
if (httpClient == null) {
|
|
||||||
setup();
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpPost httpPost = new HttpPost(url);
|
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
|
||||||
httpPost.addHeader("Content-Type", "application/json;chartset=utf-8");
|
.withMerchant(wechatPayConfig.getMchId(), wechatPayConfig.getSerialNo(), merchantPrivateKey)
|
||||||
httpPost.addHeader("Accept", "application/json");
|
.withWechatPay(listCertificates);
|
||||||
try {
|
httpClient = builder.build();
|
||||||
if (body == null) {
|
|
||||||
throw new IllegalArgumentException("data参数不能为空");
|
|
||||||
}
|
|
||||||
StringEntity stringEntity = new StringEntity(body, "utf-8");
|
|
||||||
httpPost.setEntity(stringEntity);
|
|
||||||
// 直接执行execute方法,官方会自动处理签名和验签,并进行证书自动更新
|
|
||||||
HttpResponse httpResponse = httpClient.execute(httpPost);
|
|
||||||
HttpEntity httpEntity = httpResponse.getEntity();
|
|
||||||
|
|
||||||
if (httpResponse.getStatusLine().getStatusCode() == 200) {
|
|
||||||
String jsonResult = EntityUtils.toString(httpEntity);
|
|
||||||
|
|
||||||
return JSONObject.parseObject(jsonResult);
|
|
||||||
} else {
|
|
||||||
System.err.println("微信支付错误信息" + EntityUtils.toString(httpEntity));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//获取签名
|
|
||||||
public String getSign(String appId, long timestamp, String nonceStr, String pack){
|
|
||||||
String message = buildMessage(appId, timestamp, nonceStr, pack);
|
|
||||||
String paySign= null;
|
|
||||||
try {
|
|
||||||
paySign = sign(message.getBytes("utf-8"));
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return paySign;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String buildMessage(String appId, long timestamp, String nonceStr, String pack) {
|
|
||||||
return appId + "\n"
|
|
||||||
+ timestamp + "\n"
|
|
||||||
+ nonceStr + "\n"
|
|
||||||
+ pack + "\n";
|
|
||||||
}
|
|
||||||
private String sign(byte[] message) throws Exception{
|
|
||||||
PrivateKey merchantPrivateKey = null;
|
|
||||||
X509Certificate wechatPayCertificate = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
merchantPrivateKey = PemUtil.loadPrivateKey(
|
|
||||||
new FileInputStream(privateKeyUrl));
|
|
||||||
wechatPayCertificate = PemUtil.loadCertificate(
|
|
||||||
new FileInputStream(wechatPayCertificateUrl));
|
|
||||||
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
Signature sign = Signature.getInstance("SHA256withRSA");
|
|
||||||
|
|
||||||
sign.initSign(merchantPrivateKey);
|
|
||||||
sign.update(message);
|
|
||||||
return Base64.getEncoder().encodeToString(sign.sign());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wxMchid商户号
|
||||||
|
* wxCertno证书编号
|
||||||
|
* wxCertPath证书地址
|
||||||
|
* wxPaternerKey v3秘钥
|
||||||
|
* url 下单地址
|
||||||
|
* body 构造好的消息体
|
||||||
|
*/
|
||||||
|
public JSONObject doPostWexinV3(String url, String body) {
|
||||||
|
if (httpClient == null) {
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpPost httpPost = new HttpPost(url);
|
||||||
|
httpPost.addHeader("Content-Type", "application/json;chartset=utf-8");
|
||||||
|
httpPost.addHeader("Accept", "application/json");
|
||||||
|
try {
|
||||||
|
if (body == null) {
|
||||||
|
throw new IllegalArgumentException("data参数不能为空");
|
||||||
|
}
|
||||||
|
StringEntity stringEntity = new StringEntity(body, "utf-8");
|
||||||
|
httpPost.setEntity(stringEntity);
|
||||||
|
// 直接执行execute方法,官方会自动处理签名和验签,并进行证书自动更新
|
||||||
|
HttpResponse httpResponse = httpClient.execute(httpPost);
|
||||||
|
HttpEntity httpEntity = httpResponse.getEntity();
|
||||||
|
|
||||||
|
if (httpResponse.getStatusLine().getStatusCode() == 200) {
|
||||||
|
String jsonResult = EntityUtils.toString(httpEntity);
|
||||||
|
|
||||||
|
return JSONObject.parseObject(jsonResult);
|
||||||
|
} else {
|
||||||
|
System.err.println("微信支付错误信息" + EntityUtils.toString(httpEntity));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取签名
|
||||||
|
public String getSign(String appId, long timestamp, String nonceStr, String pack) {
|
||||||
|
String message = buildMessage(appId, timestamp, nonceStr, pack);
|
||||||
|
String paySign = null;
|
||||||
|
try {
|
||||||
|
paySign = sign(message.getBytes("utf-8"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return paySign;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildMessage(String appId, long timestamp, String nonceStr, String pack) {
|
||||||
|
return appId + "\n"
|
||||||
|
+ timestamp + "\n"
|
||||||
|
+ nonceStr + "\n"
|
||||||
|
+ pack + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String sign(byte[] message) throws Exception {
|
||||||
|
PrivateKey merchantPrivateKey = null;
|
||||||
|
X509Certificate wechatPayCertificate = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
merchantPrivateKey = PemUtil.loadPrivateKey(
|
||||||
|
new FileInputStream(wechatPayConfig.getPrivateKeyUrl()));
|
||||||
|
wechatPayCertificate = PemUtil.loadCertificate(
|
||||||
|
new FileInputStream(wechatPayConfig.getWechatPayCertificateUrl()));
|
||||||
|
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
Signature sign = Signature.getInstance("SHA256withRSA");
|
||||||
|
|
||||||
|
sign.initSign(merchantPrivateKey);
|
||||||
|
sign.update(message);
|
||||||
|
return Base64.getEncoder().encodeToString(sign.sign());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
FROM shop_proudict_book spb
|
FROM shop_proudict_book spb
|
||||||
LEFT JOIN buy_order_detail bod ON spb.proudict_id = bod.product_id
|
LEFT JOIN buy_order_detail bod ON spb.proudict_id = bod.product_id
|
||||||
LEFT JOIN buy_order bo ON bo.order_id = bod.order_id
|
LEFT JOIN buy_order bo ON bo.order_id = bod.order_id
|
||||||
WHERE bo.order_sn = #{orderSn} AND del_flag != -1
|
WHERE bo.order_sn = #{orderSn} AND spb.del_flag != -1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ wxpay.notifyUrl: http://59.110.212.44:9200/pb/pay/payNotify
|
|||||||
wxpay.refundNotifyUrl: http://pjm6m9.natappfree.cc/pay/refundNotify
|
wxpay.refundNotifyUrl: http://pjm6m9.natappfree.cc/pay/refundNotify
|
||||||
# ???? /usr/local/hs/peanut_book/target/classes/cent/apiclient_key.pem
|
# ???? /usr/local/hs/peanut_book/target/classes/cent/apiclient_key.pem
|
||||||
|
|
||||||
#wxpay.keyPemPath:C:/Users/Cauchy/IdeaProjects/nuttyreading-java/src/main/resources/cent/apiclient_key.pem
|
wxpay.keyPemPath:C:/Users/Cauchy/IdeaProjects/nuttyreading-java/src/main/resources/cent/apiclient_key.pem
|
||||||
#wxpay.keyPemPath:D:/hs/nuttyreading-java/src/main/resources/cent/apiclient_key.pem
|
#wxpay.keyPemPath:/usr/local/hs/peanut_book/target/classes/cent/apiclient_key.pem
|
||||||
wxpay.keyPemPath:/usr/local/hs/peanut_book/target/classes/cent/apiclient_key.pem
|
|
||||||
#???????
|
#???????
|
||||||
wxpay.serialNo: 679AECB2F7AC4183033F713828892BA640E4EEE3
|
wxpay.serialNo: 679AECB2F7AC4183033F713828892BA640E4EEE3
|
||||||
#???????
|
#???????
|
||||||
|
|||||||
Reference in New Issue
Block a user