weixin-mp & pay

This commit is contained in:
jy.hu 2014-11-03 15:44:12 +08:00
parent c908581178
commit 45ce10141a
172 changed files with 5591 additions and 742 deletions

View File

@ -1,36 +1,64 @@
weixin4j weixin4j
======== ========
@(weixin4j)[微信开发]
微信开发工具包 微信开发工具包
-------------
功能列表 功能列表
------- -------
* weixin4j-mp
* 公众平台API封装 `公众平台API封装`
`netty构建服务器`
`微信支付(公众号)`
* weixin4j-qy
`企业号API封装`
更新LOG 更新LOG
------- -------
* 2014-10-27 * 2014-10-27
1).maven多模块分离 + maven多模块分离
2).weixin4j-mp:用netty构建http服务器并支持消息分发 + `weixin4j-mp`:用netty构建http服务器并支持消息分发
* 2014-10-28 * 2014-10-28
1).weixin4j-mp:调整ActionMapping抽象化 + `weixin4j-mp`:调整`ActionMapping`抽象化
* 2014-10-31 * 2014-10-31
1).weixin4j-mp:weixin.properties切分为API调用地址/公众号信息两部分 + `weixin4j-mp`:`weixin.properties`切分为API调用地址/公众号信息两部分
2).weixin4j-base:TokenApi重命名为TokenHolder + `weixin4j-base:`TokenApi`重命名为`TokenHolder`
3).weixin4j-base:新增WeixinConfig等类 + `weixin4j-base`:新增`WeixinConfig`等类
* 2014-11-03
+ `weixin-mp`:分离为`weixin-mp-api``weixin-mp-server`两个工程
+ `weixin-mp`:加入支付模块
接下来 接下来
------ ------
公众号支付模块引入 `退款&对账`
企业号API封装 `企业号API封装`
`公众号智能接口`
`微信消息加密`
`被扫支付`
`公众号多客服`
`微信小店`
`微信卡券`

26
pom.xml
View File

@ -7,13 +7,35 @@
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>weixin4j</name> <name>weixin4j</name>
<url>https://github.com/foxinmy/weixin4j</url>
<description>微信开发工具包</description>
<inceptionYear>2014</inceptionYear>
<licenses>
<license>
<name>MIT</name>
<url>https://github.com/foxinmy/weixin4j/blob/master/LICENSE</url>
</license>
</licenses>
<developers>
<developer>
<email>hujinyuhao@163.com</email>
<id>jinyu</id>
<name>jinyu</name>
<url>https://github.com/foxinmy</url>
<timezone>8</timezone>
<roles>
<role>developer</role>
</roles>
</developer>
</developers>
<modules> <modules>
<module>weixin4j-base</module> <module>weixin4j-base</module>
<module>weixin4j-mp</module> <module>weixin4j-mp</module>
<module>weixin4j-qy</module> <module>weixin4j-qy</module>
</modules> </modules>
<properties> <properties>
<weixin4j.version>0.0.1-SNAPSHOT</weixin4j.version> <weixin4j.base.version>0.0.1-SNAPSHOT</weixin4j.base.version>
<weixin4j.mp.version>0.0.1-SNAPSHOT</weixin4j.mp.version>
<junit.version>4.8.2</junit.version> <junit.version>4.8.2</junit.version>
<dom4j.version>1.6.1</dom4j.version> <dom4j.version>1.6.1</dom4j.version>
<logback.version>1.0.9</logback.version> <logback.version>1.0.9</logback.version>
@ -26,8 +48,10 @@
<jsoup.version>1.7.3</jsoup.version> <jsoup.version>1.7.3</jsoup.version>
<jaxen.version>1.1.6</jaxen.version> <jaxen.version>1.1.6</jaxen.version>
<jedis.version>2.6.0</jedis.version> <jedis.version>2.6.0</jedis.version>
<poi.version>3.9</poi.version>
<netty.version>4.0.23.Final</netty.version> <netty.version>4.0.23.Final</netty.version>
<commons.lang.version>3.3.2</commons.lang.version> <commons.lang.version>3.3.2</commons.lang.version>
<commons.codec.version>1.9</commons.codec.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
<build> <build>

View File

@ -1,12 +1,21 @@
weixin4j-base weixin4j-base
============= =============
tencent weixin base java sdk 微信开发基础工程 @(weixin4j)[base]
微信开发基础工程
--------------
功能列表
-------
`Token的实现`
`通用消息实体`
更新LOG 更新LOG
------- -------
* 2014-10-31 * 2014-10-31
1).TokenApi重命名为TokenHolder + `TokenApi`重命名为`TokenHolder`
2).新增WeixinConfig等类 + 新增`WeixinConfig`等类

View File

@ -10,7 +10,10 @@
</parent> </parent>
<artifactId>weixin4j-base</artifactId> <artifactId>weixin4j-base</artifactId>
<name>weixin4j-base</name> <name>weixin4j-base</name>
<url>https://github.com/foxinmy</url> <url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-base</url>
<build>
<finalName>weixin4j-base</finalName>
</build>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.thoughtworks.xstream</groupId> <groupId>com.thoughtworks.xstream</groupId>

View File

@ -1,81 +0,0 @@
package com.foxinmy.weixin4j.http;
import java.io.Serializable;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 调用接口响应值
*
* @className BaseResult
* @author jy.hu
* @date 2014年9月24日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%85%A8%E5%B1%80%E8%BF%94%E5%9B%9E%E7%A0%81%E8%AF%B4%E6%98%8E">全局返回码</a>
*/
@XStreamAlias("xml")
public class BaseResult implements Serializable {
private static final long serialVersionUID = -6185313616955051150L;
@XStreamAlias("return_code")
private String errcode = "0";
@XStreamAlias("return_msg")
private String errmsg = "";
private String msgid;
private String text;
public BaseResult() {
}
public BaseResult(String errcode, String errmsg, String text) {
this(errcode, errmsg, null, text);
}
public BaseResult(String errcode, String errmsg, String msgid, String text) {
this.errcode = errcode;
this.errmsg = errmsg;
this.msgid = msgid;
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getErrcode() {
return errcode;
}
public void setErrcode(String errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public String getMsgid() {
return msgid;
}
public void setMsgid(String msgid) {
this.msgid = msgid;
}
@Override
public String toString() {
return "BaseResult [errcode=" + errcode + ", errmsg=" + errmsg
+ ", msgid=" + msgid + ", text=" + text + "]";
}
}

View File

@ -46,6 +46,7 @@ import com.foxinmy.weixin4j.exception.WeixinException;
* @see * @see
*/ */
public class HttpRequest { public class HttpRequest {
private final String SUCCESS = "success";
private AbstractHttpClient client; private AbstractHttpClient client;
public HttpRequest() { public HttpRequest() {
@ -149,6 +150,7 @@ public class HttpRequest {
protected Response doRequest(HttpRequestBase request) protected Response doRequest(HttpRequestBase request)
throws WeixinException { throws WeixinException {
Response response = null;
try { try {
HttpResponse httpResponse = client.execute(request); HttpResponse httpResponse = client.execute(request);
StatusLine statusLine = httpResponse.getStatusLine(); StatusLine statusLine = httpResponse.getStatusLine();
@ -166,38 +168,47 @@ public class HttpRequest {
httpResponse.getFirstHeader("location"))); httpResponse.getFirstHeader("location")));
} }
byte[] data = EntityUtils.toByteArray(httpEntity); byte[] data = EntityUtils.toByteArray(httpEntity);
Response response = new Response(); response = new Response();
response.setBody(data); response.setBody(data);
response.setStatusCode(status); response.setStatusCode(status);
response.setStatusText(statusLine.getReasonPhrase()); response.setStatusText(statusLine.getReasonPhrase());
response.setStream(new ByteArrayInputStream(data)); response.setStream(new ByteArrayInputStream(data));
response.setText(new String(data, StandardCharsets.UTF_8));
EntityUtils.consume(httpEntity);
Header contentType = httpResponse Header contentType = httpResponse
.getFirstHeader(HttpHeaders.CONTENT_TYPE); .getFirstHeader(HttpHeaders.CONTENT_TYPE);
if (contentType.getValue().contains( if (contentType.getValue().contains(
ContentType.APPLICATION_JSON.getMimeType()) ContentType.APPLICATION_JSON.getMimeType())
|| contentType.getValue().contains( || contentType.getValue().contains(
ContentType.TEXT_PLAIN.getMimeType())) { ContentType.TEXT_PLAIN.getMimeType())) {
BaseResult result = null; response.setText(new String(data, StandardCharsets.UTF_8));
try { try {
result = response.getAsResult(); JsonResult jsonResult = response.getAsJsonResult();
} catch (JSONException e) { response.setJsonResult(true);
result = response.getAsXml(BaseResult.class); if (jsonResult.getCode() != 0) {
} throw new WeixinException(jsonResult.getCode() + "",
if (result.getErrcode().equals("0") jsonResult.getDesc());
|| result.getErrcode().equalsIgnoreCase("success")) { }
EntityUtils.consume(httpEntity);
return 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());
} }
throw new WeixinException(result.getErrcode(),
result.getErrmsg());
} }
} catch (IOException e) { } catch (IOException e) {
throw new WeixinException(e.getMessage()); throw new WeixinException(e.getMessage());
} finally { } finally {
request.releaseConnection(); request.releaseConnection();
} }
throw new WeixinException("-1", "request fail"); return response;
} }
} }

View File

@ -0,0 +1,67 @@
package com.foxinmy.weixin4j.http;
import java.io.Serializable;
import com.alibaba.fastjson.annotation.JSONField;
/**
* 调用接口返回JSON格式
*
* @className JsonResult
* @author jy.hu
* @date 2014年9月24日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%85%A8%E5%B1%80%E8%BF%94%E5%9B%9E%E7%A0%81%E8%AF%B4%E6%98%8E">全局返回码</a>
*/
public class JsonResult implements Serializable {
private static final long serialVersionUID = -6185313616955051150L;
@JSONField(name = "errcode")
private int code;
@JSONField(name = "errmsg")
private String desc;
private String text;
public JsonResult() {
this.desc = "";
this.text = "";
}
public JsonResult(int code, String desc, String text) {
this.code = code;
this.desc = desc;
this.text = text;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
@Override
public String toString() {
return "JsonResult [code=" + code + ", desc=" + desc + ", text=" + text
+ "]";
}
}

View File

@ -9,6 +9,7 @@ import org.dom4j.io.SAXReader;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.xml.XStream; import com.foxinmy.weixin4j.xml.XStream;
public class Response { public class Response {
@ -18,6 +19,8 @@ public class Response {
private String statusText; private String statusText;
private byte[] body; private byte[] body;
private InputStream stream; private InputStream stream;
private boolean isJsonResult;
private boolean isXmlResult;
public Response() { public Response() {
} }
@ -26,26 +29,40 @@ public class Response {
this.text = text; this.text = text;
} }
public void setJsonResult(boolean isJsonResult) {
this.isJsonResult = isJsonResult;
}
public void setXmlResult(boolean isXmlResult) {
this.isXmlResult = isXmlResult;
}
public String getAsString() { public String getAsString() {
return text; return text;
} }
public BaseResult getAsResult() { public JsonResult getAsJsonResult() {
return JSON.parseObject(text, BaseResult.class); return JSON.parseObject(text, JsonResult.class);
} }
public JSONObject getAsJson() { public JSONObject getAsJson() {
return JSON.parseObject(text); return JSON.parseObject(text);
} }
public <T> T getAsObject(Class<T> clazz) { public <T> T getAsObject(TypeReference<T> typeReference) {
return (T) JSON.parseObject(text, clazz); if (isJsonResult) {
return JSON.parseObject(text, typeReference);
}
if (isXmlResult) {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) typeReference.getType();
return XStream.get(text, clazz);
}
return null;
} }
public <T> T getAsXml(Class<T> clazz) { public XmlResult getAsXmlResult() {
XStream xStream = XStream.get(); return XStream.get(text, XmlResult.class);
xStream.processAnnotations(clazz);
return xStream.fromXML(text, clazz);
} }
/** /**
@ -56,24 +73,22 @@ public class Response {
* @return * @return
* @throws DocumentException * @throws DocumentException
*/ */
public BaseResult getBaseError() throws DocumentException { public JsonResult getTextError() throws DocumentException {
BaseResult result = getAsResult(); JsonResult result = getAsJsonResult();
if (!result.getErrcode().equals("0")) { if (result.getCode() != 0) {
SAXReader reader = new SAXReader(); SAXReader reader = new SAXReader();
Document doc = reader.read(Response.class.getResourceAsStream("error.xml")); Document doc = reader.read(Response.class
.getResourceAsStream("error.xml"));
Node node = doc.getRootElement().selectSingleNode( Node node = doc.getRootElement().selectSingleNode(
String.format("error[@code='%s']", result.getErrcode())); String.format("error/code[text()='%d']", result.getCode()));
if (node != null) { if (node != null) {
result.setText(node.getStringValue()); result.setText(node.getParent().selectSingleNode("text")
.getStringValue());
} }
} }
return result; return result;
} }
public String getText() {
return text;
}
public void setText(String text) { public void setText(String text) {
this.text = text; this.text = text;
} }

View File

@ -0,0 +1,93 @@
package com.foxinmy.weixin4j.http;
import java.io.Serializable;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 调用接口返回xml格式
*
* @className XmlResult
* @author jy
* @date 2014年11月1日
* @since JDK 1.7
* @see
*/
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 来判断 非空
@XStreamAlias("return_msg")
private String returnMsg;// 返回信息,如非 ,为错误原因 可能为空
@XStreamAlias("result_code")
private String resultCode;// 业务结果SUCCESS/FAIL 非空
@XStreamAlias("err_code")
private String errCode;// 错误代码 可为空
@XStreamAlias("err_code_des")
private String errCodeDes;// 结果信息描述 可为空
public String getReturnCode() {
return returnCode;
}
public void setReturnCode(String returnCode) {
this.returnCode = returnCode;
}
public String getReturnMsg() {
return returnMsg;
}
public void setReturnMsg(String returnMsg) {
this.returnMsg = returnMsg;
}
public String getResultCode() {
return resultCode;
}
public void setResultCode(String resultCode) {
this.resultCode = resultCode;
}
public String getErrCode() {
return errCode;
}
public void setErrCode(String errCode) {
this.errCode = errCode;
}
public String getErrCodeDes() {
return errCodeDes;
}
public void setErrCodeDes(String errCodeDes) {
this.errCodeDes = errCodeDes;
}
public XmlResult() {
this("success", "");
}
public XmlResult(String returnCode, String returnMsg) {
this.returnCode = returnCode;
this.returnMsg = returnMsg;
if (returnCode.equalsIgnoreCase(SUCCESS)) {
this.resultCode = SUCCESS.toLowerCase();
this.errCode = SUCCESS.toLowerCase();
this.errCodeDes = "";
}
}
@Override
public String toString() {
return "XmlResult [returnCode=" + returnCode + ", returnMsg="
+ returnMsg + ", resultCode=" + resultCode + ", errCode="
+ errCode + ", errCodeDes=" + errCodeDes + "]";
}
}

View File

@ -1,97 +1,427 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!-- http://mp.weixin.qq.com/wiki/index.php?title=%E5%85%A8%E5%B1%80%E8%BF%94%E5%9B%9E%E7%A0%81%E8%AF%B4%E6%98%8E --> <!-- http://mp.weixin.qq.com/wiki/index.php?title=%E5%85%A8%E5%B1%80%E8%BF%94%E5%9B%9E%E7%A0%81%E8%AF%B4%E6%98%8E -->
<errors> <errors>
<error code="-1">系统繁忙</error> <error>
<error code="40001">获取access_token时AppSecret错误或者access_token无效</error> <code>0</code>
<error code="40002">不合法的凭证类型</error> <desc>OK</desc>
<error code="40003">不合法的OpenID</error> <text>请求成功</text>
<error code="40004">不合法的媒体文件类型</error> </error>
<error code="40005">不合法的文件类型</error> <error>
<error code="40006">不合法的文件大小</error> <code>-1</code>
<error code="40007">不合法的媒体文件id</error> <desc>system error</desc>
<error code="40008">不合法的消息类型</error> <text>系统繁忙</text>
<error code="40009">不合法的图片文件大小</error> </error>
<error code="40010">不合法的语音文件大小</error> <!-- 公众平台API错误 -->
<error code="40011">不合法的视频文件大小</error> <error>
<error code="40012">不合法的缩略图文件大小</error> <code>40001</code>
<error code="40013">不合法的APPID</error> <desc>invalid credential</desc>
<error code="40014">不合法的access_token</error> <text>不合法的调用凭证</text>
<error code="40015">不合法的菜单类型</error> </error>
<error code="40016">不合法的按钮个数</error> <error>
<error code="40017">不合法的按钮个数</error> <code>40002</code>
<error code="40018">不合法的按钮名字长度</error> <desc>invalid grant_type</desc>
<error code="40019">不合法的按钮KEY长度</error> <text>不合法的grant_type</text>
<error code="40020">不合法的按钮URL长度</error> </error>
<error code="40021">不合法的菜单版本号</error> <error>
<error code="40022">不合法的子菜单级数</error> <code>40003</code>
<error code="40023">不合法的子菜单按钮个数</error> <desc>invalid openid</desc>
<error code="40024">不合法的子菜单按钮类型</error> <text>不合法的OpenID</text>
<error code="40025">不合法的子菜单按钮名字长度</error> </error>
<error code="40026">不合法的子菜单按钮KEY长度</error> <error>
<error code="40027">不合法的子菜单按钮URL长度</error> <code>40004</code>
<error code="40028">不合法的自定义菜单使用用户</error> <desc>invalid media type</desc>
<error code="40029">不合法的oauth_code</error> <text>不合法的媒体文件类型</text>
<error code="40030">不合法的refresh_token</error> </error>
<error code="40031">不合法的openid列表</error> <error>
<error code="40032">不合法的openid列表长度</error> <code>40007</code>
<error code="40033">不合法的请求字符,不能包含\uxxxx格式的字符</error> <desc>invalid media_id</desc>
<error code="40035">不合法的参数</error> <text>不合法的media_id</text>
<error code="40038">不合法的请求格式</error> </error>
<error code="40039">不合法的URL长度</error> <error>
<error code="40050">不合法的分组id</error> <code>40008</code>
<error code="40051">分组名字不合法</error> <desc>invalid message type</desc>
<error code="41001">缺少access_token参数</error> <text>不合法的message_type</text>
<error code="41002">缺少appid参数</error> </error>
<error code="41003">缺少refresh_token参数</error> <error>
<error code="41004">缺少secret参数</error> <code>40009</code>
<error code="41005">缺少多媒体文件数据</error> <desc>invalid image size</desc>
<error code="41006">缺少media_id参数</error> <text>不合法的图片大小</text>
<error code="41007">缺少子菜单数据</error> </error>
<error code="41008">缺少oauth code</error> <error>
<error code="41009">缺少openid</error> <code>40010</code>
<error code="42001">access_token超时</error> <desc>invalid voice size</desc>
<error code="42002">refresh_token超时</error> <text>不合法的语音大小</text>
<error code="42003">oauth_code超时</error> </error>
<error code="43001">需要GET请求</error> <error>
<error code="43002">需要POST请求</error> <code>40011</code>
<error code="43003">需要HTTPS请求</error> <desc>invalid video size</desc>
<error code="43004">需要接收者关注</error> <text>不合法的视频大小</text>
<error code="43005">需要好友关系</error> </error>
<error code="44001">多媒体文件为空</error> <error>
<error code="44002">POST的数据包为空</error> <code>40012</code>
<error code="44003">图文消息内容为空</error> <desc>invalid thumb size</desc>
<error code="44004">文本消息内容为空</error> <text>不合法的缩略图大小</text>
<error code="45001">多媒体文件大小超过限制</error> </error>
<error code="45002">消息内容超过限制</error> <error>
<error code="45003">标题字段超过限制</error> <code>40013</code>
<error code="45004">描述字段超过限制</error> <desc>invalid appid</desc>
<error code="45005">链接字段超过限制</error> <text>不合法的AppID</text>
<error code="45006">图片链接字段超过限制</error> </error>
<error code="45007">语音播放时间超过限制</error> <error>
<error code="45008">图文消息超过限制</error> <code>40014</code>
<error code="45009">接口调用超过限制</error> <desc>invalid access_token</desc>
<error code="45010">创建菜单个数超过限制</error> <text>不合法的access_token</text>
<error code="45015">回复时间超过限制</error> </error>
<error code="45016">系统分组,不允许修改</error> <error>
<error code="45017">分组名字过长</error> <code>40015</code>
<error code="45018">分组数量超过上限</error> <desc>invalid menu type</desc>
<error code="46001">不存在媒体数据</error> <text>不合法的菜单类型</text>
<error code="46002">不存在的菜单版本</error> </error>
<error code="46003">不存在的菜单数据</error> <error>
<error code="46004">不存在的用户</error> <code>40016</code>
<error code="47001">解析JSON/XML内容错误</error> <desc>invalid button size</desc>
<error code="48001">api功能未授权</error> <text>不合法的菜单按钮个数</text>
<error code="50001">用户未授权该api</error> </error>
<error code="SYSTEMERROR">接口后台错误</error> <error>
<error code="INVALID_TRANSACTIONID">无效 transaction_id</error> <code>40017</code>
<error code="PARAM_ERROR">提交参数错误</error> <desc>invalid button type</desc>
<error code="ORDERPAID">订单已支付</error> <text>不合法的按钮类型</text>
<error code="OUT_TRADE_NO_USED">商户订单号重复</error> </error>
<error code="NOAUTH">商户无权限</error> <error>
<error code="NOTENOUGH">余额不足</error> <code>40018</code>
<error code="NOTSUPORTCARD">不支持卡类型</error> <desc>invalid button name size</desc>
<error code="ORDERCLOSED">订单已关闭</error> <text>不合法的按钮名称长度</text>
<error code="BANKERROR">银行系统异常</error> </error>
<error code="REFUND_FEE_INVALID">退款金额大于支付金额</error> <error>
<error code="ORDERNOTEXIST">订单不存在</error> <code>40019</code>
<desc>invalid button key size</desc>
<text>不合法的按钮KEY长度</text>
</error>
<error>
<code>40020</code>
<desc>invalid button url size</desc>
<text>不合法的url长度</text>
</error>
<error>
<code>40023</code>
<desc>invalid sub button size</desc>
<text>不合法的子菜单按钮个数</text>
</error>
<error>
<code>40024</code>
<desc>invalid sub button type</desc>
<text>不合法的子菜单类型</text>
</error>
<error>
<code>40025</code>
<desc>invalid sub button name size</desc>
<text>不合法的子菜单按钮名称长度</text>
</error>
<error>
<code>40026</code>
<desc>invalid sub button key size</desc>
<text>不合法的子菜单按钮KEY长度</text>
</error>
<error>
<code>40027</code>
<desc>invalid sub button url size</desc>
<text>不合法的子菜单按钮url长度</text>
</error>
<error>
<code>40029</code>
<desc>invalid code</desc>
<text>不合法或已过期的code</text>
</error>
<error>
<code>40030</code>
<desc>invalid refresh_token</desc>
<text>不合法的refresh_token</text>
</error>
<error>
<code>40036</code>
<desc>invalid template_id size</desc>
<text>不合法的template_id长度</text>
</error>
<error>
<code>40037</code>
<desc>invalid template_id</desc>
<text>不合法的template_id</text>
</error>
<error>
<code>40039</code>
<desc>invalid url size</desc>
<text>不合法的url长度</text>
</error>
<error>
<code>40048</code>
<desc>invalid url domain</desc>
<text>不合法的url域名</text>
</error>
<error>
<code>40054</code>
<desc>invalid sub button url domain</desc>
<text>不合法的子菜单按钮url域名</text>
</error>
<error>
<code>40055</code>
<desc>invalid button url domain</desc>
<text>不合法的菜单按钮url域名</text>
</error>
<error>
<code>40066</code>
<desc>invalid url</desc>
<text>不合法的url</text>
</error>
<error>
<code>41001</code>
<desc>access_token missing</desc>
<text>缺失access_token参数</text>
</error>
<error>
<code>41002</code>
<desc>appid missing</desc>
<text>缺失appid参数</text>
</error>
<error>
<code>41003</code>
<desc>refresh_token missing</desc>
<text>缺失refresh_token参数</text>
</error>
<error>
<code>41004</code>
<desc>appsecret missing</desc>
<text>缺失secret参数</text>
</error>
<error>
<code>41005</code>
<desc>media data missing</desc>
<text>缺失二进制媒体文件</text>
</error>
<error>
<code>41006</code>
<desc>media_id missing</desc>
<text>缺失media_id参数</text>
</error>
<error>
<code>41007</code>
<desc>sub_menu data missing</desc>
<text>缺失子菜单数据</text>
</error>
<error>
<code>41008</code>
<desc>missing code</desc>
<text>缺失code参数</text>
</error>
<error>
<code>41009</code>
<desc>missing openid</desc>
<text>缺失openid参数</text>
</error>
<error>
<code>41010</code>
<desc>missing url</desc>
<text>缺失url参数</text>
</error>
<error>
<code>42001</code>
<desc>access_token expired</desc>
<text>access_token超时</text>
</error>
<error>
<code>42002</code>
<desc>refresh_token expired</desc>
<text>refresh_token超时</text>
</error>
<error>
<code>42003</code>
<desc>code expired</desc>
<text>code超时</text>
</error>
<error>
<code>43001</code>
<desc>require GET method</desc>
<text>需要使用GET方法请求</text>
</error>
<error>
<code>43002</code>
<desc>require POST method</desc>
<text>需要使用POST方法请求</text>
</error>
<error>
<code>43003</code>
<desc>require https</desc>
<text>需要使用HTTPS</text>
</error>
<error>
<code>43004</code>
<desc>require subscribe</desc>
<text>需要订阅关系</text>
</error>
<error>
<code>44001</code>
<desc>empty media data</desc>
<text>空白的二进制数据</text>
</error>
<error>
<code>44002</code>
<desc>empty post data</desc>
<text>空白的POST数据</text>
</error>
<error>
<code>44003</code>
<desc>empty news data</desc>
<text>空白的news数据</text>
</error>
<error>
<code>44004</code>
<desc>empty content</desc>
<text>空白的内容</text>
</error>
<error>
<code>44005</code>
<desc>empty list size</desc>
<text>空白的列表</text>
</error>
<error>
<code>45001</code>
<desc>media size out of limit</desc>
<text>二进制文件超过限制</text>
</error>
<error>
<code>45002</code>
<desc>content size out of limit</desc>
<text>content参数超过限制</text>
</error>
<error>
<code>45003</code>
<desc>title size out of limit</desc>
<text>title参数超过限制</text>
</error>
<error>
<code>45004</code>
<desc>description size out of limit</desc>
<text>description参数超过限制</text>
</error>
<error>
<code>45005</code>
<desc>url size out of limit</desc>
<text>url参数长度超过限制</text>
</error>
<error>
<code>45006</code>
<desc>picurl size out of limit</desc>
<text>picurl参数超过限制</text>
</error>
<error>
<code>45007</code>
<desc>playtime out of limit</desc>
<text>播放时间超过限制语音为60s最大</text>
</error>
<error>
<code>45008</code>
<desc>article size out of limit</desc>
<text>article参数超过限制</text>
</error>
<error>
<code>45009</code>
<desc>api freq out of limit</desc>
<text>接口调动频率超过限制</text>
</error>
<error>
<code>45010</code>
<desc>create menu limit</desc>
<text>建立菜单被限制</text>
</error>
<error>
<code>45011</code>
<desc>api limit</desc>
<text>频率限制</text>
</error>
<error>
<code>45012</code>
<desc>template size out of limit</desc>
<text>模板大小超过限制</text>
</error>
<error>
<code>45016</code>
<desc>can't modify sys group</desc>
<text>不能修改默认组</text>
</error>
<error>
<code>45017</code>
<desc>can't set group name too long sys group</desc>
<text>修改组名过长</text>
</error>
<error>
<code>45018</code>
<desc>too many group now, no need to add new</desc>
<text>组数量过多</text>
</error>
<error>
<code>50001</code>
<desc>api unauthorized</desc>
<text>接口未授权</text>
</error>
<!-- 微信支付API错误 -->
<error>
<code>SYSTEMERROR</code>
<desc>SYSTEMERROR</desc>
<text>接口后台错误</text>
</error>
<error>
<code>INVALID_TRANSACTIONID</code>
<desc>INVALID_TRANSACTIONID</desc>
<text>无效 transaction_id</text>
</error>
<error>
<code>PARAM_ERROR</code>
<desc>PARAM_ERROR</desc>
<text>提交参数错误</text>
</error>
<error>
<code>ORDERPAID</code>
<desc>ORDERPAID</desc>
<text>订单已支付</text>
</error>
<error>
<code>OUT_TRADE_NO_USED</code>
<desc>OUT_TRADE_NO_USED</desc>
<text>商户订单号重复</text>
</error>
<error>
<code>NOAUTH</code>
<desc>NOAUTH</desc>
<text>商户无权限</text>
</error>
<error>
<code>NOTENOUGH</code>
<desc>NOTENOUGH</desc>
<text>余额不足</text>
</error>
<error>
<code>NOTSUPORTCARD</code>
<desc>NOTSUPORTCARD</desc>
<text>不支持卡类型</text>
</error>
<error>
<code>ORDERCLOSED</code>
<desc>ORDERCLOSED</desc>
<text>订单已关闭</text>
</error>
<error>
<code>BANKERROR</code>
<desc>BANKERROR</desc>
<text>银行系统异常</text>
</error>
<error>
<code>REFUND_FEE_INVALID</code>
<desc>REFUND_FEE_INVALID</desc>
<text>退款金额大于支付金额</text>
</error>
<error>
<code>ORDERNOTEXIST</code>
<desc>ORDERNOTEXIST</desc>
<text>订单不存在</text>
</error>
</errors> </errors>

View File

@ -3,22 +3,72 @@ package com.foxinmy.weixin4j.model;
/** /**
* 微信账户信息 * 微信账户信息
* *
* @className WeixinAccountV2 * @className WeixinAccount
* @author jy * @author jy
* @date 2014年8月17日 * @date 2014年8月17日
* @since JDK 1.7 * @since JDK 1.7
* @see * @see
*/ */
public class WeixinAccount extends WeixinAccountV2 { public class WeixinAccount extends WeixinConfig {
private static final long serialVersionUID = 3689999353867189585L; private static final long serialVersionUID = 3689999353867189585L;
// 公众号支付请求中用于加密的密钥 Key,可验证商户唯一身份,PaySignKey 对应于支付场景中的 appKey
private String paySignKey;
// 财付通商户身份的标识
private String partnerId;
// 财付通商户权限密钥Key
private String partnerKey;
// 微信支付商户号V3.x版本
private String mchId;
// 微信支付分配的设备号
private String deviceInfo;
// 是否已经认证 // 是否已经认证
private boolean isAlive; private boolean isAlive;
// 是否是服务号 // 是否是服务号
private boolean isService; private boolean isService;
// 是否是订阅号 // 是否是订阅号
private boolean isSubscribe = true; private boolean isSubscribe;
// 微信支付商户号
private String mchId; public String getPaySignKey() {
return paySignKey;
}
public void setPaySignKey(String paySignKey) {
this.paySignKey = paySignKey;
}
public String getPartnerId() {
return partnerId;
}
public void setPartnerId(String partnerId) {
this.partnerId = partnerId;
}
public String getPartnerKey() {
return partnerKey;
}
public void setPartnerKey(String partnerKey) {
this.partnerKey = partnerKey;
}
public String getMchId() {
return mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
public String getDeviceInfo() {
return deviceInfo;
}
public void setDeviceInfo(String deviceInfo) {
this.deviceInfo = deviceInfo;
}
public boolean getIsAlive() { public boolean getIsAlive() {
return isAlive; return isAlive;
@ -39,46 +89,28 @@ public class WeixinAccount extends WeixinAccountV2 {
public boolean getIsSubscribe() { public boolean getIsSubscribe() {
return isSubscribe; return isSubscribe;
} }
public String getMchId() {
return mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
public void setIsSubscribe(Boolean isSubscribe) { public void setIsSubscribe(Boolean isSubscribe) {
this.isSubscribe = isSubscribe; this.isSubscribe = isSubscribe;
} }
public WeixinAccount() { public WeixinAccount() {
} }
public WeixinAccount(boolean isAlive, boolean isService, public WeixinAccount(String appId, String appSecret, String paySignKey,
boolean isSubscribe, String token, String openId) { String mchId) {
super.setToken(token); super(appId, appSecret);
super.setOpenId(openId); this.paySignKey = paySignKey;
this.isAlive = isAlive; this.mchId = mchId;
this.isService = isService;
this.isSubscribe = isSubscribe;
} }
public WeixinAccount(boolean isAlive, boolean isService, public WeixinAccount(String appId, String appSecret, String paySignKey,
boolean isSubscribe, String token, String openId, String appId, String partnerId, String partnerKey) {
String appSecret) { super(appId, appSecret);
super.setToken(token); this.paySignKey = paySignKey;
super.setOpenId(openId); this.partnerId = partnerId;
super.setAppId(appId); this.partnerKey = partnerKey;
super.setAppSecret(appSecret);
this.isAlive = isAlive;
this.isService = isService;
this.isSubscribe = isSubscribe;
} }
@Override
public String toString() {
return "WeixinAccount [isAlive=" + isAlive + ", isService=" + isService
+ ", isSubscribe=" + isSubscribe + ", mchId=" + mchId
+ ", getIsAlive()=" + getIsAlive() + ", getIsService()="
+ getIsService() + ", getIsSubscribe()=" + getIsSubscribe()
+ ", getMchId()=" + getMchId() + "]";
}
} }

View File

@ -1,56 +0,0 @@
package com.foxinmy.weixin4j.model;
/**
* 微信支付V2.7
*
* @className WeixinAccountV2
* @author jy
* @date 2014年8月17日
* @since JDK 1.7
* @see
*/
public class WeixinAccountV2 extends WeixinConfig {
private static final long serialVersionUID = 3689999353867189585L;
// 公众号支付请求中用于加密的密钥 Key,可验证商户唯一身份,PaySignKey 对应于支付场景中的 appKey
private String paySignKey;
// 财付通商户身份的标识
private String partnerId;
// 财付通商户权限密钥Key
private String partnerKey;
public String getPaySignKey() {
return paySignKey;
}
public void setPaySignKey(String paySignKey) {
this.paySignKey = paySignKey;
}
public String getPartnerId() {
return partnerId;
}
public void setPartnerId(String partnerId) {
this.partnerId = partnerId;
}
public String getPartnerKey() {
return partnerKey;
}
public void setPartnerKey(String partnerKey) {
this.partnerKey = partnerKey;
}
public WeixinAccountV2() {
}
public WeixinAccountV2(String openId, String appId, String appSecret,
String paySignKey, String partnerId, String partnerKey) {
super(null, openId, appId, appSecret);
this.paySignKey = paySignKey;
this.partnerId = partnerId;
this.partnerKey = partnerKey;
}
@Override
public String toString() {
return "WeixinAccountV2 [paySignKey=" + paySignKey + ", partnerId="
+ partnerId + ", partnerKey=" + partnerKey
+ ", getPaySignKey()=" + getPaySignKey() + ", getPartnerId()="
+ getPartnerId() + ", getPartnerKey()=" + getPartnerKey() + "]";
}
}

View File

@ -1,46 +0,0 @@
package com.foxinmy.weixin4j.model;
/**
* 微信支付V3.3.6
*
* @className WeixinConfig
* @author jy
* @date 2014年8月17日
* @since JDK 1.7
* @see
*/
public class WeixinAccountV3 extends WeixinConfig {
private static final long serialVersionUID = 3689999353867189585L;
// 公众号支付请求中用于加密的密钥 Key,可验证商户唯一身份,PaySignKey 对应于支付场景中的 appKey
private String paySignKey;
// 微信支付商户号
private String mchId;
public String getPaySignKey() {
return paySignKey;
}
public void setPaySignKey(String paySignKey) {
this.paySignKey = paySignKey;
}
public String getMchId() {
return mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
public WeixinAccountV3() {
}
public WeixinAccountV3(String appId, String appSecret, String paySignKey,
String mchId, String openId) {
super(null, openId, appId, appSecret);
this.mchId = mchId;
this.paySignKey = paySignKey;
}
@Override
public String toString() {
return "WeixinAccountV3 [paySignKey=" + paySignKey + ", mchId=" + mchId
+ ", getPaySignKey()=" + getPaySignKey() + ", getMchId()="
+ getMchId() + "]";
}
}

View File

@ -13,40 +13,48 @@ public class WeixinConfig implements Serializable {
private String appId; private String appId;
// 除了支付请求需要用到 paySignKey,公众平台接口 API 的权限获取所需密 Key // 除了支付请求需要用到 paySignKey,公众平台接口 API 的权限获取所需密 Key
private String appSecret; private String appSecret;
public String getToken() { public String getToken() {
return token; return token;
} }
public void setToken(String token) { public void setToken(String token) {
this.token = token; this.token = token;
} }
public String getOpenId() { public String getOpenId() {
return openId; return openId;
} }
public void setOpenId(String openId) { public void setOpenId(String openId) {
this.openId = openId; this.openId = openId;
} }
public String getAppId() { public String getAppId() {
return appId; return appId;
} }
public void setAppId(String appId) { public void setAppId(String appId) {
this.appId = appId; this.appId = appId;
} }
public String getAppSecret() { public String getAppSecret() {
return appSecret; return appSecret;
} }
public void setAppSecret(String appSecret) { public void setAppSecret(String appSecret) {
this.appSecret = appSecret; this.appSecret = appSecret;
} }
public WeixinConfig() { public WeixinConfig() {
} }
public WeixinConfig(String token, String openId, String appId,
String appSecret) { public WeixinConfig(String appId, String appSecret) {
this.token = token;
this.openId = openId;
this.appId = appId; this.appId = appId;
this.appSecret = appSecret; this.appSecret = appSecret;
} }
@Override @Override
public String toString() { public String toString() {
return "WeixinConfig [token=" + token + ", openId=" + openId return "WeixinConfig [token=" + token + ", openId=" + openId

View File

@ -1,14 +1,13 @@
package com.foxinmy.weixin4j.token; package com.foxinmy.weixin4j.token;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.http.HttpRequest; import com.foxinmy.weixin4j.http.HttpRequest;
import com.foxinmy.weixin4j.model.WeixinConfig; import com.foxinmy.weixin4j.model.WeixinConfig;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
/** /**
* 获取config.properties中的appid&appsecret信息 * 获取weixin.properties中的appid&appsecret信息
* *
* @className AbstractTokenApi * @className AbstractTokenHolder
* @author jy * @author jy
* @date 2014年10月6日 * @date 2014年10月6日
* @since JDK 1.7 * @since JDK 1.7
@ -17,18 +16,25 @@ import com.foxinmy.weixin4j.util.ConfigUtil;
public abstract class AbstractTokenHolder implements TokenHolder { public abstract class AbstractTokenHolder implements TokenHolder {
protected final String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; protected final String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
protected final HttpRequest request = new HttpRequest(); protected final HttpRequest request = new HttpRequest();
private final WeixinConfig weixinConfig; private final String appid;
private final String appsecret;
public AbstractTokenHolder() { public AbstractTokenHolder() {
weixinConfig = JSON.parseObject(ConfigUtil.getValue("account"), WeixinConfig weixinConfig = ConfigUtil.getWeixinConfig();
WeixinConfig.class); this.appid = weixinConfig.getAppId();
this.appsecret = weixinConfig.getAppSecret();
}
public AbstractTokenHolder(String appid, String appsecret) {
this.appid = appid;
this.appsecret = appsecret;
} }
protected String getAppid() { protected String getAppid() {
return weixinConfig.getAppId(); return this.appid;
} }
protected String getAppsecret() { protected String getAppsecret() {
return weixinConfig.getAppSecret(); return this.appsecret;
} }
} }

View File

@ -1,12 +1,14 @@
package com.foxinmy.weixin4j.token; package com.foxinmy.weixin4j.token;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Calendar; import java.util.Calendar;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
@ -26,17 +28,12 @@ import com.foxinmy.weixin4j.xml.XStream;
*/ */
public class FileTokenHolder extends AbstractTokenHolder { public class FileTokenHolder extends AbstractTokenHolder {
private final String appid;
private final String appsecret;
public FileTokenHolder() { public FileTokenHolder() {
this.appid = getAppid(); super();
this.appsecret = getAppsecret();
} }
public FileTokenHolder(String appid, String appsecret) { public FileTokenHolder(String appid, String appsecret) {
this.appid = appid; super(appid, appsecret);
this.appsecret = appsecret;
} }
/** /**
@ -53,12 +50,12 @@ public class FileTokenHolder extends AbstractTokenHolder {
*/ */
@Override @Override
public Token getToken() throws WeixinException { public Token getToken() throws WeixinException {
String appid = getAppid();
String appsecret = getAppsecret();
if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) { if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"appid or appsecret not be null!"); "appid or appsecret not be null!");
} }
XStream xstream = XStream.get();
xstream.processAnnotations(Token.class);
File token_file = new File(String.format("%s/token_%s.xml", File token_file = new File(String.format("%s/token_%s.xml",
ConfigUtil.getValue("token_path"), appid)); ConfigUtil.getValue("token_path"), appid));
Token token = null; Token token = null;
@ -66,7 +63,8 @@ public class FileTokenHolder extends AbstractTokenHolder {
long now_time = ca.getTimeInMillis(); long now_time = ca.getTimeInMillis();
try { try {
if (token_file.exists()) { if (token_file.exists()) {
token = (Token) xstream.fromXML(token_file); token = XStream.get(new FileInputStream(token_file),
Token.class);
long expise_time = token.getTime() long expise_time = token.getTime()
+ (token.getExpiresIn() * 1000) - 3; + (token.getExpiresIn() * 1000) - 3;
@ -74,23 +72,18 @@ public class FileTokenHolder extends AbstractTokenHolder {
return token; return token;
} }
} else { } else {
try { token_file.createNewFile();
token_file.createNewFile();
} catch (IOException e) {
token_file.getParentFile().mkdirs();
}
} }
String api_token_uri = String.format( String api_token_uri = String.format(tokenUrl, appid, appsecret);
tokenUrl, appid, appsecret);
Response response = request.get(api_token_uri); Response response = request.get(api_token_uri);
token = response.getAsObject(Token.class); token = response.getAsObject(new TypeReference<Token>() {
});
token.setTime(now_time); token.setTime(now_time);
token.setOpenid(appid); token.setOpenid(appid);
xstream.toXML(token, new FileOutputStream(token_file)); XStream.to(token, new FileOutputStream(token_file));
return token;
} catch (IOException e) { } catch (IOException e) {
; throw new WeixinException("-1", "IO ERROR");
} }
throw new WeixinException("-1", "request fail"); return token;
} }
} }

View File

@ -6,6 +6,7 @@ import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisPoolConfig;
import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
@ -22,13 +23,10 @@ import com.foxinmy.weixin4j.model.Token;
*/ */
public class RedisTokenHolder extends AbstractTokenHolder { public class RedisTokenHolder extends AbstractTokenHolder {
private final String appid;
private final String appsecret;
private JedisPool jedisPool; private JedisPool jedisPool;
public RedisTokenHolder() { public RedisTokenHolder() {
this.appid = getAppid(); super();
this.appsecret = getAppsecret();
} }
public RedisTokenHolder(String appid, String appsecret) { public RedisTokenHolder(String appid, String appsecret) {
@ -37,8 +35,7 @@ public class RedisTokenHolder extends AbstractTokenHolder {
public RedisTokenHolder(String appid, String appsecret, String host, public RedisTokenHolder(String appid, String appsecret, String host,
int port) { int port) {
this.appid = appid; super(appid, appsecret);
this.appsecret = appsecret;
JedisPoolConfig poolConfig = new JedisPoolConfig(); JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(50); poolConfig.setMaxTotal(50);
poolConfig.setMaxIdle(5); poolConfig.setMaxIdle(5);
@ -50,6 +47,8 @@ public class RedisTokenHolder extends AbstractTokenHolder {
@Override @Override
public Token getToken() throws WeixinException { public Token getToken() throws WeixinException {
String appid = getAppid();
String appsecret = getAppsecret();
if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) { if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"appid or appsecret not be null!"); "appid or appsecret not be null!");
@ -63,7 +62,9 @@ public class RedisTokenHolder extends AbstractTokenHolder {
if (StringUtils.isBlank(accessToken)) { if (StringUtils.isBlank(accessToken)) {
String api_token_uri = String String api_token_uri = String
.format(tokenUrl, appid, appsecret); .format(tokenUrl, appid, appsecret);
token = request.get(api_token_uri).getAsObject(Token.class); token = request.get(api_token_uri).getAsObject(
new TypeReference<Token>() {
});
jedis.setex(key, token.getExpiresIn() - 3, jedis.setex(key, token.getExpiresIn() - 3,
token.getAccessToken()); token.getAccessToken());
} else { } else {

View File

@ -6,6 +6,14 @@ import java.net.URL;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
/**
* 对class的获取
* @className ClassUtil
* @author jy
* @date 2014年10月31日
* @since JDK 1.7
* @see
*/
public class ClassUtil { public class ClassUtil {
public static Set<Class<?>> getClasses(Package _package) { public static Set<Class<?>> getClasses(Package _package) {

View File

@ -1,27 +1,46 @@
package com.foxinmy.weixin4j.util; package com.foxinmy.weixin4j.util;
import java.io.FileNotFoundException; import java.io.File;
import java.io.IOException; import java.util.ResourceBundle;
import java.util.Properties; import java.util.Set;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinConfig;
/**
* 商户配置工具类
*
* @className ConfigUtil
* @author jy
* @date 2014年10月31日
* @since JDK 1.7
* @see
*/
public class ConfigUtil { public class ConfigUtil {
private static Properties props = new Properties(); private static ResourceBundle weixin;
static { static {
try { weixin = ResourceBundle.getBundle("weixin");
props.load(Thread.currentThread().getContextClassLoader() Set<String> keySet = weixin.keySet();
.getResourceAsStream("weixin.properties")); for (String key : keySet) {
} catch (FileNotFoundException e) { if (!key.endsWith("_path")) {
e.printStackTrace(); continue;
} catch (IOException e) { }
e.printStackTrace(); new File(getValue(key)).mkdirs();
} }
} }
public static String getValue(String key) { public static String getValue(String key) {
return props.getProperty(key); return weixin.getString(key);
} }
public static void main(String[] args) { public static WeixinAccount getWeixinAccount() {
System.out.println(getValue("api_token_uri")); String text = getValue("account");
return JSON.parseObject(text, WeixinAccount.class);
}
public static WeixinConfig getWeixinConfig() {
String text = getValue("account");
return JSON.parseObject(text, WeixinConfig.class);
} }
} }

View File

@ -0,0 +1,21 @@
package com.foxinmy.weixin4j.util;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 日期工具类
*
* @className DateUtil
* @author jy
* @date 2014年10月31日
* @since JDK 1.7
* @see
*/
public class DateUtil {
private static final String YYYYMMDD = "yyyyMMdd";
public static String fortmatYYYYMMDD(Date date) {
return new SimpleDateFormat(YYYYMMDD).format(date);
}
}

View File

@ -0,0 +1,79 @@
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 com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
/**
* 签名工具类
* @className MapUtil
* @author jy
* @date 2014年10月31日
* @since JDK 1.7
* @see
*/
public class MapUtil {
private final static Charset charset = StandardCharsets.UTF_8;
public static String toJoinString(Object object, boolean encoder,
boolean lowerCase, JSONObject extra) {
String text = JSON.toJSONString(object);
Map<String, String> map = new TreeMap<String, String>(
new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
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));
}
}
StringBuilder sb = new StringBuilder();
Set<Map.Entry<String, String>> set = map.entrySet();
try {
if (encoder && lowerCase) {
for (Map.Entry<String, String> entry : set) {
sb.append(entry.getKey().toLowerCase())
.append("=")
.append(URLEncoder.encode(entry.getValue(),
charset.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("&");
}
} else if (lowerCase) {
for (Map.Entry<String, String> entry : set) {
sb.append(entry.getKey().toLowerCase()).append("=")
.append(entry.getValue()).append("&");
}
} else {
for (Map.Entry<String, String> entry : set) {
sb.append(entry.getKey()).append("=")
.append(entry.getValue()).append("&");
}
}
} catch (UnsupportedEncodingException e) {
;
}
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
}

View File

@ -17,6 +17,14 @@ import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.xml.XStream; import com.foxinmy.weixin4j.xml.XStream;
/**
* 消息工具类
* @className MessageUtil
* @author jy
* @date 2014年10月31日
* @since JDK 1.7
* @see
*/
public class MessageUtil { public class MessageUtil {
private final static Logger log = LoggerFactory private final static Logger log = LoggerFactory
@ -111,10 +119,7 @@ public class MessageUtil {
messageClass = EventType.valueOf(type.toLowerCase()) messageClass = EventType.valueOf(type.toLowerCase())
.getEventClass(); .getEventClass();
} }
XStream xstream = XStream.get(); return XStream.get(xmlMsg, messageClass);
xstream.processAnnotations(messageClass);
xstream.alias("xml", messageClass);
return xstream.fromXML(xmlMsg, messageClass);
} }
/** /**

View File

@ -0,0 +1,210 @@
package com.foxinmy.weixin4j.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.apache.commons.lang3.StringUtils;
/**
* @title 反射工具类
* @description 提供对类,字段的反射调用
* @author jy.hu , 2012-10-26
*/
public class ReflectionUtil {
// 获取包包名
public static String getPackageName(Object obj) {
return obj.getClass().getPackage().getName();
}
// 获取字段的泛型参数类型
public static Class<?> getFieldGenericType(Object obj, String fieldName) {
Field field = getAccessibleField(obj, fieldName);
Type type = field.getGenericType();
if (type instanceof ParameterizedType) {
return (Class<?>) ((ParameterizedType) type)
.getActualTypeArguments()[0];
}
return null;
}
/**
* 调用方法
*
* @param object
* 对象
*
* @param propertyName
* 属性名称
*/
public static Object invokeMethod(Object object, String propertyName) {
try {
Method getterMethod = object.getClass().getMethod(propertyName);
return getterMethod.invoke(object);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Object invokeMethod(Object object, String propertyName,
Object... args) {
try {
Method getterMethod = object.getClass().getMethod(propertyName);
return getterMethod.invoke(object, args);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 调用Getter方法
*
* @param object
* 对象
*
* @param propertyName
* 属性名称
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public static Object invokeGetterMethod(Object object, String propertyName)
throws Exception {
String getterMethodName = null;
Method getterMethod = null;
String propertyNa = null;
if (propertyName.contains(".")) {
propertyNa = StringUtils.substringBefore(propertyName, ".");
getterMethodName = "get" + StringUtils.capitalize(propertyNa);
getterMethod = object.getClass().getMethod(getterMethodName);
return invokeGetterMethod(getterMethod.invoke(object),
StringUtils.substringAfter(propertyName, "."));
} else {
getterMethodName = "get" + StringUtils.capitalize(propertyName);
getterMethod = object.getClass().getMethod(getterMethodName);
return getterMethod.invoke(object);
}
}
/**
* 调用Setter方法
*
* @param object
* 对象
*
* @param propertyName
* 属性名称
*
* @param propertyValue
* 属性值
*/
public static void invokeSetterMethod(Object object, String propertyName,
Object propertyValue) {
Class<?> setterMethodClass = propertyValue.getClass();
invokeSetterMethod(object, propertyName, propertyValue,
setterMethodClass);
}
/**
* 调用Setter方法
*
* @param object
* 对象
*
* @param propertyName
* 属性名称
*
* @param propertyValue
* 属性值
*
* @param setterMethodClass
* 参数类型
*/
public static void invokeSetterMethod(Object object, String propertyName,
Object propertyValue, Class<?> setterMethodClass) {
String setterMethodName = "set" + StringUtils.capitalize(propertyName);
try {
Method setterMethod = object.getClass().getMethod(setterMethodName,
setterMethodClass);
setterMethod.invoke(object, propertyValue);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取对象属性值,无视private/protected/getter
*
* @param object
* 对象
*
* @param fieldName
* 属性名称
*/
public static Object getFieldValue(Object object, String fieldName) {
Field field = getAccessibleField(object, fieldName);
if (field == null) {
throw new IllegalArgumentException("Could not find field "
+ fieldName);
}
Object result = null;
try {
result = field.get(object);
} catch (IllegalAccessException e) {
}
return result;
}
/**
* 设置对象属性值,无视private/protected/setter
*
* @param object
* 对象
*
* @param fieldName
* 属性名称
*/
public static void setFieldValue(Object object, String fieldName,
Object value) {
Field field = getAccessibleField(object, fieldName);
if (field == null) {
throw new IllegalArgumentException("Could not find field "
+ fieldName);
}
try {
field.set(object, value);
} catch (IllegalAccessException e) {
}
}
// 获取字段的类型
public static String getFieldType(Object object, String fieldName) {
Field field = getAccessibleField(object, fieldName);
return field.getType().getSimpleName();
}
@SuppressWarnings("unused")
private static Field getAccessibleField(final Object object,
final String fieldName) {
for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
.getSuperclass()) {
try {
Field field = superClass.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
return null;
}
}
return null;
}
}

View File

@ -1,11 +1,16 @@
package com.foxinmy.weixin4j.xml; package com.foxinmy.weixin4j.xml;
import java.util.Iterator; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.converters.collections.MapConverter; import com.thoughtworks.xstream.converters.collections.MapConverter;
import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.mapper.Mapper; import com.thoughtworks.xstream.mapper.Mapper;
@ -15,13 +20,26 @@ public class Map2ObjectConverter extends MapConverter {
super(mapper); super(mapper);
} }
@Override
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
Map<String,String> map = new HashMap<String, String>();
while(reader.hasMoreChildren()){
reader.moveDown();
map.put(reader.getNodeName(), reader.getValue());
reader.moveUp();
}
return map;
}
@Override @Override
public void marshal(Object source, HierarchicalStreamWriter writer, public void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) { MarshallingContext context) {
Map<?, ?> map = (Map<?, ?>) source; Map<?, ?> map = (Map<?, ?>) source;
for (Iterator<?> iterator = map.entrySet().iterator(); iterator for (Entry<?, ?> entry : map.entrySet()) {
.hasNext();) { if (StringUtils.isBlank((String) entry.getValue())) {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) iterator.next(); continue;
}
ExtendedHierarchicalStreamWriterHelper.startNode(writer, entry ExtendedHierarchicalStreamWriterHelper.startNode(writer, entry
.getKey().toString(), entry.getClass()); .getKey().toString(), entry.getClass());
writer.setValue(entry.getValue().toString()); writer.setValue(entry.getValue().toString());

View File

@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.xml; package com.foxinmy.weixin4j.xml;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer; import java.io.Writer;
import com.thoughtworks.xstream.core.util.QuickWriter; import com.thoughtworks.xstream.core.util.QuickWriter;
@ -50,4 +51,34 @@ public class XStream extends com.thoughtworks.xstream.XStream {
xstream.autodetectAnnotations(true); xstream.autodetectAnnotations(true);
return xstream; return xstream;
} }
public static <T> T get(InputStream inputStream, Class<T> clazz) {
XStream xStream = get();
xStream.alias("xml", clazz);
xStream.processAnnotations(clazz);
return xStream.fromXML(inputStream, clazz);
}
public static <T> T get(String xml, Class<T> clazz) {
XStream xStream = get();
xStream.alias("xml", clazz);
xStream.processAnnotations(clazz);
return xStream.fromXML(xml, clazz);
}
public static String to(Object obj) {
XStream xStream = get();
Class<?> clazz = obj.getClass();
xStream.alias("xml", clazz);
xStream.processAnnotations(clazz);
return xStream.toXML(obj);
}
public static void to(Object obj, OutputStream out) {
XStream xStream = get();
Class<?> clazz = obj.getClass();
xStream.alias("xml", clazz);
xStream.processAnnotations(clazz);
xStream.toXML(obj, out);
}
} }

View File

@ -1,66 +1,52 @@
weixin4j-mp weixin4j-mp
=========== ===========
tencent weixin platform java sdk 微信公众平台开发工具包 http://mp.weixin.qq.com/wiki @(weixin4j)[公众平台]
微信[公众平台](http://mp.weixin.qq.com/wiki)开发工具包
----------------------------------------------------
功能列表 功能列表
------- -------
* weixin4j-mp-api
* TokenHolder token的实现 + MediaApi `上传/下载媒体文件API`
* MediaApi 上传/下载媒体文件API + NotifyApi `客服消息API`
* NotifyApi 客服消息API + MassApi `群发消息API`
* MassApi 群发消息API + UserApi `用户管理API`
* UserApi 用户管理API + GroupApi `分组管理API`
* GroupApi 分组管理API + MenuApi `底部菜单API`
* MenuApi 底部菜单API + QrApi `二维码API`
* QrApi 二维码API + TmplApi `模板消息API`
* TmplApi 模板消息API + HelperApi `辅助API`
* HelperApi 辅助API * weixin4j-mp-server
`netty服务器 & 消息分发`
* netty服务器 & 消息分发
如何使用
--------
1.编辑classweixin.properties并填入appid/appsecret,当然也可通过构造函数传入.
2.实例化一个WeixinProxy对象,调用API.
WeixinProxy weixinProxy = new WeixinProxy();
// weixinProxy = new WeixinProxy(appid,appsecret);
weixinProxy.getUser(openId);
3.针对token存储有两种方案,File存储/Redis存储,当然也可自己实现TokenHolder(继承AbstractTokenHolder类并重写getToken方法),默认使用文件(xml)的方式保存token,如果环境中支持redis,建议使用RedisTokenHolder.
WeixinProxy weixinProxy = new WeixinProxy(new RedisTokenHolder());
// weixinProxy = new WeixinProxy(new RedisTokenHolder(appid,appsecret));
4.mvn package,得到一个zip的压缩包,解压到启动目录(见src/main/startup.sh/APP_HOME)
5.启动netty服务
com.foxinmy.weixin4j.mp.startup.WeixinServiceBootstrap
sh startup.sh start
更新LOG 更新LOG
------- -------
* 2014-10-27 * 2014-10-27
1).用netty构建http服务器并支持消息分发 + 用netty构建http服务器并支持消息分发
* 2014-10-28 * 2014-10-28
1).调整ActionMapping抽象化 + 调整`ActionMapping`抽象化
* 2014-10-31 * 2014-10-31
1).weixin.properties切分为API调用地址/公众号信息两部分 + `weixin.properties`切分为API调用地址/公众号信息两部分
* 2014-11-03
+ `weixin-mp`分离为`weixin-mp-api``weixin-mp-server`两个工程
+ `weixin-mp`:加入支付模块

View File

@ -8,54 +8,23 @@
<artifactId>weixin4j</artifactId> <artifactId>weixin4j</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
</parent> </parent>
<groupId>com.foxinmy.weixin</groupId>
<artifactId>weixin4j-mp</artifactId> <artifactId>weixin4j-mp</artifactId>
<name>weixin4j-mp</name> <name>weixin4j-mp</name>
<packaging>pom</packaging>
<url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-mp</url>
<description>微信公众号工具包</description>
<modules>
<module>weixin4j-mp-api</module>
<module>weixin4j-mp-server</module>
</modules>
<build> <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<finalName>weixin4j-mp</finalName> <finalName>weixin4j-mp</finalName>
</build> </build>
<dependencies> <dependencies>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>${jaxen.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.foxinmy.weixin4j</groupId> <groupId>com.foxinmy.weixin4j</groupId>
<artifactId>weixin4j-base</artifactId> <artifactId>weixin4j-base</artifactId>
<version>${weixin4j.version}</version> <version>${weixin4j.base.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

28
weixin4j-mp/weixin4j-mp-api/.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
*~
# eclipse ignore
*.settings/*
/.project
/.classpath
/.tomcatplugin
# maven ignore
target/*
# other ignore
*.log
*.tmp
Thumbs.db
/target/
.DS_Store

View File

@ -0,0 +1,87 @@
weixin4j-mp-api
===============
@(weixin4j)[公众平台]
微信[公众平台](http://mp.weixin.qq.com/wiki)开发工具包
功能列表
-------
* MediaApi `上传/下载媒体文件API`
* NotifyApi `客服消息API`
* MassApi `群发消息API`
* UserApi `用户管理API`
* GroupApi `分组管理API`
* MenuApi `底部菜单API`
* QrApi `二维码API`
* TmplApi `模板消息API`
* HelperApi `辅助API`
* PayApi `支付API`
如何使用
--------
1.API工程可以单独使用,需新增或拷贝`weixin.properties`文件到classpath
weixin.properties
| 属性名 | 说明 |
| :---------- | :-------------- |
| account | 微信公众号信息 `json格式` |
| token_path | 使用FileTokenHolder时token保存的物理路径 |
| qr_path | 调用二维码接口时保存的物理路径 |
示例
>**`account={"appId":"appId","appSecret":"appSecret",
"token":"开放者的token 非必须","openId":"公众号的openid 非必须",
"mchId":"V3.x版本下的微信商户号",
"partnerId":"财付通的商户号","partnerKey":"财付通商户权限密钥Key",
"paySignKey":"微信支付中调用API的密钥"}
token_path=/tmp/weixin/token`
`qr_path=/tmp/weixin/qr`
`media_path=/tmp/weixin/media`
`bill_path=/tmp/weixin/bill`**
2.实例化一个`WeixinProxy`对象,调用API.
``` java
WeixinProxy weixinProxy = new WeixinProxy();
// weixinProxy = new WeixinProxy(appid,appsecret);
weixinProxy.getUser(openId);
```
3.针对`token`存储有两种方案,`File存储`/`Redis存储`,当然也可自己实现`TokenHolder`(继承`AbstractTokenHolder`类并重写`getToken`方法),默认使用文件(xml)的方式保存token,如果环境中支持`redis`,建议使用`RedisTokenHolder`.
``` java
WeixinProxy weixinProxy = new WeixinProxy(new RedisTokenHolder());
// weixinProxy = new WeixinProxy(new RedisTokenHolder(appid,appsecret));
```
4.mvn package.
更新LOG
-------
* 2014-10-27
+ 用netty构建http服务器并支持消息分发
* 2014-10-28
+ 调整`ActionMapping`抽象化
* 2014-10-31
+ `weixin.properties`切分为API调用地址/公众号信息两部分
* 2014-11-03
+ 分离为`weixin-mp-api``weixin-mp-server`两个工程
+ 加入支付模块

View File

@ -0,0 +1,59 @@
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.foxinmy.weixin4j</groupId>
<artifactId>weixin4j-mp</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>weixin4j-mp-api</artifactId>
<name>weixin4j-mp-api</name>
<url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-mp</url>
<description>微信公众号API</description>
<build>
<finalName>weixin4j-mp-api</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>*.*</exclude>
</excludes>
</resource>
</resources>
</build>
<dependencies>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>${jaxen.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
<exclusions>
<exclusion>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>${poi.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -2,13 +2,14 @@ package com.foxinmy.weixin4j.mp;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Date;
import java.util.List; import java.util.List;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.model.WeixinAccountV2; import com.foxinmy.weixin4j.http.XmlResult;
import com.foxinmy.weixin4j.model.WeixinAccountV3; import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.mp.api.GroupApi; import com.foxinmy.weixin4j.mp.api.GroupApi;
import com.foxinmy.weixin4j.mp.api.HelperApi; import com.foxinmy.weixin4j.mp.api.HelperApi;
import com.foxinmy.weixin4j.mp.api.MassApi; import com.foxinmy.weixin4j.mp.api.MassApi;
@ -30,7 +31,11 @@ import com.foxinmy.weixin4j.mp.model.UserToken;
import com.foxinmy.weixin4j.mp.msg.model.Article; import com.foxinmy.weixin4j.mp.msg.model.Article;
import com.foxinmy.weixin4j.mp.msg.model.BaseMsg; import com.foxinmy.weixin4j.mp.msg.model.BaseMsg;
import com.foxinmy.weixin4j.mp.msg.notify.BaseNotify; import com.foxinmy.weixin4j.mp.msg.notify.BaseNotify;
import com.foxinmy.weixin4j.mp.payment.BillType;
import com.foxinmy.weixin4j.mp.payment.IdQuery;
import com.foxinmy.weixin4j.mp.payment.IdType;
import com.foxinmy.weixin4j.mp.payment.v2.Order; import com.foxinmy.weixin4j.mp.payment.v2.Order;
import com.foxinmy.weixin4j.mp.payment.v3.Refund;
import com.foxinmy.weixin4j.mp.response.TemplateMessage; import com.foxinmy.weixin4j.mp.response.TemplateMessage;
import com.foxinmy.weixin4j.token.FileTokenHolder; import com.foxinmy.weixin4j.token.FileTokenHolder;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
@ -74,17 +79,17 @@ public class WeixinProxy {
this(new FileTokenHolder(appid, appsecret)); this(new FileTokenHolder(appid, appsecret));
} }
public WeixinProxy(TokenHolder tokenApi) { public WeixinProxy(TokenHolder tokenHolder) {
this.mediaApi = new MediaApi(tokenApi); this.mediaApi = new MediaApi(tokenHolder);
this.notifyApi = new NotifyApi(tokenApi); this.notifyApi = new NotifyApi(tokenHolder);
this.massApi = new MassApi(tokenApi); this.massApi = new MassApi(tokenHolder);
this.userApi = new UserApi(tokenApi); this.userApi = new UserApi(tokenHolder);
this.groupApi = new GroupApi(tokenApi); this.groupApi = new GroupApi(tokenHolder);
this.menuApi = new MenuApi(tokenApi); this.menuApi = new MenuApi(tokenHolder);
this.qrApi = new QrApi(tokenApi); this.qrApi = new QrApi(tokenHolder);
this.tmplApi = new TmplApi(tokenApi); this.tmplApi = new TmplApi(tokenHolder);
this.helperApi = new HelperApi(tokenApi); this.helperApi = new HelperApi(tokenHolder);
this.payApi = new PayApi(tokenApi); this.payApi = new PayApi(tokenHolder);
} }
/** /**
@ -182,7 +187,7 @@ public class WeixinProxy {
* @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify * @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify
* @see com.foxinmy.weixin4j.mp.api.NotifyApi * @see com.foxinmy.weixin4j.mp.api.NotifyApi
*/ */
public BaseResult sendNotify(BaseNotify notify) throws WeixinException { public JsonResult sendNotify(BaseNotify notify) throws WeixinException {
return notifyApi.sendNotify(notify); return notifyApi.sendNotify(notify);
} }
@ -199,7 +204,7 @@ public class WeixinProxy {
* @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify * @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify
* @see com.foxinmy.weixin4j.mp.api.NotifyApi * @see com.foxinmy.weixin4j.mp.api.NotifyApi
*/ */
public BaseResult sendNotify(String touser, List<Article> articles) public JsonResult sendNotify(String touser, List<Article> articles)
throws WeixinException { throws WeixinException {
return notifyApi.sendNotify(touser, articles); return notifyApi.sendNotify(touser, articles);
} }
@ -220,7 +225,7 @@ public class WeixinProxy {
* @see com.foxinmy.weixin4j.mp.msg.model.Voice * @see com.foxinmy.weixin4j.mp.msg.model.Voice
* @see com.foxinmy.weixin4j.mp.api.NotifyApi * @see com.foxinmy.weixin4j.mp.api.NotifyApi
*/ */
public BaseResult sendNotify(String touser, BaseMsg baseMsg) public JsonResult sendNotify(String touser, BaseMsg baseMsg)
throws WeixinException { throws WeixinException {
return notifyApi.sendNotify(touser, baseMsg); return notifyApi.sendNotify(touser, baseMsg);
} }
@ -393,7 +398,7 @@ public class WeixinProxy {
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByGroup(JSONObject, String)} * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByGroup(JSONObject, String)}
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByOpenIds(JSONObject, String...) * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByOpenIds(JSONObject, String...)
*/ */
public BaseResult deleteMassNews(String msgid) throws WeixinException { public JsonResult deleteMassNews(String msgid) throws WeixinException {
return massApi.deleteMassNews(msgid); return massApi.deleteMassNews(msgid);
} }
@ -498,7 +503,7 @@ public class WeixinProxy {
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%AE%BE%E7%BD%AE%E7%94%A8%E6%88%B7%E5%A4%87%E6%B3%A8%E5%90%8D%E6%8E%A5%E5%8F%A3">设置用户备注名</a> * href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%AE%BE%E7%BD%AE%E7%94%A8%E6%88%B7%E5%A4%87%E6%B3%A8%E5%90%8D%E6%8E%A5%E5%8F%A3">设置用户备注名</a>
* @see com.foxinmy.weixin4j.mp.api.UserApi * @see com.foxinmy.weixin4j.mp.api.UserApi
*/ */
public BaseResult remarkUserName(String openId, String remark) public JsonResult remarkUserName(String openId, String remark)
throws WeixinException { throws WeixinException {
return userApi.remarkUserName(openId, remark); return userApi.remarkUserName(openId, remark);
} }
@ -564,7 +569,7 @@ public class WeixinProxy {
* @see com.foxinmy.weixin4j.mp.model.Group#toModifyJson() * @see com.foxinmy.weixin4j.mp.model.Group#toModifyJson()
* @see com.foxinmy.weixin4j.mp.api.GroupApi * @see com.foxinmy.weixin4j.mp.api.GroupApi
*/ */
public BaseResult modifyGroup(int groupId, String name) public JsonResult modifyGroup(int groupId, String name)
throws WeixinException { throws WeixinException {
return groupApi.modifyGroup(groupId, name); return groupApi.modifyGroup(groupId, name);
} }
@ -582,7 +587,7 @@ public class WeixinProxy {
* @see com.foxinmy.weixin4j.mp.model.Group * @see com.foxinmy.weixin4j.mp.model.Group
* @see com.foxinmy.weixin4j.mp.api.GroupApi * @see com.foxinmy.weixin4j.mp.api.GroupApi
*/ */
public BaseResult moveGroup(String openId, int groupId) public JsonResult moveGroup(String openId, int groupId)
throws WeixinException { throws WeixinException {
return groupApi.moveGroup(openId, groupId); return groupApi.moveGroup(openId, groupId);
} }
@ -598,7 +603,7 @@ public class WeixinProxy {
* @see com.foxinmy.weixin4j.type.ButtonType * @see com.foxinmy.weixin4j.type.ButtonType
* @see com.foxinmy.weixin4j.mp.api.MenuApi * @see com.foxinmy.weixin4j.mp.api.MenuApi
*/ */
public BaseResult createMenu(List<Button> btnList) throws WeixinException { public JsonResult createMenu(List<Button> btnList) throws WeixinException {
return menuApi.createMenu(btnList); return menuApi.createMenu(btnList);
} }
@ -625,7 +630,7 @@ public class WeixinProxy {
* @see com.foxinmy.weixin4j.mp.model.Button * @see com.foxinmy.weixin4j.mp.model.Button
* @see com.foxinmy.weixin4j.mp.api.MenuApi * @see com.foxinmy.weixin4j.mp.api.MenuApi
*/ */
public BaseResult deleteMenu() throws WeixinException { public JsonResult deleteMenu() throws WeixinException {
return menuApi.deleteMenu(); return menuApi.deleteMenu();
} }
@ -692,7 +697,7 @@ public class WeixinProxy {
* @seee com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage * @seee com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage
* @see com.foxinmy.weixin4j.mp.api.TmplApi * @see com.foxinmy.weixin4j.mp.api.TmplApi
*/ */
public BaseResult sendTmplMessage(TemplateMessage tplMessage) public JsonResult sendTmplMessage(TemplateMessage tplMessage)
throws WeixinException { throws WeixinException {
return tmplApi.sendTmplMessage(tplMessage); return tmplApi.sendTmplMessage(tplMessage);
} }
@ -714,8 +719,8 @@ public class WeixinProxy {
/** /**
* 发货通知 * 发货通知
* *
* @param weixinConfig * @param weixinAccount
* V2版本 * 商户信息
* @param transid * @param transid
* 交易单号 * 交易单号
* @param orderNo * @param orderNo
@ -724,31 +729,32 @@ public class WeixinProxy {
* 成功|失败 * 成功|失败
* @param statusMsg * @param statusMsg
* status为失败时携带的信息 * status为失败时携带的信息
* @return * @return 调用结果
* @throws WeixinException * @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.PayApi * @see com.foxinmy.weixin4j.mp.api.PayApi
*/ */
public BaseResult deliverNotify(WeixinAccountV2 weixinConfig, public JsonResult deliverNotify(WeixinAccount weixinAccount,
String transid, String orderNo, boolean status, String statusMsg) String transid, String orderNo, boolean status, String statusMsg)
throws WeixinException { throws WeixinException {
return payApi.deliverNotify(weixinConfig, transid, orderNo, status, return payApi.deliverNotify(weixinAccount, transid, orderNo, status,
statusMsg); statusMsg);
} }
/** /**
* 订单查询 * 订单查询
* *
* @param weixinConfig * @param weixinAccount
* V2版本 * 商户信息
* @param orderNo * @param orderNo
* 订单号 * 订单号
* @return * @return 订单信息
* @throws WeixinException * @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.PayApi * @see com.foxinmy.weixin4j.mp.api.PayApi
*/ */
public Order orderQuery(WeixinAccountV2 weixinConfig, String orderNo) public Order orderQueryV2(WeixinAccount weixinAccount, String orderNo)
throws WeixinException { throws WeixinException {
return payApi.orderQuery(weixinConfig, orderNo); return payApi.orderQueryV2(weixinAccount, new IdQuery(orderNo,
IdType.ORDERNO));
} }
/** /**
@ -758,28 +764,106 @@ public class WeixinProxy {
* 用户ID * 用户ID
* @param feedbackId * @param feedbackId
* 维权单号 * 维权单号
* @return * @return 调用结果
* @see com.foxinmy.weixin4j.mp.api.PayApi * @see com.foxinmy.weixin4j.mp.api.PayApi
* @throws WeixinException * @throws WeixinException
*/ */
public BaseResult updateFeedback(String openId, String feedbackId) public JsonResult updateFeedback(String openId, String feedbackId)
throws WeixinException { throws WeixinException {
return payApi.updateFeedback(openId, feedbackId); return payApi.updateFeedback(openId, feedbackId);
} }
/**
* V3订单查询
*
* @param weixinAccount
* 商户信息
* @param idQuery
* 商户系统内部的订单号, transaction_idout_trade_no 选一,如果同时存在优先级:
* transaction_id> out_trade_no
* @see com.foxinmy.weixin4j.mp.api.PayApi
* @throws WeixinException
*/
public com.foxinmy.weixin4j.mp.payment.v3.Order orderQueryV3(
WeixinAccount weixinAccount, IdQuery idQuery)
throws WeixinException {
return payApi.orderQueryV3(weixinAccount, idQuery);
}
/**
* 下载对账单<br>
* 1.微信侧未成功下单的交易不会出现在对账单中支付成功后撤销的交易会出现在对账 单中,跟原支付单订单号一致,bill_type
* REVOKED;<br>
* 2.微信在次日 9 点启动生成前一天的对账单,建议商户 9 点半后再获取;<br>
* 3.对账单中涉及金额的字段单位为<br>
*
* @param weixinAccount
* 商户配置
* @param billDate
* 下载对账单的日期
* @param billType
* 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单
* REFUND,返回当日退款订单
* @return excel表格
* @see com.foxinmy.weixin4j.mp.api.PayApi
* @throws WeixinException
* @throws IOException
*/
public File downloadbill(WeixinAccount weixinAccount, Date billDate,
BillType billType) throws WeixinException, IOException {
return payApi.downloadbill(weixinAccount, billDate, billType);
}
/**
* 退款查询<br/>
* 退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款 3 个工作日后重新查询退款状态
*
* @param weixinAccount
* @param idQuery
* 单号 refund_idout_refund_no out_trade_no transaction_id
* 四个参数必填一个,优先级为:
* refund_id>out_refund_no>transaction_id>out_trade_no
* @see com.foxinmy.weixin4j.mp.api.PayApi
* @return 退款记录
* @throws WeixinException
*/
public Refund refundQuery(WeixinAccount weixinAccount, IdQuery idQuery)
throws WeixinException {
return payApi.refundQuery(weixinAccount, idQuery);
}
/**
* 关闭订单<br/>
* 当订单支付失败,调用关单接口后用新订单号重新发起支付,如果关单失败,返回已完
* 成支付请按正常支付处理如果出现银行掉单,调用关单成功后,微信后台会主动发起退款
*
* @param weixinAccount
* 商户信息
* @param order
* 商户系统内部的订单号
* @return 执行结果
* @see com.foxinmy.weixin4j.mp.api.PayApi
* @throws WeixinException
*/
public XmlResult closeOrder(WeixinAccount weixinAccount, String orderNo)
throws WeixinException {
return payApi.orderQueryV3(weixinAccount, new IdQuery(orderNo,
IdType.ORDERNO));
}
/** /**
* native支付URL转短链接 * native支付URL转短链接
* *
* @param weixinConfig * @param weixinAccount
* 商户配置 * 商户信息
* @param url * @param url
* native支付URL * 具有native标识的支付URL
* @return 转换后的短链接 * @return 转换后的短链接
* @see com.foxinmy.weixin4j.mp.api.PayApi * @see com.foxinmy.weixin4j.mp.api.PayApi
* @throws WeixinException * @throws WeixinException
*/ */
public String getShorturl(WeixinAccountV3 weixinConfig, String url) public String getShorturl(WeixinAccount weixinAccount, String url)
throws WeixinException { throws WeixinException {
return payApi.getShorturl(weixinConfig, url); return payApi.getShorturl(weixinAccount, url);
} }
} }

View File

@ -2,12 +2,16 @@ package com.foxinmy.weixin4j.mp.api;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.foxinmy.weixin4j.http.HttpRequest; import com.foxinmy.weixin4j.http.HttpRequest;
import com.foxinmy.weixin4j.xml.Map2ObjectConverter;
import com.foxinmy.weixin4j.xml.XStream; import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.core.ClassLoaderReference;
import com.thoughtworks.xstream.mapper.DefaultMapper;
/** /**
* *
@ -19,12 +23,24 @@ import com.foxinmy.weixin4j.xml.XStream;
*/ */
public class BaseApi { public class BaseApi {
protected final HttpRequest request = new HttpRequest(); protected final HttpRequest request = new HttpRequest();
protected final XStream xStream = XStream.get(); protected final static XStream mapXstream = XStream.get();
protected final Charset utf8 = StandardCharsets.UTF_8; protected final Charset utf8 = StandardCharsets.UTF_8;
private final static ResourceBundle weixinBundle; private final static ResourceBundle weixinBundle;
static { static {
weixinBundle = ResourceBundle weixinBundle = ResourceBundle
.getBundle("com/foxinmy/weixin4j/mp/api/weixin"); .getBundle("com/foxinmy/weixin4j/mp/api/weixin");
mapXstream.alias("xml", Map.class);
mapXstream.registerConverter(new Map2ObjectConverter(new DefaultMapper(
new ClassLoaderReference(XStream.class.getClassLoader()))));
}
protected String map2xml(Map<?, ?> map) {
return mapXstream.toXML(map).replaceAll("__", "_");
}
@SuppressWarnings("unchecked")
protected Map<String, String> xml2map(String xml) {
return mapXstream.fromXML(xml,Map.class);
} }
protected String getRequestUri(String key) { protected String getRequestUri(String key) {

View File

@ -4,7 +4,7 @@ import java.util.List;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.model.Group; import com.foxinmy.weixin4j.mp.model.Group;
@ -23,9 +23,9 @@ import com.foxinmy.weixin4j.token.TokenHolder;
*/ */
public class GroupApi extends BaseApi { public class GroupApi extends BaseApi {
private final TokenHolder tokenApi; private final TokenHolder tokenHolder;
public GroupApi(TokenHolder tokenApi) { public GroupApi(TokenHolder tokenHolder) {
this.tokenApi = tokenApi; this.tokenHolder = tokenHolder;
} }
/** /**
@ -42,7 +42,7 @@ public class GroupApi extends BaseApi {
*/ */
public Group createGroup(String name) throws WeixinException { public Group createGroup(String name) throws WeixinException {
String group_create_uri = getRequestUri("group_create_uri"); String group_create_uri = getRequestUri("group_create_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Group group = new Group(name); Group group = new Group(name);
Response response = request.post( Response response = request.post(
String.format(group_create_uri, token.getAccessToken()), String.format(group_create_uri, token.getAccessToken()),
@ -62,7 +62,7 @@ public class GroupApi extends BaseApi {
*/ */
public List<Group> getGroups() throws WeixinException { public List<Group> getGroups() throws WeixinException {
String group_get_uri = getRequestUri("group_get_uri"); String group_get_uri = getRequestUri("group_get_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Response response = request.get(String.format(group_get_uri, Response response = request.get(String.format(group_get_uri,
token.getAccessToken())); token.getAccessToken()));
@ -83,7 +83,7 @@ public class GroupApi extends BaseApi {
*/ */
public int getGroupByOpenId(String openId) throws WeixinException { public int getGroupByOpenId(String openId) throws WeixinException {
String group_getid_uri = getRequestUri("group_getid_uri"); String group_getid_uri = getRequestUri("group_getid_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Response response = request.post( Response response = request.post(
String.format(group_getid_uri, token.getAccessToken()), String.format(group_getid_uri, token.getAccessToken()),
String.format("{\"openid\":\"%s\"}", openId)); String.format("{\"openid\":\"%s\"}", openId));
@ -104,16 +104,16 @@ public class GroupApi extends BaseApi {
* @see com.foxinmy.weixin4j.mp.model.Group * @see com.foxinmy.weixin4j.mp.model.Group
* @see com.foxinmy.weixin4j.mp.model.Group#toModifyJson() * @see com.foxinmy.weixin4j.mp.model.Group#toModifyJson()
*/ */
public BaseResult modifyGroup(int groupId, String name) public JsonResult modifyGroup(int groupId, String name)
throws WeixinException { throws WeixinException {
String group_modify_uri = getRequestUri("group_modify_uri"); String group_modify_uri = getRequestUri("group_modify_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Group group = new Group(groupId, name); Group group = new Group(groupId, name);
Response response = request.post( Response response = request.post(
String.format(group_modify_uri, token.getAccessToken()), String.format(group_modify_uri, token.getAccessToken()),
group.toModifyJson()); group.toModifyJson());
return response.getAsResult(); return response.getAsJsonResult();
} }
/** /**
@ -128,14 +128,14 @@ public class GroupApi extends BaseApi {
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E7.A7.BB.E5.8A.A8.E7.94.A8.E6.88.B7.E5.88.86.E7.BB.84">移动分组</a> * href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E7.A7.BB.E5.8A.A8.E7.94.A8.E6.88.B7.E5.88.86.E7.BB.84">移动分组</a>
* @see com.foxinmy.weixin4j.mp.model.Group * @see com.foxinmy.weixin4j.mp.model.Group
*/ */
public BaseResult moveGroup(String openId, int groupId) public JsonResult moveGroup(String openId, int groupId)
throws WeixinException { throws WeixinException {
String group_move_uri = getRequestUri("group_move_uri"); String group_move_uri = getRequestUri("group_move_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Response response = request.post(String.format(group_move_uri, Response response = request.post(String.format(group_move_uri,
token.getAccessToken()), String.format( token.getAccessToken()), String.format(
"{\"openid\":\"%s\",\"to_groupid\":%d}", openId, groupId)); "{\"openid\":\"%s\",\"to_groupid\":%d}", openId, groupId));
return response.getAsResult(); return response.getAsJsonResult();
} }
} }

View File

@ -17,10 +17,10 @@ import com.foxinmy.weixin4j.token.TokenHolder;
*/ */
public class HelperApi extends BaseApi { public class HelperApi extends BaseApi {
private final TokenHolder tokenApi; private final TokenHolder tokenHolder;
public HelperApi(TokenHolder tokenApi) { public HelperApi(TokenHolder tokenHolder) {
this.tokenApi = tokenApi; this.tokenHolder = tokenHolder;
} }
/** /**
@ -34,7 +34,7 @@ public class HelperApi extends BaseApi {
*/ */
public String getShorturl(String url) throws WeixinException { public String getShorturl(String url) throws WeixinException {
String shorturl_uri = getRequestUri("shorturl_uri"); String shorturl_uri = getRequestUri("shorturl_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("action", "long2short"); obj.put("action", "long2short");
obj.put("long_url", url); obj.put("long_url", url);

View File

@ -5,7 +5,7 @@ import java.util.List;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.model.MpArticle; import com.foxinmy.weixin4j.mp.model.MpArticle;
@ -25,10 +25,10 @@ import com.foxinmy.weixin4j.type.MediaType;
*/ */
public class MassApi extends BaseApi { public class MassApi extends BaseApi {
private final TokenHolder tokenApi; private final TokenHolder tokenHolder;
public MassApi(TokenHolder tokenApi) { public MassApi(TokenHolder tokenHolder) {
this.tokenApi = tokenApi; this.tokenHolder = tokenHolder;
} }
/** /**
@ -47,7 +47,7 @@ public class MassApi extends BaseApi {
public String uploadArticle(List<MpArticle> articles) public String uploadArticle(List<MpArticle> articles)
throws WeixinException { throws WeixinException {
String article_upload_uri = getRequestUri("article_upload_uri"); String article_upload_uri = getRequestUri("article_upload_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("articles", articles); obj.put("articles", articles);
Response response = request.post( Response response = request.post(
@ -75,7 +75,7 @@ public class MassApi extends BaseApi {
public String uploadVideo(String mediaId, String title, String desc) public String uploadVideo(String mediaId, String title, String desc)
throws WeixinException { throws WeixinException {
String video_upload_uri = getRequestUri("video_upload_uri"); String video_upload_uri = getRequestUri("video_upload_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("media_id", mediaId); obj.put("media_id", mediaId);
obj.put("title", title); obj.put("title", title);
@ -109,7 +109,7 @@ public class MassApi extends BaseApi {
private String massByGroup(JSONObject jsonPara, String groupId) private String massByGroup(JSONObject jsonPara, String groupId)
throws WeixinException { throws WeixinException {
String mass_group_uri = getRequestUri("mass_group_uri"); String mass_group_uri = getRequestUri("mass_group_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Response response = request.post( Response response = request.post(
String.format(mass_group_uri, token.getAccessToken()), String.format(mass_group_uri, token.getAccessToken()),
jsonPara.toJSONString()); jsonPara.toJSONString());
@ -133,7 +133,7 @@ public class MassApi extends BaseApi {
private String massByOpenIds(JSONObject jsonPara, String... openIds) private String massByOpenIds(JSONObject jsonPara, String... openIds)
throws WeixinException { throws WeixinException {
String mass_openid_uri = getRequestUri("mass_openid_uri"); String mass_openid_uri = getRequestUri("mass_openid_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Response response = request.post( Response response = request.post(
String.format(mass_openid_uri, token.getAccessToken()), String.format(mass_openid_uri, token.getAccessToken()),
jsonPara.toJSONString()); jsonPara.toJSONString());
@ -255,15 +255,15 @@ public class MassApi extends BaseApi {
* @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massByGroup(JSONObject, String)} * @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massByGroup(JSONObject, String)}
* @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massByOpenIds(JSONObject, String...) * @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massByOpenIds(JSONObject, String...)
*/ */
public BaseResult deleteMassNews(String msgid) throws WeixinException { public JsonResult deleteMassNews(String msgid) throws WeixinException {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("msgid", msgid); obj.put("msgid", msgid);
String mass_delete_uri = getRequestUri("mass_delete_uri"); String mass_delete_uri = getRequestUri("mass_delete_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Response response = request.post( Response response = request.post(
String.format(mass_delete_uri, token.getAccessToken()), String.format(mass_delete_uri, token.getAccessToken()),
obj.toJSONString()); obj.toJSONString());
return response.getAsResult(); return response.getAsJsonResult();
} }
} }

View File

@ -28,10 +28,10 @@ import com.foxinmy.weixin4j.util.IOUtil;
*/ */
public class MediaApi extends BaseApi { public class MediaApi extends BaseApi {
private final TokenHolder tokenApi; private final TokenHolder tokenHolder;
public MediaApi(TokenHolder tokenApi) { public MediaApi(TokenHolder tokenHolder) {
this.tokenApi = tokenApi; this.tokenHolder = tokenHolder;
} }
/** /**
@ -72,7 +72,7 @@ public class MediaApi extends BaseApi {
*/ */
public String uploadMedia(String fileName, byte[] bytes, MediaType mediaType) public String uploadMedia(String fileName, byte[] bytes, MediaType mediaType)
throws WeixinException { throws WeixinException {
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
String file_upload_uri = getRequestUri("file_upload_uri"); String file_upload_uri = getRequestUri("file_upload_uri");
Response response = request.post(String.format(file_upload_uri, Response response = request.post(String.format(file_upload_uri,
token.getAccessToken(), mediaType.name()), new PartParameter( token.getAccessToken(), mediaType.name()), new PartParameter(
@ -107,14 +107,8 @@ public class MediaApi extends BaseApi {
if (file.exists()) { if (file.exists()) {
return file; return file;
} }
FileOutputStream out = null; file.createNewFile();
try { FileOutputStream out = new FileOutputStream(file);
file.createNewFile();
} catch (IOException e) {
file.getParentFile().mkdirs();
file.createNewFile();
}
out = new FileOutputStream(file);
out.write(datas); out.write(datas);
out.close(); out.close();
return file; return file;
@ -131,7 +125,7 @@ public class MediaApi extends BaseApi {
*/ */
public byte[] downloadMediaData(String mediaId, MediaType mediaType) public byte[] downloadMediaData(String mediaId, MediaType mediaType)
throws WeixinException { throws WeixinException {
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
String file_download_uri = getRequestUri("file_download_uri"); String file_download_uri = getRequestUri("file_download_uri");
Response response = request.get(String.format(file_download_uri, Response response = request.get(String.format(file_download_uri,
token.getAccessToken(), mediaId)); token.getAccessToken(), mediaId));

View File

@ -5,7 +5,7 @@ import java.util.List;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.model.Button; import com.foxinmy.weixin4j.mp.model.Button;
@ -22,10 +22,10 @@ import com.foxinmy.weixin4j.token.TokenHolder;
*/ */
public class MenuApi extends BaseApi { public class MenuApi extends BaseApi {
private final TokenHolder tokenApi; private final TokenHolder tokenHolder;
public MenuApi(TokenHolder tokenApi) { public MenuApi(TokenHolder tokenHolder) {
this.tokenApi = tokenApi; this.tokenHolder = tokenHolder;
} }
/** /**
@ -37,16 +37,16 @@ public class MenuApi extends BaseApi {
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3">创建自定义菜单</a> * href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3">创建自定义菜单</a>
* @see com.foxinmy.weixin4j.mp.model.Button * @see com.foxinmy.weixin4j.mp.model.Button
*/ */
public BaseResult createMenu(List<Button> btnList) throws WeixinException { public JsonResult createMenu(List<Button> btnList) throws WeixinException {
String menu_create_uri = getRequestUri("menu_create_uri"); String menu_create_uri = getRequestUri("menu_create_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("button", btnList); obj.put("button", btnList);
Response response = request.post( Response response = request.post(
String.format(menu_create_uri, token.getAccessToken()), String.format(menu_create_uri, token.getAccessToken()),
obj.toJSONString()); obj.toJSONString());
return response.getAsResult(); return response.getAsJsonResult();
} }
/** /**
@ -60,7 +60,7 @@ public class MenuApi extends BaseApi {
*/ */
public List<Button> getMenu() throws WeixinException { public List<Button> getMenu() throws WeixinException {
String menu_get_uri = getRequestUri("menu_get_uri"); String menu_get_uri = getRequestUri("menu_get_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Response response = request.get(String.format(menu_get_uri, Response response = request.get(String.format(menu_get_uri,
token.getAccessToken())); token.getAccessToken()));
@ -77,12 +77,12 @@ public class MenuApi extends BaseApi {
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%A0%E9%99%A4%E6%8E%A5%E5%8F%A3">删除菜单</a> * href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%A0%E9%99%A4%E6%8E%A5%E5%8F%A3">删除菜单</a>
* @see com.foxinmy.weixin4j.mp.model.Button * @see com.foxinmy.weixin4j.mp.model.Button
*/ */
public BaseResult deleteMenu() throws WeixinException { public JsonResult deleteMenu() throws WeixinException {
String menu_delete_uri = getRequestUri("menu_delete_uri"); String menu_delete_uri = getRequestUri("menu_delete_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Response response = request.get(String.format(menu_delete_uri, Response response = request.get(String.format(menu_delete_uri,
token.getAccessToken())); token.getAccessToken()));
return response.getAsResult(); return response.getAsJsonResult();
} }
} }

View File

@ -5,7 +5,7 @@ import java.util.List;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.model.CustomRecord; import com.foxinmy.weixin4j.mp.model.CustomRecord;
@ -33,10 +33,10 @@ import com.foxinmy.weixin4j.token.TokenHolder;
*/ */
public class NotifyApi extends BaseApi { public class NotifyApi extends BaseApi {
private final TokenHolder tokenApi; private final TokenHolder tokenHolder;
public NotifyApi(TokenHolder tokenApi) { public NotifyApi(TokenHolder tokenHolder) {
this.tokenApi = tokenApi; this.tokenHolder = tokenHolder;
} }
/** /**
@ -48,14 +48,14 @@ public class NotifyApi extends BaseApi {
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E9.9F.B3.E4.B9.90.E6.B6.88.E6.81.AF">发送客服消息</a> * href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E9.9F.B3.E4.B9.90.E6.B6.88.E6.81.AF">发送客服消息</a>
*/ */
private BaseResult sendNotify(String jsonPara) throws WeixinException { private JsonResult sendNotify(String jsonPara) throws WeixinException {
String custom_notify_uri = getRequestUri("custom_notify_uri"); String custom_notify_uri = getRequestUri("custom_notify_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Response response = request.post( Response response = request.post(
String.format(custom_notify_uri, token.getAccessToken()), String.format(custom_notify_uri, token.getAccessToken()),
jsonPara); jsonPara);
return response.getAsResult(); return response.getAsJsonResult();
} }
/** /**
@ -74,7 +74,7 @@ public class NotifyApi extends BaseApi {
* @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify * @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify
* @see {@link com.foxinmy.weixin4j.mp.api.NotifyApi#sendNotify(String)} * @see {@link com.foxinmy.weixin4j.mp.api.NotifyApi#sendNotify(String)}
*/ */
public BaseResult sendNotify(BaseNotify notify) throws WeixinException { public JsonResult sendNotify(BaseNotify notify) throws WeixinException {
return sendNotify(notify.toJson()); return sendNotify(notify.toJson());
} }
@ -90,7 +90,7 @@ public class NotifyApi extends BaseApi {
* @see com.foxinmy.weixin4j.mp.msg.model.Article * @see com.foxinmy.weixin4j.mp.msg.model.Article
* @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify * @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify
*/ */
public BaseResult sendNotify(String touser, List<Article> articles) public JsonResult sendNotify(String touser, List<Article> articles)
throws WeixinException { throws WeixinException {
ArticleNotify notify = new ArticleNotify(touser); ArticleNotify notify = new ArticleNotify(touser);
notify.pushAll(articles); notify.pushAll(articles);
@ -114,7 +114,7 @@ public class NotifyApi extends BaseApi {
* @see {@link com.foxinmy.weixin4j.mp.msg.model.BaseMsg#toNotifyJson()} * @see {@link com.foxinmy.weixin4j.mp.msg.model.BaseMsg#toNotifyJson()}
* @see {@link com.foxinmy.weixin4j.mp.api.NotifyApi#sendNotify(String)} * @see {@link com.foxinmy.weixin4j.mp.api.NotifyApi#sendNotify(String)}
*/ */
public BaseResult sendNotify(String touser, BaseMsg baseMsg) public JsonResult sendNotify(String touser, BaseMsg baseMsg)
throws WeixinException { throws WeixinException {
StringBuilder jsonPara = new StringBuilder(); StringBuilder jsonPara = new StringBuilder();
String mediaType = baseMsg.getMediaType().name(); String mediaType = baseMsg.getMediaType().name();
@ -154,7 +154,7 @@ public class NotifyApi extends BaseApi {
obj.put("pagesize", pagesize > 1000 ? 1000 : pagesize); obj.put("pagesize", pagesize > 1000 ? 1000 : pagesize);
obj.put("pageindex", pageindex); obj.put("pageindex", pageindex);
String custom_record_uri = getRequestUri("custom_record_uri"); String custom_record_uri = getRequestUri("custom_record_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Response response = request.post( Response response = request.post(
String.format(custom_record_uri, token.getAccessToken()), String.format(custom_record_uri, token.getAccessToken()),
obj.toJSONString()); obj.toJSONString());

View File

@ -0,0 +1,368 @@
package com.foxinmy.weixin4j.mp.api;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.http.XmlResult;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.mp.payment.BillType;
import com.foxinmy.weixin4j.mp.payment.IdQuery;
import com.foxinmy.weixin4j.mp.payment.IdType;
import com.foxinmy.weixin4j.mp.payment.PayUtil;
import com.foxinmy.weixin4j.mp.payment.RefundConverter;
import com.foxinmy.weixin4j.mp.payment.v2.Order;
import com.foxinmy.weixin4j.mp.payment.v3.Refund;
import com.foxinmy.weixin4j.mp.util.ExcelUtil;
import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.DateUtil;
import com.foxinmy.weixin4j.util.MapUtil;
import com.foxinmy.weixin4j.util.RandomUtil;
/**
* 支付API
*
* @className PayApi
* @author jy
* @date 2014年10月28日
* @since JDK 1.7
* @see
*/
public class PayApi extends BaseApi {
private final TokenHolder tokenHolder;
public PayApi(TokenHolder tokenHolder) {
this.tokenHolder = tokenHolder;
}
/**
* 发货通知
*
* @param weixinAccount
* @param transid
* 交易单号
* @param orderNo
* 订单号
* @param status
* 成功|失败
* @param statusMsg
* status为失败时携带的信息
* @return
* @throws WeixinException
*/
public JsonResult deliverNotify(WeixinAccount weixinAccount,
String transid, String orderNo, boolean status, String statusMsg)
throws WeixinException {
String delivernotify_uri = getRequestUri("delivernotify_uri");
Token token = tokenHolder.getToken();
Map<String, String> param = new HashMap<String, String>();
param.put("appid", weixinAccount.getAppId());
param.put("appkey", weixinAccount.getPaySignKey());
// 用户购买的openId
param.put("openid", weixinAccount.getOpenId());
param.put("transid", transid);
param.put("out_trade_no", orderNo);
param.put("deliver_timestamp", System.currentTimeMillis() / 1000 + "");
param.put("deliver_status", status ? "1" : "0");
param.put("deliver_msg", statusMsg);
param.put("app_signature", DigestUtils.sha1Hex(MapUtil.toJoinString(
param, false, true, null)));
param.put("sign_method", "sha1");
Response response = request.post(
String.format(delivernotify_uri, token.getAccessToken()),
JSON.toJSONString(param));
return response.getAsJsonResult();
}
/**
* 订单查询
*
* @param weixinAccount
* 商户信息
* @param orderNo
* 订单号
* @return
* @throws WeixinException
*/
public Order orderQueryV2(WeixinAccount weixinAccount, IdQuery idQuery)
throws WeixinException {
String orderquery_uri = getRequestUri("orderquery_uri");
Token token = tokenHolder.getToken();
StringBuilder sb = new StringBuilder();
sb.append(idQuery.getType().getName()).append(idQuery.getId());
sb.append("&partner=").append(weixinAccount.getPartnerId());
String part = sb.toString();
sb.append("&key=").append(weixinAccount.getPartnerKey());
String sign = DigestUtils.md5Hex(sb.toString()).toUpperCase();
sb.delete(0, sb.length());
sb.append(part).append("&sign=").append(sign);
String timestamp = System.currentTimeMillis() / 1000 + "";
JSONObject obj = new JSONObject();
obj.put("appid", weixinAccount.getAppId());
obj.put("appkey", weixinAccount.getPaySignKey());
obj.put("package", sb.toString());
obj.put("timestamp", timestamp);
String signature = DigestUtils.sha1Hex(MapUtil.toJoinString(obj, false,
true, null));
obj = new JSONObject();
obj.put("appid", weixinAccount.getAppId());
obj.put("package", sb.toString());
obj.put("timestamp", timestamp);
obj.put("app_signature", signature);
obj.put("sign_method", "sha1");
Response response = request.post(
String.format(orderquery_uri, token.getAccessToken()),
obj.toJSONString());
String order_info = response.getAsJson().getString("order_info");
Order order = JSON.parseObject(order_info, Order.class,
Feature.IgnoreNotMatch);
order.setMapData(JSON.parseObject(order_info,
new TypeReference<Map<String, String>>() {
}));
return order;
}
/**
* 维权处理
*
* @param openId
* 用户ID
* @param feedbackId
* 维权单号
* @return
* @throws WeixinException
*/
public JsonResult updateFeedback(String openId, String feedbackId)
throws WeixinException {
String payfeedback_update_uri = ConfigUtil
.getValue("payfeedback_update_uri");
Token token = tokenHolder.getToken();
Response response = request.get(String.format(payfeedback_update_uri,
token.getAccessToken(), openId, feedbackId));
return response.getAsJsonResult();
}
/**
* V3订单查询
*
* @param weixinAccount
* 商户信息
* @param idQuery
* 商户系统内部的订单号, transaction_idout_trade_no 选一,如果同时存在优先级:
* transaction_id> out_trade_no
* @throws WeixinException
*/
public com.foxinmy.weixin4j.mp.payment.v3.Order orderQueryV3(
WeixinAccount weixinAccount, IdQuery idQuery)
throws WeixinException {
Map<String, String> map = new HashMap<String, String>();
map.put("appid", weixinAccount.getAppId());
map.put("mch_id", weixinAccount.getMchId());
map.put("nonce_str", RandomUtil.generateString(16));
map.put(idQuery.getType().getName(), idQuery.getId());
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
map.put("sign", sign);
String param = map2xml(map);
String orderquery_uri = getRequestUri("orderquery_v3_uri");
Response response = request.post(orderquery_uri, param);
return response
.getAsObject(new TypeReference<com.foxinmy.weixin4j.mp.payment.v3.Order>() {
});
}
/**
* native支付URL转短链接
*
* @param weixinAccount
* 商户信息
* @param url
* 具有native标识的支付URL
* @return 转换后的短链接
* @throws WeixinException
*/
public String getShorturl(WeixinAccount weixinAccount, String url)
throws WeixinException {
Map<String, String> map = new HashMap<String, String>();
map.put("appid", weixinAccount.getAppId());
map.put("mch_id", weixinAccount.getMchId());
map.put("long_url", url);
map.put("nonce_str", RandomUtil.generateString(16));
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
map.put("sign", sign);
try {
map.put("long_url", URLEncoder.encode(url, utf8.name()));
} catch (UnsupportedEncodingException e) {
;
}
String param = map2xml(map);
String shorturl_uri = getRequestUri("p_shorturl_uri");
Response response = request.post(shorturl_uri, param);
map = xml2map(response.getAsString());
return map.get("short_url");
}
/**
* 关闭订单<br/>
* 当订单支付失败,调用关单接口后用新订单号重新发起支付,如果关单失败,返回已完
* 成支付请按正常支付处理如果出现银行掉单,调用关单成功后,微信后台会主动发起退款
*
* @param weixinAccount
* 商户信息
* @param idQuery
* 商户系统内部的订单号
* @return
* @throws WeixinException
*/
public XmlResult closeOrder(WeixinAccount weixinAccount, IdQuery idQuery)
throws WeixinException {
Map<String, String> map = new HashMap<String, String>();
map.put("appid", weixinAccount.getAppId());
map.put("mch_id", weixinAccount.getMchId());
map.put("nonce_str", RandomUtil.generateString(16));
map.put(idQuery.getType().getName(), idQuery.getId());
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
map.put("sign", sign);
String param = map2xml(map);
String closeorder_uri = getRequestUri("closeorder_uri");
Response response = request.post(closeorder_uri, param);
return response.getAsXmlResult();
}
/**
* 下载对账单<br>
* 1.微信侧未成功下单的交易不会出现在对账单中支付成功后撤销的交易会出现在对账 单中,跟原支付单订单号一致,bill_type
* REVOKED;<br>
* 2.微信在次日 9 点启动生成前一天的对账单,建议商户 9 点半后再获取;<br>
* 3.对账单中涉及金额的字段单位为<br>
*
* @param weixinAccount
* 商户配置
* @param billDate
* 下载对账单的日期
* @param billType
* 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单
* REFUND,返回当日退款订单
* @return excel表格
* @throws WeixinException
* @throws IOException
*/
public File downloadbill(WeixinAccount weixinAccount, Date billDate,
BillType billType) throws WeixinException, IOException {
if (billDate == null) {
Calendar now = Calendar.getInstance();
now.add(Calendar.DAY_OF_MONTH, -10);
billDate = now.getTime();
}
if (billType == null) {
billType = BillType.ALL;
}
String _billDate = DateUtil.fortmatYYYYMMDD(billDate);
String bill_path = ConfigUtil.getValue("bill_path");
String fileName = String.format("%s_%s_%s.xls", _billDate, billType
.name().toLowerCase(), weixinAccount.getAppId());
File file = new File(String.format("%s/%s", bill_path, fileName));
if (file.exists()) {
return file;
}
Map<String, String> map = new HashMap<String, String>();
map.put("appid", weixinAccount.getAppId());
map.put("mch_id", weixinAccount.getMchId());
map.put("nonce_str", RandomUtil.generateString(16));
map.put("device_info", weixinAccount.getDeviceInfo());
map.put("bill_date", _billDate);
map.put("bill_type", billType.name());
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
map.put("sign", sign);
String param = map2xml(map);
String downloadbill_uri = getRequestUri("downloadbill_uri");
Response response = request.post(downloadbill_uri, param);
BufferedReader reader = new BufferedReader(new StringReader(
response.getAsString()));
String line = null;
List<String[]> bills = new LinkedList<String[]>();
while ((line = reader.readLine()) != null) {
bills.add(line.replaceAll("`", "").split(","));
}
reader.close();
List<String> headers = Arrays.asList(bills.remove(0));
List<String> totalDatas = Arrays.asList(bills.remove(bills.size() - 1));
List<String> totalHeaders = Arrays
.asList(bills.remove(bills.size() - 1));
HSSFWorkbook wb = new HSSFWorkbook();
wb.createSheet(_billDate + "对账单");
ExcelUtil.list2excel(wb, headers, bills);
ExcelUtil.list2excel(wb, totalHeaders, totalDatas);
wb.write(new FileOutputStream(file));
return file;
}
/**
* 退款查询<br/>
* 退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款 3 个工作日后重新查询退款状态
*
* @param weixinAccount
* @param idQuery
* 单号 refund_idout_refund_no out_trade_no transaction_id
* 四个参数必填一个,优先级为:
* refund_id>out_refund_no>transaction_id>out_trade_no
* @return 退款记录
* @throws WeixinException
*/
public Refund refundQuery(WeixinAccount weixinAccount, IdQuery idQuery)
throws WeixinException {
Map<String, String> map = new HashMap<String, String>();
map.put("appid", weixinAccount.getAppId());
map.put("mch_id", weixinAccount.getMchId());
map.put("nonce_str", RandomUtil.generateString(16));
map.put("device_info", weixinAccount.getDeviceInfo());
map.put(idQuery.getType().getName(), idQuery.getId());
String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey());
map.put("sign", sign);
String param = map2xml(map);
String refundquery_uri = getRequestUri("refundquery_uri");
Response response = request.post(refundquery_uri, param);
return new RefundConverter().fromXML(response.getAsString());
}
public static void main(String[] args) throws Exception {
WeixinAccount weixinAccount = new WeixinAccount("wx0d1d598c0c03c999",
null, "GATFzDwbQdbbci3QEQxX2rUBvwTrsMiZ", "10020674");
PayApi payApi = new PayApi(null);
System.out.println(payApi.refundQuery(weixinAccount, new IdQuery(
"T0002", IdType.ORDERNO)));
}
}

