近日,皇冠体育出租 dsluntan.com 企娥339 3756 370 在开发微信支付、微信退款、微信付款到零钱、微信订单查询、微信付款到银行卡的功能。以及其他微信API的使用。发现微信API的开发都是同样的套路~~封装参数–》包装成Xml—》提交到Api—》获取返回的内容就行了。因为会有多个API都设计到这些操作,特地抽取出来封装成工具类单独讲,学习完以下这5~8个放法、那么你的开发就很简便了 ~ ~ 一个支付方法简单的十五行代码立马搞定。希望对你们有帮助。个人浅薄的见解
资料下载:没积分找我拿~ ~这边分享资料一定要设个积分值,没办法
http://download.csdn.net/download/xiaozhegaa/10226929
一、微信签名的工具类
【温馨提示:】数字签名是一般开发人员容易遇到的错误,记住“你没遇到数字签名错误,都不好意思说自己做过微信开发”。
耐心解决就行
【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;
}
}12345678910111213141516171819202122232425262728293031323334353637383940
二、将当前的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;
}12345678910111213141516171819202122232425262728293031323334353637383940
/*
* 将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();
}123456789101112131415161718192021
三、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;
}
}12345678910111213141516171819202122232425262728293031323334353637
//不通用的、返回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;
} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
四、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();
}
}
} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
其他的。遇到了会补充上来。还有一个get方式,不需要证书的提交,稍后补充呗
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31551548/viewspace-2212559/
,如需转载,请注明出处,否则将追究法律责任。