去微信支付开发文档下载官方demo
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1 得到以下几个文件
编写微信常量文件用来存放密钥
代码语言:javascript复制/**
* 微信相关属性
* @author : LiYu
* @date : 2020-09-22 16:30
**/
public final class WxServiceEnvConstants {
private WxServiceEnvConstants(){}
/**
* 公众号 秘钥
*/
public static final String SECRET_KEY = "*************************";
/**
* 公众号 appId
*/
public static final String APP_ID = "*************************";
/**
* 小程序 appId
*/
public static final String APPLET_APP_ID = "*************************";
/**
* 小程序 秘钥
*/
public static final String APPLET_SECRET_KEY = "*************************";
/**
* 商家id
*/
public static final String MCH_ID = "*************************";
/**
* 商家秘钥
*/
public static final String API_SECRET_KEY = "*************************";
/**
* 商家证书地址
*/
public static final String CERT_PATH = "/cert/1554590811_20190916_cert/apiclient_cert.p12";
/**
* session_key
*/
public static final String CACHE_SESSION_KEY = "WX:SESSION_KEY:";
}
编写自己的微信配置继承WXPayConfig
代码语言:javascript复制import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
/**
* @author : LiYu
* @date : 2020-10-24 17:06
**/
public class AgentWxConfig extends WXPayConfig{
private byte[] certData;
public AgentWxConfig() throws Exception {
String certPath = WxServiceEnvConstants.CERT_PATH;
File file = new File(certPath);
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();
}
@Override
public String getAppID() {
return WxServiceEnvConstants.APPLET_APP_ID;
}
@Override
public String getMchID() {
return WxServiceEnvConstants.MCH_ID;
}
@Override
public String getKey() {
return WxServiceEnvConstants.API_SECRET_KEY;
}
@Override
public InputStream getCertStream() {
ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
return certBis;
}
@Override
public int getHttpConnectTimeoutMs() {
return 8000;
}
@Override
public int getHttpReadTimeoutMs() {
return 10000;
}
@Override
IWXPayDomain getWXPayDomain() {
return new IWXPayDomain() {
@Override
public void report(String domain, long elapsedTimeMillis, Exception ex) {
}
@Override
public DomainInfo getDomain(WXPayConfig config) {
return new DomainInfo("api.mch.weixin.qq.com", false);
}
};
}
}
微信支付实现接口
代码语言:javascript复制import lombok.Getter;
/**
* <p>微信支付类型</p>
*
* @author : LiYu
* @date : 2020-10-30 11:43
**/
@Getter
public enum WechatPaymentType {
/**支付类型**/
BUYGOODS(1,"购买商品"),
RECHARGE(2,"充值货款");
private final Integer value;
private final String desc;
WechatPaymentType(Integer value, String desc){
this.value = value;
this.desc = desc;
}
}
代码语言:javascript复制package com.merrisa.modules.agent.user.service;
import java.math.BigDecimal;
import java.util.Map;
/**
* <p>微信支付</p>
*
* @author : LiYu
* @date : 2020-10-24 17:20
**/
public interface IWxService {
/**
* 微信小程序支付
* @param orderNumber 订单号
* @param appletOpenid openId
* @param money 钱
* @param ip ip地址
* @param body 标题
* @param wechatPaymentType 支付类型
* @return Result<?>
*/
Result<?> wxApplet(String orderNumber, String appletOpenid, BigDecimal money, String ip, String body, WechatPaymentType wechatPaymentType);
/**
* 微信提现
* @param openId
* @param appId
* @param partnerTradeNo
* @param money
* @param ip
* @param name
* @param desc 描述
* @return Map<String, String>
*/
Map<String, String> wxTransfers(String openId, String appId, String partnerTradeNo,
BigDecimal money, String ip, String name, String desc) throws Exception;
}
代码语言:javascript复制package com.merrisa.modules.agent.user.service.impl;
import com.merrisa.modules.agent.user.service.IWxService;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.constant.WxServiceEnvConstants;
import org.jeecg.enums.WechatPaymentType;
import org.jeecg.wx.AgentWxConfig;
import org.jeecg.wx.WXPay;
import org.jeecg.wx.WXPayConstants;
import org.jeecg.wx.WXPayUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
/**
* <h3>jeecg-boot-parent</h3>
* <p>微信支付</p>
*
* @author : LiYu
* @date : 2020-10-24 17:20
**/
@Slf4j
@Setter
@Service
public class WxServiceImpl implements IWxService {
@Value("${agent.wx.pay.notifyUrl}")
private String notifyUrl;//微信支付回调地址
@Value("${agent.wx.pay.notifyUrlRecharge}")
private String notifyUrlRecharge;//微信支付回调地址 根据业务不同配置不同地址
@Value("${spring.profiles.active}")
private String profilesActive;
@Override
public Result<?> wxApplet(String orderNumber, String appletOpenid, BigDecimal money, String ip, String body, WechatPaymentType wechatPaymentType) {
AgentWxConfig agentWxConfig = null;
WXPay wxPay = null;
Map<String,String> resultMap=new HashMap<>();
try {
agentWxConfig = new AgentWxConfig();
wxPay = new WXPay(agentWxConfig);
} catch (Exception e) {
e.printStackTrace();
}
//生成的随机字符串
String generateNonceStr = WXPayUtil.generateNonceStr();
//统一下单接口参数
HashMap<String, String> data = new HashMap<>();
assert agentWxConfig != null;
data.put("appid", agentWxConfig.getAppID());
data.put("mch_id", agentWxConfig.getMchID());
data.put("nonce_str", generateNonceStr);
data.put("body", body);
data.put("out_trade_no",orderNumber);
BigDecimal payMoney = money.multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP);
data.put("total_fee", payMoney.toString());
data.put("spbill_create_ip", ip);
data.put("notify_url",wechatPaymentType.equals(WechatPaymentType.BUYGOODS) ? notifyUrl : notifyUrlRecharge);
data.put("trade_type","JSAPI");
data.put("openid", appletOpenid);
data.put("sign_type", WXPayConstants.MD5);
try {
assert wxPay != null;
Map<String, String> rMap = wxPay.unifiedOrder(data);
log.info("统一下单接口返回: " rMap);
String returnCode = rMap.get("return_code");
String resultCode = rMap.get("result_code");
String nonceStr = WXPayUtil.generateNonceStr();
resultMap.put("nonceStr", nonceStr);
Long timeStamp = System.currentTimeMillis() / 1000;
if ("SUCCESS".equals(returnCode) && returnCode.equals(resultCode)) {
String prepayid = rMap.get("prepay_id");
resultMap.put("package", "prepay_id=" prepayid);
resultMap.put("signType", "MD5");
//这边要将返回的时间戳转化成字符串,不然小程序端调用wx.requestPayment方法会报签名错误
resultMap.put("timeStamp", timeStamp "");
//再次签名,这个签名用于小程序端调用wx.requesetPayment方法
resultMap.put("appId", agentWxConfig.getAppID());
String sign = WXPayUtil.generateSignature(resultMap, agentWxConfig.getKey());
resultMap.put("paySign", sign);
log.info("生成的签名paySign : " sign);
return Result.OK(resultMap);
}else{
return Result.error("支付失败");
}
}catch (Exception e) {
e.printStackTrace();
return Result.error("支付失败");
}
}
@Transactional(rollbackFor = Exception.class)
@Override
public Map<String, String> wxTransfers(String openId, String appId, String partnerTradeNo, BigDecimal money, String ip, String name, String desc) throws Exception {
AgentWxConfig agentWxConfig = null;
WXPay wxPay = null;
try {
agentWxConfig = new AgentWxConfig();
wxPay = new WXPay(agentWxConfig);
} catch (Exception e) {
e.printStackTrace();
}
Map<String, String> data = new HashMap<>();
data.put("mch_appid", appId);
data.put("mchid", WxServiceEnvConstants.MCH_ID);
data.put("partner_trade_no", partnerTradeNo);
data.put("openid", openId);
data.put("check_name", "FORCE_CHECK");
data.put("re_user_name", name);
data.put("nonce_str", WXPayUtil.generateNonceStr());
if(StringUtils.equals(profilesActive,"prod")) {
data.put("amount", "100");
}else {
BigDecimal payMoney = money.multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP);
data.put("amount", payMoney.toString());
}
data.put("desc", desc);
data.put("spbill_create_ip", ip);
data.put("sign", WXPayUtil.generateSignature(data, WxServiceEnvConstants.API_SECRET_KEY, WXPayConstants.SignType.MD5));
assert agentWxConfig != null;
assert wxPay != null;
String respXml = wxPay.requestWithCert("/mmpaymkttransfers/promotion/transfers",
data, agentWxConfig.getHttpConnectTimeoutMs(), agentWxConfig.getHttpReadTimeoutMs());
return WXPayUtil.xmlToMap(respXml);
}
}
微信支付调用
会返回给前端一个json字符串,前端只需执行以下代码
代码语言:javascript复制payNow: function() {
var that = this;
wx.request({
url: app.data.requestUrl 'weChatPay/doUnifiedOrder',
header: {
"Content-Type": "application/json;charset=UTF-8"
},
data: {
requestData: {
openId: app.globalData.openId
}
},
method: 'POST',
dataType: 'json',
responseType: 'text',
success: function(res) {
console.log("服务端返回订单号");
var c=res.data;
wx.requestPayment({
timeStamp: res.data.data.timeStamp,
nonceStr: res.data.data.nonceStr,
package: res.data.data.package,
signType: 'MD5',
paySign: res.data.data.paySign,
success(res) {
console.log("统一下单接口成功");
},
fail(res) {
console.log("统一下单接口失败");
}
});
},
fail: function(res) {},
complete: function(res) {},
});
}
回调方法
代码语言:javascript复制@ApiOperation(value = "微信支付回调函数", notes = "wechatPaySuccess")
@PostMapping("/wechatPaySuccess")
private String wechatPaySuccess(HttpServletRequest request) throws Exception {
//从请求中获取到流
ServletInputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
outSteam.close();
inStream.close();
String result = new String(outSteam.toByteArray(), StandardCharsets.UTF_8);
Map<String, String> map = WXPayUtil.xmlToMap(result);
// 判断签名是否正确
boolean signVerified = WXPayUtil.isSignatureValid(result, WxServiceEnvConstants.API_SECRET_KEY);
if (signVerified) {
if ("SUCCESS".equals(map.get("result_code"))) {
String orderNumber = map.get("out_trade_no");
String tradeType = map.get("trade_type");
log.info("wxPayNotify : orderNumber={} : tradeType={}", orderNumber, tradeType);
switch (tradeType) {
case "JSAPI":
//实现业务
default:
return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[支付失败]]></return_msg></xml>";
}
}
}else{
return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[支付失败]]></return_msg></xml>";
}
return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[支付失败]]></return_msg></xml>";
}
微信提现
代码语言:javascript复制 Map<String, String> resultMap = iWxService.wxTransfers("用户的OpenId", WxServiceEnvConstants.APPLET_APP_ID,"单号","金额" ,ip,"用户真实姓名","标题");
String returnCode = resultMap.get("return_code");
if ("SUCCESS".equals(returnCode)) {
String resultCode = resultMap.get("result_code");
if ("SUCCESS".equals(resultCode)) {
//实现业务
} else {
String errCode = resultMap.get("err_code");
String errCodeDes = resultMap.get("err_code_des");
throw new JeecgBootException(errCode "---" errCodeDes);
}
} else {
throw new JeecgBootException(resultMap.get("return_msg"));
}
}
踩坑
微信官方demo WXPay是这么写的
记住只留下
代码语言:javascript复制this.signType = SignType.MD5;
否则会调用失败