微信支付Java代码及需注意的问题
最重要的是多看微信JSAPI的开发文档,一定要多看几遍再进行编码工作。
统一下单需注意的问题:
- 标价金额单位为分,且类型为整型
- 终端ip可固定写127.0.0.1
- 通知地址为自己写的支付成功回调接口,且外网可访问的
- 订单号必须在统一商户下是唯一的
- WXPay默认为256加密,所以使用WXPayUtil.generateSignature()方法时需要注意也要为256加密
- 两次加密的方式必须相同
Java代码
将调用统一下单接口及拉起支付所需要的数据封装成一个工具类,使用时直接使用即可。
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.*;
import com.huazheng.tunny.parking.api.dto.WxPayUtilDTO;
import com.huazheng.tunny.parking.controller.park.LoginController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import javax.xml.xpath.XPathConstants;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @Auther: Gary
* @Date: 2020/12/14
* @Description: com.huazheng.tunny.parking.util
* @version: 1.0
*/
@Component
public class WxPayUtil {
/**
* 下列参数需在yml文件配置
*/
//公众账号ID
@Value("${appID}")
private String appID;
//商户号
@Value("${mchID}")
private String mchID;
//API密钥
@Value("${key}")
private String key;
//通知地址
@Value("${notifyUrl}")
private String notifyUrl;
private static Logger logger = LoggerFactory.getLogger(WxPayUtil.class);
/**
* 获取沙箱key
* @return
* @throws Exception
*/
public String getSandBoxKey(WXPay wxPay) throws Exception {
Map<String, String> map = new HashMap<>();
map.put("mch_id", mchID);
//随机字符串
String randomStr = UUID.randomUUID().toString().replace("-", "");
map.put("nonce_str", randomStr);
// map.put("sign", WXPayUtil.generateSignature(map, key, WXPayConstants.SignType.HMACSHA256));
map.put("sign", WXPayUtil.generateSignature(map, key, WXPayConstants.SignType.MD5));
String url = "/sandboxnew/pay/getsignkey";
String xmlFile = wxPay.requestWithoutCert(url, map, 6*1000, 6*1000);
String sandBoxKey = "";
if (xmlFile.contains("SUCCESS")){
Document docResult= XmlUtil.readXML(xmlFile);
Object value = XmlUtil.getByXPath("//xml/sandbox_signkey", docResult, XPathConstants.STRING);
sandBoxKey = value.toString();
}
return sandBoxKey;
}
/**
* 统一下单,获取拉取订单接口所需参数
* @param wxPayUtilDTO
* @return
* @throws Exception
*/
public Map<String, String> sendWxPay(WxPayUtilDTO wxPayUtilDTO) throws Exception {
WXPay wxPay = new WXPay(new WxPayUtil.WXPayConfigCustom());
//沙箱测试使用--start
// WXPay wxPay = new WXPay(new WXPayConfigCustom(), false, true);
// String sandBoxKey = getSandBoxKey(wxPay);
// key = sandBoxKey;
//沙箱测试使用--end
Map<String, String> map = new HashMap<>();
map.put("openid", wxPayUtilDTO.getOpenId());
//设备号,PC网页或公众号内支付可以传"WEB"
map.put("device_info", "WEB");
//随机字符串
String randomStr1 = UUID.randomUUID().toString().replace("-", "");
map.put("nonce_str", randomStr1);
//商品描述
map.put("body", "智慧停车费支付");
//商户订单号
String timeStamp = System.currentTimeMillis() + "";
String tradeNo = timeStamp + RandomUtil.randomNumbers(3);
//在同一个商户号下唯一
map.put("out_trade_no", tradeNo);
//终端IP
map.put("spbill_create_ip", wxPayUtilDTO.getSpbillCreateIp());
//外网可访问地址
map.put("notify_url", notifyUrl);
//交易类型
map.put("trade_type", "JSAPI");
//标价金额,单位为分
Double v = wxPayUtilDTO.getTotalFee() * 100;
map.put("total_fee", v.intValue() + "");
//采用HMAC-SHA256方式加密
map.put("sign_type", "HMAC-SHA256");
map.put("sign", WXPayUtil.generateSignature(map, key, WXPayConstants.SignType.HMACSHA256));
//统一下单方法
Map<String, String> unifiedOrder = wxPay.unifiedOrder(map);
System.out.println(unifiedOrder);
Map<String, String> responseMap = new HashMap<>();
if ("SUCCESS".equals(unifiedOrder.get("return_code"))) {
System.out.println(map);
responseMap.put("appId", appID);
//时间戳,秒
responseMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
//随机字符串
String randomStr2 = UUID.randomUUID().toString().replace("-", "");
responseMap.put("nonceStr", randomStr2);
//订单详情扩展字符串
responseMap.put("package", "prepay_id=" + unifiedOrder.get("prepay_id"));
//采用HMAC-SHA256方式加密
responseMap.put("signType", "HMAC-SHA256");
responseMap.put("paySign", WXPayUtil.generateSignature(responseMap, key, WXPayConstants.SignType.HMACSHA256));
}
HashMap<String, String> hashMap = new HashMap<>();
if(responseMap == null){
hashMap.put("flag", "1");
hashMap.putAll(unifiedOrder);
return hashMap;
}
hashMap.put("flag", "0");
hashMap.putAll(responseMap);
return hashMap;
}
/**
* 微信配置类
*/
class WXPayConfigCustom extends WXPayConfig{
@Override
protected String getAppID() {
return appID;
}
@Override
protected String getMchID() {
return mchID;
}
@Override
protected String getKey() {
return key;
}
@Override
protected InputStream getCertStream() {
return null;
}
//统一下单域名
@Override
protected IWXPayDomain getWXPayDomain() {
return new IWXPayDomain() {
@Override
public void report(String s, long l, Exception e) {
}
@Override
public DomainInfo getDomain(WXPayConfig wxPayConfig) {
return new DomainInfo(WXPayConstants.DOMAIN_API, true);
}
};
}
}
}
WxPayUtilDTO:
import lombok.Data;
/**
* 微信支付工具实体类
* @Auther: Gary
* @Date: 2020/12/17
* @Description: com.huazheng.tunny.parking.api.dto
* @version: 1.0
*/
@Data
public class WxPayUtilDTO {
/**
*用户标识
*/
private String openId;
/**
*标价金额
*/
private Double totalFee;
/**
*终端IP,可填127.0.0.1
*/
private String spbillCreateIp;
//下列为非必填
/**
*商品详情
*/
private String detail;
/**
*附加数据
*/
private String attach;
/**
*标价币种
*/
private String feeType;
/**
*交易起始时间 yyyyMMddHHmmss
*/
private String timeStart;
/**
*交易结束时间 yyyyMMddHHmmss
*/
private String timeExpire;
/**
*订单优惠标记
*/
private String goodsTag;
/**
*商品ID
*/
private String productId;
/**
*指定支付方式
*/
private String limitPay;
/**
*电子发票入口开放标识
*/
private String receipt;
/**
*场景信息
*/
private String sceneInfo;
}