全部
常见问题
产品动态
精选推荐

微信开发常用方法xmlToMap、MapToXml、签名

管理 管理 编辑 删除

​近日,在开发微信支付、微信退款、微信付款到零钱、微信订单查询、微信付款到银行卡的功能。以及其他微信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 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;​

​    }​

​}

895bc202304231858519232.png

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

​/**​

​     * 将Map转换为XML格式的字符串​

​     *​

​     * @param data Map类型数据​

​     * @return XML格式的字符串​

​     * @throws Exception​

​     */
public static String mapToXml(Map 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 集合转化成 xml格式​

​     */​

​    public static String getRequestXml(SortedMap parameters){​

​        StringBuffer sb = new StringBuffer();​

​        sb.append("");​

​        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+">"+"");​

​            }else {​

​                sb.append("<"+k+">"+v+"");​

​            }​

​        }​

​        sb.append("");​

​        return sb.toString();​

​    }

7e916202304231901438742.png

86b3d202304231902162034.png

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

/**​

​     * XML格式字符串转换为Map​

​     *​

​     * @param strXML XML字符串​

​     * @return XML数据转换后的Map​

​     * @throws Exception​

​     */
 public static Map xmlToMap(String strXML) throws Exception {​

​        try {​

​            Map data = new HashMap();​

​            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 {​

​    /*  ​

​        ​

​        ​

​        ​

​        ​

​        ​

​        ​

​        ​

​        ​

​        ​

​    */
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 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 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(); ​

​        } ​

​    } ​

​} 


请登录后查看

CRMEB-慕白寒窗雪 最后编辑于2023-04-23 19:09:07

快捷回复
回复
回复
回复({{post_count}}) {{!is_user ? '我的回复' :'全部回复'}}
排序 默认正序 回复倒序 点赞倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level }}

作者 管理员 企业

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推荐': '推荐'}}
{{item.is_suggest == 1? '取消推荐': '推荐'}}
沙发 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暂无简介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
{{item.like_count}}
{{item.showReply ? '取消回复' : '回复'}}
删除
回复
回复

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回复 {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回复' : '回复'}}
删除
回复
回复
查看更多
2029
{{like_count}}
{{collect_count}}
添加回复 ({{post_count}})

相关推荐

快速安全登录

使用微信扫码登录
{{item.label}} 加精
{{item.label}} {{item.label}} 板块推荐 常见问题 产品动态 精选推荐 首页头条 首页动态 首页推荐
取 消 确 定
回复
回复
问题:
问题自动获取的帖子内容,不准确时需要手动修改. [获取答案]
答案:
提交
bug 需求 取 消 确 定

微信登录/注册

切换手机号登录

{{ bind_phone ? '绑定手机' : '手机登录'}}

{{codeText}}
切换微信登录/注册
暂不绑定
CRMEB客服

CRMEB咨询热线 咨询热线

400-8888-794

微信扫码咨询

CRMEB开源商城下载 源码下载 CRMEB帮助文档 帮助文档
返回顶部 返回顶部
CRMEB客服