订单接口修改
This commit is contained in:
parent
fccdb9c8ed
commit
ab8a2f0714
24
pom.xml
24
pom.xml
|
@ -62,30 +62,6 @@
|
|||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.83</version>
|
||||
</dependency>
|
||||
<!--微信支付-->
|
||||
<dependency>
|
||||
<groupId>com.github.wechatpay-apiv3</groupId>
|
||||
<artifactId>wechatpay-apache-httpclient</artifactId>
|
||||
<version>0.4.8</version>
|
||||
</dependency>
|
||||
<!-- 引入jar包-->
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>3.5.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.wechatpay-apiv3</groupId>
|
||||
<artifactId>wechatpay-java</artifactId>
|
||||
<version>0.2.14</version>
|
||||
</dependency>
|
||||
<!-- 微信支付API -->
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-pay</artifactId>
|
||||
<version>4.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Object, Object> 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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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; //退款成功的回调地址
|
||||
|
||||
}
|
|
@ -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<OrderMapper, Order> {
|
||||
@Autowired
|
||||
private WeChatPayUtil weChatPayUtil;
|
||||
@Autowired
|
||||
UserService userService;
|
||||
|
||||
|
@ -41,18 +37,26 @@ public class OrderService extends ServiceImpl<OrderMapper, Order> {
|
|||
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<OrderMapper, Order> {
|
|||
saveOrUpdate(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单支付
|
||||
*
|
||||
* @param ordersPaymentDTO
|
||||
* @return
|
||||
*/
|
||||
public Result payment(JSONObject ordersPaymentDTO) throws Exception {
|
||||
// 当前登录用户id
|
||||
String openId = ordersPaymentDTO.getString("openId");
|
||||
String orderCode = ordersPaymentDTO.getString("orderCode");
|
||||
List<User> 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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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<String, String> getSignMap(String method, String url, String body) throws InvalidKeySpecException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException, SignatureException {
|
||||
String authorization = getSign(method, url, body);
|
||||
|
||||
HashMap<String, String> 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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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<X509Certificate> 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<Object> 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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
Binary file not shown.
|
@ -1,28 +0,0 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDE4z0uWRbfuMPP
|
||||
m19ZOd3CoKmm20Rdp0EJGsYsItxWk1veEUrtUDGUevrBpAWxSW6ka6YRcs3G6nzK
|
||||
sAkrOzoFOU1xTH4I0qrspIelXwLZMYKZrdR+G+LNS9gmITrvkBKlZsrWTNOxStv1
|
||||
0CTeWPr3mBUt3SrUOHPX+eY5JR1XgBau8Y/9hd5fiYuPTCoWQsM+IUIXBrWsaEqI
|
||||
oDrymtFH8Nupgz55g8qgUX0jxb1yjcuenO7jlonqMySIpZuNrAxla4GnfERG7TAL
|
||||
36VYJ/f4QWiHpa8lg4azq/FgwegL7nVo2wcDoCcqkIjDvyYxTXtwwn7llFSa44B9
|
||||
abXQ4Ip3AgMBAAECggEBAMCtwcoB1ajLoJUjcIRZZPR7Vou8OYONks/eK+I1m3v+
|
||||
agFA2xqzSFIOqCeo5QlC28x8rOCWgVsRT17sN4zfQUCre2ZNfWoVAMDlovnrqVX0
|
||||
ZeMPgsyHbcWLW9S04IBhdl334rkmJmVy5SACupH+clyrsM5Zivh05qmOHgf+kmB1
|
||||
dpG8oJ+4gaAg5f8YQ0S3q0jJy/Tr2tZRaTU5S1Gaa3xmfDHBvte6bmmSrjF7V56M
|
||||
hibEOqvjrgK04P20FtFH7Laug4tq5IMyi6L9XVN2tE06c0epN7+Z7oBEzeTuQ+zU
|
||||
EwEnNwH7GG+JYjUIrxlQMr6XXNEWv/iDhbXKJd5zvoECgYEA/9AFOlQthPdR0dY3
|
||||
9N9q41jmrxvF0yep+MFw4+X7sEV+gnLLRATQCnsBF+Br3DHdUU2H8DwtOEYD8V9L
|
||||
Ks8j7B9ivVcbs4KT6iu3ehrQgX2DvnGov+ZlRpVwWV90CppLzubuX++0L8K/dYfF
|
||||
OPpm128k18BgwWY+4UvD1BClrU8CgYEAxQgqsEysa9RUcKFcPMMkMUG3SDvB0+q3
|
||||
vkn4EDZVgUoojQnk54vQ4U6pbF4KTPPHvNF4vrmu5DdhSWBBnHAchdLHO7NXVl7n
|
||||
cIPOHnakzauiS+jZlokpf4bMIECsQMW+n6c2WfT4mhbciCTo4+oLBu/aZ/tS/fUu
|
||||
EJyW2+/VllkCgYByexSr2toYJFpgbt7R3l5GahWqjeJFMf32DhPIWbb+Vstb86WV
|
||||
xhWYax29IrkCbOpfpTPNxhBym5rOHVhVSygHVrBojaAfALPTW0ccBP4ExTf9NX5Q
|
||||
ivoN0Xja9kXHLO/6IwzQsERSD3SBU4ZmjmERznKNf1GNm4VObAqyT9TlLwKBgQCT
|
||||
R1OBjQ6lW4Xy2urzkHqRRyoVmHV+TskiOHBwzeyEREajhm3QlraAdCg4lOLmOqNn
|
||||
BL1Y87tDZBIYoxboNPVdIv1CJwB102L0u9Fq/AycoFskmt1qpQScCsqyoSUhFa8z
|
||||
7+20uGTL6aLXMZ/UHbI4cTm02CxlIMxaJnKt3EyvoQKBgQCeZwTjaqIQmR3fBrNm
|
||||
MG0qO652ONVLirzEsfn7DpxPC6+ON3MGuPZxaiSaYwAhQq3dqQ/dpJoxrInPMScH
|
||||
bebJz33OLTH4+1t4NvNDJkauWwuDI46uZhX+MVfIelNC5j5V+qrd1n614nQe9pJJ
|
||||
UMlUt8FS3+aqnzvtYMOs6MNO9g==
|
||||
-----END PRIVATE KEY-----
|
|
@ -1,4 +1,3 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIEFDCCAvygAwIBAgIUQpczR139zr4qYTVIX5hO4zcpf08wDQYJKoZIhvcNAQEL
|
||||
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
|
||||
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
|
||||
|
@ -21,4 +20,3 @@ IRlGr714v8WoudsIwuT7U6t4rws6mekrPrh9tTtDr6xpEuuLaYe0gJrpFM0UbryO
|
|||
H20I1g2mxzmXl3MuGq8zB+fGQUy+MIO4EoUGIIEM6q7HzcCAPIVn+Qb/MCto56Ne
|
||||
YPr5a+w7g6u4UZ+sVix2AddlOnqJPBIv/t91sQtFSzew9yztW/r2b1AyUHAsYa0n
|
||||
76QTS6cjmV/Ee726l9d6tYGhF/NR9lUcXK7hr4JzA9e0zKr0JnAy8Q==
|
||||
-----END CERTIFICATE-----
|
|
@ -1,19 +1,8 @@
|
|||
package com.bigdata.wxappserver;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.bigdata.wxappserver.utils.SignV3Util;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -25,35 +14,5 @@ class WxappServerApplicationTests {
|
|||
void contextLoads() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
CloseableHttpClient httpClient = HttpClients.createDefault();
|
||||
//处理请求参数
|
||||
String param = JSON.toJSONString("请求参数");
|
||||
//获取签名请求头
|
||||
HashMap<String, String> 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<String, String> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue