java实现微信h5支付

来源:互联网 发布:amd优化档案 编辑:程序博客网 时间:2024/05/16 16:16

微信h5支付需要在微信商户平台-》产品中心开通h5支付。
这里写图片描述
官网提供的开发文档中需要的参数:
这里写图片描述这里写图片描述这里写图片描述
h5支付主要是scene_info中的参数wap_url必须是可以访问到的地址。spbill_create_ip的获取必须和调起微信支付的ip一致。
代码实现如下:
action中代码:

private static DecimalFormat df = new DecimalFormat("0.00"); @Action("weChatUnifiedorder")   public String weChatUnifiedorder(){       try {df.setRoundingMode(RoundingMode.HALF_UP);// 获取用户ID            String memberId = Struts2Utils.getRequest().getParameter("memberId");            String integer = Struts2Utils.getRequest().getParameter("integer");            String type = Struts2Utils.getRequest().getParameter("type");//我这里的ip直接从前端页面获取部分手机不能获取            String spbill_create_ip = Struts2Utils.getRequest().getParameter("ip");            if (StringUtils.isNotBlank(memberId)                    && StringUtils.isNotBlank(integer)                    && StringUtils.isNotBlank(type)) {                Integer score = Integer.valueOf(integer);                // 产生订单号                String outTradeNo = UuIdUtils.getUUID();                // WeixinConfigUtils config = new WeixinConfigUtils();                // 参数组                String appid = config.appid;                String mch_id = config.mch_id;                String nonce_str = RandCharsUtils.getRandomString(16);                String body = "";                   if (type.equals("0")) {                    body = "购买" + score + "积分,支付" + df.format(score / 100)                            + "元";                } else if (type.equals("1")) {                    body = "购买商品支付" + String.valueOf(score / 100) + "元";                }                String attach = "暂时无用(这个用于区分不同版本)";                String out_trade_no = outTradeNo;                int total_fee = score;// 单位是分,现在按照ios传递过来的参数进行                String notify_url = config.notify_url;                String trade_type = "MWEB";                // 参数:开始生成第一次签名                parameters.put("appid", appid);                parameters.put("mch_id", mch_id);                parameters.put("body", body);                parameters.put("nonce_str", nonce_str);                parameters.put("attach", attach);                parameters.put("out_trade_no", out_trade_no);                parameters.put("total_fee", total_fee);                parameters.put("notify_url", notify_url);                parameters.put("trade_type", trade_type);                parameters.put("spbill_create_ip", spbill_create_ip);                parameters.put("scene_info", "'h5_info':{'type':'Wap','wap_url':'http://www.abc.com(必须可以直接访问)','wap_name': '应用名(会在微信订单页显示)'}");                String sign = WXSignUtils.createSign("UTF-8", parameters);                // 微信统一下单                unifiedorder.setAppid(appid);                unifiedorder.setMch_id(mch_id);                unifiedorder.setNonce_str(nonce_str);                unifiedorder.setSign(sign);                unifiedorder.setBody(body);                unifiedorder.setAttach(attach);                unifiedorder.setOut_trade_no(out_trade_no);                unifiedorder.setTotal_fee(total_fee);                unifiedorder.setSpbill_create_ip(spbill_create_ip);                unifiedorder.setNotify_url(notify_url);                unifiedorder.setTrade_type(trade_type);                unifiedorder.setScene_info("'h5_info':{'type':'Wap','wap_url':'http://www.abc.com(必须可以直接访问)','wap_name': '应用名(会在微信订单页显示)'}");                Map<String, String> msgMap = HttpXmlUtils.getUrl(unifiedorder);                if (msgMap.get("return_code").equals("SUCCESS") && msgMap.get("result_code").equals("SUCCESS")) {                    aLiPay.setApp_id(appid);                    aLiPay.setSubject(body);                    aLiPay.setScore(integer);                    aLiPay.setGmt_create(simpleDateFormat.format(new Date()));                    if (null != memberId && !"".equals(memberId)) {                        aLiPay.setMember(memberService.getMemberById(Integer                                .valueOf(memberId)));                    }                    aLiPay.setOut_trade_no(out_trade_no);                    aLiPay.setPayStatus(PayStatusEnum.WAITPAY.getComment());                    aLiPay.setPayType(PayTypeEnum.WEIXIN.getComment());                    aLiPay.setState(0);                    aLiPay.setTotal_amount(String.valueOf(total_fee / 100));                    aLiPay.setSign(sign);                    aLiPay.setTotalFee(total_fee);                    aLiPayService.addALiPay(aLiPay);                    msg.put("ok", true);    //将回调地址发回前端,支付完成后会自动跳转该页面                    msg.put("url", msgMap.get("mweb_url")+"&redirect_url=http://www.jabc.com/member/toMemberIntegral.do");                    Struts2Utils.renderJson(msg);                }else {                    msg.put("ok", false);                }            }            return NONE;        } catch (Exception e) {            log.error(e.getMessage());            return "500";        }   }

微信支付签名代码:

public class WXSignUtils {    /**     * 微信支付签名算法sign     * @param characterEncoding     * @param parameters     * @return     */    @SuppressWarnings("rawtypes")    public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){        StringBuffer sb = new StringBuffer();        Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)        Iterator it = es.iterator();        while(it.hasNext()) {            Map.Entry entry = (Map.Entry)it.next();            String k = (String)entry.getKey();            Object v = entry.getValue();            if(null != v && !"".equals(v)                     && !"sign".equals(k) && !"key".equals(k)) {                sb.append(k + "=" + v + "&");            }        }        sb.append("key=" + weixinConstant.KEY);        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();        return sign;    }}

