新增V2版本"退款申请","退款查询","对账单下载"三个接口以及语义理解接口鸡肋实现

This commit is contained in:
jy.hu
2014-11-08 21:12:03 +08:00
parent 1371d1d5c7
commit ff436b6f03
41 changed files with 1037 additions and 248 deletions
+5
View File
@@ -103,5 +103,10 @@
<artifactId>commons-codec</artifactId>
<version>${commons.codec.version}</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
</dependency>
</dependencies>
</project>
@@ -22,6 +22,7 @@ public class WeixinException extends Exception {
}
public WeixinException(String errorMsg) {
this.errorCode = "";
this.errorMsg = errorMsg;
}
@@ -3,10 +3,11 @@ package com.foxinmy.weixin4j.http;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
@@ -32,9 +33,13 @@ import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import com.alibaba.fastjson.JSONException;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.util.MapUtil;
import com.thoughtworks.xstream.mapper.CannotResolveClassException;
/**
* 调用微信相关接口的HttpRequest,对于其他请求可能并不试用
@@ -46,7 +51,7 @@ import com.foxinmy.weixin4j.exception.WeixinException;
* @see
*/
public class HttpRequest {
private final String SUCCESS = "success";
protected AbstractHttpClient client;
public HttpRequest() {
@@ -84,6 +89,14 @@ public class HttpRequest {
return get(url, (Parameter[]) null);
}
public Response get(String url, Map<String, String> para)
throws WeixinException {
return get(
String.format("%s?%s", url,
MapUtil.toJoinString(para, false, false, null)),
(Parameter[]) null);
}
public Response get(String url, Parameter... parameters)
throws WeixinException {
StringBuilder sb = new StringBuilder(url);
@@ -106,11 +119,13 @@ public class HttpRequest {
public Response post(String url, Parameter... parameters)
throws WeixinException {
HttpPost method = new HttpPost(url);
List<NameValuePair> params = new ArrayList<NameValuePair>();
for (Parameter parameter : parameters) {
params.add(parameter.toPostPara());
if (parameters != null && parameters.length > 0) {
List<NameValuePair> params = new ArrayList<NameValuePair>();
for (Parameter parameter : parameters) {
params.add(parameter.toPostPara());
}
method.setEntity(new UrlEncodedFormEntity(params, Consts.UTF_8));
}
method.setEntity(new UrlEncodedFormEntity(params, Consts.UTF_8));
return doRequest(method);
}
@@ -167,42 +182,39 @@ public class HttpRequest {
String.format("the page was redirected to %s",
httpResponse.getFirstHeader("location")));
}
byte[] data = EntityUtils.toByteArray(httpEntity);
response = new Response();
response.setBody(data);
response.setStatusCode(status);
response.setStatusText(statusLine.getReasonPhrase());
response.setStream(new ByteArrayInputStream(data));
response.setText(new String(data, Consts.UTF_8));
EntityUtils.consume(httpEntity);
Header contentType = httpResponse
.getFirstHeader(HttpHeaders.CONTENT_TYPE);
// error with html
if (contentType.getValue().contains(
ContentType.APPLICATION_JSON.getMimeType())
|| contentType.getValue().contains(
ContentType.TEXT_PLAIN.getMimeType())) {
response.setText(new String(data, StandardCharsets.UTF_8));
ContentType.TEXT_HTML.getMimeType())) {
response.setText(new String(data, "gbk"));
Document doc = Jsoup.parse(response.getAsString());
throw new WeixinException(doc.body().text());
} else if (contentType.getValue().contains(
ContentType.APPLICATION_JSON.getMimeType())) {
checkJson(response);
} else if (contentType.getValue().contains(
ContentType.TEXT_XML.getMimeType())) {
checkXml(response);
} else if (contentType.getValue().contains(
ContentType.TEXT_PLAIN.getMimeType())) {
try {
JsonResult jsonResult = response.getAsJsonResult();
response.setJsonResult(true);
if (jsonResult.getCode() != 0) {
throw new WeixinException(Integer.toString(jsonResult
.getCode()), jsonResult.getDesc());
}
checkJson(response);
return response;
} catch (JSONException e) {
;
}
XmlResult xmlResult = response.getAsXmlResult();
response.setXmlResult(true);
if (!xmlResult.getReturnCode().equalsIgnoreCase(SUCCESS)) {
throw new WeixinException(xmlResult.getReturnCode(),
xmlResult.getReturnMsg());
}
if (!xmlResult.getResultCode().equalsIgnoreCase(SUCCESS)) {
throw new WeixinException(xmlResult.getErrCode(),
xmlResult.getErrCodeDes());
}
checkXml(response);
}
} catch (IOException e) {
throw new WeixinException("-1", e.getMessage());
@@ -211,4 +223,48 @@ public class HttpRequest {
}
return response;
}
private void checkJson(Response response) throws WeixinException {
response.setJsonResult(true);
JsonResult jsonResult = response.getAsJsonResult();
if (jsonResult.getCode() != 0) {
if (StringUtils.isBlank(jsonResult.getDesc())) {
jsonResult = response.getTextError(jsonResult.getCode());
}
throw new WeixinException(Integer.toString(jsonResult.getCode()),
jsonResult.getDesc());
}
}
private void checkXml(Response response) throws WeixinException {
response.setXmlResult(true);
XmlResult xmlResult = null;
try {
xmlResult = response.getAsXmlResult();
} catch (CannotResolveClassException ex) {
// <?xml><root><data..../data></root>
String newXml = response.getAsString()
.replaceFirst("<root>", "<xml>")
.replaceFirst("<retcode>", "<return_code>")
.replaceFirst("</retcode>", "</return_code>")
.replaceFirst("<retmsg>", "<return_msg>")
.replaceFirst("</retmsg>", "</return_msg>")
.replaceFirst("</root>", "</xml>");
response.setText(newXml);
xmlResult = response.getAsXmlResult();
}
if (xmlResult.getReturnCode().equals("0")) {
return;
}
if (!xmlResult.getReturnCode().equalsIgnoreCase(
com.foxinmy.weixin4j.model.Consts.SUCCESS)) {
throw new WeixinException(xmlResult.getReturnCode(),
xmlResult.getReturnMsg());
}
if (!xmlResult.getResultCode().equalsIgnoreCase(
com.foxinmy.weixin4j.model.Consts.SUCCESS)) {
throw new WeixinException(xmlResult.getErrCode(),
xmlResult.getErrCodeDes());
}
}
}
@@ -2,15 +2,13 @@ package com.foxinmy.weixin4j.http;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import org.apache.http.Consts;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
public class Parameter {
private final static String CHARSET = StandardCharsets.UTF_8.name();
private String name;
private String value;
@@ -41,7 +39,8 @@ public class Parameter {
public String toGetPara() {
try {
return String.format("&%s=%s", name, URLEncoder.encode(value, CHARSET));
return String.format("&%s=%s", name,
URLEncoder.encode(value, Consts.UTF_8.name()));
} catch (UnsupportedEncodingException e) {
return String.format("&%s=%s", name, value);
}
@@ -49,7 +48,8 @@ public class Parameter {
public NameValuePair toPostPara() {
try {
return new BasicNameValuePair(name, URLEncoder.encode(value, CHARSET));
return new BasicNameValuePair(name, URLEncoder.encode(value,
Consts.UTF_8.name()));
} catch (UnsupportedEncodingException e) {
return new BasicNameValuePair(name, value);
}
@@ -2,6 +2,7 @@ package com.foxinmy.weixin4j.http;
import java.io.InputStream;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
@@ -73,18 +74,41 @@ public class Response {
* @return
* @throws DocumentException
*/
public JsonResult getTextError() throws DocumentException {
JsonResult result = getAsJsonResult();
if (result.getCode() != 0) {
SAXReader reader = new SAXReader();
Document doc = reader.read(Response.class
.getResourceAsStream("error.xml"));
Node node = doc.getRootElement().selectSingleNode(
String.format("error/code[text()='%d']", result.getCode()));
if (node != null) {
result.setText(node.getParent().selectSingleNode("text")
.getStringValue());
public JsonResult getTextError(int code) {
JsonResult result = new JsonResult();
result.setCode(code);
SAXReader reader = new SAXReader();
Document doc = null;
try {
doc = reader.read(Response.class.getResourceAsStream("error.xml"));
} catch (DocumentException e) {
e.printStackTrace();
}
Node node = doc.getRootElement().selectSingleNode(
String.format("error/code[text()=%d]", code));
if (node != null) {
node = node.getParent();
String desc = null;
Node _node = node.selectSingleNode("desc");
if (_node != null) {
desc = _node.getStringValue();
}
String text = null;
_node = node.selectSingleNode("text");
if (_node != null) {
text = _node.getStringValue();
}
if (StringUtils.isBlank(desc) && StringUtils.isNotBlank(text)) {
desc = text;
}
if (StringUtils.isBlank(text) && StringUtils.isNotBlank(desc)) {
text = desc;
}
result.setDesc(desc);
result.setText(text);
} else {
result.setDesc("unknown error");
result.setText("未知错误");
}
return result;
}
@@ -6,7 +6,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
/**
@@ -27,7 +30,8 @@ public class SSLHttpRequest extends HttpRequest {
public SSLHttpRequest(String password, InputStream inputStream) {
super();
try {
KeyStore trustStore = KeyStore.getInstance("PKCS12");
KeyStore trustStore = KeyStore
.getInstance(com.foxinmy.weixin4j.model.Consts.PKCS12);
trustStore.load(inputStream, password.toCharArray());
SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore,
password);
@@ -45,4 +49,11 @@ public class SSLHttpRequest extends HttpRequest {
}
}
}
public SSLHttpRequest(SSLContext sslContext) {
super();
SchemeSocketFactory socketFactory = new SSLSocketFactory(sslContext);
client.getConnectionManager().getSchemeRegistry()
.register(new Scheme("https", 443, socketFactory));
}
}
@@ -2,6 +2,7 @@ package com.foxinmy.weixin4j.http;
import java.io.Serializable;
import com.foxinmy.weixin4j.model.Consts;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
@@ -16,8 +17,6 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
public class XmlResult implements Serializable {
private static final long serialVersionUID = -6185313616955051150L;
public static final String SUCCESS = "SUCCESS";
public static final String FAIL = "FAIL";
@XStreamAlias("return_code")
private String returnCode;// 此字段是通信标识,非交易 标识,交易是否成功需要查 看 result_code 来判断 非空
@@ -71,15 +70,15 @@ public class XmlResult implements Serializable {
}
public XmlResult() {
this(SUCCESS.toLowerCase(), "");
this(Consts.SUCCESS.toLowerCase(), "");
}
public XmlResult(String returnCode, String returnMsg) {
this.returnCode = returnCode;
this.returnMsg = returnMsg;
if (returnCode.equalsIgnoreCase(SUCCESS)) {
this.resultCode = SUCCESS.toLowerCase();
this.errCode = SUCCESS.toLowerCase();
if (returnCode.equalsIgnoreCase(Consts.SUCCESS)) {
this.resultCode = Consts.SUCCESS.toLowerCase();
this.errCode = Consts.SUCCESS.toLowerCase();
this.errCodeDes = "";
}
}
@@ -362,6 +362,83 @@
<desc>api unauthorized</desc>
<text>接口未授权</text>
</error>
<!-- 语义理解API错误 -->
<error>
<code>7000000</code>
<text>请求正常,无语义结果</text>
</error>
<error>
<code>7000001</code>
<text>缺失请求参数</text>
</error>
<error>
<code>7000002</code>
<text>signature 参数无效</text>
</error>
<error>
<code>7000003</code>
<text>地理位置相关配置 1 无效</text>
</error>
<error>
<code>7000004</code>
<text>地理位置相关配置 2 无效</text>
</error>
<error>
<code>7000005</code>
<text>请求地理位置信息失败</text>
</error>
<error>
<code>7000006</code>
<text>地理位置结果解析失败</text>
</error>
<error>
<code>7000007</code>
<text>内部初始化失败</text>
</error>
<error>
<code>7000008</code>
<text>非法 appid(获取密钥失败)</text>
</error>
<error>
<code>7000009</code>
<text>请求语义服务失败</text>
</error>
<error>
<code>7000010</code>
<text>非法 post 请求</text>
</error>
<error>
<code>7000011</code>
<text>post 请求 json 字段无效</text>
</error>
<error>
<code>7000030</code>
<text>查询 query 太短</text>
</error>
<error>
<code>7000031</code>
<text>查询 query 太长</text>
</error>
<error>
<code>7000032</code>
<text>城市、经纬度信息缺失</text>
</error>
<error>
<code>7000033</code>
<text>query 请求语义处理失败</text>
</error>
<error>
<code>7000034</code>
<text>获取天气信息失败</text>
</error>
<error>
<code>7000035</code>
<text>获取股票信息失败</text>
</error>
<error>
<code>7000036</code>
<text>utf8 编码转换失败</text>
</error>
<!-- 微信支付API错误 -->
<error>
<code>SYSTEMERROR</code>
@@ -0,0 +1,11 @@
package com.foxinmy.weixin4j.model;
public final class Consts {
public static final String SUCCESS = "SUCCESS";
public static final String FAIL = "FAIL";
public static final String SunX509 = "SunX509";
public static final String JKS = "JKS";
public static final String PKCS12 = "PKCS12";
public static final String TLS = "TLS";
public static final String X509 = "X.509";
}
@@ -2,6 +2,8 @@ package com.foxinmy.weixin4j.model;
import java.io.Serializable;
import org.apache.commons.lang3.StringUtils;
/**
* 微信账户信息
*
@@ -31,6 +33,8 @@ public class WeixinAccount implements Serializable {
private String mchId;
// 微信支付分配的设备号
private String deviceInfo;
// 微信支付版本号(如果无则按照mchId来做判断)
private int version;
// 是否已经认证
private boolean isAlive;
@@ -135,6 +139,17 @@ public class WeixinAccount implements Serializable {
this.isSubscribe = isSubscribe;
}
public int getVersion() {
if (version == 0) {
return StringUtils.isNotBlank(mchId) ? 3 : 2;
}
return version;
}
public void setVersion(int version) {
this.version = version;
}
public WeixinAccount() {
}
@@ -19,7 +19,6 @@ public class ScanEventMessage extends EventMessage {
}
private static final long serialVersionUID = 8078674062833071562L;
private static final String PARA_PREFIX = "qrscene_";
@XStreamAlias("EventKey")
private String eventKey; // 事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id
@@ -35,7 +34,7 @@ public class ScanEventMessage extends EventMessage {
}
public String getParameter() {
return eventKey.replace(PARA_PREFIX, "");
return eventKey.replace("qrscene_", "");
}
@Override
@@ -16,12 +16,15 @@ import java.util.Date;
*/
public class DateUtil {
private static final String yyyyMMdd = "yyyyMMdd";
private static final String yyyy_MM_dd = "yyyy-MM-dd";
private static final String yyyyMMddHHmmss = "yyyyMMddHHmmss";
public static String fortmat2yyyyMMdd(Date date) {
return new SimpleDateFormat(yyyyMMdd).format(date);
}
public static String fortmat2yyyy_MM_dd(Date date) {
return new SimpleDateFormat(yyyy_MM_dd).format(date);
}
public static String fortmat2yyyyMMddHHmmss(Date date) {
return new SimpleDateFormat(yyyyMMddHHmmss).format(date);
}
@@ -2,19 +2,19 @@ package com.foxinmy.weixin4j.util;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.http.Consts;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
/**
* 签名工具类
*
* @className MapUtil
* @author jy
* @date 2014年10月31日
@@ -22,10 +22,8 @@ import com.alibaba.fastjson.TypeReference;
* @see
*/
public class MapUtil {
private final static Charset charset = StandardCharsets.UTF_8;
public static String toJoinString(Object object, boolean encoder,
boolean lowerCase, JSONObject extra) {
boolean lowerCase, Map<String, String> extra) {
String text = JSON.toJSONString(object);
Map<String, String> map = new TreeMap<String, String>(
new Comparator<String>() {
@@ -34,14 +32,18 @@ public class MapUtil {
return o1.compareTo(o2);
}
});
map.putAll(JSON.parseObject(text,
new TypeReference<Map<String, String>>() {
}));
if (extra != null && !extra.isEmpty()) {
for (String key : extra.keySet()) {
map.put(key, extra.getString(key));
}
map.putAll(extra);
}
return toJoinString(map, encoder, lowerCase);
}
public static String toJoinString(Map<String, String> map, boolean encoder,
boolean lowerCase) {
StringBuilder sb = new StringBuilder();
Set<Map.Entry<String, String>> set = map.entrySet();
try {
@@ -50,14 +52,14 @@ public class MapUtil {
sb.append(entry.getKey().toLowerCase())
.append("=")
.append(URLEncoder.encode(entry.getValue(),
charset.name())).append("&");
Consts.UTF_8.name())).append("&");
}
} else if (encoder) {
for (Map.Entry<String, String> entry : set) {
sb.append(entry.getKey())
.append("=")
.append(URLEncoder.encode(entry.getValue(),
charset.name())).append("&");
Consts.UTF_8.name())).append("&");
}
} else if (lowerCase) {
for (Map.Entry<String, String> entry : set) {