微信的H5支付区别与APP支付,主要在于预下单(返回的参数不一样),其它大体相同(基本没什么区别,区别在于有些人加密喜欢用MD5有些人喜欢用官方提供的加密方式加密,我用的是官方的),贴一下H5支付预下单的业务层以及控制层代码方便以后参考,其它代码可以参考微信APP支付。
- 业务层(预下单)
import com.aone.app.common.util.RandomNumUtil;
import com.aone.app.common.wx.*;
import com.aone.app.service.WxH5PayService;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map; @Service
public class WxH5PayServiceImpl implements WxH5PayService { private static final Logger logger = LoggerFactory.getLogger("WxH5PayServiceImpl");
@Autowired
private WxCfg wxCfg; /**
* /H5微信支付(预下单)
* @param type
* @param out_trade_no
* @param money
* @return
* @throws Exception
*/
@Override
public Map<String, String> dounifiedOrder(String type, String out_trade_no, String money, HttpServletRequest request) throws Exception {
//返回参数
Map<String, String> returnMap = new HashMap<>();
//微信配置
WXConfigUtil config = new WXConfigUtil();
WXPay wxpay = new WXPay(config);
//请求参数封装
Map<String, String> data = new HashMap<>();
data.put("appid", config.getAppID());
data.put("mch_id", config.getMchID());
data.put("nonce_str", WXPayUtil.generateNonceStr());
data.put("body", "H5订单支付");
data.put("out_trade_no", RandomNumUtil.getOrderIdByTime());//订单号
data.put("total_fee", "1");//支付金额
data.put("spbill_create_ip", IpAddr.getIpAddr(request)); //自己的服务器IP地址
data.put("notify_url", wxCfg.getH5NotifyUrl());//异步通知地址(请注意必须是外网)
data.put("trade_type", wxCfg.getH5Type());//交易类型
data.put("attach", type);//附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
String s = WXPayUtil.generateSignature(data, config.getKey()); //签名
data.put("sign", s);//签名
try {
logger.info("sign{}",data.get("sign"));
//使用官方API请求预付订单
Map<String, String> response = wxpay.unifiedOrder(data);
String returnCode = response.get("return_code");//获取返回码
logger.info("返回码{}",returnCode); //获取返回码
//若返回码为SUCCESS,则会返回一个result_code,再对该result_code进行判断
if (returnCode.equals("SUCCESS")) {
returnMap.put("ok", "200");
//拼接返回跳转地址
String url= UrlEnCode.urlEncode(wxCfg.getRedirect_url());
logger.info("url{}",url);
returnMap.put("url", response.get("mweb_url")+"&redirect_url="+url);
} else {
returnMap.put("ok", "201");
returnMap.put("url",null);
return returnMap;
}
} catch (Exception e) {
System.out.println(e);
//系统等其他错误的时候
}
return returnMap;
} }
- 控制层下单接口以及回调接口
import com.aone.app.common.wx.XMLUtils;
import com.aone.app.service.WxH5PayService;
import io.swagger.annotations.Api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.util.HashMap;
import java.util.Map; @RestController
@RequestMapping("h5pay")
@Api("H5支付")
public class PayH5Controller { private static final Logger log = LoggerFactory.getLogger("PayH5Controller"); @Autowired
private WxH5PayService wxH5PayService; /**
* H5支付统一下单
* @param request
* @return
* @throws Exception
*/
@ResponseBody
@RequestMapping(value = "wxPay")
public Map<String, String> weixinPay(HttpServletRequest request) throws Exception{
String type= request.getParameter("type");
String orderNo= request.getParameter("orderNo");
String money= request.getParameter("money");
return wxH5PayService.dounifiedOrder(type,orderNo, money,request);
} /**
* H5微信支付异步结果通知
* @param request
* @param response
* @throws Exception
*/
@RequestMapping(value = "notify")
public void weixinPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
BufferedReader reader = request.getReader();
String line = "";
Map map = new HashMap();
String xml = "<xml><return_code><![CDATA[FAIL]]></xml>";;
StringBuffer inputString = new StringBuffer();
while ((line = reader.readLine()) != null) {
inputString.append(line);
}
request.getReader().close();
log.error("----接收到的报文---{}",inputString.toString());
if(inputString.toString().length()>0){
map = XMLUtils.parseXmlToList(inputString.toString());
}else{
log.error("接受微信报文为空");
}
log.error("map={}",map);
if(map!=null && "SUCCESS".equals(map.get("result_code"))){
//成功的业务。。。
xml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
String type=map.get("attach").toString();
String orderNo=map.get("out_trade_no").toString();
log.error("订单号{}",map.get("out_trade_no"));log.error("其它必须参数{}",map.get("attach"));
if(StringUtils.isEmpty(type)||StringUtils.isEmpty(orderNo)){
log.error("当前参数类型异常");
}else{
//回调业务处理 }
}else{
//失败的业务。。。
}
//告诉微信端已经确认支付成功
response.getWriter().write(xml);
} }
- H5回调接口中解析微信通知XML的工具类
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.xml.sax.InputSource; import java.io.StringReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map; public class XMLUtils { /**
* 解析微信通知xml
* @param xml
* @return
*/
@SuppressWarnings({ "unused", "rawtypes", "unchecked" })
public static Map parseXmlToList(String xml) {
Map retMap = new HashMap();
try {
StringReader read = new StringReader(xml);
// 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
InputSource source = new InputSource(read);
// 创建一个新的SAXBuilder
SAXBuilder sb = new SAXBuilder();
// 通过输入源构造一个Document
Document doc = (Document) sb.build(source);
Element root = doc.getRootElement();// 指向根节点
List<Element> es = root.getChildren();
if (es != null && es.size() != 0) {
for (Element element : es) {
retMap.put(element.getName(), element.getValue());
}
}
} catch (Exception e) {
e.printStackTrace();
}
return retMap; }
}
微信支付过程中所需其它参数(应用AppID,商户密钥,商户号,以及商户证书的下载),参考微信官方开发文档。