向微信发送post数据并解析返回的微信订单号

public class HttpXmlUtils {/**     * h5支付时 解析返回的值并返回prepareid     * @throws IOException      * @throws JDOMException      */    public static Map<String, String> getUrl(Unifiedorder unifiedorder) throws JDOMException, IOException{    //构造xml        String xmlInfo = HttpXmlUtils.xmlH5Info(unifiedorder);        String wxUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";        String method = "POST";        //获取微信返回的结果        String weixinPost = HttpXmlUtils.httpsRequest(wxUrl, method, xmlInfo).toString();        //解析返回的xml        ParseXMLUtils.jdomParseXml(weixinPost);        StringReader read = new StringReader(weixinPost);        // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入        InputSource source = new InputSource(read);        // 创建一个新的SAXBuilder        SAXBuilder sb = new SAXBuilder();        // 通过输入源构造一个Document        org.jdom.Document doc;        doc = (org.jdom.Document) sb.build(source);        org.jdom.Element root = doc.getRootElement();// 指向根节点        List<org.jdom.Element> list = root.getChildren();        String prepayId =null;        Map<String, String> msg = new HashMap<String, String>();        if(list!=null&&list.size()>0){            for (org.jdom.Element element : list) {            msg.put(element.getName(), element.getText());            }            }        return msg;    }    /**     * 构造xml参数     * @param xml     * @return     */    public static String xmlH5Info(Unifiedorder unifiedorder){        if(unifiedorder!=null){            StringBuffer bf = new StringBuffer();            bf.append("<xml>");            bf.append("<appid><![CDATA[");            bf.append(unifiedorder.getAppid());            bf.append("]]></appid>");            bf.append("<mch_id><![CDATA[");            bf.append(unifiedorder.getMch_id());            bf.append("]]></mch_id>");            bf.append("<nonce_str><![CDATA[");            bf.append(unifiedorder.getNonce_str());            bf.append("]]></nonce_str>");            bf.append("<sign><![CDATA[");            bf.append(unifiedorder.getSign());            bf.append("]]></sign>");            bf.append("<body><![CDATA[");            bf.append(unifiedorder.getBody());            bf.append("]]></body>");            bf.append("<attach><![CDATA[");            bf.append(unifiedorder.getAttach());            bf.append("]]></attach>");            bf.append("<out_trade_no><![CDATA[");            bf.append(unifiedorder.getOut_trade_no());            bf.append("]]></out_trade_no>");            bf.append("<total_fee><![CDATA[");            bf.append(unifiedorder.getTotal_fee());            bf.append("]]></total_fee>");            bf.append("<spbill_create_ip><![CDATA[");            bf.append(unifiedorder.getSpbill_create_ip());            bf.append("]]></spbill_create_ip>");            bf.append("<notify_url><![CDATA[");            bf.append(unifiedorder.getNotify_url());            bf.append("]]></notify_url>");            bf.append("<trade_type><![CDATA[");            bf.append(unifiedorder.getTrade_type());            bf.append("]]></trade_type>");            bf.append("<scene_info><![CDATA[");            bf.append(unifiedorder.getScene_info());            bf.append("]]></scene_info>");            bf.append("</xml>");            return bf.toString();        }        return "";    }/**     * post请求并得到返回结果     * @param requestUrl     * @param requestMethod     * @param output     * @return     */    public static String httpsRequest(String requestUrl, String requestMethod, String output) {        try{            URL url = new URL(requestUrl);            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();            connection.setDoOutput(true);            connection.setDoInput(true);            connection.setUseCaches(false);            connection.setRequestMethod(requestMethod);            if (null != output) {                OutputStream outputStream = connection.getOutputStream();                outputStream.write(output.getBytes("UTF-8"));                outputStream.close();            }            // 从输入流读取返回内容            InputStream inputStream = connection.getInputStream();            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);            String str = null;            StringBuffer buffer = new StringBuffer();            while ((str = bufferedReader.readLine()) != null) {                buffer.append(str);            }            bufferedReader.close();            inputStreamReader.close();            inputStream.close();            inputStream = null;            connection.disconnect();            return buffer.toString();        }catch(Exception ex){            ex.printStackTrace();        }        return "";    }}

解析微信返回的xml

/**     * 3、JDOM解析XML     * 解析的时候自动去掉CDMA     * @param xml     */    @SuppressWarnings("unchecked")    public static void jdomParseXml(String xml){        try {             StringReader read = new StringReader(xml);            // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入            InputSource source = new InputSource(read);            // 创建一个新的SAXBuilder            SAXBuilder sb = new SAXBuilder();            // 通过输入源构造一个Document            org.jdom.Document doc;            doc = (org.jdom.Document) sb.build(source);            org.jdom.Element root = doc.getRootElement();// 指向根节点            List<org.jdom.Element> list = root.getChildren();            if(list!=null&&list.size()>0){                for (org.jdom.Element element : list) {                }            }        } catch (JDOMException e) {            e.printStackTrace();        }  catch (IOException e) {            e.printStackTrace();        }catch (Exception e) {            e.printStackTrace();        }    }

封装支付参数的实体类:(参数名与官网参数名一致,此类封装了h5、app支付和退款的参数)

package com.wellness.platfront.entity.weixin;import java.io.Serializable;import com.wellness.platfront.entity.member.Member;/** * 统一下单提交为微信的参数 * @author  * @date 2017年08月11日 */public class Unifiedorder implements Serializable{    private static final long serialVersionUID = 1L;    //微信支付表id    private Integer weixinId;    //微信分配的公众账号ID(企业号corpid即为此appId)    private String appid;    //商户id    private String mch_id;    //终端设备号(门店号或收银设备ID),注意:PC网页或公众号内支付请传"WEB"    private String device_info;    //随机字符串:数字+大写字母的组合,32位    private String nonce_str;    //签名    private String sign;    //商品或支付单简要描述    private String body;    //商品名称明细列表    private String detail;    //附加参数(例如:用于区别本商户不同的分店)    private String attach;    //商户系统内部的订单号    private String out_trade_no;    //货币类型:符合ISO 4217标准的三位字母代码,默认人民币:CNY    private String fee_type;    //总金额    private int total_fee;    //APP和网页支付提交[用户端ip],Native支付填调用微信支付API的机器IP。    private String spbill_create_ip;    //订单生成时间,格式为yyyyMMddHHmmss,    private String time_start;    //订单失效时间,格式为yyyyMMddHHmmss,最短失效时间间隔必须大于5分钟[支付宝是30分钟,同样30分钟]    private String time_expire;    //商品标记,代金券或立减优惠功能的参数    private String goods_tag;    //接收微信支付异步通知回调地址    private String notify_url;    //交易类型:JSAPI,NATIVE,APP h5为 MWEB    private String trade_type;    //trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。    private String product_id;    //no_credit--指定不能使用信用卡支付    private String limit_pay;    //trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识    private String openid;    //商户内部自己的退款单号    private String out_refund_no;    //退款总金额单位为分    private int refund_fee;    //操作员的id默认为mch_id    private String op_user_id;    //微信官方提供的订单号    private String prepayid;    //记录所对应的member    private Member member;    //返回给微信的状态码(用于支付回调时)    public String return_code;    //微信h5支付时候的场景信息官方的信息模板 {"h5_info"://h5支付固定传"h5_info"     //{"type":"",//场景类型 "wap_url":"",//WAP网站URL地址"wap_name": ""//WAP 网站名}}    public String scene_info;    public String getScene_info() {        return scene_info;    }    public void setScene_info(String scene_info) {        this.scene_info = scene_info;    }    public String getReturn_code() {        return return_code;    }    public void setReturn_code(String return_code) {        this.return_code = return_code;    }    public String getAppid() {        return appid;    }    public String getMch_id() {        return mch_id;    }    public String getDevice_info() {        return device_info;    }    public String getNonce_str() {        return nonce_str;    }    public String getSign() {        return sign;    }    public String getBody() {        return body;    }    public String getDetail() {        return detail;    }    public String getAttach() {        return attach;    }    public String getOut_trade_no() {        return out_trade_no;    }    public String getFee_type() {        return fee_type;    }    public int getTotal_fee() {        return total_fee;    }    public String getSpbill_create_ip() {        return spbill_create_ip;    }    public String getTime_start() {        return time_start;    }    public String getTime_expire() {        return time_expire;    }    public String getGoods_tag() {        return goods_tag;    }    public String getNotify_url() {        return notify_url;    }    public String getTrade_type() {        return trade_type;    }    public String getProduct_id() {        return product_id;    }    public String getLimit_pay() {        return limit_pay;    }    public String getOpenid() {        return openid;    }    public void setAppid(String appid) {        this.appid = appid;    }    public void setMch_id(String mch_id) {        this.mch_id = mch_id;    }    public void setDevice_info(String device_info) {        this.device_info = device_info;    }    public void setNonce_str(String nonce_str) {        this.nonce_str = nonce_str;    }    public void setSign(String sign) {        this.sign = sign;    }    public void setBody(String body) {        this.body = body;    }    public void setDetail(String detail) {        this.detail = detail;    }    public void setAttach(String attach) {        this.attach = attach;    }    public void setOut_trade_no(String out_trade_no) {        this.out_trade_no = out_trade_no;    }    public void setFee_type(String fee_type) {        this.fee_type = fee_type;    }    public void setTotal_fee(int total_fee) {        this.total_fee = total_fee;    }    public void setSpbill_create_ip(String spbill_create_ip) {        this.spbill_create_ip = spbill_create_ip;    }    public void setTime_start(String time_start) {        this.time_start = time_start;    }    public void setTime_expire(String time_expire) {        this.time_expire = time_expire;    }    public void setGoods_tag(String goods_tag) {        this.goods_tag = goods_tag;    }    public void setNotify_url(String notify_url) {        this.notify_url = notify_url;    }    public void setTrade_type(String trade_type) {        this.trade_type = trade_type;    }    public void setProduct_id(String product_id) {        this.product_id = product_id;    }    public void setLimit_pay(String limit_pay) {        this.limit_pay = limit_pay;    }    public void setOpenid(String openid) {        this.openid = openid;    }    public String getOut_refund_no() {        return out_refund_no;    }    public void setOut_refund_no(String out_refund_no) {        this.out_refund_no = out_refund_no;    }    public int getRefund_fee() {        return refund_fee;    }    public void setRefund_fee(int refund_fee) {        this.refund_fee = refund_fee;    }    public Integer getWeixinId() {        return weixinId;    }    public void setWeixinId(Integer weixinId) {        this.weixinId = weixinId;    }    public Member getMember() {        return member;    }    public void setMember(Member member) {        this.member = member;    }    public String getPrepayid() {        return prepayid;    }    public void setPrepayid(String prepayid) {        this.prepayid = prepayid;    }    public String getOp_user_id() {        return op_user_id;    }    public void setOp_user_id(String op_user_id) {        this.op_user_id = op_user_id;    }}

前端获取ip:

<script src="http://pv.sohu.com/cityjson?ie=utf-8">var ip = returnCitySN.cip;(有些手机不行,目前发现的是魅族和三星)判断正不正确可以查自己的ip地址,微信获取的是你所处网络的ip。也可以在java后台获取</script>

在h5支付时出现的一些问题
这个
这个页面就是你传递的ip和微信获取的发起支付的ip不一致,这个时候你就要检查获取ip的代码
这里写图片描述
出现这个情况的原因有两个1.你的scene_info中的wap_url与你配置的授权域名不一致,需要去商户平台的产品中心->开发配置中修改 2. 配置的redirect_url与授权域名不一致,需要修改。
这个地方还有其他的一些错误,我没遇到,以上两个错误我遇到很多次,后来查看官方文档才看见的(https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_4)。