weixin-mp & pay
This commit is contained in:
parent
c908581178
commit
45ce10141a
48
README.md
48
README.md
@ -1,36 +1,64 @@
|
||||
weixin4j
|
||||
========
|
||||
|
||||
@(weixin4j)[微信开发]
|
||||
|
||||
微信开发工具包
|
||||
-------------
|
||||
|
||||
功能列表
|
||||
-------
|
||||
* weixin4j-mp
|
||||
|
||||
* 公众平台API封装
|
||||
|
||||
`公众平台API封装`
|
||||
|
||||
`netty构建服务器`
|
||||
|
||||
`微信支付(公众号)`
|
||||
|
||||
* weixin4j-qy
|
||||
`企业号API封装`
|
||||
|
||||
更新LOG
|
||||
-------
|
||||
* 2014-10-27
|
||||
|
||||
1).maven多模块分离
|
||||
+ maven多模块分离
|
||||
|
||||
2).weixin4j-mp:用netty构建http服务器并支持消息分发
|
||||
+ `weixin4j-mp`:用netty构建http服务器并支持消息分发
|
||||
|
||||
* 2014-10-28
|
||||
|
||||
1).weixin4j-mp:调整ActionMapping抽象化
|
||||
+ `weixin4j-mp`:调整`ActionMapping`抽象化
|
||||
|
||||
* 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
26
pom.xml
@ -7,13 +7,35 @@
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<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>
|
||||
<module>weixin4j-base</module>
|
||||
<module>weixin4j-mp</module>
|
||||
<module>weixin4j-qy</module>
|
||||
</modules>
|
||||
<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>
|
||||
<dom4j.version>1.6.1</dom4j.version>
|
||||
<logback.version>1.0.9</logback.version>
|
||||
@ -26,8 +48,10 @@
|
||||
<jsoup.version>1.7.3</jsoup.version>
|
||||
<jaxen.version>1.1.6</jaxen.version>
|
||||
<jedis.version>2.6.0</jedis.version>
|
||||
<poi.version>3.9</poi.version>
|
||||
<netty.version>4.0.23.Final</netty.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>
|
||||
</properties>
|
||||
<build>
|
||||
|
||||
@ -1,12 +1,21 @@
|
||||
weixin4j-base
|
||||
=============
|
||||
|
||||
tencent weixin base java sdk 微信开发基础工程
|
||||
@(weixin4j)[base]
|
||||
|
||||
微信开发基础工程
|
||||
--------------
|
||||
|
||||
功能列表
|
||||
-------
|
||||
`Token的实现`
|
||||
|
||||
`通用消息实体`
|
||||
|
||||
更新LOG
|
||||
-------
|
||||
* 2014-10-31
|
||||
|
||||
1).TokenApi重命名为TokenHolder
|
||||
+ `TokenApi`重命名为`TokenHolder`
|
||||
|
||||
2).新增WeixinConfig等类
|
||||
+ 新增`WeixinConfig`等类
|
||||
@ -10,7 +10,10 @@
|
||||
</parent>
|
||||
<artifactId>weixin4j-base</artifactId>
|
||||
<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>
|
||||
<dependency>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
|
||||
@ -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 + "]";
|
||||
}
|
||||
}
|
||||
@ -46,6 +46,7 @@ import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
* @see
|
||||
*/
|
||||
public class HttpRequest {
|
||||
private final String SUCCESS = "success";
|
||||
private AbstractHttpClient client;
|
||||
|
||||
public HttpRequest() {
|
||||
@ -149,6 +150,7 @@ public class HttpRequest {
|
||||
|
||||
protected Response doRequest(HttpRequestBase request)
|
||||
throws WeixinException {
|
||||
Response response = null;
|
||||
try {
|
||||
HttpResponse httpResponse = client.execute(request);
|
||||
StatusLine statusLine = httpResponse.getStatusLine();
|
||||
@ -166,38 +168,47 @@ public class HttpRequest {
|
||||
httpResponse.getFirstHeader("location")));
|
||||
}
|
||||
byte[] data = EntityUtils.toByteArray(httpEntity);
|
||||
Response response = new Response();
|
||||
response = new Response();
|
||||
response.setBody(data);
|
||||
response.setStatusCode(status);
|
||||
response.setStatusText(statusLine.getReasonPhrase());
|
||||
response.setStream(new ByteArrayInputStream(data));
|
||||
response.setText(new String(data, StandardCharsets.UTF_8));
|
||||
|
||||
EntityUtils.consume(httpEntity);
|
||||
Header contentType = httpResponse
|
||||
.getFirstHeader(HttpHeaders.CONTENT_TYPE);
|
||||
if (contentType.getValue().contains(
|
||||
ContentType.APPLICATION_JSON.getMimeType())
|
||||
|| contentType.getValue().contains(
|
||||
ContentType.TEXT_PLAIN.getMimeType())) {
|
||||
BaseResult result = null;
|
||||
response.setText(new String(data, StandardCharsets.UTF_8));
|
||||
try {
|
||||
result = response.getAsResult();
|
||||
} catch (JSONException e) {
|
||||
result = response.getAsXml(BaseResult.class);
|
||||
}
|
||||
if (result.getErrcode().equals("0")
|
||||
|| result.getErrcode().equalsIgnoreCase("success")) {
|
||||
EntityUtils.consume(httpEntity);
|
||||
JsonResult jsonResult = response.getAsJsonResult();
|
||||
response.setJsonResult(true);
|
||||
if (jsonResult.getCode() != 0) {
|
||||
throw new WeixinException(jsonResult.getCode() + "",
|
||||
jsonResult.getDesc());
|
||||
}
|
||||
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) {
|
||||
throw new WeixinException(e.getMessage());
|
||||
} finally {
|
||||
request.releaseConnection();
|
||||
}
|
||||
throw new WeixinException("-1", "request fail");
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
+ "]";
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,7 @@ import org.dom4j.io.SAXReader;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.foxinmy.weixin4j.xml.XStream;
|
||||
|
||||
public class Response {
|
||||
@ -18,6 +19,8 @@ public class Response {
|
||||
private String statusText;
|
||||
private byte[] body;
|
||||
private InputStream stream;
|
||||
private boolean isJsonResult;
|
||||
private boolean isXmlResult;
|
||||
|
||||
public Response() {
|
||||
}
|
||||
@ -26,26 +29,40 @@ public class Response {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public void setJsonResult(boolean isJsonResult) {
|
||||
this.isJsonResult = isJsonResult;
|
||||
}
|
||||
|
||||
public void setXmlResult(boolean isXmlResult) {
|
||||
this.isXmlResult = isXmlResult;
|
||||
}
|
||||
|
||||
public String getAsString() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public BaseResult getAsResult() {
|
||||
return JSON.parseObject(text, BaseResult.class);
|
||||
public JsonResult getAsJsonResult() {
|
||||
return JSON.parseObject(text, JsonResult.class);
|
||||
}
|
||||
|
||||
public JSONObject getAsJson() {
|
||||
return JSON.parseObject(text);
|
||||
}
|
||||
|
||||
public <T> T getAsObject(Class<T> clazz) {
|
||||
return (T) JSON.parseObject(text, clazz);
|
||||
public <T> T getAsObject(TypeReference<T> typeReference) {
|
||||
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) {
|
||||
XStream xStream = XStream.get();
|
||||
xStream.processAnnotations(clazz);
|
||||
return xStream.fromXML(text, clazz);
|
||||
public XmlResult getAsXmlResult() {
|
||||
return XStream.get(text, XmlResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,24 +73,22 @@ public class Response {
|
||||
* @return
|
||||
* @throws DocumentException
|
||||
*/
|
||||
public BaseResult getBaseError() throws DocumentException {
|
||||
BaseResult result = getAsResult();
|
||||
if (!result.getErrcode().equals("0")) {
|
||||
public JsonResult getTextError() throws DocumentException {
|
||||
JsonResult result = getAsJsonResult();
|
||||
if (result.getCode() != 0) {
|
||||
SAXReader reader = new SAXReader();
|
||||
Document doc = reader.read(Response.class.getResourceAsStream("error.xml"));
|
||||
Document doc = reader.read(Response.class
|
||||
.getResourceAsStream("error.xml"));
|
||||
Node node = doc.getRootElement().selectSingleNode(
|
||||
String.format("error[@code='%s']", result.getErrcode()));
|
||||
String.format("error/code[text()='%d']", result.getCode()));
|
||||
if (node != null) {
|
||||
result.setText(node.getStringValue());
|
||||
result.setText(node.getParent().selectSingleNode("text")
|
||||
.getStringValue());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@ -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 + "]";
|
||||
}
|
||||
}
|
||||
@ -1,97 +1,427 @@
|
||||
<?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 -->
|
||||
<errors>
|
||||
<error code="-1">系统繁忙</error>
|
||||
<error code="40001">获取access_token时AppSecret错误,或者access_token无效</error>
|
||||
<error code="40002">不合法的凭证类型</error>
|
||||
<error code="40003">不合法的OpenID</error>
|
||||
<error code="40004">不合法的媒体文件类型</error>
|
||||
<error code="40005">不合法的文件类型</error>
|
||||
<error code="40006">不合法的文件大小</error>
|
||||
<error code="40007">不合法的媒体文件id</error>
|
||||
<error code="40008">不合法的消息类型</error>
|
||||
<error code="40009">不合法的图片文件大小</error>
|
||||
<error code="40010">不合法的语音文件大小</error>
|
||||
<error code="40011">不合法的视频文件大小</error>
|
||||
<error code="40012">不合法的缩略图文件大小</error>
|
||||
<error code="40013">不合法的APPID</error>
|
||||
<error code="40014">不合法的access_token</error>
|
||||
<error code="40015">不合法的菜单类型</error>
|
||||
<error code="40016">不合法的按钮个数</error>
|
||||
<error code="40017">不合法的按钮个数</error>
|
||||
<error code="40018">不合法的按钮名字长度</error>
|
||||
<error code="40019">不合法的按钮KEY长度</error>
|
||||
<error code="40020">不合法的按钮URL长度</error>
|
||||
<error code="40021">不合法的菜单版本号</error>
|
||||
<error code="40022">不合法的子菜单级数</error>
|
||||
<error code="40023">不合法的子菜单按钮个数</error>
|
||||
<error code="40024">不合法的子菜单按钮类型</error>
|
||||
<error code="40025">不合法的子菜单按钮名字长度</error>
|
||||
<error code="40026">不合法的子菜单按钮KEY长度</error>
|
||||
<error code="40027">不合法的子菜单按钮URL长度</error>
|
||||
<error code="40028">不合法的自定义菜单使用用户</error>
|
||||
<error code="40029">不合法的oauth_code</error>
|
||||
<error code="40030">不合法的refresh_token</error>
|
||||
<error code="40031">不合法的openid列表</error>
|
||||
<error code="40032">不合法的openid列表长度</error>
|
||||
<error code="40033">不合法的请求字符,不能包含\uxxxx格式的字符</error>
|
||||
<error code="40035">不合法的参数</error>
|
||||
<error code="40038">不合法的请求格式</error>
|
||||
<error code="40039">不合法的URL长度</error>
|
||||
<error code="40050">不合法的分组id</error>
|
||||
<error code="40051">分组名字不合法</error>
|
||||
<error code="41001">缺少access_token参数</error>
|
||||
<error code="41002">缺少appid参数</error>
|
||||
<error code="41003">缺少refresh_token参数</error>
|
||||
<error code="41004">缺少secret参数</error>
|
||||
<error code="41005">缺少多媒体文件数据</error>
|
||||
<error code="41006">缺少media_id参数</error>
|
||||
<error code="41007">缺少子菜单数据</error>
|
||||
<error code="41008">缺少oauth code</error>
|
||||
<error code="41009">缺少openid</error>
|
||||
<error code="42001">access_token超时</error>
|
||||
<error code="42002">refresh_token超时</error>
|
||||
<error code="42003">oauth_code超时</error>
|
||||
<error code="43001">需要GET请求</error>
|
||||
<error code="43002">需要POST请求</error>
|
||||
<error code="43003">需要HTTPS请求</error>
|
||||
<error code="43004">需要接收者关注</error>
|
||||
<error code="43005">需要好友关系</error>
|
||||
<error code="44001">多媒体文件为空</error>
|
||||
<error code="44002">POST的数据包为空</error>
|
||||
<error code="44003">图文消息内容为空</error>
|
||||
<error code="44004">文本消息内容为空</error>
|
||||
<error code="45001">多媒体文件大小超过限制</error>
|
||||
<error code="45002">消息内容超过限制</error>
|
||||
<error code="45003">标题字段超过限制</error>
|
||||
<error code="45004">描述字段超过限制</error>
|
||||
<error code="45005">链接字段超过限制</error>
|
||||
<error code="45006">图片链接字段超过限制</error>
|
||||
<error code="45007">语音播放时间超过限制</error>
|
||||
<error code="45008">图文消息超过限制</error>
|
||||
<error code="45009">接口调用超过限制</error>
|
||||
<error code="45010">创建菜单个数超过限制</error>
|
||||
<error code="45015">回复时间超过限制</error>
|
||||
<error code="45016">系统分组,不允许修改</error>
|
||||
<error code="45017">分组名字过长</error>
|
||||
<error code="45018">分组数量超过上限</error>
|
||||
<error code="46001">不存在媒体数据</error>
|
||||
<error code="46002">不存在的菜单版本</error>
|
||||
<error code="46003">不存在的菜单数据</error>
|
||||
<error code="46004">不存在的用户</error>
|
||||
<error code="47001">解析JSON/XML内容错误</error>
|
||||
<error code="48001">api功能未授权</error>
|
||||
<error code="50001">用户未授权该api</error>
|
||||
<error code="SYSTEMERROR">接口后台错误</error>
|
||||
<error code="INVALID_TRANSACTIONID">无效 transaction_id</error>
|
||||
<error code="PARAM_ERROR">提交参数错误</error>
|
||||
<error code="ORDERPAID">订单已支付</error>
|
||||
<error code="OUT_TRADE_NO_USED">商户订单号重复</error>
|
||||
<error code="NOAUTH">商户无权限</error>
|
||||
<error code="NOTENOUGH">余额不足</error>
|
||||
<error code="NOTSUPORTCARD">不支持卡类型</error>
|
||||
<error code="ORDERCLOSED">订单已关闭</error>
|
||||
<error code="BANKERROR">银行系统异常</error>
|
||||
<error code="REFUND_FEE_INVALID">退款金额大于支付金额</error>
|
||||
<error code="ORDERNOTEXIST">订单不存在</error>
|
||||
<error>
|
||||
<code>0</code>
|
||||
<desc>OK</desc>
|
||||
<text>请求成功</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>-1</code>
|
||||
<desc>system error</desc>
|
||||
<text>系统繁忙</text>
|
||||
</error>
|
||||
<!-- 公众平台API错误 -->
|
||||
<error>
|
||||
<code>40001</code>
|
||||
<desc>invalid credential</desc>
|
||||
<text>不合法的调用凭证</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40002</code>
|
||||
<desc>invalid grant_type</desc>
|
||||
<text>不合法的grant_type</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40003</code>
|
||||
<desc>invalid openid</desc>
|
||||
<text>不合法的OpenID</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40004</code>
|
||||
<desc>invalid media type</desc>
|
||||
<text>不合法的媒体文件类型</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40007</code>
|
||||
<desc>invalid media_id</desc>
|
||||
<text>不合法的media_id</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40008</code>
|
||||
<desc>invalid message type</desc>
|
||||
<text>不合法的message_type</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40009</code>
|
||||
<desc>invalid image size</desc>
|
||||
<text>不合法的图片大小</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40010</code>
|
||||
<desc>invalid voice size</desc>
|
||||
<text>不合法的语音大小</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40011</code>
|
||||
<desc>invalid video size</desc>
|
||||
<text>不合法的视频大小</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40012</code>
|
||||
<desc>invalid thumb size</desc>
|
||||
<text>不合法的缩略图大小</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40013</code>
|
||||
<desc>invalid appid</desc>
|
||||
<text>不合法的AppID</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40014</code>
|
||||
<desc>invalid access_token</desc>
|
||||
<text>不合法的access_token</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40015</code>
|
||||
<desc>invalid menu type</desc>
|
||||
<text>不合法的菜单类型</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40016</code>
|
||||
<desc>invalid button size</desc>
|
||||
<text>不合法的菜单按钮个数</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40017</code>
|
||||
<desc>invalid button type</desc>
|
||||
<text>不合法的按钮类型</text>
|
||||
</error>
|
||||
<error>
|
||||
<code>40018</code>
|
||||
<desc>invalid button name size</desc>
|
||||
<text>不合法的按钮名称长度</text>
|
||||
</error>
|
||||
<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>
|
||||
@ -3,22 +3,72 @@ package com.foxinmy.weixin4j.model;
|
||||
/**
|
||||
* 微信账户信息
|
||||
*
|
||||
* @className WeixinAccountV2
|
||||
* @className WeixinAccount
|
||||
* @author jy
|
||||
* @date 2014年8月17日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class WeixinAccount extends WeixinAccountV2 {
|
||||
public class WeixinAccount extends WeixinConfig {
|
||||
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 isService;
|
||||
// 是否是订阅号
|
||||
private boolean isSubscribe = true;
|
||||
// 微信支付商户号
|
||||
private String mchId;
|
||||
private boolean isSubscribe;
|
||||
|
||||
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() {
|
||||
return isAlive;
|
||||
@ -39,46 +89,28 @@ public class WeixinAccount extends WeixinAccountV2 {
|
||||
public boolean getIsSubscribe() {
|
||||
return isSubscribe;
|
||||
}
|
||||
public String getMchId() {
|
||||
return mchId;
|
||||
}
|
||||
public void setMchId(String mchId) {
|
||||
this.mchId = mchId;
|
||||
}
|
||||
|
||||
public void setIsSubscribe(Boolean isSubscribe) {
|
||||
this.isSubscribe = isSubscribe;
|
||||
}
|
||||
|
||||
public WeixinAccount() {
|
||||
|
||||
}
|
||||
|
||||
public WeixinAccount(boolean isAlive, boolean isService,
|
||||
boolean isSubscribe, String token, String openId) {
|
||||
super.setToken(token);
|
||||
super.setOpenId(openId);
|
||||
this.isAlive = isAlive;
|
||||
this.isService = isService;
|
||||
this.isSubscribe = isSubscribe;
|
||||
public WeixinAccount(String appId, String appSecret, String paySignKey,
|
||||
String mchId) {
|
||||
super(appId, appSecret);
|
||||
this.paySignKey = paySignKey;
|
||||
this.mchId = mchId;
|
||||
}
|
||||
|
||||
public WeixinAccount(boolean isAlive, boolean isService,
|
||||
boolean isSubscribe, String token, String openId, String appId,
|
||||
String appSecret) {
|
||||
super.setToken(token);
|
||||
super.setOpenId(openId);
|
||||
super.setAppId(appId);
|
||||
super.setAppSecret(appSecret);
|
||||
this.isAlive = isAlive;
|
||||
this.isService = isService;
|
||||
this.isSubscribe = isSubscribe;
|
||||
public WeixinAccount(String appId, String appSecret, String paySignKey,
|
||||
String partnerId, String partnerKey) {
|
||||
super(appId, appSecret);
|
||||
this.paySignKey = paySignKey;
|
||||
this.partnerId = partnerId;
|
||||
this.partnerKey = partnerKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WeixinAccount [isAlive=" + isAlive + ", isService=" + isService
|
||||
+ ", isSubscribe=" + isSubscribe + ", mchId=" + mchId
|
||||
+ ", getIsAlive()=" + getIsAlive() + ", getIsService()="
|
||||
+ getIsService() + ", getIsSubscribe()=" + getIsSubscribe()
|
||||
+ ", getMchId()=" + getMchId() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@ -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() + "]";
|
||||
}
|
||||
}
|
||||
@ -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() + "]";
|
||||
}
|
||||
}
|
||||
@ -13,40 +13,48 @@ public class WeixinConfig implements Serializable {
|
||||
private String appId;
|
||||
// 除了支付请求需要用到 paySignKey,公众平台接口 API 的权限获取所需密 钥 Key
|
||||
private String appSecret;
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String getOpenId() {
|
||||
return openId;
|
||||
}
|
||||
|
||||
public void setOpenId(String openId) {
|
||||
this.openId = openId;
|
||||
}
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
|
||||
public String getAppSecret() {
|
||||
return appSecret;
|
||||
}
|
||||
|
||||
public void setAppSecret(String appSecret) {
|
||||
this.appSecret = appSecret;
|
||||
}
|
||||
|
||||
public WeixinConfig() {
|
||||
|
||||
}
|
||||
public WeixinConfig(String token, String openId, String appId,
|
||||
String appSecret) {
|
||||
this.token = token;
|
||||
this.openId = openId;
|
||||
|
||||
public WeixinConfig(String appId, String appSecret) {
|
||||
this.appId = appId;
|
||||
this.appSecret = appSecret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WeixinConfig [token=" + token + ", openId=" + openId
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
package com.foxinmy.weixin4j.token;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.foxinmy.weixin4j.http.HttpRequest;
|
||||
import com.foxinmy.weixin4j.model.WeixinConfig;
|
||||
import com.foxinmy.weixin4j.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* 获取config.properties中的appid&appsecret信息
|
||||
* 获取weixin.properties中的appid&appsecret信息
|
||||
*
|
||||
* @className AbstractTokenApi
|
||||
* @className AbstractTokenHolder
|
||||
* @author jy
|
||||
* @date 2014年10月6日
|
||||
* @since JDK 1.7
|
||||
@ -17,18 +16,25 @@ import com.foxinmy.weixin4j.util.ConfigUtil;
|
||||
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 HttpRequest request = new HttpRequest();
|
||||
private final WeixinConfig weixinConfig;
|
||||
private final String appid;
|
||||
private final String appsecret;
|
||||
|
||||
public AbstractTokenHolder() {
|
||||
weixinConfig = JSON.parseObject(ConfigUtil.getValue("account"),
|
||||
WeixinConfig.class);
|
||||
WeixinConfig weixinConfig = ConfigUtil.getWeixinConfig();
|
||||
this.appid = weixinConfig.getAppId();
|
||||
this.appsecret = weixinConfig.getAppSecret();
|
||||
}
|
||||
|
||||
public AbstractTokenHolder(String appid, String appsecret) {
|
||||
this.appid = appid;
|
||||
this.appsecret = appsecret;
|
||||
}
|
||||
|
||||
protected String getAppid() {
|
||||
return weixinConfig.getAppId();
|
||||
return this.appid;
|
||||
}
|
||||
|
||||
protected String getAppsecret() {
|
||||
return weixinConfig.getAppSecret();
|
||||
return this.appsecret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
package com.foxinmy.weixin4j.token;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Calendar;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
import com.foxinmy.weixin4j.http.Response;
|
||||
import com.foxinmy.weixin4j.model.Token;
|
||||
@ -26,17 +28,12 @@ import com.foxinmy.weixin4j.xml.XStream;
|
||||
*/
|
||||
public class FileTokenHolder extends AbstractTokenHolder {
|
||||
|
||||
private final String appid;
|
||||
private final String appsecret;
|
||||
|
||||
public FileTokenHolder() {
|
||||
this.appid = getAppid();
|
||||
this.appsecret = getAppsecret();
|
||||
super();
|
||||
}
|
||||
|
||||
public FileTokenHolder(String appid, String appsecret) {
|
||||
this.appid = appid;
|
||||
this.appsecret = appsecret;
|
||||
super(appid, appsecret);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -53,12 +50,12 @@ public class FileTokenHolder extends AbstractTokenHolder {
|
||||
*/
|
||||
@Override
|
||||
public Token getToken() throws WeixinException {
|
||||
String appid = getAppid();
|
||||
String appsecret = getAppsecret();
|
||||
if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) {
|
||||
throw new IllegalArgumentException(
|
||||
"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",
|
||||
ConfigUtil.getValue("token_path"), appid));
|
||||
Token token = null;
|
||||
@ -66,7 +63,8 @@ public class FileTokenHolder extends AbstractTokenHolder {
|
||||
long now_time = ca.getTimeInMillis();
|
||||
try {
|
||||
if (token_file.exists()) {
|
||||
token = (Token) xstream.fromXML(token_file);
|
||||
token = XStream.get(new FileInputStream(token_file),
|
||||
Token.class);
|
||||
|
||||
long expise_time = token.getTime()
|
||||
+ (token.getExpiresIn() * 1000) - 3;
|
||||
@ -74,23 +72,18 @@ public class FileTokenHolder extends AbstractTokenHolder {
|
||||
return token;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
token_file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
token_file.getParentFile().mkdirs();
|
||||
}
|
||||
token_file.createNewFile();
|
||||
}
|
||||
String api_token_uri = String.format(
|
||||
tokenUrl, appid, appsecret);
|
||||
String api_token_uri = String.format(tokenUrl, appid, appsecret);
|
||||
Response response = request.get(api_token_uri);
|
||||
token = response.getAsObject(Token.class);
|
||||
token = response.getAsObject(new TypeReference<Token>() {
|
||||
});
|
||||
token.setTime(now_time);
|
||||
token.setOpenid(appid);
|
||||
xstream.toXML(token, new FileOutputStream(token_file));
|
||||
return token;
|
||||
XStream.to(token, new FileOutputStream(token_file));
|
||||
} catch (IOException e) {
|
||||
;
|
||||
throw new WeixinException("-1", "IO ERROR");
|
||||
}
|
||||
throw new WeixinException("-1", "request fail");
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
import com.foxinmy.weixin4j.model.Token;
|
||||
|
||||
@ -22,13 +23,10 @@ import com.foxinmy.weixin4j.model.Token;
|
||||
*/
|
||||
public class RedisTokenHolder extends AbstractTokenHolder {
|
||||
|
||||
private final String appid;
|
||||
private final String appsecret;
|
||||
private JedisPool jedisPool;
|
||||
|
||||
public RedisTokenHolder() {
|
||||
this.appid = getAppid();
|
||||
this.appsecret = getAppsecret();
|
||||
super();
|
||||
}
|
||||
|
||||
public RedisTokenHolder(String appid, String appsecret) {
|
||||
@ -37,8 +35,7 @@ public class RedisTokenHolder extends AbstractTokenHolder {
|
||||
|
||||
public RedisTokenHolder(String appid, String appsecret, String host,
|
||||
int port) {
|
||||
this.appid = appid;
|
||||
this.appsecret = appsecret;
|
||||
super(appid, appsecret);
|
||||
JedisPoolConfig poolConfig = new JedisPoolConfig();
|
||||
poolConfig.setMaxTotal(50);
|
||||
poolConfig.setMaxIdle(5);
|
||||
@ -50,6 +47,8 @@ public class RedisTokenHolder extends AbstractTokenHolder {
|
||||
|
||||
@Override
|
||||
public Token getToken() throws WeixinException {
|
||||
String appid = getAppid();
|
||||
String appsecret = getAppsecret();
|
||||
if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) {
|
||||
throw new IllegalArgumentException(
|
||||
"appid or appsecret not be null!");
|
||||
@ -63,7 +62,9 @@ public class RedisTokenHolder extends AbstractTokenHolder {
|
||||
if (StringUtils.isBlank(accessToken)) {
|
||||
String api_token_uri = String
|
||||
.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,
|
||||
token.getAccessToken());
|
||||
} else {
|
||||
|
||||
@ -6,6 +6,14 @@ import java.net.URL;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 对class的获取
|
||||
* @className ClassUtil
|
||||
* @author jy
|
||||
* @date 2014年10月31日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class ClassUtil {
|
||||
|
||||
public static Set<Class<?>> getClasses(Package _package) {
|
||||
|
||||
@ -1,27 +1,46 @@
|
||||
package com.foxinmy.weixin4j.util;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import java.io.File;
|
||||
import java.util.ResourceBundle;
|
||||
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 {
|
||||
private static Properties props = new Properties();
|
||||
private static ResourceBundle weixin;
|
||||
static {
|
||||
try {
|
||||
props.load(Thread.currentThread().getContextClassLoader()
|
||||
.getResourceAsStream("weixin.properties"));
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
weixin = ResourceBundle.getBundle("weixin");
|
||||
Set<String> keySet = weixin.keySet();
|
||||
for (String key : keySet) {
|
||||
if (!key.endsWith("_path")) {
|
||||
continue;
|
||||
}
|
||||
new File(getValue(key)).mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getValue(String key) {
|
||||
return props.getProperty(key);
|
||||
return weixin.getString(key);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(getValue("api_token_uri"));
|
||||
public static WeixinAccount getWeixinAccount() {
|
||||
String text = getValue("account");
|
||||
return JSON.parseObject(text, WeixinAccount.class);
|
||||
}
|
||||
|
||||
public static WeixinConfig getWeixinConfig() {
|
||||
String text = getValue("account");
|
||||
return JSON.parseObject(text, WeixinConfig.class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,14 @@ import com.foxinmy.weixin4j.type.EventType;
|
||||
import com.foxinmy.weixin4j.type.MessageType;
|
||||
import com.foxinmy.weixin4j.xml.XStream;
|
||||
|
||||
/**
|
||||
* 消息工具类
|
||||
* @className MessageUtil
|
||||
* @author jy
|
||||
* @date 2014年10月31日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class MessageUtil {
|
||||
|
||||
private final static Logger log = LoggerFactory
|
||||
@ -111,10 +119,7 @@ public class MessageUtil {
|
||||
messageClass = EventType.valueOf(type.toLowerCase())
|
||||
.getEventClass();
|
||||
}
|
||||
XStream xstream = XStream.get();
|
||||
xstream.processAnnotations(messageClass);
|
||||
xstream.alias("xml", messageClass);
|
||||
return xstream.fromXML(xmlMsg, messageClass);
|
||||
return XStream.get(xmlMsg, messageClass);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,16 @@
|
||||
package com.foxinmy.weixin4j.xml;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.HashMap;
|
||||
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.UnmarshallingContext;
|
||||
import com.thoughtworks.xstream.converters.collections.MapConverter;
|
||||
import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||
import com.thoughtworks.xstream.mapper.Mapper;
|
||||
|
||||
@ -15,13 +20,26 @@ public class Map2ObjectConverter extends MapConverter {
|
||||
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
|
||||
public void marshal(Object source, HierarchicalStreamWriter writer,
|
||||
MarshallingContext context) {
|
||||
Map<?, ?> map = (Map<?, ?>) source;
|
||||
for (Iterator<?> iterator = map.entrySet().iterator(); iterator
|
||||
.hasNext();) {
|
||||
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) iterator.next();
|
||||
for (Entry<?, ?> entry : map.entrySet()) {
|
||||
if (StringUtils.isBlank((String) entry.getValue())) {
|
||||
continue;
|
||||
}
|
||||
ExtendedHierarchicalStreamWriterHelper.startNode(writer, entry
|
||||
.getKey().toString(), entry.getClass());
|
||||
writer.setValue(entry.getValue().toString());
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.foxinmy.weixin4j.xml;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
|
||||
import com.thoughtworks.xstream.core.util.QuickWriter;
|
||||
@ -50,4 +51,34 @@ public class XStream extends com.thoughtworks.xstream.XStream {
|
||||
xstream.autodetectAnnotations(true);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,66 +1,52 @@
|
||||
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
|
||||
|
||||
* NotifyApi 客服消息API
|
||||
|
||||
* MassApi 群发消息API
|
||||
|
||||
* UserApi 用户管理API
|
||||
|
||||
* GroupApi 分组管理API
|
||||
|
||||
* MenuApi 底部菜单API
|
||||
|
||||
* QrApi 二维码API
|
||||
|
||||
* TmplApi 模板消息API
|
||||
|
||||
* HelperApi 辅助API
|
||||
|
||||
* 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
|
||||
+ MediaApi `上传/下载媒体文件API`
|
||||
|
||||
+ NotifyApi `客服消息API`
|
||||
|
||||
+ MassApi `群发消息API`
|
||||
|
||||
+ UserApi `用户管理API`
|
||||
|
||||
+ GroupApi `分组管理API`
|
||||
|
||||
+ MenuApi `底部菜单API`
|
||||
|
||||
+ QrApi `二维码API`
|
||||
|
||||
+ TmplApi `模板消息API`
|
||||
|
||||
+ HelperApi `辅助API`
|
||||
|
||||
* weixin4j-mp-server
|
||||
`netty服务器 & 消息分发`
|
||||
|
||||
更新LOG
|
||||
-------
|
||||
* 2014-10-27
|
||||
|
||||
1).用netty构建http服务器并支持消息分发
|
||||
+ 用netty构建http服务器并支持消息分发
|
||||
|
||||
* 2014-10-28
|
||||
|
||||
1).调整ActionMapping抽象化
|
||||
+ 调整`ActionMapping`抽象化
|
||||
|
||||
* 2014-10-31
|
||||
|
||||
1).weixin.properties切分为API调用地址/公众号信息两部分
|
||||
+ `weixin.properties`切分为API调用地址/公众号信息两部分
|
||||
|
||||
* 2014-11-03
|
||||
|
||||
+ `weixin-mp`分离为`weixin-mp-api`和`weixin-mp-server`两个工程
|
||||
|
||||
+ `weixin-mp`:加入支付模块
|
||||
@ -8,54 +8,23 @@
|
||||
<artifactId>weixin4j</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>com.foxinmy.weixin</groupId>
|
||||
<artifactId>weixin4j-mp</artifactId>
|
||||
<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>
|
||||
<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>
|
||||
</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>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.foxinmy.weixin4j</groupId>
|
||||
<artifactId>weixin4j-base</artifactId>
|
||||
<version>${weixin4j.version}</version>
|
||||
<version>${weixin4j.base.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
28
weixin4j-mp/weixin4j-mp-api/.gitignore
vendored
Normal file
28
weixin4j-mp/weixin4j-mp-api/.gitignore
vendored
Normal 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
|
||||
87
weixin4j-mp/weixin4j-mp-api/README.md
Normal file
87
weixin4j-mp/weixin4j-mp-api/README.md
Normal 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`两个工程
|
||||
|
||||
+ 加入支付模块
|
||||
59
weixin4j-mp/weixin4j-mp-api/pom.xml
Normal file
59
weixin4j-mp/weixin4j-mp-api/pom.xml
Normal 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>
|
||||
@ -2,13 +2,14 @@ package com.foxinmy.weixin4j.mp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
import com.foxinmy.weixin4j.http.BaseResult;
|
||||
import com.foxinmy.weixin4j.model.WeixinAccountV2;
|
||||
import com.foxinmy.weixin4j.model.WeixinAccountV3;
|
||||
import com.foxinmy.weixin4j.http.JsonResult;
|
||||
import com.foxinmy.weixin4j.http.XmlResult;
|
||||
import com.foxinmy.weixin4j.model.WeixinAccount;
|
||||
import com.foxinmy.weixin4j.mp.api.GroupApi;
|
||||
import com.foxinmy.weixin4j.mp.api.HelperApi;
|
||||
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.BaseMsg;
|
||||
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.v3.Refund;
|
||||
import com.foxinmy.weixin4j.mp.response.TemplateMessage;
|
||||
import com.foxinmy.weixin4j.token.FileTokenHolder;
|
||||
import com.foxinmy.weixin4j.token.TokenHolder;
|
||||
@ -74,17 +79,17 @@ public class WeixinProxy {
|
||||
this(new FileTokenHolder(appid, appsecret));
|
||||
}
|
||||
|
||||
public WeixinProxy(TokenHolder tokenApi) {
|
||||
this.mediaApi = new MediaApi(tokenApi);
|
||||
this.notifyApi = new NotifyApi(tokenApi);
|
||||
this.massApi = new MassApi(tokenApi);
|
||||
this.userApi = new UserApi(tokenApi);
|
||||
this.groupApi = new GroupApi(tokenApi);
|
||||
this.menuApi = new MenuApi(tokenApi);
|
||||
this.qrApi = new QrApi(tokenApi);
|
||||
this.tmplApi = new TmplApi(tokenApi);
|
||||
this.helperApi = new HelperApi(tokenApi);
|
||||
this.payApi = new PayApi(tokenApi);
|
||||
public WeixinProxy(TokenHolder tokenHolder) {
|
||||
this.mediaApi = new MediaApi(tokenHolder);
|
||||
this.notifyApi = new NotifyApi(tokenHolder);
|
||||
this.massApi = new MassApi(tokenHolder);
|
||||
this.userApi = new UserApi(tokenHolder);
|
||||
this.groupApi = new GroupApi(tokenHolder);
|
||||
this.menuApi = new MenuApi(tokenHolder);
|
||||
this.qrApi = new QrApi(tokenHolder);
|
||||
this.tmplApi = new TmplApi(tokenHolder);
|
||||
this.helperApi = new HelperApi(tokenHolder);
|
||||
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.api.NotifyApi
|
||||
*/
|
||||
public BaseResult sendNotify(BaseNotify notify) throws WeixinException {
|
||||
public JsonResult sendNotify(BaseNotify notify) throws WeixinException {
|
||||
return notifyApi.sendNotify(notify);
|
||||
}
|
||||
|
||||
@ -199,7 +204,7 @@ public class WeixinProxy {
|
||||
* @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify
|
||||
* @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 {
|
||||
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.api.NotifyApi
|
||||
*/
|
||||
public BaseResult sendNotify(String touser, BaseMsg baseMsg)
|
||||
public JsonResult sendNotify(String touser, BaseMsg baseMsg)
|
||||
throws WeixinException {
|
||||
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#massByOpenIds(JSONObject, String...)
|
||||
*/
|
||||
public BaseResult deleteMassNews(String msgid) throws WeixinException {
|
||||
public JsonResult deleteMassNews(String msgid) throws WeixinException {
|
||||
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>
|
||||
* @see com.foxinmy.weixin4j.mp.api.UserApi
|
||||
*/
|
||||
public BaseResult remarkUserName(String openId, String remark)
|
||||
public JsonResult remarkUserName(String openId, String remark)
|
||||
throws WeixinException {
|
||||
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.api.GroupApi
|
||||
*/
|
||||
public BaseResult modifyGroup(int groupId, String name)
|
||||
public JsonResult modifyGroup(int groupId, String name)
|
||||
throws WeixinException {
|
||||
return groupApi.modifyGroup(groupId, name);
|
||||
}
|
||||
@ -582,7 +587,7 @@ public class WeixinProxy {
|
||||
* @see com.foxinmy.weixin4j.mp.model.Group
|
||||
* @see com.foxinmy.weixin4j.mp.api.GroupApi
|
||||
*/
|
||||
public BaseResult moveGroup(String openId, int groupId)
|
||||
public JsonResult moveGroup(String openId, int groupId)
|
||||
throws WeixinException {
|
||||
return groupApi.moveGroup(openId, groupId);
|
||||
}
|
||||
@ -598,7 +603,7 @@ public class WeixinProxy {
|
||||
* @see com.foxinmy.weixin4j.type.ButtonType
|
||||
* @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);
|
||||
}
|
||||
|
||||
@ -625,7 +630,7 @@ public class WeixinProxy {
|
||||
* @see com.foxinmy.weixin4j.mp.model.Button
|
||||
* @see com.foxinmy.weixin4j.mp.api.MenuApi
|
||||
*/
|
||||
public BaseResult deleteMenu() throws WeixinException {
|
||||
public JsonResult deleteMenu() throws WeixinException {
|
||||
return menuApi.deleteMenu();
|
||||
}
|
||||
|
||||
@ -692,7 +697,7 @@ public class WeixinProxy {
|
||||
* @seee com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage
|
||||
* @see com.foxinmy.weixin4j.mp.api.TmplApi
|
||||
*/
|
||||
public BaseResult sendTmplMessage(TemplateMessage tplMessage)
|
||||
public JsonResult sendTmplMessage(TemplateMessage tplMessage)
|
||||
throws WeixinException {
|
||||
return tmplApi.sendTmplMessage(tplMessage);
|
||||
}
|
||||
@ -714,8 +719,8 @@ public class WeixinProxy {
|
||||
/**
|
||||
* 发货通知
|
||||
*
|
||||
* @param weixinConfig
|
||||
* V2版本
|
||||
* @param weixinAccount
|
||||
* 商户信息
|
||||
* @param transid
|
||||
* 交易单号
|
||||
* @param orderNo
|
||||
@ -724,31 +729,32 @@ public class WeixinProxy {
|
||||
* 成功|失败
|
||||
* @param statusMsg
|
||||
* status为失败时携带的信息
|
||||
* @return
|
||||
* @return 调用结果
|
||||
* @throws WeixinException
|
||||
* @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)
|
||||
throws WeixinException {
|
||||
return payApi.deliverNotify(weixinConfig, transid, orderNo, status,
|
||||
return payApi.deliverNotify(weixinAccount, transid, orderNo, status,
|
||||
statusMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单查询
|
||||
*
|
||||
* @param weixinConfig
|
||||
* V2版本
|
||||
* @param weixinAccount
|
||||
* 商户信息
|
||||
* @param orderNo
|
||||
* 订单号
|
||||
* @return
|
||||
* @return 订单信息
|
||||
* @throws WeixinException
|
||||
* @see com.foxinmy.weixin4j.mp.api.PayApi
|
||||
*/
|
||||
public Order orderQuery(WeixinAccountV2 weixinConfig, String orderNo)
|
||||
public Order orderQueryV2(WeixinAccount weixinAccount, String orderNo)
|
||||
throws WeixinException {
|
||||
return payApi.orderQuery(weixinConfig, orderNo);
|
||||
return payApi.orderQueryV2(weixinAccount, new IdQuery(orderNo,
|
||||
IdType.ORDERNO));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -758,28 +764,106 @@ public class WeixinProxy {
|
||||
* 用户ID
|
||||
* @param feedbackId
|
||||
* 维权单号
|
||||
* @return
|
||||
* @return 调用结果
|
||||
* @see com.foxinmy.weixin4j.mp.api.PayApi
|
||||
* @throws WeixinException
|
||||
*/
|
||||
public BaseResult updateFeedback(String openId, String feedbackId)
|
||||
public JsonResult updateFeedback(String openId, String feedbackId)
|
||||
throws WeixinException {
|
||||
return payApi.updateFeedback(openId, feedbackId);
|
||||
}
|
||||
|
||||
/**
|
||||
* V3订单查询
|
||||
*
|
||||
* @param weixinAccount
|
||||
* 商户信息
|
||||
* @param idQuery
|
||||
* 商户系统内部的订单号, transaction_id、out_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_id、out_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转短链接
|
||||
*
|
||||
* @param weixinConfig
|
||||
* 商户配置
|
||||
* @param weixinAccount
|
||||
* 商户信息
|
||||
* @param url
|
||||
* native支付URL
|
||||
* 具有native标识的支付URL
|
||||
* @return 转换后的短链接
|
||||
* @see com.foxinmy.weixin4j.mp.api.PayApi
|
||||
* @throws WeixinException
|
||||
*/
|
||||
public String getShorturl(WeixinAccountV3 weixinConfig, String url)
|
||||
public String getShorturl(WeixinAccount weixinAccount, String url)
|
||||
throws WeixinException {
|
||||
return payApi.getShorturl(weixinConfig, url);
|
||||
return payApi.getShorturl(weixinAccount, url);
|
||||
}
|
||||
}
|
||||
@ -2,12 +2,16 @@ package com.foxinmy.weixin4j.mp.api;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.foxinmy.weixin4j.http.HttpRequest;
|
||||
import com.foxinmy.weixin4j.xml.Map2ObjectConverter;
|
||||
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 {
|
||||
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;
|
||||
private final static ResourceBundle weixinBundle;
|
||||
static {
|
||||
weixinBundle = ResourceBundle
|
||||
.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) {
|
||||
@ -4,7 +4,7 @@ import java.util.List;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
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.model.Token;
|
||||
import com.foxinmy.weixin4j.mp.model.Group;
|
||||
@ -23,9 +23,9 @@ import com.foxinmy.weixin4j.token.TokenHolder;
|
||||
*/
|
||||
public class GroupApi extends BaseApi {
|
||||
|
||||
private final TokenHolder tokenApi;
|
||||
public GroupApi(TokenHolder tokenApi) {
|
||||
this.tokenApi = tokenApi;
|
||||
private final TokenHolder tokenHolder;
|
||||
public GroupApi(TokenHolder tokenHolder) {
|
||||
this.tokenHolder = tokenHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -42,7 +42,7 @@ public class GroupApi extends BaseApi {
|
||||
*/
|
||||
public Group createGroup(String name) throws WeixinException {
|
||||
String group_create_uri = getRequestUri("group_create_uri");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
Group group = new Group(name);
|
||||
Response response = request.post(
|
||||
String.format(group_create_uri, token.getAccessToken()),
|
||||
@ -62,7 +62,7 @@ public class GroupApi extends BaseApi {
|
||||
*/
|
||||
public List<Group> getGroups() throws WeixinException {
|
||||
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,
|
||||
token.getAccessToken()));
|
||||
|
||||
@ -83,7 +83,7 @@ public class GroupApi extends BaseApi {
|
||||
*/
|
||||
public int getGroupByOpenId(String openId) throws WeixinException {
|
||||
String group_getid_uri = getRequestUri("group_getid_uri");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
Response response = request.post(
|
||||
String.format(group_getid_uri, token.getAccessToken()),
|
||||
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#toModifyJson()
|
||||
*/
|
||||
public BaseResult modifyGroup(int groupId, String name)
|
||||
public JsonResult modifyGroup(int groupId, String name)
|
||||
throws WeixinException {
|
||||
String group_modify_uri = getRequestUri("group_modify_uri");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
Group group = new Group(groupId, name);
|
||||
|
||||
Response response = request.post(
|
||||
String.format(group_modify_uri, token.getAccessToken()),
|
||||
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>
|
||||
* @see com.foxinmy.weixin4j.mp.model.Group
|
||||
*/
|
||||
public BaseResult moveGroup(String openId, int groupId)
|
||||
public JsonResult moveGroup(String openId, int groupId)
|
||||
throws WeixinException {
|
||||
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,
|
||||
token.getAccessToken()), String.format(
|
||||
"{\"openid\":\"%s\",\"to_groupid\":%d}", openId, groupId));
|
||||
|
||||
return response.getAsResult();
|
||||
return response.getAsJsonResult();
|
||||
}
|
||||
}
|
||||
@ -17,10 +17,10 @@ import com.foxinmy.weixin4j.token.TokenHolder;
|
||||
*/
|
||||
public class HelperApi extends BaseApi {
|
||||
|
||||
private final TokenHolder tokenApi;
|
||||
private final TokenHolder tokenHolder;
|
||||
|
||||
public HelperApi(TokenHolder tokenApi) {
|
||||
this.tokenApi = tokenApi;
|
||||
public HelperApi(TokenHolder tokenHolder) {
|
||||
this.tokenHolder = tokenHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -34,7 +34,7 @@ public class HelperApi extends BaseApi {
|
||||
*/
|
||||
public String getShorturl(String url) throws WeixinException {
|
||||
String shorturl_uri = getRequestUri("shorturl_uri");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("action", "long2short");
|
||||
obj.put("long_url", url);
|
||||
@ -5,7 +5,7 @@ import java.util.List;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
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.model.Token;
|
||||
import com.foxinmy.weixin4j.mp.model.MpArticle;
|
||||
@ -25,10 +25,10 @@ import com.foxinmy.weixin4j.type.MediaType;
|
||||
*/
|
||||
public class MassApi extends BaseApi {
|
||||
|
||||
private final TokenHolder tokenApi;
|
||||
private final TokenHolder tokenHolder;
|
||||
|
||||
public MassApi(TokenHolder tokenApi) {
|
||||
this.tokenApi = tokenApi;
|
||||
public MassApi(TokenHolder tokenHolder) {
|
||||
this.tokenHolder = tokenHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,7 +47,7 @@ public class MassApi extends BaseApi {
|
||||
public String uploadArticle(List<MpArticle> articles)
|
||||
throws WeixinException {
|
||||
String article_upload_uri = getRequestUri("article_upload_uri");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("articles", articles);
|
||||
Response response = request.post(
|
||||
@ -75,7 +75,7 @@ public class MassApi extends BaseApi {
|
||||
public String uploadVideo(String mediaId, String title, String desc)
|
||||
throws WeixinException {
|
||||
String video_upload_uri = getRequestUri("video_upload_uri");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("media_id", mediaId);
|
||||
obj.put("title", title);
|
||||
@ -109,7 +109,7 @@ public class MassApi extends BaseApi {
|
||||
private String massByGroup(JSONObject jsonPara, String groupId)
|
||||
throws WeixinException {
|
||||
String mass_group_uri = getRequestUri("mass_group_uri");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
Response response = request.post(
|
||||
String.format(mass_group_uri, token.getAccessToken()),
|
||||
jsonPara.toJSONString());
|
||||
@ -133,7 +133,7 @@ public class MassApi extends BaseApi {
|
||||
private String massByOpenIds(JSONObject jsonPara, String... openIds)
|
||||
throws WeixinException {
|
||||
String mass_openid_uri = getRequestUri("mass_openid_uri");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
Response response = request.post(
|
||||
String.format(mass_openid_uri, token.getAccessToken()),
|
||||
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#massByOpenIds(JSONObject, String...)
|
||||
*/
|
||||
public BaseResult deleteMassNews(String msgid) throws WeixinException {
|
||||
public JsonResult deleteMassNews(String msgid) throws WeixinException {
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("msgid", msgid);
|
||||
String mass_delete_uri = getRequestUri("mass_delete_uri");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
Response response = request.post(
|
||||
String.format(mass_delete_uri, token.getAccessToken()),
|
||||
obj.toJSONString());
|
||||
|
||||
return response.getAsResult();
|
||||
return response.getAsJsonResult();
|
||||
}
|
||||
}
|
||||
@ -28,10 +28,10 @@ import com.foxinmy.weixin4j.util.IOUtil;
|
||||
*/
|
||||
public class MediaApi extends BaseApi {
|
||||
|
||||
private final TokenHolder tokenApi;
|
||||
private final TokenHolder tokenHolder;
|
||||
|
||||
public MediaApi(TokenHolder tokenApi) {
|
||||
this.tokenApi = tokenApi;
|
||||
public MediaApi(TokenHolder tokenHolder) {
|
||||
this.tokenHolder = tokenHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,7 +72,7 @@ public class MediaApi extends BaseApi {
|
||||
*/
|
||||
public String uploadMedia(String fileName, byte[] bytes, MediaType mediaType)
|
||||
throws WeixinException {
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
String file_upload_uri = getRequestUri("file_upload_uri");
|
||||
Response response = request.post(String.format(file_upload_uri,
|
||||
token.getAccessToken(), mediaType.name()), new PartParameter(
|
||||
@ -107,14 +107,8 @@ public class MediaApi extends BaseApi {
|
||||
if (file.exists()) {
|
||||
return file;
|
||||
}
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
}
|
||||
out = new FileOutputStream(file);
|
||||
file.createNewFile();
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
out.write(datas);
|
||||
out.close();
|
||||
return file;
|
||||
@ -131,7 +125,7 @@ public class MediaApi extends BaseApi {
|
||||
*/
|
||||
public byte[] downloadMediaData(String mediaId, MediaType mediaType)
|
||||
throws WeixinException {
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
String file_download_uri = getRequestUri("file_download_uri");
|
||||
Response response = request.get(String.format(file_download_uri,
|
||||
token.getAccessToken(), mediaId));
|
||||
@ -5,7 +5,7 @@ import java.util.List;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
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.model.Token;
|
||||
import com.foxinmy.weixin4j.mp.model.Button;
|
||||
@ -22,10 +22,10 @@ import com.foxinmy.weixin4j.token.TokenHolder;
|
||||
*/
|
||||
public class MenuApi extends BaseApi {
|
||||
|
||||
private final TokenHolder tokenApi;
|
||||
private final TokenHolder tokenHolder;
|
||||
|
||||
public MenuApi(TokenHolder tokenApi) {
|
||||
this.tokenApi = tokenApi;
|
||||
public MenuApi(TokenHolder tokenHolder) {
|
||||
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>
|
||||
* @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");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("button", btnList);
|
||||
Response response = request.post(
|
||||
String.format(menu_create_uri, token.getAccessToken()),
|
||||
obj.toJSONString());
|
||||
|
||||
return response.getAsResult();
|
||||
return response.getAsJsonResult();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,7 +60,7 @@ public class MenuApi extends BaseApi {
|
||||
*/
|
||||
public List<Button> getMenu() throws WeixinException {
|
||||
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,
|
||||
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>
|
||||
* @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");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
Response response = request.get(String.format(menu_delete_uri,
|
||||
token.getAccessToken()));
|
||||
|
||||
return response.getAsResult();
|
||||
return response.getAsJsonResult();
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,7 @@ import java.util.List;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
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.model.Token;
|
||||
import com.foxinmy.weixin4j.mp.model.CustomRecord;
|
||||
@ -33,10 +33,10 @@ import com.foxinmy.weixin4j.token.TokenHolder;
|
||||
*/
|
||||
public class NotifyApi extends BaseApi {
|
||||
|
||||
private final TokenHolder tokenApi;
|
||||
private final TokenHolder tokenHolder;
|
||||
|
||||
public NotifyApi(TokenHolder tokenApi) {
|
||||
this.tokenApi = tokenApi;
|
||||
public NotifyApi(TokenHolder tokenHolder) {
|
||||
this.tokenHolder = tokenHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,14 +48,14 @@ public class NotifyApi extends BaseApi {
|
||||
* @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>
|
||||
*/
|
||||
private BaseResult sendNotify(String jsonPara) throws WeixinException {
|
||||
private JsonResult sendNotify(String jsonPara) throws WeixinException {
|
||||
String custom_notify_uri = getRequestUri("custom_notify_uri");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
Response response = request.post(
|
||||
String.format(custom_notify_uri, token.getAccessToken()),
|
||||
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 {@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());
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ public class NotifyApi extends BaseApi {
|
||||
* @see com.foxinmy.weixin4j.mp.msg.model.Article
|
||||
* @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 {
|
||||
ArticleNotify notify = new ArticleNotify(touser);
|
||||
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.api.NotifyApi#sendNotify(String)}
|
||||
*/
|
||||
public BaseResult sendNotify(String touser, BaseMsg baseMsg)
|
||||
public JsonResult sendNotify(String touser, BaseMsg baseMsg)
|
||||
throws WeixinException {
|
||||
StringBuilder jsonPara = new StringBuilder();
|
||||
String mediaType = baseMsg.getMediaType().name();
|
||||
@ -154,7 +154,7 @@ public class NotifyApi extends BaseApi {
|
||||
obj.put("pagesize", pagesize > 1000 ? 1000 : pagesize);
|
||||
obj.put("pageindex", pageindex);
|
||||
String custom_record_uri = getRequestUri("custom_record_uri");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
Response response = request.post(
|
||||
String.format(custom_record_uri, token.getAccessToken()),
|
||||
obj.toJSONString());
|
||||
@ -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_id、out_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_id、out_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)));
|
||||
}
|
||||
}
|
||||
@ -24,10 +24,10 @@ import com.foxinmy.weixin4j.token.TokenHolder;
|
||||
*/
|
||||
public class QrApi extends BaseApi {
|
||||
|
||||
private final TokenHolder tokenApi;
|
||||
private final TokenHolder tokenHolder;
|
||||
|
||||
public QrApi(TokenHolder tokenApi) {
|
||||
this.tokenApi = tokenApi;
|
||||
public QrApi(TokenHolder tokenHolder) {
|
||||
this.tokenHolder = tokenHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -39,7 +39,7 @@ public class QrApi extends BaseApi {
|
||||
* @see {@link com.foxinmy.weixin4j.mp.api.QrApi#getQR(QRParameter)}
|
||||
*/
|
||||
public byte[] getQRData(QRParameter parameter) throws WeixinException {
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
String qr_uri = getRequestUri("qr_ticket_uri");
|
||||
Response response = request.post(
|
||||
String.format(qr_uri, token.getAccessToken()),
|
||||
@ -97,14 +97,8 @@ public class QrApi extends BaseApi {
|
||||
return file;
|
||||
}
|
||||
byte[] datas = getQRData(parameter);
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
}
|
||||
out = new FileOutputStream(file);
|
||||
file.createNewFile();
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
out.write(datas);
|
||||
out.close();
|
||||
return file;
|
||||
@ -1,7 +1,7 @@
|
||||
package com.foxinmy.weixin4j.mp.api;
|
||||
|
||||
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.model.Token;
|
||||
import com.foxinmy.weixin4j.mp.response.TemplateMessage;
|
||||
@ -18,10 +18,10 @@ import com.foxinmy.weixin4j.token.TokenHolder;
|
||||
*/
|
||||
public class TmplApi extends BaseApi {
|
||||
|
||||
private final TokenHolder tokenApi;
|
||||
private final TokenHolder tokenHolder;
|
||||
|
||||
public TmplApi(TokenHolder tokenApi) {
|
||||
this.tokenApi = tokenApi;
|
||||
public TmplApi(TokenHolder tokenHolder) {
|
||||
this.tokenHolder = tokenHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,14 +35,14 @@ public class TmplApi extends BaseApi {
|
||||
* @see com.foxinmy.weixin4j.mp.response.TemplateMessage
|
||||
* @seee com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage
|
||||
*/
|
||||
public BaseResult sendTmplMessage(TemplateMessage tplMessage)
|
||||
public JsonResult sendTmplMessage(TemplateMessage tplMessage)
|
||||
throws WeixinException {
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
String template_send_uri = getRequestUri("template_send_uri");
|
||||
Response response = request.post(
|
||||
String.format(template_send_uri, token.getAccessToken()),
|
||||
tplMessage.toJson());
|
||||
|
||||
return response.getAsResult();
|
||||
return response.getAsJsonResult();
|
||||
}
|
||||
}
|
||||
@ -5,8 +5,9 @@ import java.util.List;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
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.model.Token;
|
||||
import com.foxinmy.weixin4j.mp.model.Following;
|
||||
@ -25,10 +26,10 @@ import com.foxinmy.weixin4j.token.TokenHolder;
|
||||
*/
|
||||
public class UserApi extends BaseApi {
|
||||
|
||||
private final TokenHolder tokenApi;
|
||||
private final TokenHolder tokenHolder;
|
||||
|
||||
public UserApi(TokenHolder tokenApi) {
|
||||
this.tokenApi = tokenApi;
|
||||
public UserApi(TokenHolder tokenHolder) {
|
||||
this.tokenHolder = tokenHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,7 +47,8 @@ public class UserApi extends BaseApi {
|
||||
String user_token_uri = getRequestUri("sns_user_token_uri");
|
||||
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,
|
||||
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 {
|
||||
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,
|
||||
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 {
|
||||
String fllowing_uri = getRequestUri("following_uri");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
Response response = request.get(String.format(fllowing_uri,
|
||||
token.getAccessToken(), nextOpenId == null ? "" : nextOpenId));
|
||||
|
||||
Following following = response.getAsObject(Following.class);
|
||||
Following following = response
|
||||
.getAsObject(new TypeReference<Following>() {
|
||||
});
|
||||
|
||||
if (following.getCount() > 0) {
|
||||
List<String> openIds = JSON.parseArray(following.getDataJson()
|
||||
@ -165,10 +171,10 @@ public class UserApi extends BaseApi {
|
||||
* @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>
|
||||
*/
|
||||
public BaseResult remarkUserName(String openId, String remark)
|
||||
public JsonResult remarkUserName(String openId, String remark)
|
||||
throws WeixinException {
|
||||
String updateremark_uri = getRequestUri("updateremark_uri");
|
||||
Token token = tokenApi.getToken();
|
||||
Token token = tokenHolder.getToken();
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("openid", openId);
|
||||
obj.put("remark", remark);
|
||||
@ -176,6 +182,6 @@ public class UserApi extends BaseApi {
|
||||
String.format(updateremark_uri, token.getAccessToken()),
|
||||
obj.toJSONString());
|
||||
|
||||
return response.getAsResult();
|
||||
return response.getAsJsonResult();
|
||||
}
|
||||
}
|
||||
@ -65,9 +65,17 @@ p_shorturl_uri={mch_base_url}/tools/shorturl
|
||||
updateremark_uri={api_base_url}/user/info/updateremark?access_token=%s
|
||||
# \u6a21\u677f\u6d88\u606f
|
||||
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
|
||||
# \u53d1\u8d27\u901a\u77e5
|
||||
delivernotify_uri={api_base_url}/pay/delivernotify?access_token=%s
|
||||
# \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
|
||||
@ -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
|
||||
+ "]";
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
* <xml><br/>
|
||||
* <OpenId><![CDATA[111222]]></OpenId><br/>
|
||||
* <AppId><![CDATA[wwwwb4f85f3a797777]]></AppId><br/>
|
||||
* <IsSubscribe>1</IsSubscribe><br/>
|
||||
* <TimeStamp>1369743511</TimeStamp><br/>
|
||||
* <NonceStr><![CDATA[jALldRTHAFd5Tgs5]]></NonceStr><br/>
|
||||
* <AppSignature><![CDATA[bafe07f060f22dcda0bfdb4b5ff756f973aecffa]]>
|
||||
* </AppSignature><br/>
|
||||
* <SignMethod><![CDATA[sha1]]></SignMethod><br/>
|
||||
* </xml><br/>
|
||||
* 参与签名的字段为: appid、appkey、timestamp、noncestr、openid、issubscribe
|
||||
*
|
||||
* @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 <xml><br>
|
||||
* <return_code>SUCCESS/FAIL</return_code><br>
|
||||
* <return_msg>如非空,为错误 原因签名失败参数格式校验错误</return_msg><br>
|
||||
* </xml>
|
||||
*/
|
||||
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/>
|
||||
* <xml><br/>
|
||||
* <AppId><![CDATA[wxf8b4f85f3a794e77]]></AppId><br/>
|
||||
* <ErrorType>1001</ErrorType><br/>
|
||||
* <Description><![CDATA[错误描述]]></Description><br/>
|
||||
* <AlarmContent><![CDATA[错误详情]]></AlarmContent><br/>
|
||||
* <TimeStamp>1393860740</TimeStamp><br/>
|
||||
* <AppSignature><![CDATA[签名方式跟JsPayRequest中的paySign一样]]></
|
||||
* AppSignature><br/>
|
||||
* <SignMethod><![CDATA[sha1]]></SignMethod><br/>
|
||||
* </xml><br/>
|
||||
* 参与签名字段:alarmcontent、appid、appkey、description、errortype、timestamp
|
||||
*
|
||||
* @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>
|
||||
* <xml><br/>
|
||||
* <OpenId><![CDATA[111222]]></OpenId><br/>
|
||||
* <AppId><![CDATA[wwwwb4f85f3a797777]]></AppId><br/>
|
||||
* <IsSubscribe>1</IsSubscribe><br/>
|
||||
* <ProductId>[CDATA[000000]]</ProductId><br/>
|
||||
* <TimeStamp>1369743511</TimeStamp><br/>
|
||||
* <NonceStr><![CDATA[jALldRTHAFd5Tgs5]]></NonceStr><br/>
|
||||
* <AppSignature><![CDATA[bafe07f060f22dcda0bfdb4b5ff756f973aecffa]]>
|
||||
* </AppSignature><br/>
|
||||
* <SignMethod><![CDATA[sha1]]></SignMethod><br/>
|
||||
* </xml><br/>
|
||||
* 参与签名的字段为: appid、appkey、timestamp、noncestr、openid、issubscribe、productId
|
||||
*
|
||||
* @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>
|
||||
* <xml><br/>
|
||||
* <openid><![CDATA[111222]]></openid><br/>
|
||||
* <appid><![CDATA[wwwwb4f85f3a797777]]></appid><br/>
|
||||
* <mch_id><![CDATA[1100022]]></mch_id><br/>
|
||||
* <is_subscribe>1</is_subscribe><br/>
|
||||
* <product_id>[CDATA[000000]]</product_id><br/>
|
||||
* <nonce_str><![CDATA[jALldRTHAFd5Tgs5]]></nonce_str><br/>
|
||||
* <sign><![CDATA[bafe07f060f22dcda0bfdb4b5ff756f973aecffa]]></sign&
|
||||
* gt<br/>
|
||||
* </xml><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) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -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 + "]";
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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×tamp=%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();
|
||||
}
|
||||
}
|
||||
@ -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 + "]";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
支付模块【JSP AY】【NATIVE PAY】【APP PAY】
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
package com.foxinmy.weixin4j.mp.payment;
|
||||
|
||||
public enum SignType {
|
||||
SHA1,MD5
|
||||
}
|
||||
@ -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;// 支付失败(其他 原因,如银行返回失败)
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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() + "]";
|
||||
}
|
||||
}
|
||||
@ -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() + "]";
|
||||
}
|
||||
}
|
||||
@ -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() + "]";
|
||||
}
|
||||
}
|
||||
@ -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 + "]";
|
||||
}
|
||||
}
|
||||
@ -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 + "]";
|
||||
}
|
||||
}
|
||||
@ -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() + "]";
|
||||
}
|
||||
}
|
||||
@ -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() + "]";
|
||||
}
|
||||
}
|
||||
@ -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() + "]";
|
||||
}
|
||||
}
|
||||
@ -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() + "]";
|
||||
}
|
||||
}
|
||||
@ -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; // 交易类型JSAPI、NATIVE、APP 必须
|
||||
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() + "]";
|
||||
}
|
||||
}
|
||||
@ -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() + "]";
|
||||
}
|
||||
}
|
||||
@ -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;// 交易类型JSAPI、NATIVE、APP 非空
|
||||
@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() + "]";
|
||||
}
|
||||
}
|
||||
@ -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() + "]";
|
||||
}
|
||||
}
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user