微信开发用到的常见的工具方法~~xmlToMap、MapToXml、签名等等

更多精彩文章请关注微信公众号:Java编程指南

 

近日,在开发微信支付、微信退款、微信付款到零钱、微信订单查询、微信付款到银行卡的功能。以及其他微信API的使用。发现微信API的开发都是同样的套路~~封装参数–》包装成Xml—》提交到Api—》获取返回的内容就行了。因为会有多个API都设计到这些操作,特地抽取出来封装成工具类单独讲,学习完以下这5~8个放法、那么你的开发就很简便了 ~ ~ 一个支付方法简单的十五行代码立马搞定。希望对你们有帮助。个人浅薄的见解 
 

一、微信签名的工具类
【Description】简单来解释,就是对自己要发送的数据进行加密处理、换句话说假如说你要传递A/B/C,就对这三者进行加密。初开发者的误区:例如看到别人代码拿D和E等去数字签名、然后在自己的开发中就拿D和E去签名,这是错误的做法,会出现数字签名错误。你要看一下你的开发需要传递D和F去后台,那么你应该拿D和F去签名就对了

package com.fh.util.weixin;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import com.fh.controller.app.nrb.bargain.wxconfig;
/**
 * 签名工具类
 * @author 小郑
 * @date 2018年02月22日
 * @Notice:wxconfig.apikey。这句代码是获取商务号设置的api秘钥。这里不方便贴出来,
 * 复制签名代码的人,需要把该常量改成自己商务号的key值。原因是Api规定了签名必须加上自己的key值哦 
 * */
public class SignUtils {

    /**
     * @param characterEncoding 编码格式 utf-8
     * */
    public static String creatSign(String characterEncoding,
            SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();
        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 + "&");
            }
        }
        //wxconfig.apikey。这句代码是获取商务号设置的api秘钥。这里不方便贴出来,
        //复制签名代码的人,需要把该常量改成自己商务号的key值。原因是Api规定了签名必须加上自己的key值哦 
        sb.append("key=" + wxconfig.apikey);
        String sign = MD5Utils.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        System.out.println(sign);
        return sign;
    }
}


