Merge remote-tracking branch 'origin/bugfix/wechatcallback'

# Conflicts:
#	src/main/resources/weChatConfig.properties
This commit is contained in:
wangjinlei
2023-10-09 15:43:08 +08:00
6 changed files with 213 additions and 450 deletions

View File

@@ -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无需进行应答签名验证跳过验签的流程
*/ */

View File

@@ -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);
}
} }

View File

@@ -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;
}
} }

View File

@@ -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());
}
}

View File

@@ -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>

View File

@@ -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
#??????? #???????