From ab8a2f07143434a0687c3ebe85b32cc86bf5fe69 Mon Sep 17 00:00:00 2001 From: Cool <747682928@qq.com> Date: Wed, 4 Sep 2024 23:27:31 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A2=E5=8D=95=E6=8E=A5=E5=8F=A3=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 24 -- .../wxappserver/config/MyWxPayConfig.java | 47 ---- .../controller/OrderController.java | 13 +- .../controller/PayNotifyController.java | 118 --------- .../controller/TestController.java | 57 ----- .../com/bigdata/wxappserver/entity/Order.java | 2 +- .../properties/WeChatProperties.java | 22 -- .../wxappserver/service/OrderService.java | 54 +--- .../bigdata/wxappserver/utils/SignV3Util.java | 138 ----------- .../wxappserver/utils/WeChatPayUtil.java | 233 ------------------ src/main/resources/application.yml | 12 +- .../resources/template/apiclient_cert.p12 | Bin 2782 -> 0 bytes .../bddf2dc508484b6bb086fe748e813260.pem | 28 --- ...9733475DFDCEBE2A6135485F984EE337297F4F.pem | 2 - .../WxappServerApplicationTests.java | 41 --- 15 files changed, 15 insertions(+), 776 deletions(-) delete mode 100644 src/main/java/com/bigdata/wxappserver/config/MyWxPayConfig.java delete mode 100644 src/main/java/com/bigdata/wxappserver/controller/PayNotifyController.java delete mode 100644 src/main/java/com/bigdata/wxappserver/controller/TestController.java delete mode 100644 src/main/java/com/bigdata/wxappserver/properties/WeChatProperties.java delete mode 100644 src/main/java/com/bigdata/wxappserver/utils/SignV3Util.java delete mode 100644 src/main/java/com/bigdata/wxappserver/utils/WeChatPayUtil.java delete mode 100644 src/main/resources/template/apiclient_cert.p12 delete mode 100644 src/main/resources/template/bddf2dc508484b6bb086fe748e813260.pem diff --git a/pom.xml b/pom.xml index ca57eb3..a78147a 100644 --- a/pom.xml +++ b/pom.xml @@ -62,30 +62,6 @@ fastjson 1.2.83 - - - com.github.wechatpay-apiv3 - wechatpay-apache-httpclient - 0.4.8 - - - - com.squareup.okhttp3 - okhttp - 3.5.0 - - - com.github.wechatpay-apiv3 - wechatpay-java - 0.2.14 - - - - com.github.binarywang - weixin-java-pay - 4.1.0 - - commons-lang commons-lang diff --git a/src/main/java/com/bigdata/wxappserver/config/MyWxPayConfig.java b/src/main/java/com/bigdata/wxappserver/config/MyWxPayConfig.java deleted file mode 100644 index 5009672..0000000 --- a/src/main/java/com/bigdata/wxappserver/config/MyWxPayConfig.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.bigdata.wxappserver.config; - -import com.bigdata.wxappserver.properties.WeChatProperties; -import com.github.binarywang.wxpay.config.WxPayConfig; -import com.github.binarywang.wxpay.service.WxPayService; -import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; -import org.apache.commons.lang.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Created with IntelliJ IDEA. - * - * @Author: Cool - * @Date: 2024/09/03/22:19 - * @Description: - */ - -@Configuration -@ConditionalOnClass(WxPayService.class) -public class MyWxPayConfig { - - @Autowired - private WeChatProperties properties; - - @Bean - @ConditionalOnMissingBean - public WxPayService wxService() { - WxPayConfig payConfig = new WxPayConfig(); - payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId())); - payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId())); - payConfig.setMchKey(StringUtils.trimToNull(this.properties.getSecret())); - payConfig.setApiV3Key(StringUtils.trimToNull(this.properties.getApiV3Key())); - payConfig.setPrivateKeyPath(StringUtils.trimToNull(this.properties.getPrivateKeyFilePath())); - payConfig.setPrivateCertPath(StringUtils.trimToNull(this.properties.getWeChatPayCertFilePath())); - // payConfig.setPrivateKeyPath(); - // 可以指定是否使用沙箱环境 - payConfig.setUseSandboxEnv(false); - - WxPayService wxPayService = new WxPayServiceImpl(); - wxPayService.setConfig(payConfig); - return wxPayService; - } -} diff --git a/src/main/java/com/bigdata/wxappserver/controller/OrderController.java b/src/main/java/com/bigdata/wxappserver/controller/OrderController.java index d9b596c..f8925fe 100644 --- a/src/main/java/com/bigdata/wxappserver/controller/OrderController.java +++ b/src/main/java/com/bigdata/wxappserver/controller/OrderController.java @@ -22,7 +22,7 @@ public class OrderController { OrderService orderService; @RequestMapping("addOrUpdate") - public JSONObject addOrUpdate(@RequestBody JSONObject jsonObject){ + public Result addOrUpdate(@RequestBody JSONObject jsonObject){ return orderService.addOrUpdate(jsonObject); } @@ -41,15 +41,4 @@ public class OrderController { return orderService.delete(id); } - /** - * 订单支付 - * - * @param - * @return - */ - @PutMapping("/payment") - public Result payment(@RequestBody JSONObject jsonObject) throws Exception { - return orderService.payment(jsonObject); - } - } diff --git a/src/main/java/com/bigdata/wxappserver/controller/PayNotifyController.java b/src/main/java/com/bigdata/wxappserver/controller/PayNotifyController.java deleted file mode 100644 index c26fa3c..0000000 --- a/src/main/java/com/bigdata/wxappserver/controller/PayNotifyController.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.bigdata.wxappserver.controller; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.bigdata.wxappserver.properties.WeChatProperties; -import com.bigdata.wxappserver.service.OrderService; -import com.wechat.pay.contrib.apache.httpclient.util.AesUtil; -import lombok.extern.slf4j.Slf4j; -import org.apache.http.entity.ContentType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.BufferedReader; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; - -/** - * 支付回调相关接口 - */ -@RestController -@RequestMapping("/notify") -@Slf4j -public class PayNotifyController { - @Autowired - private OrderService orderService; - @Autowired - private WeChatProperties weChatProperties; - - /** - * 支付成功回调 - * - * @param request - */ - @RequestMapping("/paySuccess") - public void paySuccessNotify(HttpServletRequest request, HttpServletResponse response) throws Exception { - //读取数据 - String body = readData(request); - log.info("支付成功回调:{}", body); - - //数据解密 - String plainText = decryptData(body); - log.info("解密后的文本:{}", plainText); - - JSONObject jsonObject = JSON.parseObject(plainText); - String outTradeNo = jsonObject.getString("out_trade_no");//商户平台订单号 - String transactionId = jsonObject.getString("transaction_id");//微信支付交易号 - - log.info("商户平台订单号:{}", outTradeNo); - log.info("微信支付交易号:{}", transactionId); - - //业务处理,修改订单状态、来单提醒 - orderService.paySuccess(outTradeNo); - - //给微信响应 - responseToWeixin(response); - } - - /** - * 读取数据 - * - * @param request - * @return - * @throws Exception - */ - private String readData(HttpServletRequest request) throws Exception { - BufferedReader reader = request.getReader(); - StringBuilder result = new StringBuilder(); - String line = null; - while ((line = reader.readLine()) != null) { - if (result.length() > 0) { - result.append("\n"); - } - result.append(line); - } - return result.toString(); - } - - /** - * 数据解密 - * - * @param body - * @return - * @throws Exception - */ - private String decryptData(String body) throws Exception { - JSONObject resultObject = JSON.parseObject(body); - JSONObject resource = resultObject.getJSONObject("resource"); - String ciphertext = resource.getString("ciphertext"); - String nonce = resource.getString("nonce"); - String associatedData = resource.getString("associated_data"); - - AesUtil aesUtil = new AesUtil(weChatProperties.getApiV3Key().getBytes(StandardCharsets.UTF_8)); - //密文解密 - String plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), - nonce.getBytes(StandardCharsets.UTF_8), - ciphertext); - - return plainText; - } - - /** - * 给微信响应 - * - * @param response - */ - private void responseToWeixin(HttpServletResponse response) throws Exception { - response.setStatus(200); - HashMap map = new HashMap<>(); - map.put("code", "SUCCESS"); - map.put("message", "SUCCESS"); - response.setHeader("Content-type", ContentType.APPLICATION_JSON.toString()); - response.getOutputStream().write(JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8)); - response.flushBuffer(); - } -} diff --git a/src/main/java/com/bigdata/wxappserver/controller/TestController.java b/src/main/java/com/bigdata/wxappserver/controller/TestController.java deleted file mode 100644 index e0c1218..0000000 --- a/src/main/java/com/bigdata/wxappserver/controller/TestController.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.bigdata.wxappserver.controller; - -import com.bigdata.wxappserver.result.Result; -import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; -import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult; -import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; -import com.github.binarywang.wxpay.service.WxPayService; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.UUID; - -/** - * Created with IntelliJ IDEA. - * - * @Author: Cool - * @Date: 2024/09/03/22:25 - * @Description: - */ -@RestController -@Slf4j -public class TestController { - @Autowired - private WxPayService wxService; - - - @PostMapping("/unifiedOrder") - public Result unifiedOrder() throws Exception { - String orderCode = UUID.randomUUID().toString().replace("-", ""); - WxPayUnifiedOrderV3Request wxPayUnifiedOrderRequest = new WxPayUnifiedOrderV3Request(); - - wxPayUnifiedOrderRequest.setDescription("商品描述"); - wxPayUnifiedOrderRequest.setOutTradeNo(orderCode); - wxPayUnifiedOrderRequest.setNotifyUrl("https://49.233.248.140:8082/order/loadData"); - - WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount(); - amount.setTotal(100); // 订单总金额,单位为分 - wxPayUnifiedOrderRequest.setAmount(amount); - WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer(); - payer.setOpenid(UUID.randomUUID().toString().replace("-", "")); // 需要获取用户的OpenID - wxPayUnifiedOrderRequest.setPayer(payer); - wxService.createOrderV3(TradeTypeEnum.JSAPI, wxPayUnifiedOrderRequest); - return Result.success(); - } - - @PostMapping("/queryOrder") - public Result queryOrder(String outTradeNo) throws Exception { - WxPayOrderQueryResult wxPayOrderQueryResult = wxService.queryOrder(null, outTradeNo); - log.info(wxPayOrderQueryResult.toString()); - return Result.success(wxPayOrderQueryResult); - } - - -} diff --git a/src/main/java/com/bigdata/wxappserver/entity/Order.java b/src/main/java/com/bigdata/wxappserver/entity/Order.java index 82ca120..cdcee9c 100644 --- a/src/main/java/com/bigdata/wxappserver/entity/Order.java +++ b/src/main/java/com/bigdata/wxappserver/entity/Order.java @@ -21,8 +21,8 @@ public class Order extends Base { private Integer userId; private Integer goodsId; + private String orderCode; private String address; - private LocalDateTime deliveryTime; /** * 订单状态 @see diff --git a/src/main/java/com/bigdata/wxappserver/properties/WeChatProperties.java b/src/main/java/com/bigdata/wxappserver/properties/WeChatProperties.java deleted file mode 100644 index 9256bf6..0000000 --- a/src/main/java/com/bigdata/wxappserver/properties/WeChatProperties.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.bigdata.wxappserver.properties; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.stereotype.Component; - -@Component -@ConfigurationProperties(prefix = "dx.wechat") -@Data -public class WeChatProperties { - - private String appId; //小程序的appid - private String secret; //小程序的秘钥 - private String mchId; //商户号 - private String mchSerialNo; //商户API证书的证书序列号 - private String privateKeyFilePath; //商户私钥文件 - private String apiV3Key; //证书解密的密钥 - private String weChatPayCertFilePath; //平台证书 - private String notifyUrl; //支付成功的回调地址 - private String refundNotifyUrl; //退款成功的回调地址 - -} diff --git a/src/main/java/com/bigdata/wxappserver/service/OrderService.java b/src/main/java/com/bigdata/wxappserver/service/OrderService.java index 12a1534..d96b7a3 100644 --- a/src/main/java/com/bigdata/wxappserver/service/OrderService.java +++ b/src/main/java/com/bigdata/wxappserver/service/OrderService.java @@ -10,7 +10,6 @@ import com.bigdata.wxappserver.entity.User; import com.bigdata.wxappserver.enums.OrderStatusEnum; import com.bigdata.wxappserver.mapper.OrderMapper; import com.bigdata.wxappserver.result.Result; -import com.bigdata.wxappserver.utils.WeChatPayUtil; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -19,7 +18,6 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.math.BigDecimal; -import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; @@ -32,8 +30,6 @@ import java.util.stream.Collectors; */ @Service public class OrderService extends ServiceImpl { - @Autowired - private WeChatPayUtil weChatPayUtil; @Autowired UserService userService; @@ -41,18 +37,26 @@ public class OrderService extends ServiceImpl { GoodsService goodsService; @Transactional(rollbackFor = Exception.class) - public JSONObject addOrUpdate(JSONObject jsonObject) { + public Result addOrUpdate(JSONObject jsonObject) { Order order = jsonObject.toJavaObject(Order.class); if (order == null) { - return new JSONObject().fluentPut("success", false).fluentPut("message", "参数错误"); + return Result.error("参数错误"); } if (!StringUtils.hasLength(order.getAddress())) { User user = userService.getById(order.getUserId()); order.setAddress(user.getAddress()); } - // TODO 判空 + if (order.getUserId() == null || order.getAddress() == null || order.getNum() == null || order.getGoodsId() == null) { + return Result.error("请携带完整的参数"); + } + String orderCode = UUID.randomUUID().toString().replace("-", ""); + order.setOrderCode(orderCode); boolean success = saveOrUpdate(order); - return new JSONObject().fluentPut("message", "success").fluentPut("success", success); + if(success){ + return Result.success(orderCode); + }else { + return Result.error("未知错误,请联系管理员!"); + } } public JSONObject list(JSONObject jsonObject) { @@ -131,39 +135,5 @@ public class OrderService extends ServiceImpl { saveOrUpdate(order); } - /** - * 订单支付 - * - * @param ordersPaymentDTO - * @return - */ - public Result payment(JSONObject ordersPaymentDTO) throws Exception { - // 当前登录用户id - String openId = ordersPaymentDTO.getString("openId"); - String orderCode = ordersPaymentDTO.getString("orderCode"); - List userList = userService.list(); - User user = userList.stream().filter(e -> Objects.equals(e.getOpenId(), openId)).findFirst().orElse(null); - if (user == null) { - return Result.error("查询不到该用户"); - } - //调用微信支付接口,生成预支付交易单 - JSONObject jsonObject = weChatPayUtil.pay( - orderCode, //商户订单号 - new BigDecimal(0.01), //支付金额,单位 元 - "Test123", //商品描述 - user.getOpenId() //微信用户的openid - ); - - if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) { - return Result.error("该订单已支付"); - } - -// OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class); -// vo.setPackageStr(jsonObject.getString("package")); -// -// return vo; - return Result.success(); - } - } diff --git a/src/main/java/com/bigdata/wxappserver/utils/SignV3Util.java b/src/main/java/com/bigdata/wxappserver/utils/SignV3Util.java deleted file mode 100644 index c3d921a..0000000 --- a/src/main/java/com/bigdata/wxappserver/utils/SignV3Util.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.bigdata.wxappserver.utils; - -import okhttp3.HttpUrl; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import javax.crypto.Cipher; -import javax.crypto.NoSuchPaddingException; -import java.io.UnsupportedEncodingException; -import java.security.*; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.util.Base64; -import java.util.HashMap; -import java.util.Random; - -/** - * Created with IntelliJ IDEA. - * - * @Author: Cool - * @Date: 2024/09/03/20:34 - * @Description: - */ -@Component -public class SignV3Util{ - //V3主商户ID - private static String merchantId; - //微信商户平台APIv3证书序列号 - private static String certificateSerialNo; - //私钥(不要把私钥文件暴露在公共场合,如上传到Github,写在客户端代码等。) - private static String privateKey; - - //配置文件配置好主商户号 - @Value("${dx.wechat.mchid}") - public void setMerchantId(String merchantId) { - SignV3Util.merchantId = merchantId; - } - - //配置文件配置好序列号 - @Value("${dx.wechat.mchSerialNo}") - public void setCertificateSerialNo(String certificateSerialNo) { - SignV3Util.certificateSerialNo = certificateSerialNo; - } - - //配置文件配置好私钥 - @Value("${dx.wechat.apiV3Key}") - public void setPrivateKey(String privateKey) { - SignV3Util.privateKey = privateKey; - } - - /** - * 使用方法 - * - * @param method 请求方法 - * @param url 请求url - * @param body 请求内容 - * @return - */ - public static HashMap getSignMap(String method, String url, String body) throws InvalidKeySpecException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException, SignatureException { - String authorization = getSign(method, url, body); - - HashMap headsMap = new HashMap<>(); - headsMap.put("Authorization", authorization); - headsMap.put("Content-Type", "application/json"); - headsMap.put("Accept", "application/json"); - - return headsMap; - } - - public static String getSign(String method, String url, String body) throws NoSuchAlgorithmException, SignatureException, InvalidKeySpecException, InvalidKeyException, UnsupportedEncodingException { - return "WECHATPAY2-SHA256-RSA2048 " + getToken(method, HttpUrl.parse(url), body); - } - - public static String getToken(String method, HttpUrl url, String body) throws UnsupportedEncodingException, SignatureException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException { - String nonceStr = nonceString(); - long timestamp = System.currentTimeMillis() / 1000; - String message = buildMessage(method, url, timestamp, nonceStr, body); - String signature = sign(message.getBytes("utf-8")); - return "mchid=\"" + merchantId + "\"," - + "nonce_str=\"" + nonceStr + "\"," - + "timestamp=\"" + timestamp + "\"," - + "serial_no=\"" + certificateSerialNo + "\"," - + "signature=\"" + signature + "\""; - } - - public static String sign(byte[] message) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException { - Signature sign = Signature.getInstance("SHA256withRSA"); - sign.initSign(getPKCS8PrivateKey(privateKey)); - sign.update(message); - - return Base64.getEncoder().encodeToString(sign.sign()); - } - - public static String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) { - String canonicalUrl = url.encodedPath(); - if (url.encodedQuery() != null) { - canonicalUrl += "?" + url.encodedQuery(); - } - - return method + "\n" - + canonicalUrl + "\n" - + timestamp + "\n" - + nonceStr + "\n" - + body + "\n"; - } - - - private static PrivateKey getPKCS8PrivateKey(String strPk) throws NoSuchAlgorithmException, InvalidKeySpecException { - String realPK = strPk.replaceAll("-----END PRIVATE KEY-----", "") - .replaceAll("-----BEGIN PRIVATE KEY-----", "") - .replaceAll("\n", ""); - - byte[] b1 = Base64.getDecoder().decode(realPK); - - PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(b1); - - KeyFactory kf = KeyFactory.getInstance("RSA"); - - return kf.generatePrivate(spec); - } - - public static String nonceString() { - - String currTime = String.format("%d", (long) System.currentTimeMillis() / 1000); - - String strTime = currTime.substring(8, currTime.length()); - - Random random = new Random(); - int num = (int) (random.nextDouble() * (1000000 - 100000) + 100000); - String code = String.format("%06d", num); - - String nonce_str = currTime.substring(2) + code; - return nonce_str; - - } -} - - diff --git a/src/main/java/com/bigdata/wxappserver/utils/WeChatPayUtil.java b/src/main/java/com/bigdata/wxappserver/utils/WeChatPayUtil.java deleted file mode 100644 index c1d4991..0000000 --- a/src/main/java/com/bigdata/wxappserver/utils/WeChatPayUtil.java +++ /dev/null @@ -1,233 +0,0 @@ -package com.bigdata.wxappserver.utils; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.bigdata.wxappserver.properties.WeChatProperties; -import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder; -import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; -import org.apache.commons.lang.RandomStringUtils; -import org.apache.http.HttpHeaders; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.util.EntityUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.math.BigDecimal; -import java.security.PrivateKey; -import java.security.Signature; -import java.security.cert.X509Certificate; -import java.util.*; - -/** - * 微信支付工具类 - */ -@Component -public class WeChatPayUtil { - - //微信支付下单接口地址 - public static final String PAY_API = "https://api.mch.weixin.qq.com/pay/unifiedorder"; - - //申请退款接口地址 - public static final String REFUNDS = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"; - - @Autowired - private WeChatProperties weChatProperties; - - /** - * 获取调用微信接口的客户端工具对象 - * - * @return - */ - private CloseableHttpClient getClient() { - PrivateKey merchantPrivateKey = null; - try { - //merchantPrivateKey商户API私钥,如何加载商户API私钥请看常见问题 - merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(new File(weChatProperties.getPrivateKeyFilePath()))); - //加载平台证书文件 - X509Certificate x509Certificate = PemUtil.loadCertificate(new FileInputStream(new File(weChatProperties.getWeChatPayCertFilePath()))); - //wechatPayCertificates微信支付平台证书列表。你也可以使用后面章节提到的“定时更新平台证书功能”,而不需要关心平台证书的来龙去脉 - List wechatPayCertificates = Arrays.asList(x509Certificate); - - WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create() - .withMerchant(weChatProperties.getMchId(), weChatProperties.getMchSerialNo(), merchantPrivateKey) - .withWechatPay(wechatPayCertificates); - - // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签 - CloseableHttpClient httpClient = builder.build(); - return httpClient; - } catch (FileNotFoundException e) { - e.printStackTrace(); - return null; - } - } - - /** - * 发送post方式请求 - * - * @param url - * @param body - * @return - */ - private String post(String url, String body) throws Exception { - CloseableHttpClient httpClient = getClient(); - - HttpPost httpPost = new HttpPost(url); - httpPost.addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString()); - httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); - httpPost.addHeader("Wechatpay-Serial", weChatProperties.getMchSerialNo()); - httpPost.setEntity(new StringEntity(body, "UTF-8")); - - CloseableHttpResponse response = httpClient.execute(httpPost); - try { - String bodyAsString = EntityUtils.toString(response.getEntity()); - return bodyAsString; - } finally { - httpClient.close(); - response.close(); - } - } - - /** - * 发送get方式请求 - * - * @param url - * @return - */ - private String get(String url) throws Exception { - CloseableHttpClient httpClient = getClient(); - - HttpGet httpGet = new HttpGet(url); - httpGet.addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString()); - httpGet.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); - httpGet.addHeader("Wechatpay-Serial", weChatProperties.getMchSerialNo()); - - CloseableHttpResponse response = httpClient.execute(httpGet); - try { - String bodyAsString = EntityUtils.toString(response.getEntity()); - return bodyAsString; - } finally { - httpClient.close(); - response.close(); - } - } - - /** - * jsapi下单 - * - * @param orderNum 商户订单号 - * @param total 总金额 - * @param description 商品描述 - * @param openid 微信用户的openid - * @return - */ - private String jsapi(String orderNum, BigDecimal total, String description, String openid) throws Exception { - JSONObject jsonObject = new JSONObject(); - jsonObject.put("appid", weChatProperties.getAppId()); - jsonObject.put("mchid", weChatProperties.getMchId()); - jsonObject.put("description", description); - jsonObject.put("out_trade_no", orderNum); - jsonObject.put("nonce_str", UUID.randomUUID().toString()); - jsonObject.put("notify_url", weChatProperties.getNotifyUrl()); - - JSONObject amount = new JSONObject(); - amount.put("total", total.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue()); - amount.put("currency", "CNY"); - - jsonObject.put("amount", amount); - - JSONObject payer = new JSONObject(); - payer.put("openid", openid); - - jsonObject.put("payer", payer); - - String body = jsonObject.toJSONString(); - return post(PAY_API, body); - } - - /** - * 小程序支付 - * - * @param orderNum 商户订单号 - * @param total 金额,单位 元 - * @param description 商品描述 - * @param openid 微信用户的openid - * @return - */ - public JSONObject pay(String orderNum, BigDecimal total, String description, String openid) throws Exception { - //统一下单,生成预支付交易单 - String bodyAsString = jsapi(orderNum, total, description, openid); - //解析返回结果 - JSONObject jsonObject = JSON.parseObject(bodyAsString); - System.out.println(jsonObject); - - String prepayId = jsonObject.getString("prepay_id"); - if (prepayId != null) { - String timeStamp = String.valueOf(System.currentTimeMillis() / 1000); - String nonceStr = RandomStringUtils.randomNumeric(32); - ArrayList list = new ArrayList<>(); - list.add(weChatProperties.getAppId()); - list.add(timeStamp); - list.add(nonceStr); - list.add("prepay_id=" + prepayId); - //二次签名,调起支付需要重新签名 - StringBuilder stringBuilder = new StringBuilder(); - for (Object o : list) { - stringBuilder.append(o).append("\n"); - } - String signMessage = stringBuilder.toString(); - byte[] message = signMessage.getBytes(); - - Signature signature = Signature.getInstance("SHA256withRSA"); - signature.initSign(PemUtil.loadPrivateKey(new FileInputStream(new File(weChatProperties.getPrivateKeyFilePath())))); - signature.update(message); - String packageSign = Base64.getEncoder().encodeToString(signature.sign()); - - //构造数据给微信小程序,用于调起微信支付 - JSONObject jo = new JSONObject(); - jo.put("timeStamp", timeStamp); - jo.put("nonceStr", nonceStr); - jo.put("package", "prepay_id=" + prepayId); - jo.put("signType", "RSA"); - jo.put("paySign", packageSign); - - return jo; - } - return jsonObject; - } - - /** - * 申请退款 - * - * @param outTradeNo 商户订单号 - * @param outRefundNo 商户退款单号 - * @param refund 退款金额 - * @param total 原订单金额 - * @return - */ - public String refund(String outTradeNo, String outRefundNo, BigDecimal refund, BigDecimal total) throws Exception { - JSONObject jsonObject = new JSONObject(); - jsonObject.put("out_trade_no", outTradeNo); - jsonObject.put("out_refund_no", outRefundNo); - - JSONObject amount = new JSONObject(); - amount.put("refund", refund.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue()); - amount.put("total", total.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue()); - amount.put("currency", "CNY"); - - jsonObject.put("amount", amount); - jsonObject.put("notify_url", weChatProperties.getRefundNotifyUrl()); - - String body = jsonObject.toJSONString(); - - //调用申请退款接口 - return post(REFUNDS, body); - } -} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 225351a..1ee0a4d 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -14,14 +14,4 @@ mybatis-plus: mapper-locations: classpath*:/mapper/*Mapper.xml configuration: map-underscore-to-camel-case: true -dx: - wechat: - appId: wx865aefa5a7115ae0 - secret: df0817d59696a6160de2770222d8ec53 - mchId: 1684540409 - mchSerialNo: 1E860B81D50719F1AA6AB92F00033A222F81C72C - privateKeyFilePath: classpath:template/wechatpay_429733475DFDCEBE2A6135485F984EE337297F4F.pem - apiV3Key: d5a58d44588b42cbbe01daa5cfa4e792 - weChatPayCertFilePath: classpath:template/wechatpay_429733475DFDCEBE2A6135485F984EE337297F4F.pem - notifyUrl: https://www.weixin.qq.com/wxpay/pay.php - refundNotifyUrl: https://www.weixin.qq.com/wxpay/pay.php + diff --git a/src/main/resources/template/apiclient_cert.p12 b/src/main/resources/template/apiclient_cert.p12 deleted file mode 100644 index b5f65f10f36107c525a3b5998417097b634f895c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2782 zcmY+^cRU-476ZMACe71U~KkD9%u6sbL`t)ddMw%U}`rZ!b2 zMywXsj2hQYjpu$o@4frpALnyE=XcKM{P{&v#}5W5(_?|0{-3h|JeYMSE-@@{y-0;MlyhDYfzd_<0Ua(R8+Kp zP%OCj&Tt+H{C?T{yz)zZ!6St~I@MfX_==k|G9d~bAMdJSLDE- zF&)|;6{yS~XqE2&)06zNBpaG335PE`QbO}`)m~ZWW{psEW%ZKbE&{>)n!7hx;&;MX ze$SGuS9fe%G-0N!X(=Spsav=ESC>*HB{WhU>=rZ+SB&H!Plm_d8I@+_hfp7UU_SH+ zO7l&mAIQ}`mXE$Kp0bzCXz|%y0^TD&{(01g|7F8UO^wRRk!q1#*|r@%6xeIb6DgD) zM~k;EWzeu^_zTRKeE0S<5+WgCsmlZ-{^C(Un74bm-y=!7GEUOZ*!Hib)649j*a*p_ zG{mk*fE2)WqBC7tMtZRV8ni2ANH`5TT-J7-JqWbr1q>+_G&=HC$r zy`z$oYr7n%sPkIQ+Blz!`O=Dmy3FH!iutH1o1J6F3}i=Hn)~Hy&1XzBu}+mNpO1Y%c( zxdd7TnGk9cvChW&*|4We*VhkPR4!rlb5KHt0X6%Ey=xxTjnF*lMSmi9e7uj(>}!s(6(ugJ`#`1*;tEx5_Y-ltdEJ>=pP6+FRv{rrxoR1m(FW$sL9@&U= z&9_veVu1#3E_)-xQ}C$bf>oof=z9zK5rb?mPs|ANI*zSR+@Ac|-r{zZ6r2`UtgSrO z_l^I&q6qKx)57(;jtHj<6sO>&yBr^RV6VJ>{)v3=e5oWX%Bw?=82heng}pb2n%yIC zW4{UAsD+5*T*hw7(<@}{K7Ym&_}1RKFpF!r-7=0pcpdQArHpS@{X@nz@~X9hakFFh zQ<~*HV7F+5dyY2SOsK@zTZEtN8^YFhvtiznN>E#9jN2&Z8Fgc6x}i9LRUXcH*v+zMlL?QAo1z{z;{8S6BrA@T*S5)Wkn79 z4}(x3RW=s9c>(46|LF+&TSw5rQGstYP5$3Hf-iJ*wJPjX|7+EzO3Hd8?|i03CklVS z)L8${sq%(QbFh3Q1H#8(T8=*eo^{7V$(&ATt~}b7K(mbzc@=q&{4poz5g(gJYB`k@ zIW?9?WJfrqDD^B5RvR;oN0QqP=apC?Ij?)T2SGYvU}xje8#H$aHa)(>7~JKVhZa8* zVL^m+M>&)@^D~kjdJ+UV(uk|zGASJAn07bzEp!_ULU-vm)nrU@T08;SKTP&XaW;N( zdPkQJp^J!qhx&NyHtr@LR{dHv8vxvaG<~bB>1Jk^l&+qzjS={SB;c!1Oe#fr_@hPmQb7MxH z`@6wxstSn!6%=?sf6R7gxjfUlw$%(VCiQEk&M6ly^GCCpQa)&LbAg!7t?K%q^MS?O z`Q2_y&!_n_-g<8f!i(E>hC90&R3D#LY9x1UsZMy;!bk}Q?H%5BOH;>1YUt?{kwo66 zh_G}P+FuiUf-2~;+>^;NGigfLQj#f`qyg}KA3U}zb(AqARxSyp`v^Jc$*fFM|u?*iyZ`=Ceyf_fX z%9Wz4fM&w2lN7ZIQKTjtbPmq&MPD3+^L#ZV9@dy+;O*_iA2`f=J4?N)DUO4t&A*?ICY5)mlvdW2ODn!b zQQbG9+gL)+#>_5Z&mPZwHPH%da9JjPwdj6`fPVR$UC(W!_cqdea810}Rnupq@Ux#2 zw>33RGt>MDmOWa(3lNS!PFSb=f;X#Knr*fi;yJJS`4NZ+e=E&)ISnX>Q6tF5Js$ zbGD2OsjJ>UN#96?M;eWofvY^p?)x@#be(^~CfAye!JcDpjv zb3w;1SM2k`#|rDOu~rUwtXAb>Pro{!>o`6a9cn5URmQ$Jp9^dL&f(O%6c6InhTyao z2SdwO(QqirZ|rmSk8+DIU5Y@$By(-S-Gzr$Y^---fdvWmN>T<*A&34tYU0nmN=q_Rm}FA` heads = SignV3Util.getSignMap("POST", "https://api.mch.weixin.qq.com/pay/unifiedorder", param); - //请求微信接口 - HttpPost post = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder"); - for (Map.Entry entry : heads.entrySet()) { - post.addHeader(entry.getKey(), entry.getValue()); - } - // 设置请求参数 - StringEntity entity = new StringEntity(JSON.toJSONString("请求参数"), "UTF-8"); - post.setEntity(entity); - // 发送POST请求 - CloseableHttpResponse response = httpClient.execute(post); - - try { - // 获取响应实体 - HttpEntity responseEntity = response.getEntity(); - - if (responseEntity != null) { - // 打印响应内容 - System.out.println("Response content: " + EntityUtils.toString(responseEntity, "UTF-8")); - } - } finally { - response.close(); - } - } }
v#}5W5(_?|0{-3h|JeYMSE-@@{y-0;MlyhDYfzd_<0Ua(R8+Kp zP%OCj&Tt+H{C?T{yz)zZ!6St~I@MfX_==k|G9d~bAMdJSLDE- zF&)|;6{yS~XqE2&)06zNBpaG335PE`QbO}`)m~ZWW{psEW%ZKbE&{>)n!7hx;&;MX ze$SGuS9fe%G-0N!X(=Spsav=ESC>*HB{WhU>=rZ+SB&H!Plm_d8I@+_hfp7UU_SH+ zO7l&mAIQ}`mXE$Kp0bzCXz|%y0^TD&{(01g|7F8UO^wRRk!q1#*|r@%6xeIb6DgD) zM~k;EWzeu^_zTRKeE0S<5+WgCsmlZ-{^C(Un74bm-y=!7GEUOZ*!Hib)649j*a*p_ zG{mk*fE2)WqBC7tMtZRV8ni2ANH`5TT-J7-JqWbr1q>+_G&=HC$r zy`z$oYr7n%sPkIQ+Blz!`O=Dmy3FH!iutH1o1J6F3}i=Hn)~Hy&1XzBu}+mNpO1Y%c( zxdd7TnGk9cvChW&*|4We*VhkPR4!rlb5KHt0X6%Ey=xxTjnF*lMSmi9e7uj(>}!s(6(ugJ`#`1*;tEx5_Y-ltdEJ>=pP6+FRv{rrxoR1m(FW$sL9@&U= z&9_veVu1#3E_)-xQ}C$bf>oof=z9zK5rb?mPs|ANI*zSR+@Ac|-r{zZ6r2`UtgSrO z_l^I&q6qKx)57(;jtHj<6sO>&yBr^RV6VJ>{)v3=e5oWX%Bw?=82heng}pb2n%yIC zW4{UAsD+5*T*hw7(<@}{K7Ym&_}1RKFpF!r-7=0pcpdQArHpS@{X@nz@~X9hakFFh zQ<~*HV7F+5dyY2SOsK@zTZEtN8^YFhvtiznN>E#9jN2&Z8Fgc6x}i9LRUXcH*v+zMlL?QAo1z{z;{8S6BrA@T*S5)Wkn79 z4}(x3RW=s9c>(46|LF+&TSw5rQGstYP5$3Hf-iJ*wJPjX|7+EzO3Hd8?|i03CklVS z)L8${sq%(QbFh3Q1H#8(T8=*eo^{7V$(&ATt~}b7K(mbzc@=q&{4poz5g(gJYB`k@ zIW?9?WJfrqDD^B5RvR;oN0QqP=apC?Ij?)T2SGYvU}xje8#H$aHa)(>7~JKVhZa8* zVL^m+M>&)@^D~kjdJ+UV(uk|zGASJAn07bzEp!_ULU-vm)nrU@T08;SKTP&XaW;N( zdPkQJp^J!qhx&NyHtr@LR{dHv8vxvaG<~bB>1Jk^l&+qzjS={SB;c!1Oe#fr_@hPmQb7MxH z`@6wxstSn!6%=?sf6R7gxjfUlw$%(VCiQEk&M6ly^GCCpQa)&LbAg!7t?K%q^MS?O z`Q2_y&!_n_-g<8f!i(E>hC90&R3D#LY9x1UsZMy;!bk}Q?H%5BOH;>1YUt?{kwo66 zh_G}P+FuiUf-2~;+>^;NGigfLQj#f`qyg}KA3U}zb(AqARxSyp`v^Jc$*fFM|u?*iyZ`=Ceyf_fX z%9Wz4fM&w2lN7ZIQKTjtbPmq&MPD3+^L#ZV9@dy+;O*_iA2`f=J4?N)DUO4t&A*?ICY5)mlvdW2ODn!b zQQbG9+gL)+#>_5Z&mPZwHPH%da9JjPwdj6`fPVR$UC(W!_cqdea810}Rnupq@Ux#2 zw>33RGt>MDmOWa(3lNS!PFSb=f;X#Knr*fi;yJJS`4NZ+e=E&)ISnX>Q6tF5Js$ zbGD2OsjJ>UN#96?M;eWofvY^p?)x@#be(^~CfAye!JcDpjv zb3w;1SM2k`#|rDOu~rUwtXAb>Pro{!>o`6a9cn5URmQ$Jp9^dL&f(O%6c6InhTyao z2SdwO(QqirZ|rmSk8+DIU5Y@$By(-S-Gzr$Y^---fdvWmN>T<*A&34tYU0nmN=q_Rm}FA` heads = SignV3Util.getSignMap("POST", "https://api.mch.weixin.qq.com/pay/unifiedorder", param); - //请求微信接口 - HttpPost post = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder"); - for (Map.Entry entry : heads.entrySet()) { - post.addHeader(entry.getKey(), entry.getValue()); - } - // 设置请求参数 - StringEntity entity = new StringEntity(JSON.toJSONString("请求参数"), "UTF-8"); - post.setEntity(entity); - // 发送POST请求 - CloseableHttpResponse response = httpClient.execute(post); - - try { - // 获取响应实体 - HttpEntity responseEntity = response.getEntity(); - - if (responseEntity != null) { - // 打印响应内容 - System.out.println("Response content: " + EntityUtils.toString(responseEntity, "UTF-8")); - } - } finally { - response.close(); - } - } }