微信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,商户密钥,商户号,以及商户证书的下载),参考微信官方开发文档。