1、相关controller
package org.jeecg.modules.business.dispatch.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.DateUtils;
import org.jeecg.config.shiro.IgnoreAuth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.jeecg.modules.business.dispatch.utils.WechatPayUtil.*;
@RestController
@RequestMapping("/wx/payment")
@Slf4j
public class WxPayController {
// @Value("${wx.pay.app-id}")
// private String appId;
//
// @Value("${wx.pay.secret}")
// private String secret;
//
// @Value("${wx.pay.mch-id}")
// private String mchId;
//
// @Value("${wx.pay.serial-no}")
// private String serialNo;
//
// @Value("${wx.pay.service-domain}")
// private String serviceDomain;
//
// @Value("${wx.pay.private-key-path}")
// private String privateKeyPath;
// @Value("${wx.pay.public-key-path}")
// private String publicKeyPath;
private String appId = "wx06e3492xxxxxxxxx";
private String secret = "85837128xxxxxxxxxxxxxxxxxxxx";
private String mchId = "1715xxxxxxxx9";
private String serialNo = "332E1ED427B648Axxxxxxxxxxxxxxxxxxxxx";
private String serviceDomain = "https://api.mch.weixin.qq.com";
private String privateKeyPath = "xxxxxxxxx\apiclient_key.pem";
private String publicKeyPath = "xxxxxxxxxx\pub_key.pem";
private String certPath = "xxxxxxxxxxxx\apiclient_cert.pem";
private String apiv3Key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
private String notifyUrl = "http://xxx.xxx.xxx/wx/payment/notify";
private final PrivateKey privateKey;
private final PublicKey publicKey;
@Autowired
private IJsUnloadmoneyService jsUnloadmoneyService;
@Autowired
private IJhDispatchService jhDispatchService;
@Autowired
private IJhDispatchmaterialService jhDispatchmaterialService;
@Autowired
private IUnloadtypeService unloadtypeService;
@Autowired
private IJcVehicleService jcVehicleService;
public WxPayController() throws Exception {
this.privateKey = loadPrivateKey(privateKeyPath);
this.publicKey = readPEMPublicKey(publicKeyPath);
// this.publicKey = loadPublicKey(certPath);
}
/**
* 获取openId
* @param code
* @return
* @throws IOException
*/
// @IgnoreAuth
@GetMapping(value = "/getOpenId")
public Map<String,Object> getOpenId(@RequestParam(name = "code") String code) throws IOException {
Map<String,Object> map = new HashMap<>();
if (code != null && code.length() > 0) {
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId
+ "&secret=" + secret
+ "&js_code=" + code
+ "&grant_type=authorization_code";
HttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
HttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
// 将响应实体转为字符串
String result = EntityUtils.toString(entity);
System.out.println("result======="+result);
JSONObject json = JSONObject.parseObject(result);
String openid = json.getString("openid");
map.put("openId",openid);
String sessionKey = json.getString("session_key");
map.put("sessionKey",sessionKey);
}
return map;
}
/**
* 创建订单
* @param orderRequest
* @param response
* @return
* @throws Exception
*/
@PostMapping("/unifiedorder")
public JSONObject unifiedOrder(@RequestBody OrderRequest orderRequest, HttpServletResponse response) throws Exception {
System.out.println("openId======="+orderRequest.getOpenId());
JSONObject result = WechatPayUtil.createUnifiedOrder(orderRequest, mchId, serialNo, privateKey, serviceDomain,appId,notifyUrl);
return result;
}
//回调方法
@IgnoreAuth
@PostMapping("/notify")
public String notify(@RequestBody String body,
@RequestHeader("Wechatpay-Timestamp") String timestamp,
@RequestHeader("Wechatpay-Nonce") String nonceStr,
@RequestHeader("Wechatpay-Signature") String signature,
HttpServletRequest request) throws GeneralSecurityException, IOException {
System.out.println("body=========="+body);
JSONObject resourceObj = JSONObject.parseObject(body);
JSONObject jsonObject = JSONObject.parseObject(resourceObj.getString("resource"));
byte [] associatedData = jsonObject.getString("associated_data").getBytes();
byte [] nonce = jsonObject.getString("nonce").getBytes();
String ciphertext = jsonObject.getString("ciphertext");
//1 解密
AesUtil aesUtil = new AesUtil(apiv3Key.getBytes());
String decryptStr = aesUtil.decryptToString(associatedData, nonce, ciphertext);
System.out.println("decryptStr============"+decryptStr);
JSONObject decryptStrJson = JSONObject.parseObject(decryptStr);
//验签
try {
boolean isValid = WechatPayUtil.verifySignature(timestamp, nonceStr, body, signature, publicKey);
if (isValid) {
JSONObject responseBody = new JSONObject();
responseBody.put("code", "SUCCESS");
responseBody.put("message", "OK");
System.out.println("验签成功");
//相关业务处理逻辑
return responseBody.toJSONString();
} else {
System.err.println("Invalid signature");
return "{\"code\":\"FAIL\",\"message\":\"Invalid Signature\"}";
}
} catch (Exception e) {
System.err.println("Error verifying signature="+e);
return "{\"code\":\"FAIL\",\"message\":\"Internal Server Error\"}";
}
}
}
2、相实体类
package org.jeecg.modules.business.dispatch.entity;
public class OrderRequest {
private String outTradeNo;
private int amount;
private String openId;
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getOutTradeNo() {
return outTradeNo;
}
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
}
3、相关工具类
3.1 解密
package org.jeecg.modules.business.dispatch.utils;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AesUtil {
static final int KEY_LENGTH_BYTE = 32;
static final int TAG_LENGTH_BIT = 128;
private final byte[] aesKey;
public AesUtil(byte[] key) {
if (key.length != KEY_LENGTH_BYTE) {
throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
}
this.aesKey = key;
}
public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext)
throws GeneralSecurityException, IOException {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData);
return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e);
}
}
}
3.2支付相关
package org.jeecg.modules.business.dispatch.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
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.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.operator.ContentVerifierProvider;
import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
import org.jeecg.modules.business.dispatch.entity.OrderRequest;
import java.io.FileReader;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
public class WechatPayUtil {
/**
* 创建下单
*
* @param orderRequest
* @param mchId
* @param serialNo
* @param privateKey
* @param apiUrl
* @param appId
* @return
* @throws Exception
*/
public static JSONObject createUnifiedOrder(OrderRequest orderRequest, String mchId, String serialNo, PrivateKey privateKey, String apiUrl, String appId,String notifyUrl) throws Exception {
CloseableHttpClient httpClient = HttpClients.custom().build();
String url = apiUrl + "/v3/pay/transactions/jsapi";
HttpPost httpPost = new HttpPost(url);
// 请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("appid", appId); // 替换为你的小程序AppID
requestBody.put("mchid", mchId);
requestBody.put("description", "司机缴费");
requestBody.put("notify_url", notifyUrl);
requestBody.put("out_trade_no", orderRequest.getOutTradeNo());
//TODO 当前费用为测试费用,需要更改成实际费用
requestBody.put("amount", Map.of("total", 1));
// requestBody.put("amount", Map.of("total", orderRequest.getAmount()));
requestBody.put("payer", Map.of("openid", orderRequest.getOpenId())); // 替换为实际的用户openid
String jsonBody = JSON.toJSONString(requestBody);
System.out.println("jsonBody==========" + jsonBody);
StringEntity entity = new StringEntity(jsonBody, StandardCharsets.UTF_8);
httpPost.setEntity(entity);
httpPost.setHeader("Content-Type", "application/json");
httpPost.setHeader("Accept", "application/json");
// 签名
String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");
// String timestamp = LocalDateTime.now().format(FORMATTER).replace("+0000", "Z");
String timestamp = new Date().getTime() / 1000 + "";
System.out.println("timestamp=============" + timestamp);
String message = "POST" + "\n"
+ "/v3/pay/transactions/jsapi" + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ jsonBody + "\n";
String signature = sign(message.getBytes(StandardCharsets.UTF_8), privateKey);
httpPost.setHeader("Authorization", "WECHATPAY2-SHA256-RSA2048 "
+ "mchid=\"" + mchId + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "signature=\"" + signature + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"" + serialNo + "\"");
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
HttpEntity responseEntity = response.getEntity();
System.out.println("-------1------");
if (responseEntity != null) {
String responseBody = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
System.out.println("responseBody============" + responseBody);
String prepayId = JSONObject.parseObject(responseBody).getString("prepay_id");
JSONObject jsonObject = new JSONObject();
String payMessage = appId + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ "prepay_id=" + prepayId + "\n";
String paySignature = sign(payMessage.getBytes(StandardCharsets.UTF_8), privateKey);
jsonObject.put("prepayId", prepayId);
jsonObject.put("nonceStr", nonceStr);
jsonObject.put("signature", paySignature);
jsonObject.put("signType", "RSA");
jsonObject.put("timestamp", timestamp);
return jsonObject;
}
System.out.println("-------2------");
}
return null;
}
/**
* 验签
*
* @param timestamp
* @param nonceStr
* @param body
* @param signature
* @param publicKey
* @return
* @throws Exception
*/
public static boolean verifySignature(String timestamp, String nonceStr, String body, String signature, PublicKey publicKey) throws Exception {
// 拼接待签名字符串
String message = timestamp + "\n"
+ nonceStr + "\n"
+ body + "\n";
// 添加 Bouncy Castle 提供者支持
Security.addProvider(new BouncyCastleProvider());
// 初始化 Signature 实例
Signature signatureInstance = Signature.getInstance("SHA256withRSA", "BC");
signatureInstance.initVerify(publicKey);
signatureInstance.update(message.getBytes());
// 解码签名字符串为字节数组
byte[] decodedSignature = Base64.getDecoder().decode(signature);
// 执行验签
return signatureInstance.verify(decodedSignature);
}
/**
* 获取公钥
*
* @param publicKeyPath
* @return
* @throws Exception
*/
public static PublicKey loadPublicKey(String publicKeyPath) throws Exception {
try (FileReader reader = new FileReader(publicKeyPath);
PEMParser pemParser = new PEMParser(reader)) {
Object object = pemParser.readObject();
if (object instanceof X509CertificateHolder) {
X509CertificateHolder certHolder = (X509CertificateHolder) object;
JcaX509CertificateConverter converter = new JcaX509CertificateConverter();
converter.setProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
java.security.cert.Certificate certificate = converter.getCertificate(certHolder);
System.out.println("certificate.getPublicKey()========"+certificate.getPublicKey());
return certificate.getPublicKey();
} else {
throw new IllegalArgumentException("Unsupported key type: " + object.getClass().getName());
}
}
}
public static PublicKey readPEMPublicKey(String pemFilePath) throws Exception {
Security.addProvider(new BouncyCastleProvider());
// 1. 读取 PEM 文件
FileReader fileReader = new FileReader(pemFilePath);
PEMParser pemParser = new PEMParser(fileReader);
Object object = pemParser.readObject();
pemParser.close();
// 2. 转换为 PublicKey
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
return converter.getPublicKey((SubjectPublicKeyInfo) object);
}
/**
* 签名
*
* @param message
* @param privateKey
* @return
* @throws Exception
*/
private static String sign(byte[] message, PrivateKey privateKey) throws Exception {
Security.addProvider(new BouncyCastleProvider());
java.security.Signature signatureInstance = java.security.Signature.getInstance("SHA256withRSA", "BC");
signatureInstance.initSign(privateKey);
signatureInstance.update(message);
byte[] signedBytes = signatureInstance.sign();
return Base64.getEncoder().encodeToString(signedBytes);
}
/**
* 获取私钥
*
* @param path
* @return
* @throws Exception
*/
public static PrivateKey loadPrivateKey(String path) throws Exception {
Security.addProvider(new BouncyCastleProvider());
try (FileReader reader = new FileReader(path);
PEMParser pemParser = new PEMParser(reader)) {
Object object = pemParser.readObject();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
converter.setProvider(BouncyCastleProvider.PROVIDER_NAME);
if (object instanceof PEMKeyPair) {
PEMKeyPair pemKeyPair = (PEMKeyPair) object;
return converter.getPrivateKey(pemKeyPair.getPrivateKeyInfo());
} else if (object instanceof PrivateKeyInfo) {
PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) object;
return converter.getPrivateKey(privateKeyInfo);
} else {
throw new IllegalArgumentException("Unsupported key type: " + object.getClass().getName());
}
}
}
}
&spm=1001.2101.3001.5002&articleId=147616431&d=1&t=3&u=7567a255495643dc9da164297b3d65d6)
147

被折叠的 条评论
为什么被折叠?