View File

@ -24,10 +24,10 @@ import com.foxinmy.weixin4j.token.TokenHolder;
*/ */
public class QrApi extends BaseApi { public class QrApi extends BaseApi {
private final TokenHolder tokenApi; private final TokenHolder tokenHolder;
public QrApi(TokenHolder tokenApi) { public QrApi(TokenHolder tokenHolder) {
this.tokenApi = tokenApi; this.tokenHolder = tokenHolder;
} }
/** /**
@ -39,7 +39,7 @@ public class QrApi extends BaseApi {
* @see {@link com.foxinmy.weixin4j.mp.api.QrApi#getQR(QRParameter)} * @see {@link com.foxinmy.weixin4j.mp.api.QrApi#getQR(QRParameter)}
*/ */
public byte[] getQRData(QRParameter parameter) throws WeixinException { public byte[] getQRData(QRParameter parameter) throws WeixinException {
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
String qr_uri = getRequestUri("qr_ticket_uri"); String qr_uri = getRequestUri("qr_ticket_uri");
Response response = request.post( Response response = request.post(
String.format(qr_uri, token.getAccessToken()), String.format(qr_uri, token.getAccessToken()),
@ -97,14 +97,8 @@ public class QrApi extends BaseApi {
return file; return file;
} }
byte[] datas = getQRData(parameter); byte[] datas = getQRData(parameter);
FileOutputStream out = null; file.createNewFile();
try { FileOutputStream out = new FileOutputStream(file);
file.createNewFile();
} catch (IOException e) {
file.getParentFile().mkdirs();
file.createNewFile();
}
out = new FileOutputStream(file);
out.write(datas); out.write(datas);
out.close(); out.close();
return file; return file;

View File

@ -1,7 +1,7 @@
package com.foxinmy.weixin4j.mp.api; package com.foxinmy.weixin4j.mp.api;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.response.TemplateMessage; import com.foxinmy.weixin4j.mp.response.TemplateMessage;
@ -18,10 +18,10 @@ import com.foxinmy.weixin4j.token.TokenHolder;
*/ */
public class TmplApi extends BaseApi { public class TmplApi extends BaseApi {
private final TokenHolder tokenApi; private final TokenHolder tokenHolder;
public TmplApi(TokenHolder tokenApi) { public TmplApi(TokenHolder tokenHolder) {
this.tokenApi = tokenApi; this.tokenHolder = tokenHolder;
} }
/** /**
@ -35,14 +35,14 @@ public class TmplApi extends BaseApi {
* @see com.foxinmy.weixin4j.mp.response.TemplateMessage * @see com.foxinmy.weixin4j.mp.response.TemplateMessage
* @seee com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage * @seee com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage
*/ */
public BaseResult sendTmplMessage(TemplateMessage tplMessage) public JsonResult sendTmplMessage(TemplateMessage tplMessage)
throws WeixinException { throws WeixinException {
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
String template_send_uri = getRequestUri("template_send_uri"); String template_send_uri = getRequestUri("template_send_uri");
Response response = request.post( Response response = request.post(
String.format(template_send_uri, token.getAccessToken()), String.format(template_send_uri, token.getAccessToken()),
tplMessage.toJson()); tplMessage.toJson());
return response.getAsResult(); return response.getAsJsonResult();
} }
} }

View File

@ -5,8 +5,9 @@ import java.util.List;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.model.Following; import com.foxinmy.weixin4j.mp.model.Following;
@ -25,10 +26,10 @@ import com.foxinmy.weixin4j.token.TokenHolder;
*/ */
public class UserApi extends BaseApi { public class UserApi extends BaseApi {
private final TokenHolder tokenApi; private final TokenHolder tokenHolder;
public UserApi(TokenHolder tokenApi) { public UserApi(TokenHolder tokenHolder) {
this.tokenApi = tokenApi; this.tokenHolder = tokenHolder;
} }
/** /**
@ -46,7 +47,8 @@ public class UserApi extends BaseApi {
String user_token_uri = getRequestUri("sns_user_token_uri"); String user_token_uri = getRequestUri("sns_user_token_uri");
Response response = request.get(String.format(user_token_uri, code)); Response response = request.get(String.format(user_token_uri, code));
return response.getAsObject(UserToken.class); return response.getAsObject(new TypeReference<UserToken>() {
});
} }
/** /**
@ -67,7 +69,8 @@ public class UserApi extends BaseApi {
Response response = request.get(String.format(user_info_uri, Response response = request.get(String.format(user_info_uri,
token.getAccessToken(), token.getOpenid())); token.getAccessToken(), token.getOpenid()));
return response.getAsObject(User.class); return response.getAsObject(new TypeReference<User>() {
});
} }
/** /**
@ -87,11 +90,12 @@ public class UserApi extends BaseApi {
*/ */
public User getUser(String openId) throws WeixinException { public User getUser(String openId) throws WeixinException {
String user_info_uri = getRequestUri("api_user_info_uri"); String user_info_uri = getRequestUri("api_user_info_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Response response = request.get(String.format(user_info_uri, Response response = request.get(String.format(user_info_uri,
token.getAccessToken(), openId)); token.getAccessToken(), openId));
return response.getAsObject(User.class); return response.getAsObject(new TypeReference<User>() {
});
} }
/** /**
@ -107,11 +111,13 @@ public class UserApi extends BaseApi {
*/ */
public Following getFollowing(String nextOpenId) throws WeixinException { public Following getFollowing(String nextOpenId) throws WeixinException {
String fllowing_uri = getRequestUri("following_uri"); String fllowing_uri = getRequestUri("following_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
Response response = request.get(String.format(fllowing_uri, Response response = request.get(String.format(fllowing_uri,
token.getAccessToken(), nextOpenId == null ? "" : nextOpenId)); token.getAccessToken(), nextOpenId == null ? "" : nextOpenId));
Following following = response.getAsObject(Following.class); Following following = response
.getAsObject(new TypeReference<Following>() {
});
if (following.getCount() > 0) { if (following.getCount() > 0) {
List<String> openIds = JSON.parseArray(following.getDataJson() List<String> openIds = JSON.parseArray(following.getDataJson()
@ -165,10 +171,10 @@ public class UserApi extends BaseApi {
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%AE%BE%E7%BD%AE%E7%94%A8%E6%88%B7%E5%A4%87%E6%B3%A8%E5%90%8D%E6%8E%A5%E5%8F%A3">设置用户备注名</a> * href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%AE%BE%E7%BD%AE%E7%94%A8%E6%88%B7%E5%A4%87%E6%B3%A8%E5%90%8D%E6%8E%A5%E5%8F%A3">设置用户备注名</a>
*/ */
public BaseResult remarkUserName(String openId, String remark) public JsonResult remarkUserName(String openId, String remark)
throws WeixinException { throws WeixinException {
String updateremark_uri = getRequestUri("updateremark_uri"); String updateremark_uri = getRequestUri("updateremark_uri");
Token token = tokenApi.getToken(); Token token = tokenHolder.getToken();
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("openid", openId); obj.put("openid", openId);
obj.put("remark", remark); obj.put("remark", remark);
@ -176,6 +182,6 @@ public class UserApi extends BaseApi {
String.format(updateremark_uri, token.getAccessToken()), String.format(updateremark_uri, token.getAccessToken()),
obj.toJSONString()); obj.toJSONString());
return response.getAsResult(); return response.getAsJsonResult();
} }
} }

View File

@ -65,9 +65,17 @@ p_shorturl_uri={mch_base_url}/tools/shorturl
updateremark_uri={api_base_url}/user/info/updateremark?access_token=%s updateremark_uri={api_base_url}/user/info/updateremark?access_token=%s
# \u6a21\u677f\u6d88\u606f # \u6a21\u677f\u6d88\u606f
template_send_uri={api_base_url}/message/template/send?access_token=%s template_send_uri={api_base_url}/message/template/send?access_token=%s
# \u67e5\u8be2\u8ba2\u5355 # \u8ba2\u5355\u67e5\u8be2
orderquery_uri={api_base_url}/pay/orderquery?access_token=%s orderquery_uri={api_base_url}/pay/orderquery?access_token=%s
# \u53d1\u8d27\u901a\u77e5 # \u53d1\u8d27\u901a\u77e5
delivernotify_uri={api_base_url}/pay/delivernotify?access_token=%s delivernotify_uri={api_base_url}/pay/delivernotify?access_token=%s
# \u7ef4\u6743\u5904\u7406 # \u7ef4\u6743\u5904\u7406
payfeedback_update_uri={api_base_url}/payfeedback/update?access_token=%s&openid=%s&feedbackid=%s payfeedback_update_uri={api_base_url}/payfeedback/update?access_token=%s&openid=%s&feedbackid=%s
# \u8ba2\u5355\u67e5\u8be2
orderquery_v3_uri={mch_base_url}/pay/orderquery
# \u5173\u95ed\u8ba2\u5355
closeorder_uri={mch_base_url}/pay/closeorder
# \u5bf9\u8d26\u5355\u4e0b\u8f7d
downloadbill_uri={mch_base_url}/pay/downloadbill
# \u9000\u6b3e\u67e5\u8be2
refundquery_uri={mch_base_url}/pay/refundquery

View File

@ -0,0 +1,83 @@
package com.foxinmy.weixin4j.mp.payment;
import com.foxinmy.weixin4j.http.XmlResult;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 调用V3.x接口返回的公用字段
*
* @className ApiResult
* @author jy
* @date 2014年10月21日
* @since JDK 1.7
* @see
*/
public class ApiResult extends XmlResult {
private static final long serialVersionUID = -8430005768959715444L;
@XStreamAlias("appid")
private String appId;// 微信分配的公众账号 ID商户号 非空
@XStreamAlias("mch_id")
private String mchId;// 微信支付分配的商户号 非空
@XStreamAlias("nonce_str")
private String nonceStr;// 随机字符串 非空
private String sign;// 签名 非空
@XStreamAlias("device_info")
private String deviceInfo;// 微信支付分配的终端设备号 可能为空
public ApiResult() {
}
public ApiResult(String returnCode, String returnMsg) {
super(returnCode, returnMsg);
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getMchId() {
return mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
public String getNonceStr() {
return nonceStr;
}
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getDeviceInfo() {
return deviceInfo;
}
public void setDeviceInfo(String deviceInfo) {
this.deviceInfo = deviceInfo;
}
@Override
public String toString() {
return "ApiResult [appId=" + appId + ", mchId=" + mchId + ", nonceStr="
+ nonceStr + ", sign=" + sign + ", deviceInfo=" + deviceInfo
+ "]";
}
}

View File

@ -0,0 +1,13 @@
package com.foxinmy.weixin4j.mp.payment;
/**
* 对账单类型
* @className BillType
* @author jy
* @date 2014年10月31日
* @since JDK 1.7
* @see
*/
public enum BillType {
ALL, SUCCESS, REFUND
}

View File

@ -0,0 +1,23 @@
package com.foxinmy.weixin4j.mp.payment;
/**
* 币种
*
* @className CurrencyType
* @author jy
* @date 2014年11月2日
* @since JDK 1.7
* @see
*/
public enum CurrencyType {
CNY("人民币"), HKD("港元"), TWD("台币"), EUR("欧元"), USD("美元"), GBP("英镑"), JPY("日元");
private String desc;
CurrencyType(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
}

View File

@ -0,0 +1,40 @@
package com.foxinmy.weixin4j.mp.payment;
import java.io.Serializable;
/**
* ID查询
*
* @className IdQuery
* @author jy
* @date 2014年11月1日
* @since JDK 1.7
* @see
*/
public class IdQuery implements Serializable {
private static final long serialVersionUID = -5273675987521807370L;
private String id;
private IdType type;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public IdType getType() {
return type;
}
public void setType(IdType type) {
this.type = type;
}
public IdQuery(String id, IdType idType) {
this.id = id;
this.type = idType;
}
}

View File

@ -0,0 +1,26 @@
package com.foxinmy.weixin4j.mp.payment;
/**
* ID类型
*
* @className IdType
* @author jy
* @date 2014年11月1日
* @since JDK 1.7
* @see
*/
public enum IdType {
REFUNDID("refund_id"), // 微信退款单号
TRANSACTIONID("transaction_id"), // 微信订单号
ORDERNO("out_trade_no"), // 商户订单号
REFUNDNO("out_refund_no"); // 商户退款号
private String name;
IdType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,109 @@
package com.foxinmy.weixin4j.mp.payment;
import java.io.Serializable;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* JSAPI支付回调时的POST信息
*
* @className JsPayNotify
* @author jy
* @date 2014年8月19日
* @since JDK 1.7
* @see
*/
public class JsPayNotify implements Serializable {
private static final long serialVersionUID = -4659030958445259803L;
@XStreamAlias("AppId")
private String appid; // 公众号ID
@XStreamAlias("TimeStamp")
private String timestamp; // 时间戳
@XStreamAlias("NonceStr")
private String noncestr; // 随机字符串
@XStreamAlias("OpenId")
private String openid; // 用户ID
@XStreamAlias("AppSignature")
private String appsignature; // 签名结果
@XStreamAlias("IsSubscribe")
private int issubscribe;
@XStreamAlias("SignMethod")
private String signmethod; // 签名方式
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getNoncestr() {
return noncestr;
}
public void setNoncestr(String noncestr) {
this.noncestr = noncestr;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getAppsignature() {
return appsignature;
}
public void setAppsignature(String appsignature) {
this.appsignature = appsignature;
}
public int getIssubscribe() {
return issubscribe;
}
public void setIssubscribe(int issubscribe) {
this.issubscribe = issubscribe;
}
public String getSignmethod() {
return signmethod;
}
public void setSignmethod(String signmethod) {
this.signmethod = signmethod;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[JsPayNotify appid=").append(appid);
sb.append(", timestamp=").append(timestamp);
sb.append(", noncestr=").append(noncestr);
sb.append(", openid=").append(openid);
sb.append(", appsignature=").append(appsignature);
sb.append(", issubscribe=").append(issubscribe);
sb.append(", signmethod=").append(signmethod).append("]");
return sb.toString();
}
}

View File

@ -0,0 +1,314 @@
package com.foxinmy.weixin4j.mp.payment;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.PayException;
import com.foxinmy.weixin4j.http.XmlResult;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.mp.payment.v2.NativePayNotifyV2;
import com.foxinmy.weixin4j.mp.payment.v2.NativePayResponseV2;
import com.foxinmy.weixin4j.mp.payment.v2.PayFeedback;
import com.foxinmy.weixin4j.mp.payment.v2.PayPackageV2;
import com.foxinmy.weixin4j.mp.payment.v3.NativePayNotifyV3;
import com.foxinmy.weixin4j.mp.payment.v3.NativePayResponseV3;
import com.foxinmy.weixin4j.mp.payment.v3.PayPackageV3;
import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.xml.XStream;
/**
* 支付示例
*
* @className PayAction
* @author jy
* @date 2014年10月28日
* @since JDK 1.7
* @see
*/
public class PayAction {
private final Logger log = LoggerFactory.getLogger(getClass());
/**
* JSAPI支付
*
* @return
*/
public JSONObject jsPay() {
JSONObject obj = new JSONObject();
PayPackage payPackage = null;
// V3 支付
// 此处的openid为微信用户的openid
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
weixinAccount.setOpenId("用户的openId");
payPackage = new PayPackageV3(weixinAccount, "商品描述", "系统内部订单号", 1d,
"IP地址", TradeType.JSAPI);
// V2 支付
payPackage = new PayPackageV2("商品描述", weixinAccount.getPartnerId(),
"系统内部订单号", 1d, "回调地址", "IP地址");
payPackage.setAttach("ID");
String jspay = null;
try {
jspay = PayUtil.createPayJsRequestJson(payPackage, weixinAccount);
jspay = PayUtil.createPayJsRequestJson(payPackage, weixinAccount);
} catch (PayException e) {
log.error("create jspay error,{}", weixinAccount, e);
}
if (StringUtils.isBlank(jspay)) {
obj.put("code", "-2");
obj.put("msg", "创建支付链接失败!");
return obj;
}
obj.put("code", "0");
obj.put("jspay", jspay);
/*
* 编辑收货地址 SnsToken token = (SnsToken) getSession("AccessToken");
* obj.put("editaddress", PayUtil.createAddressRequestJson(
* wx.getAppId(), getFullLoction(), token.getAccess_token()));
*/
log.info("js pay....{}", obj);
return obj;
}
/**
* JSAPI(V2)支付成功时的回调通知<br>
* &ltxml&gt<br/>
* &ltOpenId&gt&lt![CDATA[111222]]&gt&lt/OpenId&gt<br/>
* &ltAppId&gt&lt![CDATA[wwwwb4f85f3a797777]]&gt&lt/AppId&gt<br/>
* &ltIsSubscribe&gt1&lt/IsSubscribe&gt<br/>
* &ltTimeStamp&gt1369743511&lt/TimeStamp&gt<br/>
* &ltNonceStr&gt&lt![CDATA[jALldRTHAFd5Tgs5]]&gt&lt/NonceStr&gt<br/>
* &ltAppSignature>&lt![CDATA[bafe07f060f22dcda0bfdb4b5ff756f973aecffa]]&gt
* &lt/AppSignature&gt<br/>
* &ltSignMethod>&lt![CDATA[sha1]]&gt&lt/SignMethod&gt<br/>
* &lt/xml&gt<br/>
* 参与签名的字段为: appidappkeytimestampnoncestropenidissubscribe
*
* @param 订单信息
* @param inputStream
* 用户信息
*
* @see com.foxinmy.weixin4j.mp.payment.JsPayNotify
* @return success或其他
*/
public String jsNotifyV2(InputStream inputStream) {
Map<String, String> objMap = new HashMap<String, String>();
/*
* 收集url中携带的参数 /pay/notify/back?attach=8&bank_billno=201410293351060&
* bank_type=2032&discount=0&fee_type=1&input_charset=UTF-8&
* notify_id=9fKbVf_qg6y-
* wSjtSMV0PLXeEn2oGfTM1s9dWSvR2B9U6iFQRTzmjrMWKUxvh9mpBLvnh8aqFbC_OFk1pTvFnFUO00Lln4fh
* & out_trade_no=D14102900031&partner=1221928801&product_fee=1&sign=
* B9D6E772C271C9B86B8436FC9F5DFC1A&
* sign_type=MD5&time_end=20141029183707
* &total_fee=1&trade_mode=1&trade_state=0&
* transaction_id=1221928801201410296039230054&transport_fee=0
*/
log.info("pay_notify_orderinfo,{}", objMap);
JsPayNotify payNotify = XStream.get(inputStream, JsPayNotify.class);
log.info("pay_notify_userinfo,{}", payNotify);
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
// 验证财付通签名
String sign = objMap.get("sign");
objMap.remove("sign");
String _sign = PayUtil
.paysignMd5(objMap, weixinAccount.getPartnerKey());
log.info("财付通签名----->sign={},vaild_sign={}", sign, _sign);
if (!sign.equals(_sign)) {
return "fail";
}
objMap.clear();
// 验证微信签名
sign = payNotify.getAppsignature();
payNotify.setAppsignature(null);
payNotify.setSignmethod(null);
String vaild_sign = PayUtil.paysignSha(payNotify,
weixinAccount.getPaySignKey());
log.info("微信签名----->sign={},vaild_sign={}", sign, vaild_sign);
if (!sign.equals(vaild_sign)) {
return "fail";
}
// 处理业务逻辑
return "success";
}
/**
* JSAPI(V3)支付成功时的回调通知
*
*
* @param inputStream
* 订单细腻
* @return &ltxml&gt<br>
* &ltreturn_code&gtSUCCESS/FAIL&lt/return_code&gt<br>
* &ltreturn_msg&gt如非空,为错误 原因签名失败参数格式校验错误&lt/return_msg&gt<br>
* &lt/xml&gt
*/
public String jsNotifyV3(InputStream inputStream) {
com.foxinmy.weixin4j.mp.payment.v3.Order order = XStream.get(
inputStream, com.foxinmy.weixin4j.mp.payment.v3.Order.class);
log.info("order_info:", order);
String sign = order.getSign();
order.setSign(null);
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
String valid_sign = PayUtil.paysignMd5(order,
weixinAccount.getPaySignKey());
log.info("微信签名----->sign={},vaild_sign={}", sign, valid_sign);
if (!sign.equals(valid_sign)) {
return XStream.to(new XmlResult(XmlResult.FAIL, "签名错误"));
}
return XStream.to(new XmlResult());
}
/**
* 告警通知 需要成功返回 success <br/>
* &ltxml&gt<br/>
* &ltAppId&gt&lt![CDATA[wxf8b4f85f3a794e77]]&gt&lt/AppId&gt<br/>
* &ltErrorType&gt1001&lt/ErrorType&gt<br/>
* &ltDescription&gt&lt![CDATA[错误描述]]>&lt/Description&gt<br/>
* &ltAlarmContent&gt&lt![CDATA[错误详情]]>&lt/AlarmContent&gt<br/>
* &ltTimeStamp&gt1393860740&lt/TimeStamp&gt<br/>
* &ltAppSignature&gt&lt![CDATA[签名方式跟JsPayRequest中的paySign一样]]&gt&lt/
* AppSignature&gt<br/>
* &ltSignMethod&gt&lt![CDATA[sha1]]&gt&lt/SignMethod&gt<br/>
* &lt/xml&gt<br/>
* 参与签名字段:alarmcontentappidappkeydescriptionerrortypetimestamp
*
* @param inputStream
* xml数据
* @see com.foxinmy.weixin4j.mp.payment.PayWarn
* @return
*/
public String warning(InputStream inputStream) {
PayWarn payWarn = XStream.get(inputStream, PayWarn.class);
log.info("pay_warning,{}", payWarn);
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
String sign = payWarn.getAppsignature();
payWarn.setSignmethod(null);
payWarn.setAppsignature(null);
// 验证微信签名
String vaild_sign = PayUtil.paysignSha(payWarn,
weixinAccount.getPaySignKey());
log.info("微信签名----->sign={},vaild_sign={}", sign, vaild_sign);
return "success";
}
/**
* V2.x版本Native支付时POST数据<br>
* &ltxml&gt<br/>
* &ltOpenId&gt&lt![CDATA[111222]]&gt&lt/OpenId&gt<br/>
* &ltAppId&gt&lt![CDATA[wwwwb4f85f3a797777]]&gt&lt/AppId&gt<br/>
* &ltIsSubscribe&gt1&lt/IsSubscribe&gt<br/>
* &ltProductId&gt[CDATA[000000]]&lt/ProductId&gt<br/>
* &ltTimeStamp&gt1369743511&lt/TimeStamp&gt<br/>
* &ltNonceStr&gt&lt![CDATA[jALldRTHAFd5Tgs5]]&gt&lt/NonceStr&gt<br/>
* &ltAppSignature>&lt![CDATA[bafe07f060f22dcda0bfdb4b5ff756f973aecffa]]&gt
* &lt/AppSignature&gt<br/>
* &ltSignMethod>&lt![CDATA[sha1]]&gt&lt/SignMethod&gt<br/>
* &lt/xml&gt<br/>
* 参与签名的字段为: appidappkeytimestampnoncestropenidissubscribeproductId
*
* @param inputStream
*
* @return 必须返回一个带有Package信息的xml字符串
*/
public String nativeNotifyV2(InputStream inputStream) {
// V2.x版本
NativePayNotifyV2 payNotify = XStream.get(inputStream,
NativePayNotifyV2.class);
log.info("native_pay_notify,{}", payNotify);
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
String sign = payNotify.getAppsignature();
payNotify.setAppsignature(null);
payNotify.setSignmethod(null);
// 验证微信签名
String vaild_sign = PayUtil.paysignSha(payNotify,
weixinAccount.getPaySignKey());
log.info("微信签名----->sign={},vaild_sign={}", sign, vaild_sign);
if (!sign.equals(vaild_sign)) {
return "fail";
}
// 构造订单信息
PayPackageV2 payPackage = new PayPackageV2("商品描述",
weixinAccount.getPartnerId(), "系统内部订单号", 1d, "回调地址", "IP地址");
NativePayResponseV2 payResponse = new NativePayResponseV2(
weixinAccount, payPackage);
return XStream.to(payResponse);
}
/**
* V3.x版本native回调<br>
* &ltxml&gt<br/>
* &ltopenid&gt&lt![CDATA[111222]]&gt&lt/openid&gt<br/>
* &ltappid&gt&lt![CDATA[wwwwb4f85f3a797777]]&gt&lt/appid&gt<br/>
* &ltmch_id&gt&lt![CDATA[1100022]]&gt&lt/mch_id&gt<br/>
* &ltis_subscribe&gt1&lt/is_subscribe&gt<br/>
* &ltproduct_id&gt[CDATA[000000]]&lt/product_id&gt<br/>
* &ltnonce_str&gt&lt![CDATA[jALldRTHAFd5Tgs5]]&gt&lt/nonce_str&gt<br/>
* &ltsign>&lt![CDATA[bafe07f060f22dcda0bfdb4b5ff756f973aecffa]]&gt&lt/sign&
* gt<br/>
* &lt/xml&gt<br/>
*
* @return
* @throws PayException
*/
public String nativeNotifyV3(InputStream inputStream) throws PayException {
NativePayNotifyV3 payNotify = XStream.get(inputStream,
NativePayNotifyV3.class);
String sign = payNotify.getSign();
payNotify.setSign(null);
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
String valid_sign = PayUtil.paysignMd5(payNotify,
weixinAccount.getPaySignKey());
log.info("微信签名----->sign={},vaild_sign={}", sign, valid_sign);
// 生成Package
PayPackageV3 payPackage = new PayPackageV3(weixinAccount, "商品描述",
"系统内部订单号", 1d, "IP地址", TradeType.NATIVE);
payPackage.setProduct_id(payNotify.getProductId());
if (!sign.equals(valid_sign)) {
NativePayResponseV3 payReponse = new NativePayResponseV3(
payPackage, "签名失败", null);
payReponse.setSign(PayUtil.paysignMd5(payReponse,
weixinAccount.getPaySignKey()));
return XStream.to(payReponse);
}
NativePayResponseV3 payReponse = new NativePayResponseV3(payPackage,
null, null);
payReponse.setSign(PayUtil.paysignMd5(payReponse,
weixinAccount.getPaySignKey()));
return XStream.to(payReponse);
}
/**
* 用户维权
*
* @param inputStream
* @see com.foxinmy.weixin4j.mp.payment.v2.PayFeedback
* @return
*/
public String feedback(InputStream inputStream) {
PayFeedback feedback = XStream.get(inputStream, PayFeedback.class);
log.info("pay_feedback_info:{}", feedback);
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
// 验证微信签名
Map<String, String> obj = new HashMap<String, String>();
obj.put("openid", feedback.getOpenId());
obj.put("appid", feedback.getAppId());
obj.put("timestamp", feedback.getTimeStamp());
String sign = PayUtil.paysignSha(obj, weixinAccount.getPaySignKey());
log.info("微信签名----->sign={},vaild_sign={}", sign,
feedback.getAppSignature());
return "success";
}
public static void main(String[] args) {
}
}

View File

@ -0,0 +1,121 @@
package com.foxinmy.weixin4j.mp.payment;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class PayPackage implements Serializable {
private static final long serialVersionUID = 3450161267802545790L;
protected static final NumberFormat FEE_FORMAT = new DecimalFormat("#");
protected static final DateFormat DATE_FORMAT = new SimpleDateFormat(
"yyyyMMddHHmmss");
private String body; // 商品描述 必须
private String attach; // 附加数据,原样返回 非必须
private String out_trade_no; // 商户系统内部的订单号 ,32 个字符内 可包含字母 ,确保 在商户系统唯一 必须
private String total_fee; // 订单总金额,单位为分, 能带小数点 必须
private String spbill_create_ip; // 订单生成的机器 IP 必须
private String time_start; // 订单生成时间,格式 yyyyMMddHHmmss, 2009
// 12月25日9点10分10秒表 示为 20091225091010时区 GMT+8
// beijing该时间取 自商户服务器 非必须
private String time_expire; // 订单失效时间,格式 yyyyMMddHHmmss, 2009
// 12月27日9点10分10秒表 示为 20091227091010时区 GMT+8
// beijing该时间取 自商户服务商品标记 非必须
private String goods_tag; // 商品标记,该字段不能随便 ,不使用请填空 非必须
private String notify_url; // 通知地址接收微信支付成功通知 必须
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getAttach() {
return attach;
}
public void setAttach(String attach) {
this.attach = attach;
}
public String getOut_trade_no() {
return out_trade_no;
}
public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public String getTotal_fee() {
return total_fee;
}
public void setTotal_fee(double total_fee) {
this.total_fee = FEE_FORMAT.format(total_fee);
}
public String getSpbill_create_ip() {
return spbill_create_ip;
}
public void setSpbill_create_ip(String spbill_create_ip) {
this.spbill_create_ip = spbill_create_ip;
}
public String getTime_start() {
return time_start;
}
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 setTime_start(Date time_start) {
this.time_start = time_start != null
? DATE_FORMAT.format(time_start)
: null;;
}
public String getTime_expire() {
return time_expire;
}
public void setTime_expire(Date time_expire) {
this.time_expire = time_expire != null ? DATE_FORMAT
.format(time_expire) : null;;
}
public String getGoods_tag() {
return goods_tag;
}
public void setGoods_tag(String goods_tag) {
this.goods_tag = goods_tag;
}
public String getNotify_url() {
return notify_url;
}
public void setNotify_url(String notify_url) {
this.notify_url = notify_url;
}
public PayPackage() {
}
public PayPackage(String body, String attach, String out_trade_no,
double total_fee, String spbill_create_ip, Date time_start,
Date time_expire, String goods_tag, String notify_url) {
this.body = body;
this.attach = attach;
this.out_trade_no = out_trade_no;
this.total_fee = FEE_FORMAT.format(total_fee * 100);
this.spbill_create_ip = spbill_create_ip;
this.time_start = time_start != null
? DATE_FORMAT.format(time_start)
: null;
this.time_expire = time_expire != null ? DATE_FORMAT
.format(time_expire) : null;
this.goods_tag = goods_tag;
this.notify_url = notify_url;
}
@Override
public String toString() {
return "PayPackage [body=" + body + ", attach=" + attach
+ ", out_trade_no=" + out_trade_no + ", total_fee=" + total_fee
+ ", spbill_create_ip=" + spbill_create_ip + ", time_start="
+ time_start + ", time_expire=" + time_expire + ", goods_tag="
+ goods_tag + ", notify_url=" + notify_url + "]";
}
}

View File

@ -0,0 +1,95 @@
package com.foxinmy.weixin4j.mp.payment;
import java.io.Serializable;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.util.RandomUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias;
public class PayRequest implements Serializable {
private static final long serialVersionUID = -453746488398523883L;
// 公众号ID
@XStreamAlias("AppId")
private String appId;
// 当前时间戳
@XStreamAlias("TimeStamp")
private String timeStamp;
// 随机字符串
@XStreamAlias("NonceStr")
private String nonceStr;
// 订单详情扩展 订单信息组成该字符串
@XStreamAlias("Package")
private String packageInfo;
// 签名方式 数取值"SHA1"
@XStreamAlias("SignMethod")
private String signType;
// 商户将接口列表中的参数按照指定方式进行 签名,签名方式使用 signType中标示的签名方式,
@XStreamAlias("Appsignature")
private String paySign;
public PayRequest() {
this.timeStamp = System.currentTimeMillis() / 1000 + "";
this.nonceStr = RandomUtil.generateString(16);
}
public PayRequest(String appId, String packageInfo, SignType signType,
String paySign) {
this.appId = appId;
this.timeStamp = System.currentTimeMillis() / 1000 + "";
this.nonceStr = RandomUtil.generateString(16);
this.packageInfo = packageInfo;
this.signType = signType.name();
this.paySign = paySign;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp;
}
public String getNonceStr() {
return nonceStr;
}
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
@JSONField(name = "package")
public String getPackageInfo() {
return packageInfo;
}
public void setPackageInfo(String packageInfo) {
this.packageInfo = packageInfo;
}
public String getSignType() {
return signType;
}
public void setSignType(SignType signType) {
this.signType = signType.name();
}
public String getPaySign() {
return paySign;
}
public void setPaySign(String paySign) {
this.paySign = paySign;
}
}

View File

@ -0,0 +1,369 @@
package com.foxinmy.weixin4j.mp.payment;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.PayException;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.mp.payment.v2.JsPayRequestV2;
import com.foxinmy.weixin4j.mp.payment.v2.NativePayResponseV2;
import com.foxinmy.weixin4j.mp.payment.v2.PayPackageV2;
import com.foxinmy.weixin4j.mp.payment.v3.PayRequestV3;
import com.foxinmy.weixin4j.mp.payment.v3.PayPackageV3;
import com.foxinmy.weixin4j.mp.payment.v3.PrePay;
import com.foxinmy.weixin4j.util.MapUtil;
import com.foxinmy.weixin4j.util.RandomUtil;
import com.foxinmy.weixin4j.xml.XStream;
/**
* 支付工具类
*
* @className PayUtil
* @author jy
* @date 2014年10月28日
* @since JDK 1.7
* @see
*/
public class PayUtil {
private static final String UNIFIEDORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
private static final String NATIVEURLV2 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&productid=%s&timestamp=%s&noncestr=%s";
private static final String NATIVEURLV3 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s";
/**
* 生成JSAPI字符串
*
* @param payPackage
* 订单信息
* @param weixinConfig
* appid等信息
* @return
* @throws PayException
*/
public static String createPayJsRequestJson(PayPackage payPackage,
WeixinAccount weixinAccount) throws PayException {
if (payPackage instanceof PayPackageV2) {
return createPayJsRequestJsonV2((PayPackageV2) payPackage,
weixinAccount);
} else if (payPackage instanceof PayPackageV3) {
return createPayJsRequestJsonV3((PayPackageV3) payPackage,
weixinAccount);
}
throw new PayException("-1", "unknown pay");
}
/**
* 生成V2.x版本JSAPI支付字符串
*
* @param payPackage
* 订单信息
* @param weixinConfig
* appid等信息
* @return
*/
public static String createPayJsRequestJsonV2(PayPackageV2 payPackage,
WeixinAccount weixinAccount) {
if (StringUtils.isBlank(payPackage.getPartner())) {
payPackage.setPartner(weixinAccount.getPartnerId());
}
JsPayRequestV2 jsPayRequest = new JsPayRequestV2(weixinAccount,
payPackage);
jsPayRequest.setPaySign(paysignSha(jsPayRequest,
weixinAccount.getPaySignKey()));
jsPayRequest.setSignType(SignType.SHA1);
return JSON.toJSONString(jsPayRequest);
}
/**
* 生成V2.x版本JSAPI支付字符串
*
* @param body
* 支付详情
* @param orderNo
* 订单号
* @param orderFee
* 订单总额
* @param ip
* @param weixinConfig
* appid等信息
* @return
*/
public static String createPayJsRequestJsonV2(String body, String orderNo,
double orderFee, String ip, WeixinAccount weixinAccount) {
PayPackageV2 payPackage = new PayPackageV2(body, orderNo, orderFee, ip);
payPackage.setPartner(weixinAccount.getPartnerId());
return createPayJsRequestJsonV2(payPackage, weixinAccount);
}
/**
* V2.x版本的PayRequest签名
*
* @param jsPayRequestV2
* 支付请求
* @param paySignKey
* 支付API的密钥
* @return
*/
public static String paysignSha(Object obj, String paySignKey) {
JSONObject extra = null;
if (StringUtils.isNotBlank(paySignKey)) {
extra = new JSONObject();
extra.put("appKey", paySignKey);
}
return DigestUtils.sha1Hex(MapUtil
.toJoinString(obj, false, true, extra));
}
/**
* V3.x版本的PayRequest签名
*
* @param jsPayRequestV3
* 支付请求
* @param paySignKey
* 支付API的密钥
* @return
*/
public static String paysignMd5(Object obj, String paySignKey) {
StringBuilder sb = new StringBuilder();
// a--->string1
sb.append(MapUtil.toJoinString(obj, false, false, null));
// b--->
// string1 最后拼接上 key=paternerKey 得到 stringSignTemp 字符串,
// stringSignTemp 进行 md5 运算
// 再将得到的 字符串所有字符转换为大写 ,得到 sign signValue
sb.append("&key=").append(paySignKey);
return DigestUtils.md5Hex(sb.toString()).toUpperCase();
}
/**
* 生成V3.x版本JSAPI支付字符串
*
* @param body
* 订单描述
* @param orderNo
* 订单号
* @param orderFee
* 订单总额
* @param ip
* @param notifyUrl
* 支付通知地址
* @param weixinConfig
* appid等信息
* @return
* @throws PayException
*/
public static String createPayJsRequestJsonV3(String body, String orderNo,
double orderFee, String ip, String notifyUrl,
WeixinAccount weixinAccount) throws PayException {
PayPackageV3 payPackage = new PayPackageV3(weixinAccount, body,
orderNo, orderFee, ip, TradeType.JSAPI);
payPackage.setNotify_url(notifyUrl);
return createPayJsRequestJsonV3(payPackage, weixinAccount);
}
/**
* 生成V3.x版本JSAPI支付字符串
*
* @param payPackage
* 订单信息
* @param weixinConfig
* appid等信息
* @return
* @throws PayException
*/
public static String createPayJsRequestJsonV3(PayPackageV3 payPackage,
WeixinAccount weixinAccount) throws PayException {
String paySignKey = weixinAccount.getPaySignKey();
payPackage.setSign(paysignMd5(payPackage, paySignKey));
PrePay prePay = createPrePay(payPackage);
PayRequestV3 jsPayRequest = new PayRequestV3(prePay);
jsPayRequest.setPaySign(paysignMd5(jsPayRequest, paySignKey));
jsPayRequest.setSignType(SignType.MD5);
return JSON.toJSONString(jsPayRequest);
}
public static PrePay createPrePay(PayPackageV3 payPackage) {
String payJsRequestXml = XStream.to(payPackage).replaceAll("__", "_");
HttpClient client = null;
try {
client = new DefaultHttpClient();
HttpPost post = new HttpPost(UNIFIEDORDER);
post.setEntity(new StringEntity(payJsRequestXml,
StandardCharsets.UTF_8));
HttpResponse response = client.execute(post);
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
return new PrePay("-1", "网络异常[" + statusLine.getStatusCode()
+ "," + statusLine.getReasonPhrase() + "]");
}
String returnXml = EntityUtils.toString(response.getEntity(),
StandardCharsets.UTF_8);
return XStream.get(returnXml, PrePay.class);
} catch (IOException e) {
e.printStackTrace();
} finally {
client.getConnectionManager().shutdown();
}
return new PrePay("-1", "request fail");
}
/**
* <p>
* 生成编辑地址请求
* </p>
*
* err_msg edit_address:ok获取编辑收货地址成功<br/>
* edit_address:fail获取编辑收货地址失败<br/>
* userName 收货人姓名<br/>
* telNumber 收货人电话<br/>
* addressPostalCode 邮编<br/>
* proviceFirstStageName 国标收货地址第一级地址<br/>
* addressCitySecondStageName 国标收货地址第二级地址<br/>
* addressCountiesThirdStageName 国标收货地址第三级地址<br/>
* addressDetailInfo 详细收货地址信息<br/>
* nationalCode 收货地址国家码<br/>
*
* @param appId
* 公众号的ID
* @param url
* 当前访问页的URL
* @param accessToken
* snsapi_base授权时产生的token
* @return
*/
public static String createAddressRequestJson(String appId, String url,
String accessToken) {
Map<String, String> param = new HashMap<String, String>();
param.put("appId", appId);
param.put("url", url);
param.put("timeStamp", System.currentTimeMillis() / 1000 + "");
param.put("nonceStr", RandomUtil.generateString(16));
param.put("accessToken", accessToken);
String sign = paysignSha(param, null);
JSONObject obj = new JSONObject();
obj.put("appId", appId);
obj.put("scope", "jsapi_address");
obj.put("signType", "sha1");
obj.put("addrSign", sign);
obj.put("timeStamp", param.get("timeStamp"));
obj.put("nonceStr", param.get("nonceStr"));
return obj.toJSONString();
}
/**
* 创建V2.x NativePay支付链接
*
* @param weixinConfig
* 支付配置信息
* @param productId
* 与订单ID等价
* @return
*/
public String createNativePayRequestURLV2(WeixinAccount weixinAccount,
String productId) {
Map<String, String> map = new HashMap<String, String>();
String timestamp = System.currentTimeMillis() / 1000 + "";
String noncestr = RandomUtil.generateString(16);
map.put("appid", weixinAccount.getAppId());
map.put("timestamp", timestamp);
map.put("noncestr", noncestr);
map.put("productid", productId);
String sign = paysignSha(map, weixinAccount.getPaySignKey());
return String.format(NATIVEURLV2, sign, weixinAccount.getAppId(),
productId, timestamp, noncestr);
}
/**
* 创建V3.x NativePay支付链接
*
* @param weixinConfig
* 支付配置信息
* @param productId
* 与订单ID等价
* @return
*/
public String createNativePayRequestURLV3(WeixinAccount weixinAccount,
String productId) {
Map<String, String> map = new HashMap<String, String>();
String timestamp = System.currentTimeMillis() / 1000 + "";
String noncestr = RandomUtil.generateString(16);
map.put("appid", weixinAccount.getAppId());
map.put("mch_id", weixinAccount.getMchId());
map.put("time_stamp", timestamp);
map.put("nonce_str", noncestr);
map.put("product_id", productId);
String sign = paysignMd5(map, weixinAccount.getPaySignKey());
return String.format(NATIVEURLV3, sign, weixinAccount.getAppId(),
weixinAccount.getMchId(), productId, timestamp, noncestr);
}
public static String createNativePayRequestV2(WeixinAccount weixinAccount,
PayPackageV2 payPackage) {
NativePayResponseV2 payRequest = new NativePayResponseV2(weixinAccount,
payPackage);
Map<String, String> map = new HashMap<String, String>();
String timestamp = System.currentTimeMillis() / 1000 + "";
String noncestr = RandomUtil.generateString(16);
map.put("appid", weixinAccount.getAppId());
map.put("timestamp", timestamp);
map.put("noncestr", noncestr);
map.put("package", payRequest.getPackageInfo());
map.put("retcode", payRequest.getRetCode());
map.put("reterrmsg", payRequest.getRetMsg());
payRequest.setPaySign(paysignSha(map, weixinAccount.getPaySignKey()));
return XStream.to(payRequest);
}
/**
* 测试js支付请求
*
* @return
*/
private static void createTestPayJsRequestJson() {
// V2.xAPI支付
PayPackageV2 payPackage = new PayPackageV2("pay_test", "1220403701",
"D123456", 0.01, "http://182.92.74.85:8082/pay/notify",
"192.168.1.1");
WeixinAccount weixinAccount = new WeixinAccount("wx0d1d598c0c03c999",
"2270e6c67cf4ff48fe2c6d7cc5a42157",
"GATFzDwbQdbbci3QEQxX2rUBvwTrsMiZ", "1221966601",
"6b506ef5fefba3142653a9affd2648d8");
System.out.println(PayUtil.createPayJsRequestJsonV2(payPackage,
weixinAccount));
// V3.xJSAPI支付
try {
weixinAccount = new WeixinAccount("wx0d1d598c0c03c999",
"2270e6c67cf4ff48fe2c6d7cc5a42157",
"6b506ef5fefba3142653a9affd2648d8", "10020674",
"oyFLst1bqtuTcxK-ojF8hOGtLQao");
System.out.println(PayUtil.createPayJsRequestJsonV3("测试", "T001",
1d, "192.0.0.1", "http://182.92.74.85:8082/pay/notify",
weixinAccount));
} catch (PayException e) {
e.printStackTrace();
}
// V2.xNative支付
System.out.println(PayUtil.createNativePayRequestV2(weixinAccount,
payPackage));
}
public static void main(String[] args) {
createTestPayJsRequestJson();
}
}

View File

@ -0,0 +1,96 @@
package com.foxinmy.weixin4j.mp.payment;
import java.io.Serializable;
import com.thoughtworks.xstream.annotations.XStreamAlias;
@XStreamAlias("xml")
public class PayWarn implements Serializable {
private static final long serialVersionUID = 2334592957844332640L;
@XStreamAlias("AppId")
private String appid;
@XStreamAlias("ErrorType")
private String errortype;
@XStreamAlias("Description")
private String description;
@XStreamAlias("AlarmContent")
private String alarmcontent;
@XStreamAlias("TimeStamp")
private String timestamp;
@XStreamAlias("AppSignature")
private String appsignature;
@XStreamAlias("SignMethod")
private String signmethod;
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getErrortype() {
return errortype;
}
public void setErrortype(String errortype) {
this.errortype = errortype;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getAlarmcontent() {
return alarmcontent;
}
public void setAlarmcontent(String alarmcontent) {
this.alarmcontent = alarmcontent;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getAppsignature() {
return appsignature;
}
public void setAppsignature(String appsignature) {
this.appsignature = appsignature;
}
public String getSignmethod() {
return signmethod;
}
public void setSignmethod(String signmethod) {
this.signmethod = signmethod;
}
@Override
public String toString() {
return "PayWarn [appid=" + appid + ", errortype=" + errortype
+ ", description=" + description + ", alarmcontent="
+ alarmcontent + ", timestamp=" + timestamp + ", appsignature="
+ appsignature + ", signmethod=" + signmethod + "]";
}
}

View File

@ -0,0 +1 @@
支付模块【JSP AY】【NATIVE PAY】【APP PAY】

View File

@ -0,0 +1,117 @@
package com.foxinmy.weixin4j.mp.payment;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.foxinmy.weixin4j.mp.payment.v3.Refund;
import com.foxinmy.weixin4j.mp.payment.v3.RefundDetail;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.mapper.Mapper;
/**
* 退款查询接口调用结果转换类
* @className RefundConverter
* @author jy
* @date 2014年11月2日
* @since JDK 1.7
* @see
*/
public class RefundConverter {
private final static XStream xStream = XStream.get();
private final ReflectionConverter reflectionConverter;
public RefundConverter() {
xStream.processAnnotations(Refund.class);
xStream.registerConverter(new RefundConverter.$());
reflectionConverter = new ReflectionConverter(xStream.getMapper(),
xStream.getReflectionProvider());
}
public String toXML(Refund refund) {
return xStream.toXML(refund);
}
public Refund fromXML(String xml) {
return xStream.fromXML(xml, Refund.class);
}
private class $ implements Converter {
@Override
public boolean canConvert(@SuppressWarnings("rawtypes") Class clazz) {
return clazz.equals(Refund.class);
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
reflectionConverter.marshal(source, writer, context);
}
@SuppressWarnings("unchecked")
@Override
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
Refund refund = new Refund();
Mapper mapper = xStream.getMapper();
ReflectionProvider reflectionProvider = xStream
.getReflectionProvider();
Pattern pattern = Pattern.compile("(_\\d)$");
Matcher matcher = null;
Map<String, Map<String, String>> outMap = new HashMap<String, Map<String, String>>();
while (reader.hasMoreChildren()) {
reader.moveDown();
String nodeName = reader.getNodeName();
String fieldName = mapper.realMember(Refund.class, nodeName);
Field field = reflectionProvider.getFieldOrNull(Refund.class,
fieldName);
if (field != null) {
Object value = context.convertAnother(refund,
field.getType());
reflectionProvider.writeField(refund, fieldName, value,
field.getDeclaringClass());
} else if ((matcher = pattern.matcher(nodeName)).find()) {
String key = matcher.group();
Map<String, String> innerMap = null;
if ((innerMap = outMap.get(key)) == null) {
innerMap = new HashMap<String, String>();
outMap.put(key, innerMap);
}
innerMap.put(nodeName.replace(key, ""), reader.getValue());
}
reader.moveUp();
}
StringBuilder detailXml = new StringBuilder();
detailXml.append("<list>");
String detailCanonicalName = RefundDetail.class.getCanonicalName();
for (Iterator<Entry<String, Map<String, String>>> outIt = outMap
.entrySet().iterator(); outIt.hasNext();) {
detailXml.append("<").append(detailCanonicalName).append(">");
for (Iterator<Entry<String, String>> innerIt = outIt.next()
.getValue().entrySet().iterator(); innerIt.hasNext();) {
Entry<String, String> entry = innerIt.next();
detailXml.append("<").append(entry.getKey()).append(">");
detailXml.append(entry.getValue());
detailXml.append("</").append(entry.getKey()).append(">");
}
detailXml.append("</").append(detailCanonicalName).append(">");
}
detailXml.append("</list>");
xStream.processAnnotations(RefundDetail.class);
refund.setDetails(xStream.fromXML(detailXml.toString(), List.class));
return refund;
}
}
}

View File

@ -0,0 +1,20 @@
package com.foxinmy.weixin4j.mp.payment;
/**
* 退款状态
*
* @className RefundStatus
* @author jy
* @date 2014年11月2日
* @since JDK 1.7
* @see
*/
public enum RefundStatus {
SUCCES, // 退款成功
FAIL, // 退款失败
PROCESSING, // 退款处理中
NOTSURE, // 未确定,需要商户 原退款单号重新发起
// 转入代发,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,资金回流到商户的现金帐号,需要商户人工干
// ,通过线下或者财付通转 账的方式进行退款
CHANGE;
}

View File

@ -0,0 +1,5 @@
package com.foxinmy.weixin4j.mp.payment;
public enum SignType {
SHA1,MD5
}

View File

@ -0,0 +1,21 @@
package com.foxinmy.weixin4j.mp.payment;
/**
* 交易状态
*
* @className TradeState
* @author jy
* @date 2014年11月2日
* @since JDK 1.7
* @see
*/
public enum TradeState {
SUCCESS, // 支付成功
REFUND, // 转入退款
NOTPAY, // 未支付
CLOSED, // 已关闭
REVOKED, // 已撤销
USERPAYING, // 用户支付中
NOPAY, // 未支付(输入密码或 确认支付超时)
PAYERROR;// 支付失败(其他 原因,如银行返回失败)
}

View File

@ -0,0 +1,14 @@
package com.foxinmy.weixin4j.mp.payment;
/**
* 微信支付类型
*
* @className TradeType
* @author jy
* @date 2014年10月21日
* @since JDK 1.7
* @see
*/
public enum TradeType {
JSAPI, MICROPAY, NATIVE, APP;
}

View File

@ -0,0 +1,64 @@
package com.foxinmy.weixin4j.mp.payment.v2;
import org.apache.commons.codec.digest.DigestUtils;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.mp.payment.PayRequest;
import com.foxinmy.weixin4j.util.MapUtil;
/**
* 微信JS支付:get_brand_wcpay_request<br/>
* <font color="red">所列参数均为非空字符串</font>
* <p>
* get_brand_wcpay_request:ok 支付成功<br>
* get_brand_wcpay_request:cancel 支付过程中用户取消<br>
* get_brand_wcpay_request:fail 支付失败
* </p>
*
* @className JsPayRequestV2
* @author jy
* @date 2014年8月17日
* @since JDK 1.7
* @see
*/
public class JsPayRequestV2 extends PayRequest {
private static final long serialVersionUID = -5972173459255255197L;
public JsPayRequestV2(WeixinAccount weixinAccount, PayPackageV2 payPackage) {
this.setAppId(weixinAccount.getAppId());
this.setPackageInfo(package2string(payPackage,
weixinAccount.getPartnerKey()));
}
@JSONField(serialize = false)
private String package2string(PayPackageV2 payPackage, String partnerKey) {
StringBuilder sb = new StringBuilder();
// a.对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序) ,
// 使用 URL 键值 对的格式( key1=value1&key2=value2...)拼接成字符串 string1
// 注意:值为空的参数不参与签名
sb.append(MapUtil.toJoinString(payPackage, false, false, null));
// b--->
// string1 最后拼接上 key=paternerKey 得到 stringSignTemp 字符串,
// stringSignTemp 进行 md5 运算
// 再将得到的 字符串所有字符转换为大写 ,得到 sign signValue
sb.append("&key=").append(partnerKey);
// c---> & d---->
String sign = DigestUtils.md5Hex(sb.toString()).toUpperCase();
sb.delete(0, sb.length());
// c.对传入参数中所有键值对的 value 进行 urlencode 转码后重新拼接成字符串 string2
sb.append(MapUtil.toJoinString(payPackage, true, false, null))
.append("&sign=").append(sign);
return sb.toString();
}
@Override
public String toString() {
return "JsPayRequest [getAppId()=" + getAppId() + ", getTimeStamp()="
+ getTimeStamp() + ", getNonceStr()=" + getNonceStr()
+ ", getPackageInfo()=" + getPackageInfo() + ", getSignType()="
+ getSignType() + ", getPaySign()=" + getPaySign() + "]";
}
}

View File

@ -0,0 +1,38 @@
package com.foxinmy.weixin4j.mp.payment.v2;
import com.foxinmy.weixin4j.mp.payment.JsPayNotify;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* Native支付回调时POST的信息
*
* @className PayNativeNotifyV2
* @author jy
* @date 2014年10月28日
* @since JDK 1.7
* @see
*/
public class NativePayNotifyV2 extends JsPayNotify {
private static final long serialVersionUID = 1868431159301749988L;
@XStreamAlias("ProductId")
private String productId;
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
@Override
public String toString() {
return "PayNativeNotifyV2 [productId=" + productId + ", getAppid()="
+ getAppid() + ", getTimestamp()=" + getTimestamp()
+ ", getNoncestr()=" + getNoncestr() + ", getOpenid()="
+ getOpenid() + ", getAppsignature()=" + getAppsignature()
+ ", getIssubscribe()=" + getIssubscribe()
+ ", getSignmethod()=" + getSignmethod() + "]";
}
}

View File

@ -0,0 +1,55 @@
package com.foxinmy.weixin4j.mp.payment.v2;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* Native支付响应
*
* @className NativePayResponseV2
* @author jy
* @date 2014年10月28日
* @since JDK 1.7
* @see
*/
@XStreamAlias("xml")
public class NativePayResponseV2 extends JsPayRequestV2 {
private static final long serialVersionUID = 6119895998783333012L;
@XStreamAlias("RetCode")
private String retCode;
@XStreamAlias("RetErrMsg")
private String retMsg;
public NativePayResponseV2(WeixinAccount weixinAccount,
PayPackageV2 payPackage) {
super(weixinAccount, payPackage);
this.retCode = "0";
this.retMsg = "OK";
}
public String getRetCode() {
return retCode;
}
public void setRetCode(String retCode) {
this.retCode = retCode;
}
public String getRetMsg() {
return retMsg;
}
public void setRetMsg(String retMsg) {
this.retMsg = retMsg;
}
@Override
public String toString() {
return "NativePayResponseV2 [retCode=" + retCode + ", retMsg=" + retMsg
+ ", getAppId()=" + getAppId() + ", getTimeStamp()="
+ getTimeStamp() + ", getNonceStr()=" + getNonceStr()
+ ", getPackageInfo()=" + getPackageInfo() + ", getSignType()="
+ getSignType() + ", getPaySign()=" + getPaySign() + "]";
}
}

View File

@ -0,0 +1,245 @@
package com.foxinmy.weixin4j.mp.payment.v2;
import java.util.Map;
import com.foxinmy.weixin4j.http.JsonResult;
/**
* 订单信息
*
* @className Order
* @author jy
* @date 2014年11月2日
* @since JDK 1.7
* @see
*/
public class Order extends JsonResult {
private static final long serialVersionUID = 4543552984506609920L;
// 是查询结果状态码,0 表明成功,其他表明错误;
private String ret_code;
// 是查询结果出错信息;
private String ret_msg;
// 是返回信息中的编码方式;
private String input_charset;
// 是订单状态,0 为成功,其他为失败;
private String trade_state;
// 是交易模式,1 为即时到帐,其他保留;
private String trade_mode;
// 是财付通商户号,即前文的 partnerid;
private String partner;
// 是银行类型;
private String bank_type;
// 是银行订单号;
private String bank_billno;
// 是总金额,单位为分;
private String total_fee;
// 是币种,1 为人民币;
private String fee_type;
// 是财付通订单号;
private String transaction_id;
// 是第三方订单号;
private String out_trade_no;
// 表明是否分账,false 为无分账,true 为有分账;
private boolean is_split;
// 表明是否退款,false 为无退款,ture 为退款;
private boolean is_refund;
// attach 是商户数据包,即生成订单package 时商户填入的 attach;
private String attach;
// 支付完成时间;
private String time_end;
// 物流费用,单位为分;
private String transport_fee;
// 物品费用,单位为分;
private String product_fee;
// 折扣价格,单位为分;
private String discount;
// 换算成人民币之后的总金额,单位为分,一般看 total_fee 即可
private String rmb_total_fee;
public String getRet_code() {
return ret_code;
}
public void setRet_code(String ret_code) {
this.ret_code = ret_code;
}
public String getRet_msg() {
return ret_msg;
}
public void setRet_msg(String ret_msg) {
this.ret_msg = ret_msg;
}
public String getInput_charset() {
return input_charset;
}
public void setInput_charset(String input_charset) {
this.input_charset = input_charset;
}
public String getTrade_state() {
return trade_state;
}
public void setTrade_state(String trade_state) {
this.trade_state = trade_state;
}
public String getTrade_mode() {
return trade_mode;
}
public void setTrade_mode(String trade_mode) {
this.trade_mode = trade_mode;
}
public String getPartner() {
return partner;
}
public void setPartner(String partner) {
this.partner = partner;
}
public String getBank_type() {
return bank_type;
}
public void setBank_type(String bank_type) {
this.bank_type = bank_type;
}
public String getBank_billno() {
return bank_billno;
}
public void setBank_billno(String bank_billno) {
this.bank_billno = bank_billno;
}
public String getTotal_fee() {
return total_fee;
}
public void setTotal_fee(String total_fee) {
this.total_fee = total_fee;
}
public String getFee_type() {
return fee_type;
}
public void setFee_type(String fee_type) {
this.fee_type = fee_type;
}
public String getTransaction_id() {
return transaction_id;
}
public void setTransaction_id(String transaction_id) {
this.transaction_id = transaction_id;
}
public String getOut_trade_no() {
return out_trade_no;
}
public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public boolean isIs_split() {
return is_split;
}
public void setIs_split(boolean is_split) {
this.is_split = is_split;
}
public boolean isIs_refund() {
return is_refund;
}
public void setIs_refund(boolean is_refund) {
this.is_refund = is_refund;
}
public String getAttach() {
return attach;
}
public void setAttach(String attach) {
this.attach = attach;
}
public String getTime_end() {
return time_end;
}
public void setTime_end(String time_end) {
this.time_end = time_end;
}
public String getTransport_fee() {
return transport_fee;
}
public void setTransport_fee(String transport_fee) {
this.transport_fee = transport_fee;
}
public String getProduct_fee() {
return product_fee;
}
public void setProduct_fee(String product_fee) {
this.product_fee = product_fee;
}
public String getDiscount() {
return discount;
}
public void setDiscount(String discount) {
this.discount = discount;
}
public String getRmb_total_fee() {
return rmb_total_fee;
}
public void setRmb_total_fee(String rmb_total_fee) {
this.rmb_total_fee = rmb_total_fee;
}
private Map<String, String> mapData;
public Map<String, String> getMapData() {
return mapData;
}
public void setMapData(Map<String, String> mapData) {
this.mapData = mapData;
}
@Override
public String toString() {
return "Order [ret_code=" + ret_code + ", ret_msg=" + ret_msg
+ ", input_charset=" + input_charset + ", trade_state="
+ trade_state + ", trade_mode=" + trade_mode + ", partner="
+ partner + ", bank_type=" + bank_type + ", bank_billno="
+ bank_billno + ", total_fee=" + total_fee + ", fee_type="
+ fee_type + ", transaction_id=" + transaction_id
+ ", out_trade_no=" + out_trade_no + ", is_split=" + is_split
+ ", is_refund=" + is_refund + ", attach=" + attach
+ ", time_end=" + time_end + ", transport_fee=" + transport_fee
+ ", product_fee=" + product_fee + ", discount=" + discount
+ ", rmb_total_fee=" + rmb_total_fee + "]";
}
}

View File

@ -0,0 +1,140 @@
package com.foxinmy.weixin4j.mp.payment.v2;
import java.io.Serializable;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 维权POST的数据
*
* @className PayFeedback
* @author jy
* @date 2014年10月29日
* @since JDK 1.7
* @see
*/
@XStreamAlias("xml")
public class PayFeedback implements Serializable {
private static final long serialVersionUID = 7230049346213966310L;
@XStreamAlias("FeedBackId")
private String feedbackId;
@XStreamAlias("OpenId")
private String openId;
@XStreamAlias("TransId")
private String transId;
@XStreamAlias("Reason")
private String reason;
@XStreamAlias("Solution")
private String solution;
@XStreamAlias("ExtInfo")
private String extInfo;
@XStreamAlias("PicInfo")
private String picInfo;
@XStreamAlias("MsgType")
private String status;
@XStreamAlias("AppId")
private String appId;
@XStreamAlias("TimeStamp")
private String timeStamp;
@XStreamAlias("AppSignature")
private String appSignature;
public String getFeedbackId() {
return feedbackId;
}
public void setFeedbackId(String feedbackId) {
this.feedbackId = feedbackId;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getTransId() {
return transId;
}
public void setTransId(String transId) {
this.transId = transId;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public String getSolution() {
return solution;
}
public void setSolution(String solution) {
this.solution = solution;
}
public String getExtInfo() {
return extInfo;
}
public void setExtInfo(String extInfo) {
this.extInfo = extInfo;
}
public String getPicInfo() {
return picInfo;
}
public void setPicInfo(String picInfo) {
this.picInfo = picInfo;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp;
}
public String getAppSignature() {
return appSignature;
}
public void setAppSignature(String appSignature) {
this.appSignature = appSignature;
}
@Override
public String toString() {
return "PayFeedback [feedbackId=" + feedbackId + ", openId=" + openId
+ ", transId=" + transId + ", reason=" + reason + ", solution="
+ solution + ", extInfo=" + extInfo + ", picInfo=" + picInfo
+ ", status=" + status + ", appId=" + appId + ", timeStamp="
+ timeStamp + ", appSignature=" + appSignature + "]";
}
}

View File

@ -0,0 +1,139 @@
package com.foxinmy.weixin4j.mp.payment.v2;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import com.foxinmy.weixin4j.mp.payment.PayPackage;
/**
* 微信支付的订单详情
*
* @className PayPackageV2
* @author jy
* @date 2014年8月17日
* @since JDK 1.7
* @see
*/
public class PayPackageV2 extends PayPackage {
private static final long serialVersionUID = 5557542103637795834L;
// 银行通道类型 固定为"WX" 非空
private String bank_type;
// 商户号 注册时分配的财付通商户号 非空
private String partner;
// 支付币种 默认值是"1" 非空
private String fee_type;
// 物流费用 可为空 如果有值,必须保 transport_fee + product_fee=total_fee传进来的参数按照实际金额即可
// 也就是元为单位
private String transport_fee;
// 商品费用 可为空 商品费用,单位为分如果有值,必须保 transport_fee +
// product_fee=total_fee;传进来的参数按照实际金额即可 也就是元为单位
private String product_fee;
// 传入参数字符编码 取值范围:"GBK""UTF-8",默认:"GBK" 可为空
private String input_charset;
private String goods_tag;// 􏱙􏴱􏲹􏺯􏱮􏺰􏺱􏺲􏱫􏱥􏵧􏲛􏳙􏱙􏴱􏲹􏺯􏱮􏺰􏺱􏺲􏱫􏱥􏵧􏲛􏳙􏱙􏴱􏲹􏺯􏱮􏺰􏺱􏺲􏱫􏱥􏵧􏲛􏳙􏱙􏴱􏲹􏺯􏱮􏺰􏺱􏺲􏱫􏱥􏵧􏲛􏳙􏱙􏴱􏲹􏺯􏱮􏺰􏺱􏺲􏱫􏱥􏵧􏲛􏳙商品标记优惠券可能用到
// 可为空
public String getBank_type() {
return bank_type;
}
public void setBank_type(String bank_type) {
this.bank_type = bank_type;
}
public void setBody(String body) {
super.setBody(StringUtils.isBlank(body) ? "服务费用" : body);
}
public String getPartner() {
return partner;
}
public void setPartner(String partner) {
this.partner = partner;
}
public String getFee_type() {
return fee_type;
}
public void setFee_type(String fee_type) {
this.fee_type = fee_type;
}
public void setNotify_url(String notify_url) {
super.setNotify_url(notify_url);
}
public String getTransport_fee() {
return transport_fee;
}
public void setTransport_fee(double transport_fee) {
this.transport_fee = FEE_FORMAT.format(transport_fee);
}
public String getProduct_fee() {
return product_fee;
}
public void setProduct_fee(double product_fee) {
this.product_fee = FEE_FORMAT.format(product_fee);
}
public String getGoods_tag() {
return goods_tag;
}
public void setGoods_tag(String goods_tag) {
this.goods_tag = goods_tag;
}
public String getInput_charset() {
return input_charset;
}
public void setInput_charset(String input_charset) {
this.input_charset = input_charset;
}
public PayPackageV2() {
this.bank_type = "WX";
this.fee_type = "1";
this.input_charset = "UTF-8";
}
public PayPackageV2(String out_trade_no, double total_fee,
String spbill_create_ip) {
this(null, null, null, out_trade_no, total_fee, null, spbill_create_ip,
null, null, 0d, 0d, null);
}
public PayPackageV2(String body, String out_trade_no, double total_fee,
String spbill_create_ip) {
this(body, null, null, out_trade_no, total_fee, null, spbill_create_ip,
null, null, 0d, 0d, null);
}
public PayPackageV2(String body, String partner, String out_trade_no,
double total_fee, String notify_url, String spbill_create_ip) {
this(body, null, partner, out_trade_no, total_fee, notify_url,
spbill_create_ip, null, null, 0d, 0d, null);
}
public PayPackageV2(String body, String attach, String partner,
String out_trade_no, double total_fee, String notify_url,
String spbill_create_ip, Date time_start, Date time_expire,
double transport_fee, double product_fee, String goods_tag) {
super(body, attach, out_trade_no, total_fee, spbill_create_ip,
time_start, time_expire, goods_tag, notify_url);
this.bank_type = "WX";
this.fee_type = "1";
this.input_charset = "UTF-8";
this.transport_fee = transport_fee > 0d ? FEE_FORMAT
.format(transport_fee * 100) : null;
this.product_fee = product_fee > 0 ? FEE_FORMAT
.format(product_fee * 100) : null;
}
@Override
public String toString() {
return "PayPackageV2 [bank_type=" + bank_type + ", partner=" + partner
+ ", fee_type=" + fee_type + ", transport_fee=" + transport_fee
+ ", product_fee=" + product_fee + ", input_charset="
+ input_charset + ", goods_tag=" + goods_tag
+ ", getBank_type()=" + getBank_type() + ", getPartner()="
+ getPartner() + ", getFee_type()=" + getFee_type()
+ ", getTransport_fee()=" + getTransport_fee()
+ ", getProduct_fee()=" + getProduct_fee()
+ ", getGoods_tag()=" + getGoods_tag()
+ ", getInput_charset()=" + getInput_charset() + "]";
}
}

View File

@ -0,0 +1,52 @@
package com.foxinmy.weixin4j.mp.payment.v3;
import com.foxinmy.weixin4j.mp.payment.ApiResult;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* V3 Native支付回调时POST的信息
*
* @className PayNativeNotifyV3
* @author jy
* @date 2014年10月30日
* @since JDK 1.7
* @see
*/
@XStreamAlias("xml")
public class NativePayNotifyV3 extends ApiResult {
private static final long serialVersionUID = 4515471400239795492L;
@XStreamAlias("mch_id")
private String mchId;
@XStreamAlias("product_id")
private String productId;
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getMchId() {
return mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
@Override
public String toString() {
return "NativePayNotifyV3 [mchId=" + mchId + ", productId=" + productId
+ ", getAppId()=" + getAppId() + ", getNonceStr()="
+ getNonceStr() + ", getSign()=" + getSign()
+ ", getDeviceInfo()=" + getDeviceInfo() + ", toString()="
+ super.toString() + ", getReturnCode()=" + getReturnCode()
+ ", getReturnMsg()=" + getReturnMsg() + ", getResultCode()="
+ getResultCode() + ", getErrCode()=" + getErrCode()
+ ", getErrCodeDes()=" + getErrCodeDes() + "]";
}
}

View File

@ -0,0 +1,58 @@
package com.foxinmy.weixin4j.mp.payment.v3;
import org.apache.commons.lang3.StringUtils;
import com.foxinmy.weixin4j.exception.PayException;
import com.foxinmy.weixin4j.mp.payment.ApiResult;
import com.foxinmy.weixin4j.mp.payment.PayUtil;
import com.foxinmy.weixin4j.util.RandomUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* Native支付响应
*
* @className NativePayResponseV3
* @author jy
* @date 2014年10月28日
* @since JDK 1.7
* @see
*/
@XStreamAlias("xml")
public class NativePayResponseV3 extends ApiResult {
private static final long serialVersionUID = 6119895998783333012L;
private String prepay_id;
public NativePayResponseV3(PayPackageV3 payPackage, String returnMsg,
String resultMsg) throws PayException {
super.setReturnMsg(returnMsg);
super.setReturnCode(StringUtils.isNotBlank(returnMsg) ? FAIL : SUCCESS);
this.setErrCodeDes(resultMsg);
this.setResultCode(StringUtils.isNotBlank(resultMsg) ? FAIL : SUCCESS);
this.setMchId(payPackage.getMch_id());
this.setAppId(payPackage.getAppid());
this.setNonceStr(RandomUtil.generateString(16));
this.prepay_id = PayUtil.createPrePay(payPackage).getPrepayId();
}
public String getPrepay_id() {
return prepay_id;
}
public void setPrepay_id(String prepay_id) {
this.prepay_id = prepay_id;
}
@Override
public String toString() {
return "NativePayResponseV3 [prepay_id=" + prepay_id + ", getAppId()="
+ getAppId() + ", getMchId()=" + getMchId()
+ ", getNonceStr()=" + getNonceStr() + ", getSign()="
+ getSign() + ", getDeviceInfo()=" + getDeviceInfo()
+ ", toString()=" + super.toString() + ", getReturnCode()="
+ getReturnCode() + ", getReturnMsg()=" + getReturnMsg()
+ ", getResultCode()=" + getResultCode() + ", getErrCode()="
+ getErrCode() + ", getErrCodeDes()=" + getErrCodeDes() + "]";
}
}

View File

@ -0,0 +1,172 @@
package com.foxinmy.weixin4j.mp.payment.v3;
import com.foxinmy.weixin4j.mp.payment.ApiResult;
import com.foxinmy.weixin4j.mp.payment.CurrencyType;
import com.foxinmy.weixin4j.mp.payment.TradeState;
import com.foxinmy.weixin4j.mp.payment.TradeType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 订单信息
*
* @className Order
* @author jy
* @date 2014年11月2日
* @since JDK 1.7
* @see
*/
@XStreamAlias("xml")
public class Order extends ApiResult {
private static final long serialVersionUID = 5636828325595317079L;
// SUCCESS支付成功 REFUND转入退款 NOTPAY未支付 CLOSED已关闭 REVOKED已撤销
// USERPAYING--用户支付中 NOPAY--未支付(输入密码或 确认支付超时) PAYERROR--支付失败(其他 原因,如银行返回失败)
// 以下字段在 return_code result_code 都为 SUCCESS 的时候有返回
@XStreamAlias("trade_state")
private TradeState tradeState;
// 用户标识ID
@XStreamAlias("openid")
private String openId;
// 用户是否关注公众账号,Y- 关注,N-未关注,仅在公众 账号类型支付有效
private String isSubscribe;
// 交易类型
@XStreamAlias("trade_type")
private TradeType tradeType;
// 银行类型
@XStreamAlias("bank_type")
private String bankType;
// 订单总金额,单位为分
@XStreamAlias("total_fee")
private int totalFee;
// 现金券支付金额<=订单总金 ,订单总金额-现金券金额 为现金支付金额
@XStreamAlias("coupon_fee")
private int couponFee;
// 货币类型,符合 ISO 4217 标准的三位字母代码,默认人民币:CNY
@XStreamAlias("fee_type")
private CurrencyType feeType;
// 微信支付订单号
@XStreamAlias("transaction_id")
private String transactionId;
// 商户订单号
@XStreamAlias("out_rade_no")
private String outTradeNo;
// 商家数据包
@XStreamAlias("attach")
private String attach;
// 支付完成时间,格式为 yyyyMMddhhmmss
@XStreamAlias("time_end")
private String timeEnd;
public TradeState getTradeState() {
return tradeState;
}
public void setTradeState(TradeState tradeState) {
this.tradeState = tradeState;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getIsSubscribe() {
return isSubscribe;
}
public void setIsSubscribe(String isSubscribe) {
this.isSubscribe = isSubscribe;
}
public TradeType getTradeType() {
return tradeType;
}
public void setTradeType(TradeType tradeType) {
this.tradeType = tradeType;
}
public String getBankType() {
return bankType;
}
public void setBankType(String bankType) {
this.bankType = bankType;
}
public int getTotalFee() {
return totalFee;
}
public void setTotalFee(int totalFee) {
this.totalFee = totalFee;
}
public int getCouponFee() {
return couponFee;
}
public void setCouponFee(int couponFee) {
this.couponFee = couponFee;
}
public CurrencyType getFeeType() {
return feeType;
}
public void setFeeType(CurrencyType feeType) {
this.feeType = feeType;
}
public String getTransactionId() {
return transactionId;
}
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
public String getOutTradeNo() {
return outTradeNo;
}
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
public String getAttach() {
return attach;
}
public void setAttach(String attach) {
this.attach = attach;
}
public String getTimeEnd() {
return timeEnd;
}
public void setTimeEnd(String timeEnd) {
this.timeEnd = timeEnd;
}
@Override
public String toString() {
return "Order [tradeState=" + tradeState + ", openId=" + openId
+ ", isSubscribe=" + isSubscribe + ", tradeType=" + tradeType
+ ", bankType=" + bankType + ", totalFee=" + totalFee
+ ", couponFee=" + couponFee + ", feeType=" + feeType
+ ", transactionId=" + transactionId + ", outTradeNo="
+ outTradeNo + ", attach=" + attach + ", timeEnd=" + timeEnd
+ ", getAppId()=" + getAppId() + ", getMchId()=" + getMchId()
+ ", getNonceStr()=" + getNonceStr() + ", getSign()="
+ getSign() + ", getDeviceInfo()=" + getDeviceInfo()
+ ", toString()=" + super.toString() + ", getReturnCode()="
+ getReturnCode() + ", getReturnMsg()=" + getReturnMsg()
+ ", getResultCode()=" + getResultCode() + ", getErrCode()="
+ getErrCode() + ", getErrCodeDes()=" + getErrCodeDes() + "]";
}
}

View File

@ -0,0 +1,161 @@
package com.foxinmy.weixin4j.mp.payment.v3;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.mp.payment.PayPackage;
import com.foxinmy.weixin4j.mp.payment.TradeType;
import com.foxinmy.weixin4j.util.RandomUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 微信支付V3<br/>
* 注意:
* <font color="red">total_fee字段传入时单位为元,创建支付时会转换为分</font>
* @className PayPackageV3
* @author jy
* @date 2014年10月21日
* @since JDK 1.7
* @see
*/
@XStreamAlias("xml")
public class PayPackageV3 extends PayPackage {
private static final long serialVersionUID = 8944928173669656177L;
private String appid; // 微信分配的公众账号 必须
private String mch_id; // 微信支付分配的商户号 必须
private String device_info; // 微信支付分配的终端设备号 非必须
private String nonce_str; // 随机字符串,不长于 32 必须
private String sign; // 签名 必须
private String trade_type; // 交易类型JSAPINATIVEAPP 必须
private String openid; // 用户在商户 appid 下的唯一 标识, trade_type JSAPI ,此参数必传
private String product_id; // 只在 trade_type NATIVE 时需要填写 非必须
public PayPackageV3() {
}
public PayPackageV3(WeixinAccount weixinAccount, String body,
String out_trade_no, double total_fee, String spbill_create_ip,
TradeType tradeType) {
this(weixinAccount.getAppId(), weixinAccount.getMchId(), null,
RandomUtil.generateString(16), body, null, out_trade_no,
total_fee, spbill_create_ip, null, null, null, null, tradeType,
weixinAccount.getOpenId(), null, weixinAccount.getPaySignKey());
}
public PayPackageV3(WeixinAccount weixinAccount, String body,
String attach, String out_trade_no, double total_fee,
String spbill_create_ip, String notify_url, TradeType tradeType) {
this(weixinAccount.getAppId(), weixinAccount.getMchId(), null, RandomUtil
.generateString(16), body, attach, out_trade_no, total_fee,
spbill_create_ip, null, null, null, notify_url, tradeType,
weixinAccount.getOpenId(), null, weixinAccount.getPaySignKey());
}
public PayPackageV3(String appid, String mch_id, String device_info,
String nonce_str, String body, String attach, String out_trade_no,
double total_fee, String spbill_create_ip, Date time_start,
Date time_expire, String goods_tag, String notify_url,
TradeType tradeType, String openid, String product_id,
String paySignKey) {
super(body, attach, out_trade_no, total_fee, spbill_create_ip,
time_start, time_expire, goods_tag, notify_url);
this.appid = appid;
this.mch_id = mch_id;
this.device_info = device_info;
this.nonce_str = nonce_str;
this.trade_type = tradeType.name();
this.openid = openid;
this.product_id = product_id;
}
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getMch_id() {
return mch_id;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
public String getDevice_info() {
return device_info;
}
public void setDevice_info(String device_info) {
this.device_info = device_info;
}
public String getNonce_str() {
return nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public void setBody(String body) {
super.setBody(StringUtils.isBlank(body) ? "服务费用" : body);
}
public void setNotify_url(String notify_url) {
super.setNotify_url(notify_url);
}
public String getTrade_type() {
return trade_type;
}
public void setTrade_type(TradeType tradeType) {
this.trade_type = tradeType.name();
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getProduct_id() {
return product_id;
}
public void setProduct_id(String product_id) {
this.product_id = product_id;
}
@Override
public String toString() {
return "PayPackageV3 [appid=" + appid + ", mch_id=" + mch_id
+ ", device_info=" + device_info + ", nonce_str=" + nonce_str
+ ", sign=" + sign + ", trade_type=" + trade_type + ", openid="
+ openid + ", product_id=" + product_id + ", getAppid()="
+ getAppid() + ", getMch_id()=" + getMch_id()
+ ", getDevice_info()=" + getDevice_info()
+ ", getNonce_str()=" + getNonce_str() + ", getSign()="
+ getSign() + ", getTrade_type()=" + getTrade_type()
+ ", getOpenid()=" + getOpenid() + ", getProduct_id()="
+ getProduct_id() + "]";
}
}

View File

@ -0,0 +1,62 @@
package com.foxinmy.weixin4j.mp.payment.v3;
import java.beans.Transient;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.exception.PayException;
import com.foxinmy.weixin4j.http.XmlResult;
import com.foxinmy.weixin4j.mp.payment.PayRequest;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
/**
* JS支付:get_brand_wcpay_request<br/>
* <p>
* get_brand_wcpay_request:ok 支付成功<br>
* get_brand_wcpay_request:cancel 支付过程中用户取消<br>
* get_brand_wcpay_request:fail 支付失败
* </p>
* <p>
* NATIVE支付:PayRequest.TradeType=NATIVE
* </p>
*
* @className PayRequestV3
* @author jy
* @date 2014年8月17日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.mp.payment.v3.PayRequestV3.PrePay
*/
public class PayRequestV3 extends PayRequest {
private static final long serialVersionUID = -5972173459255255197L;
@XStreamOmitField
private PrePay prePay;
public PayRequestV3(PrePay prePay) throws PayException {
if (!prePay.getReturnCode().equalsIgnoreCase(XmlResult.SUCCESS)) {
throw new PayException(prePay.getReturnMsg(),
prePay.getReturnCode());
}
if (!prePay.getResultCode().equalsIgnoreCase(XmlResult.SUCCESS)) {
throw new PayException(prePay.getResultCode(),
prePay.getErrCodeDes());
}
this.prePay = prePay;
this.setAppId(prePay.getAppId());
this.setPackageInfo("prepay_id=" + prePay.getPrepayId());
}
@Transient
@JSONField(serialize = false)
public PrePay getPrePay() {
return prePay;
}
@Override
public String toString() {
return "PayRequestV3 [getAppId()=" + getAppId() + ", getTimeStamp()="
+ getTimeStamp() + ", getNonceStr()=" + getNonceStr()
+ ", getPackageInfo()=" + getPackageInfo() + ", getSignType()="
+ getSignType() + "]";
}
}

View File

@ -0,0 +1,73 @@
package com.foxinmy.weixin4j.mp.payment.v3;
import com.foxinmy.weixin4j.mp.payment.ApiResult;
import com.foxinmy.weixin4j.mp.payment.TradeType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 预生成订单信息
*
* @className PrePay
* @author jy
* @date 2014年10月21日
* @since JDK 1.7
* @see
*/
@XStreamAlias("xml")
public class PrePay extends ApiResult {
private static final long serialVersionUID = -8430005768959715444L;
@XStreamAlias("trade_type")
private TradeType tradeType;// 交易类型JSAPINATIVEAPP 非空
@XStreamAlias("prepay_id")
private String prepayId;// 微信生成的预支付 ID,用于后续接口调用中使用二维码链接 非空
@XStreamAlias("code_url")
private String codeUrl;// trade_type NATIVE 是有 返回,此参数可直接生成二 维码展示出来进行扫码支付
// 可能为空
public PrePay() {
}
public PrePay(String returnCode, String returnMsg) {
super(returnCode, returnMsg);
}
public TradeType getTradeType() {
return tradeType;
}
public void setTradeType(TradeType tradeType) {
this.tradeType = tradeType;
}
public String getPrepayId() {
return prepayId;
}
public void setPrepayId(String prepayId) {
this.prepayId = prepayId;
}
public String getCodeUrl() {
return codeUrl;
}
public void setCodeUrl(String codeUrl) {
this.codeUrl = codeUrl;
}
@Override
public String toString() {
return "PrePay [tradeType=" + tradeType + ", prepayId=" + prepayId
+ ", codeUrl=" + codeUrl + ", getAppId()=" + getAppId()
+ ", getMchId()=" + getMchId() + ", getNonceStr()="
+ getNonceStr() + ", getSign()=" + getSign()
+ ", getDeviceInfo()=" + getDeviceInfo() + ", toString()="
+ super.toString() + ", getReturnCode()=" + getReturnCode()
+ ", getReturnMsg()=" + getReturnMsg() + ", getResultCode()="
+ getResultCode() + ", getErrCode()=" + getErrCode()
+ ", getErrCodeDes()=" + getErrCodeDes() + "]";
}
}

View File

@ -0,0 +1,87 @@
package com.foxinmy.weixin4j.mp.payment.v3;
import java.util.List;
import com.foxinmy.weixin4j.mp.payment.ApiResult;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
/**
* 退款记录
*
* @className Refund
* @author jy
* @date 2014年11月1日
* @since JDK 1.7
* @see
*/
@XStreamAlias("xml")
public class Refund extends ApiResult {
private static final long serialVersionUID = -2971132874939642721L;
@XStreamAlias("transaction_id")
private String transactionId;// 微信订单号
@XStreamAlias("out_trade_no")
private String orderNo;// 商户订单号
@XStreamAlias("sub_mch_id")
private String subMchId; //
@XStreamAlias("refund_count")
private int count;// 退款笔数
@XStreamOmitField
private List<RefundDetail> details;
public String getTransactionId() {
return transactionId;
}
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public String getSubMchId() {
return subMchId;
}
public void setSubMchId(String subMchId) {
this.subMchId = subMchId;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public List<RefundDetail> getDetails() {
return details;
}
public void setDetails(List<RefundDetail> details) {
this.details = details;
}
@Override
public String toString() {
return "Refund [transactionId=" + transactionId + ", subMchId="
+ subMchId + ", orderNo=" + orderNo + ", count=" + count
+ ", details=" + details + ", getAppId()=" + getAppId()
+ ", getMchId()=" + getMchId() + ", getNonceStr()="
+ getNonceStr() + ", getSign()=" + getSign()
+ ", getDeviceInfo()=" + getDeviceInfo() + ", toString()="
+ super.toString() + ", getReturnCode()=" + getReturnCode()
+ ", getReturnMsg()=" + getReturnMsg() + ", getResultCode()="
+ getResultCode() + ", getErrCode()=" + getErrCode()
+ ", getErrCodeDes()=" + getErrCodeDes() + "]";
}
}

View File

@ -0,0 +1,89 @@
package com.foxinmy.weixin4j.mp.payment.v3;
import java.io.Serializable;
import com.foxinmy.weixin4j.mp.payment.RefundStatus;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 退款详细
*
* @className RefundDetail
* @author jy
* @date 2014年11月2日
* @since JDK 1.7
* @see
*/
public class RefundDetail implements Serializable {
private static final long serialVersionUID = 2828640496307351988L;
@XStreamAlias("out_refund_no")
private String outRefundNo; // 商户退款单号
@XStreamAlias("refund_id")
private String refundId; // 微信退款单号
@XStreamAlias("refund_channel")
private String refundChannel; // 退款渠道 ORIGINAL原路退款 BALANCE退回到余额
@XStreamAlias("refund_fee")
private int refundFee; // 退款总金额,单位为分,可以做部分退款
@XStreamAlias("coupon_refund_fee")
private int couponRefundFee; // 现金券退款金额<=退款金额,退款金额-现金券退款金额为现金
@XStreamAlias("refund_status")
private RefundStatus refundStatus; // 退款状态
public String getOutRefundNo() {
return outRefundNo;
}
public void setOutRefundNo(String outRefundNo) {
this.outRefundNo = outRefundNo;
}
public String getRefundId() {
return refundId;
}
public void setRefundId(String refundId) {
this.refundId = refundId;
}
public String getRefundChannel() {
return refundChannel;
}
public void setRefundChannel(String refundChannel) {
this.refundChannel = refundChannel;
}
public int getRefundFee() {
return refundFee;
}
public void setRefundFee(int refundFee) {
this.refundFee = refundFee;
}
public int getCouponRefundFee() {
return couponRefundFee;
}
public void setCouponRefundFee(int couponRefundFee) {
this.couponRefundFee = couponRefundFee;
}
public RefundStatus getRefundStatus() {
return refundStatus;
}
public void setRefundStatus(RefundStatus refundStatus) {
this.refundStatus = refundStatus;
}
@Override
public String toString() {
return "RefundDetail [outRefundNo=" + outRefundNo + ", refundId="
+ refundId + ", refundChannel=" + refundChannel
+ ", refundFee=" + refundFee + ", couponRefundFee="
+ couponRefundFee + ", refundStatus=" + refundStatus + "]";
}
}

Some files were not shown because too many files have changed in this diff Show More