一:配置信息
在yml文件中填好以下微信支付的配置,记得enabled一定要true,因为后面用到的注解是必须要这个值为true,springboot才能识别到那个bean
wechat:
enabled: false
appId: 你的微信服务号信息(h5的时候需要,小程序的时候不需要)
secret: 你的微信服务号信息(h5的时候需要,小程序的时候不需要)
merchantId: 微信支付商户号
privateKeyPath: 微信支付密钥地址相对地址
merchantSerialNumber: 微信支付密钥对应的序列号
apiV3key: 微信支付apiV3key
notifyUrl: 微信支付回调地址
miniProgramAppId: 小程序apppid(h5的时候不需要)
miniProgramSecret: 小程序Secret(h5的时候不需要)
引入工具包
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.9</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.13</version>
</dependency>
service中的支付方法
返回给前端调用微信支付所有必要的参数,传入的是您自己的订单信息
/**
* 订单支付
*
* @param req 支付请求
* @return
*/
@Autowired(required = false)
private WechatPayService wechatPayService;
public OrderPayVO orderPay(PointOrder req) {
String orderDesc = "测试订单描述文字";
String openId = "oBV-e5OwrFph1yfp0nHREKJaXeNY";
String appId = "填写您的appId";
//请开启微信支付 wechat.enabled=true
String prepayId;
try {
//调用wx的jsapi拿prepayId,返回签名等信息
prepayId = wechatPayService.jsapiPay(
String.valueOf(req.getOrderNumber()),
orderDesc,
(int) 1,
openId,
100L,
appId
);
} catch (Exception e) {
throw new RuntimeException(e);
}
OrderPayVO response = new OrderPayVO();
response.setPayType(2);
String nonceStr = WechatPayUtil.generateNonceStr();
long timeStamp = WechatPayUtil.getCurrentTimestamp();
prepayId = "prepay_id=" + prepayId;
String signType = "RSA";
String paySign = null;
String signatureStr = Stream.of(appId, String.valueOf(timeStamp), nonceStr, prepayId)
.collect(Collectors.joining("\n", "", "\n"));
try {
paySign = WechatPayUtil.getSign(signatureStr, WechatPayData.privateKeyPath);
} catch (Exception e) {
throw new RuntimeException("支付失败");
}
response.setAppId(appId);
response.setTimeStamp(String.valueOf(timeStamp));
response.setNonceStr(nonceStr);
response.setSignType(signType);
response.setPackage_(prepayId);
response.setPaySign(paySign);
return response;
}
WechatPayService类
传入金额等参数调用JsapiService中的prepay方法
package com.ruoyi.wechat;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
@Service
@Slf4j
@ConditionalOnProperty(prefix = "wechat", name = "enabled", havingValue = "true")
public class WechatPayService {
@Autowired
private JsapiService service;
@Autowired
private RefundService refundService;
/**
* jsapi下单
* @param orderNo 订单号
* @param desc 订单描述
* @param totalAmount 总金额,单位:分
* @param openId 用户openid
* @return prepay_id
*/
public String jsapiPay(String orderNo,String desc,Integer totalAmount,String openId, Long memberId,String appId){
PrepayRequest prepayRequest = new PrepayRequest();
prepayRequest.setAppid(appId);
prepayRequest.setMchid(WechatPayData.merchantId);
prepayRequest.setDescription(desc);
prepayRequest.setOutTradeNo(orderNo);
prepayRequest.setAttach(String.valueOf(memberId));
prepayRequest.setNotifyUrl(WechatPayData.notifyUrl);
Amount amount = new Amount();
amount.setTotal(totalAmount);
prepayRequest.setAmount(amount);
Payer payer = new Payer();
payer.setOpenid(openId);
prepayRequest.setPayer(payer);
PrepayResponse response = service.prepay(prepayRequest);
return response.getPrepayId();
}
public Refund refundPay(String refundId,String payId,String notifyUrl,Long refundAmount, Long totalAmount,String reason) {
//请求参数
CreateRequest request = new CreateRequest();
request.setReason(reason);
//设置退款金额 根据自己的实际业务自行填写
AmountReq amountReq = new AmountReq();
amountReq.setRefund(refundAmount);
amountReq.setTotal(totalAmount);
amountReq.setCurrency("CNY");
request.setAmount(amountReq);
//支付成功后回调回来的transactionId 按照实际情况填写
request.setOutTradeNo(payId);
//支付成功后回调回来的transactionId 按照实际情况填写
request.setOutRefundNo(refundId);
//退款成功的回调地址
request.setNotifyUrl(notifyUrl);
//发起请求,申请退款
return refundService.create(request);
}
}
WechatConfig类
package com.ruoyi.wechat;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.refund.RefundService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
@Configuration
@DependsOn("WechatPayData")
@ConditionalOnProperty(prefix = "wechat", name = "enabled", havingValue = "true")
public class WechatConfig {
@Bean
public JsapiService jsapiService(){
return new JsapiService.Builder().config(WechatPayConfig.getInstance()).build();
}
@Bean
public RefundService refundService(){
return new RefundService.Builder().config(WechatPayConfig.getInstance()).build();
}
}
WechatPayConfig
package com.ruoyi.wechat;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
public class WechatPayConfig {
private static Config wechatPayConfig;
private WechatPayConfig(){}
public static Config getInstance() {
if (wechatPayConfig == null) {
wechatPayConfig = new RSAAutoCertificateConfig.Builder()
.merchantId(WechatPayData.merchantId)
.privateKeyFromPath(WechatPayData.privateKeyPath)
.merchantSerialNumber(WechatPayData.merchantSerialNumber)
.apiV3Key(WechatPayData.apiV3key)
.build();
}
return wechatPayConfig;
}
}
WechatPayData
这个类是映射配置文件中的微信支付配置
package com.ruoyi.wechat;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@ConfigurationProperties(prefix = "wechat")
@Component("WechatPayData")
public class WechatPayData {
/** 商户号 */
public static String appId;
public static String secret;
public static String merchantId;
/** 商户API私钥路径 */
public static String privateKeyPath;
/** 商户证书序列号 */
public static String merchantSerialNumber;
/** 商户APIV3密钥 */
public static String apiV3key;
public static String notifyUrl;
public static String miniProgramAppId;
public static String miniProgramSecret;
// 设置商户号
public void setAppId(String appId) {
WechatPayData.appId = appId;
}
// 设置密钥
public void setSecret(String secret) {
WechatPayData.secret = secret;
}
// 设置商户号
public void setMerchantId(String merchantId) {
WechatPayData.merchantId = merchantId;
}
// 设置商户API私钥路径
public void setPrivateKeyPath(String privateKeyPath) {
WechatPayData.privateKeyPath = privateKeyPath;
}
// 设置商户证书序列号
public void setMerchantSerialNumber(String merchantSerialNumber) {
WechatPayData.merchantSerialNumber = merchantSerialNumber;
}
// 设置商户APIV3密钥
public void setApiV3key(String apiV3key) {
WechatPayData.apiV3key = apiV3key;
}
// 设置通知地址
public void setNotifyUrl(String notifyUrl) {
WechatPayData.notifyUrl = notifyUrl;
}
// 设置小程序AppId
public void setMiniProgramAppId(String miniProgramAppId) {
WechatPayData.miniProgramAppId = miniProgramAppId;
}
// 设置小程序密钥
public void setMiniProgramSecret(String miniProgramSecret) {
WechatPayData.miniProgramSecret = miniProgramSecret;
}
}
WechatPayUtil
package com.ruoyi.wechat;
import cn.hutool.crypto.PemUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.util.Random;
public class WechatPayUtil {
private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final Random RANDOM = new SecureRandom();
public static String getSign(String signatureStr,String privateKey) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException, IOException, URISyntaxException {
//replace 根据实际情况,不一定都需要
String replace = privateKey.replace("\\n", "\n");
InputStream certStream = Files.newInputStream(Paths.get(privateKey));
PrivateKey merchantPrivateKey = PemUtil.readPemPrivateKey(certStream);
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(merchantPrivateKey);
sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return Base64Utils.encodeToString(sign.sign());
}
/**
* 获取随机字符串 Nonce Str
*
* @return String 随机字符串
*/
public static String generateNonceStr() {
char[] nonceChars = new char[32];
for (int index = 0; index < nonceChars.length; ++index) {
nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
}
return new String(nonceChars);
}
/**
* 日志
* @return
*/
public static Logger getLogger() {
Logger logger = LoggerFactory.getLogger("wxpay java sdk");
return logger;
}
/**
* 获取当前时间戳,单位秒
* @return
*/
public static long getCurrentTimestamp() {
return System.currentTimeMillis()/1000;
}
/**
* 获取当前时间戳,单位毫秒
* @return
*/
public static long getCurrentTimestampMs() {
return System.currentTimeMillis();
}
}
把以上几个类全部放在项目中就ok了 此代码为不含订单逻辑的