微信H5支付(基于Java实现微信H5支付)
微信的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,商户密钥,商户号,以及商户证书的下载),参考微信官方开发文档。