二、将当前的map结合转化成xml格式 ~~ 微信请求参数是必须要封装成Xml格式的,在java中写xml很不方便,但是写Map集合很方便。故需要提供map转化xml的方法

 

    /**
     * 将Map转换为XML格式的字符串
     *
     * @param data Map类型数据
     * @return XML格式的字符串
     * @throws Exception
     */
    public static String mapToXml(Map<String, String> data) throws Exception {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
        org.w3c.dom.Document document = documentBuilder.newDocument();
        org.w3c.dom.Element root = document.createElement("xml");
        document.appendChild(root);
        for (String key: data.keySet()) {
            String value = data.get(key);
            if (value == null) {
                value = "";
            }
            value = value.trim();
            org.w3c.dom.Element filed = document.createElement(key);
            filed.appendChild(document.createTextNode(value));
            root.appendChild(filed);
        }
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        DOMSource source = new DOMSource(document);
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        StringWriter writer = new StringWriter();
        StreamResult result = new StreamResult(writer);
        transformer.transform(source, result);
        String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
        try {
            writer.close();
        }
        catch (Exception ex) {
        }
        return output;
    }


 

 /*
     * 将SortedMap<Object,Object> 集合转化成 xml格式
     */
    public static String getRequestXml(SortedMap<Object,Object> parameters){
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            String v = (String)entry.getValue();
            if ("attach".equalsIgnoreCase(k)||"body".equalsIgnoreCase(k)||"sign".equalsIgnoreCase(k)) {
                sb.append("<"+k+">"+"<![CDATA["+v+"]]></"+k+">");
            }else {
                sb.append("<"+k+">"+v+"</"+k+">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }

 

三、xml转化成map或者Bean
微信返回的信息是Xml格式、需要一个工具类把它解析成Map集合或者是一个Bean。方便我们去获取里面返回值。这里会介绍两种方式,一种是转化成Map集合,通过get出来使用,这个方法是通用的,第二种是转化成Bean、这种的话不通用。每个bean基本都不大一样,需要定制

 //通用的。返回map格式
 /**
     * XML格式字符串转换为Map
     *
     * @param strXML XML字符串
     * @return XML数据转换后的Map
     * @throws Exception
     */
    public static Map<String, String> xmlToMap(String strXML) throws Exception {
        try {
            Map<String, String> data = new HashMap<String, String>();
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
            org.w3c.dom.Document doc = documentBuilder.parse(stream);
            doc.getDocumentElement().normalize();
            NodeList nodeList = doc.getDocumentElement().getChildNodes();
            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                Node node = nodeList.item(idx);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
                    data.put(element.getNodeName(), element.getTextContent());
                }
            }
            try {
                stream.close();
            } catch (Exception ex) {
                // do nothing
            }
            return data;
        } catch (Exception ex) {
            WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. 
            Error message: {}. XML content: {}", ex.getMessage(), strXML);
            throw ex;
        }

    }


//不通用的、返回Bean格式//以企业付款到零钱为例子~~根据Api会返回的参数,书写一个Bean类型

package com.fh.entity.nrb.xiaozheng;
/**
 * 
 * 企业 付款到 客户  的 实体类
 * @author xiaozheng
 * @version 1.0 
 * @description: 收集企业 支付给客户成功后的返回信息
 * @time : 2018-01-16 16:00:00
 */
public class EnterpriceToCustomer {
    /*    <xml>
        <return_code><![CDATA[SUCCESS]]></return_code>
        <return_msg><![CDATA[]]></return_msg>
        <mchid><![CDATA[1488323162]]></mchid>
        <nonce_str><![CDATA[o9fcpfvqow1aks48a2omvayu1ne7c709]]></nonce_str>
        <result_code><![CDATA[SUCCESS]]></result_code>
        <partner_trade_no><![CDATA[xvuct0087w4t1dpr87iqj98w5f71ljae]]></partner_trade_no>
        <payment_no><![CDATA[1000018301201801163213961289]]></payment_no>
        <payment_time><![CDATA[2018-01-16 14:52:16]]></payment_time>
        </xml>
    */
    
    private String return_code;
    private String return_msg;
    private String mchid;
    private String nonce_str;
    private String result_code;
    private String partner_trade_no;
    private String payment_no;
    private String payment_time;

    /*
     * 支付错误时,返回的代码
     *  key是:return_code,值是:SUCCESS
        key是:return_msg,值是:支付失败
        key是:mch_appid,值是:wx49c22ad731b679c3
        key是:mchid,值是:1488323162
        key是:result_code,值是:FAIL
        key是:err_code,值是:AMOUNT_LIMIT
        key是:err_code_des,值是:付款金额超出限制。低于最小金额1.00元或累计超过20000.00元。
     * 
     */
    private String err_code;
    private String err_code_des;

    public String getErr_code() {
        return err_code;
    }
    public void setErr_code(String errCode) {
        err_code = errCode;
    }
    public String getErr_code_des() {
        return err_code_des;
    }
    public void setErr_code_des(String errCodeDes) {
        err_code_des = errCodeDes;
    }
    public String getReturn_code() {
        return return_code;
    }
    public void setReturn_code(String returnCode) {
        return_code = returnCode;
    }
    public String getReturn_msg() {
        return return_msg;
    }
    public void setReturn_msg(String returnMsg) {
        return_msg = returnMsg;
    }
    public String getMchid() {
        return mchid;
    }
    public void setMchid(String mchid) {
        this.mchid = mchid;
    }
    public String getNonce_str() {
        return nonce_str;
    }
    public void setNonce_str(String nonceStr) {
        nonce_str = nonceStr;
    }
    public String getResult_code() {
        return result_code;
    }
    public void setResult_code(String resultCode) {
        result_code = resultCode;
    }
    public String getPartner_trade_no() {
        return partner_trade_no;
    }
    public void setPartner_trade_no(String partnerTradeNo) {
        partner_trade_no = partnerTradeNo;
    }
    public String getPayment_no() {
        return payment_no;
    }
    public void setPayment_no(String paymentNo) {
        payment_no = paymentNo;
    }
    public String getPayment_time() {
        return payment_time;
    }
    public void setPayment_time(String paymentTime) {
        payment_time = paymentTime;
    }
    @Override
    public String toString() {
        return "EnterpriceToCustomer [err_code=" + err_code + ", err_code_des="
                + err_code_des + ", mchid=" + mchid + ", nonce_str="
                + nonce_str + ", partner_trade_no=" + partner_trade_no
                + ", payment_no=" + payment_no + ", payment_time="
                + payment_time + ", result_code=" + result_code
                + ", return_code=" + return_code + ", return_msg=" + return_msg
                + "]";
    }
}

/** 
    下面是需要通过跟节点,找找到对应的类属性,手动把它set进去。因此API返回的参数不一样。需要写每个返回的Bean。看个人的习惯呗~~我喜欢用bean存储数据的方式
    * 解析企业支付申请 
    * 解析的时候自动去掉CDMA 
    * @param xml 
    */ 
    @SuppressWarnings("unchecked") 
    public static EnterpriceToCustomer parseXmlToMapEnterpriceToCustomer(String xml){ 
            EnterpriceToCustomer enterpriceToCustomer = new EnterpriceToCustomer(); 
            try { 
                    StringReader read = new StringReader(xml); 
                    // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入 
                    InputSource source = new InputSource(read); 
                    // 创建一个新的SAXBuilder 
                    SAXBuilder sb = new SAXBuilder(); 
                    // 通过输入源构造一个Document 
                    Document doc; 
                    doc = (Document) sb.build(source); 
                
                    Element root = doc.getRootElement();// 指向根节点 
                    List<Element> list = root.getChildren(); 
                
                    if(list!=null&&list.size()>0){ 
                    for (Element element : list) { 
                        System.out.println("key是:"+element.getName()+",值是:"+element.getText()); 
                        if("return_code".equals(element.getName())){ 
                                enterpriceToCustomer.setReturn_code(element.getText()); 
                            } 
                    
                        if("return_msg".equals(element.getName())){ 
                                enterpriceToCustomer.setReturn_msg(element.getText()); 
                            } 
                        
                        if("mchid".equals(element.getName())){ 
                            enterpriceToCustomer.setMchid(element.getText()); 
                        }
                        
                        if("nonce_str".equals(element.getName())){ 
                            enterpriceToCustomer.setNonce_str(element.getText()); 
                        }
                        if("result_code".equals(element.getName())){ 
                            enterpriceToCustomer.setResult_code(element.getText()); 
                        }
                        if("partner_trade_no".equals(element.getName())){ 
                            enterpriceToCustomer.setPartner_trade_no(element.getText()); 
                        }
                        if("payment_no".equals(element.getName())){ 
                            enterpriceToCustomer.setPayment_no(element.getText()); 
                        }
                        if("payment_time".equals(element.getName())){ 
                            enterpriceToCustomer.setPayment_time(element.getText()); 
                        }    
                        //错误的编码
                        /*
                           private String err_code;
                           private String err_code_des;
                         * */
                        if("err_code".equals(element.getName())){ 
                            enterpriceToCustomer.setErr_code(element.getText()); 
                        }
                        if("err_code_des".equals(element.getName())){ 
                            enterpriceToCustomer.setErr_code_des(element.getText()); 
                        }    
                        
                    }
                }
                

            } catch (JDOMException e) { 
            e.printStackTrace(); 
            } catch (IOException e) { 
            e.printStackTrace(); 
            }catch (Exception e) { 
            e.printStackTrace(); 
            } 
                
            return enterpriceToCustomer; 
        } 


四、Post请求+证书~~亲测可以的

package com.fh.entity.nrb.weixinResult;
import java.io.File; 
import java.io.FileInputStream; 
import java.security.KeyStore; 

import javax.net.ssl.SSLContext; 

import org.apache.http.HttpEntity; 
import org.apache.http.client.methods.CloseableHttpResponse; 
import org.apache.http.client.methods.HttpPost; 
import org.apache.http.conn.ssl.SSLConnectionSocketFactory; 
import org.apache.http.conn.ssl.SSLContexts; 
import org.apache.http.entity.StringEntity; 
import org.apache.http.impl.client.CloseableHttpClient; 
import org.apache.http.impl.client.HttpClients; 
import org.apache.http.util.EntityUtils; 

import com.fh.controller.app.nrb.bargain.wxconfig;

/** 
* This example demonstrates how to create secure connections with a custom SSL 
* context. 
*/ 
public class ClientCustomSSL { 

@SuppressWarnings("deprecation")
public static String doRefund(String url,String data) throws Exception { 
        /** 
        * 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的 
        */ 
        
        KeyStore keyStore = KeyStore.getInstance("PKCS12"); 
        /**
        *此处要改
        *wxconfig.SSLCERT_PATH : 指向你的证书的绝对路径,带着证书去访问
        */
        
        FileInputStream instream = new FileInputStream(new File(wxconfig.SSLCERT_PATH));//P12文件目录 
        try { 
        /** 
        * 此处要改 
        * 
        * 下载证书时的密码、默认密码是你的MCHID mch_id
        * */ 
        keyStore.load(instream, wxconfig.SSLCERT_PASSWORD.toCharArray());//这里写密码
        } finally { 
            instream.close(); 
        } 
        
        // Trust own CA and all self-signed certs 
        /** 
        * 此处要改 
        * 下载证书时的密码、默认密码是你的MCHID mch_id
        * */ 
        SSLContext sslcontext = SSLContexts.custom() 
        .loadKeyMaterial(keyStore, wxconfig.SSLCERT_PASSWORD.toCharArray())//这里也是写密码的 
        .build(); 
        // Allow TLSv1 protocol only 
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( 
        sslcontext, 
        new String[] { "TLSv1" }, 
        null, 
        SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); 
        CloseableHttpClient httpclient = HttpClients.custom() 
        .setSSLSocketFactory(sslsf) 
        .build(); 
        try { 
        HttpPost httpost = new HttpPost(url); // 设置响应头信息 
        httpost.addHeader("Connection", "keep-alive"); 
        httpost.addHeader("Accept", "*/*"); 
        httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); 
        httpost.addHeader("Host", "api.mch.weixin.qq.com"); 
        httpost.addHeader("X-Requested-With", "XMLHttpRequest"); 
        httpost.addHeader("Cache-Control", "max-age=0"); 
        httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) "); 
        httpost.setEntity(new StringEntity(data, "UTF-8")); 
        CloseableHttpResponse response = httpclient.execute(httpost); 
        try { 
        HttpEntity entity = response.getEntity(); 
        
        String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8"); 
        EntityUtils.consume(entity); 
        return jsonStr; 
        } finally { 
        response.close(); 
        } 
        } finally { 
        httpclient.close(); 
        } 
    } 
} 

                                    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值