1. 准备
首先导入jar包(maven导入jar包)
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
2. 配置类
import java.io.InputStream;
import com.github.wxpay.sdk.WXPayConfig;
import com.qx.rdes.wx.util.PropertiesUtils;
/**
* 配置类
*
* @author 豆浆油条
* @date
**/
public class MyConfig implements WXPayConfig {
@Override
public String getAppID() {
return "自己的appid";
}
public String getSecret() {
return "自己的秘钥";
}
public String getNotifyUrl() {
return "回调地址";
}
@Override
public String getMchID() {
return "商户号";
}
@Override
public String getKey() {
return "商户秘钥";
}
@Override
public InputStream getCertStream() {
return null;
}
@Override
public int getHttpConnectTimeoutMs() {
return 8000;
}
@Override
public int getHttpReadTimeoutMs() {
return 10000;
}
}
3. 代码实现
1.微信统一下单接口
/**
* 微信统一下单接口
* @return
*/
@RequestMapping(value = "/doUnifiedOrder", method = RequestMethod.POST)
public synchronized Map doUnifiedOrder(HttpServletRequest request, HttpServletResponse response) {
// BaseResponse<Map> response = new BaseResponse<>();
Map resultMap=new HashMap();
String openid = "openid";
MyConfig config = null;
WXPay wxpay =null;
try {
config = new MyConfig();
wxpay= new WXPay(config);
} catch (Exception e) {
e.printStackTrace();
}
//生成的随机字符串
String nonce_str = WXPayUtil.generateNonceStr();
//获取客户端的ip地址
//获取本机的ip地址
InetAddress addr = null;
try {
addr = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
String spbill_create_ip = addr.getHostAddress();
//支付金额,需要转成字符串类型,否则后面的签名会失败
int total_fee= 100;
//商品描述
String body = "描述";
//商户订单号
// String out_trade_no= WXPayUtil.generateNonceStr();
String currTime = TenpayUtil.getCurrTime();
// 8位日期
String strTime = currTime.substring(8, currTime.length());
// 四位随机数
String strRandom = TenpayUtil.buildRandom(4) + "";
// 10位序列号,可以自行调整。
String strReq = currTime + strRandom;
// 订单号,此处用时间加随机数生成,商户根据自己情况调整,只要保持全局唯一就行
String out_trade_no = strReq;
//统一下单接口参数
HashMap<String, String> data = new HashMap<String, String>();
data.put("appid", config.getAppID());
data.put("mch_id", config.getMchID());
data.put("nonce_str", nonce_str);
data.put("body", body);
data.put("out_trade_no",out_trade_no);
data.put("total_fee", String.valueOf(total_fee));
data.put("spbill_create_ip", spbill_create_ip);
data.put("notify_url", config.getNotifyUrl());
data.put("trade_type","JSAPI");
data.put("openid", openid);
try {
Map<String, String> rMap = wxpay.unifiedOrder(data);
System.out.println("统一下单接口返回: " + rMap);
String return_code = (String) rMap.get("return_code");
String result_code = (String) rMap.get("result_code");
String nonceStr = WXPayUtil.generateNonceStr();
resultMap.put("nonceStr", nonceStr);
Long timeStamp = System.currentTimeMillis() / 1000;
if ("SUCCESS".equals(return_code) && return_code.equals(result_code)) {
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",config.getAppID());
String sign = WXPayUtil.generateSignature(resultMap, config.getKey());
resultMap.put("paySign", sign);
System.out.println("生成的签名paySign : "+ sign);
// response.setData(resultMap);
return resultMap;
}else{
resultMap.put("msg", "支付异常,请联系管理员");
return resultMap;
}
} catch (Exception e) {
e.printStackTrace();
resultMap.put("msg", "下单失败!");
return resultMap;
}
}
2.支付回调
/**
* 微信小程序支付成功回调函数
* @param request
* @param response
* @throws Exception
*/
@RequestMapping(value = "/callback")
public void wxNotify(HttpServletRequest request,HttpServletResponse response) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream)request.getInputStream()));
String line = null;
StringBuilder sb = new StringBuilder();
while((line = br.readLine()) != null){
sb.append(line);
}
br.close();
//修复XXE漏洞
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//修复方法1:不允许DTDS(DOCTYPE),优先选择的解决方案,几乎可以阻止所有的XML实体攻击
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
//修复方法2:
//true表示实现安全的处理XML,会对XML的结构进行限制,避免出现利用XXE进行文件读取的攻击行为
//如果设置为false,表示根据XML的规范处理XML,忽略安全问题
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,true);
//其它说明:如果没办法完全不允许DTDS,至少按照如下方法修复
//该feature的作用是配置是否包含参数实体,设置false禁用参数实体
//xerces 1:http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
//xerces 2:http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
//该feature的功能指是否包含外部生成的实体,设置false禁用外部实体。
//利用外部实体的payload示例:
/*
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxesec [<!ENTITY xxe SYSTEM "http://aaa.8ug564.ceye.io" >]>
<methodname>&xxe;</methodname>
*/
//xerces 1:http://xerces.apache.org/xerces-j/features.html#external-general-entities
//xerces 2:http://xerces.apache.org/xerces2-j/features.html#external-general-entities
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
//该feature的功能指是否包含外部DTD,设置false禁用外部Dtd
//xerces:http://xerces.apache.org/xerces-j/features.html#load-external-dtd
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",false);
//sb为微信返回的xml
String notityXml = sb.toString();
String resXml = "";
System.out.println("接收到的报文:" + notityXml);
MyConfig config = new MyConfig();
WXPay wxPay = new WXPay(config);
Map map = WXPayUtil.xmlToMap(notityXml);
String returnCode = (String) map.get("return_code");
//验证签名是否正确
if("SUCCESS".equals(returnCode)){
//回调验签时需要去除sign和空值参数
Map<String, String> validParams = WXPayUtil.paraFilter(map);
//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
String validStr = PayUtil.createLinkString(validParams);
//拼装生成服务器端验证的签名
String sign = PayUtil.sign(validStr, Configure.getKey(), "utf-8").toUpperCase();
// 因为微信回调会有八次之多,所以当第一次回调成功了,那么我们就不再执行逻辑了
//根据微信官网的介绍,此处不仅对回调的参数进行验签,还需要对返回的金额与系统订单的金
//额进行比对等
if(sign.equals(map.get("sign"))){
/**此处添加自己的业务逻辑代码start**/
// bla bla bla....
/**此处添加自己的业务逻辑代码end**/
//通知微信服务器已经支付成功
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
} else {
System.out.println("微信支付回调失败!签名不一致");
}
}else{
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
}
System.out.println(resXml);
System.out.println("微信支付回调数据结束");
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
}