maven多模块分离
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1 @@
|
||||
/target/
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>weixin4j-base</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,4 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//src/main/java=UTF-8
|
||||
encoding//src/test/java=UTF-8
|
||||
encoding/<project>=UTF-8
|
||||
@@ -0,0 +1,13 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.7
|
||||
@@ -0,0 +1,4 @@
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
||||
@@ -0,0 +1,4 @@
|
||||
weixin4j-base
|
||||
=============
|
||||
|
||||
tencent weixin base java sdk 微信开发基础工程
|
||||
@@ -0,0 +1,104 @@
|
||||
<?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</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>weixin4j-base</artifactId>
|
||||
<name>weixin4j-base</name>
|
||||
<url>https://github.com/foxinmy</url>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
<artifactId>xstream</artifactId>
|
||||
<version>${xstream.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>${httpclient.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpmime</artifactId>
|
||||
<version>${httpclient.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons.lang.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>${dom4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>${jcl.over.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
<version>${log4j.over.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>${jedis.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>${commons.codec.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.foxinmy.weixin4j.exception;
|
||||
|
||||
public class PayException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 7148145661883468514L;
|
||||
|
||||
private String errorCode;
|
||||
private String errorMsg;
|
||||
|
||||
public PayException(String errorCode, String errorMsg) {
|
||||
this.errorCode = errorCode;
|
||||
this.errorMsg = errorMsg;
|
||||
}
|
||||
|
||||
public PayException(String errorMsg) {
|
||||
this.errorCode = "-1";
|
||||
this.errorMsg = errorMsg;
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
return this.errorCode;
|
||||
}
|
||||
|
||||
public String getErrorMsg() {
|
||||
return this.errorMsg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return String.format("%s,%s", getErrorMsg(), getErrorCode());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.foxinmy.weixin4j.exception;
|
||||
|
||||
/**
|
||||
* 调用微信接口抛出的异常
|
||||
*
|
||||
* @className WeixinException
|
||||
* @author jy.hu
|
||||
* @date 2014年4月10日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class WeixinException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 7148145661883468514L;
|
||||
|
||||
private int errorCode;
|
||||
private String errorMsg;
|
||||
|
||||
public WeixinException(int errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public WeixinException(int errorCode, String errorMsg) {
|
||||
this.errorCode = errorCode;
|
||||
this.errorMsg = errorMsg;
|
||||
}
|
||||
|
||||
public WeixinException(String errorMsg) {
|
||||
this.errorMsg = errorMsg;
|
||||
}
|
||||
|
||||
public int getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
public String getErrorMsg() {
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return this.errorCode + "," + this.errorMsg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.foxinmy.weixin4j.http;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 调用接口响应值
|
||||
*
|
||||
* @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>
|
||||
*/
|
||||
public class BaseResult implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6185313616955051150L;
|
||||
|
||||
private int errcode;
|
||||
private String errmsg;
|
||||
private String msgid;
|
||||
private String text;
|
||||
|
||||
public BaseResult() {
|
||||
|
||||
}
|
||||
|
||||
public BaseResult(int errcode, String errmsg, String text) {
|
||||
this.errcode = errcode;
|
||||
this.errmsg = errmsg;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public BaseResult(int 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 int getErrcode() {
|
||||
return errcode;
|
||||
}
|
||||
|
||||
public void setErrcode(int 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 + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
package com.foxinmy.weixin4j.http;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.Consts;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.client.params.ClientPNames;
|
||||
import org.apache.http.client.params.CookiePolicy;
|
||||
import org.apache.http.entity.ByteArrayEntity;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.FileEntity;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.entity.mime.MultipartEntity;
|
||||
import org.apache.http.impl.client.AbstractHttpClient;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.impl.conn.PoolingClientConnectionManager;
|
||||
import org.apache.http.params.CoreConnectionPNames;
|
||||
import org.apache.http.params.CoreProtocolPNames;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
|
||||
/**
|
||||
* 调用微信相关接口的HttpRequest,对于其他请求可能并不试用
|
||||
*
|
||||
* @className HttpRequest
|
||||
* @author jy
|
||||
* @date 2014年8月21日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class HttpRequest {
|
||||
private AbstractHttpClient client;
|
||||
|
||||
public HttpRequest() {
|
||||
this(150, 100, 10000, 10000);
|
||||
}
|
||||
|
||||
public HttpRequest(int maxConPerRoute, int maxTotal, int socketTimeout,
|
||||
int connectionTimeout) {
|
||||
PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager();
|
||||
// 指定IP并发最大数
|
||||
connectionManager.setDefaultMaxPerRoute(maxConPerRoute);
|
||||
// socket最大创建数
|
||||
connectionManager.setMaxTotal(maxTotal);
|
||||
|
||||
client = new DefaultHttpClient(connectionManager);
|
||||
client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,
|
||||
socketTimeout);
|
||||
client.getParams().setParameter(
|
||||
CoreConnectionPNames.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
client.getParams().setBooleanParameter(
|
||||
CoreConnectionPNames.TCP_NODELAY, false);
|
||||
client.getParams().setParameter(
|
||||
CoreConnectionPNames.SOCKET_BUFFER_SIZE, 1024 * 1024);
|
||||
client.getParams().setParameter(ClientPNames.COOKIE_POLICY,
|
||||
CookiePolicy.IGNORE_COOKIES);
|
||||
client.getParams().setParameter(
|
||||
CoreProtocolPNames.HTTP_CONTENT_CHARSET, Consts.UTF_8);
|
||||
client.getParams().setParameter(HttpHeaders.CONTENT_ENCODING,
|
||||
Consts.UTF_8);
|
||||
client.getParams().setParameter(HttpHeaders.ACCEPT_CHARSET,
|
||||
Consts.UTF_8);
|
||||
}
|
||||
|
||||
public Response get(String url) throws WeixinException {
|
||||
return get(url, (Parameter[]) null);
|
||||
}
|
||||
|
||||
public Response get(String url, Parameter... parameters)
|
||||
throws WeixinException {
|
||||
StringBuilder sb = new StringBuilder(url);
|
||||
if (parameters != null && parameters.length > 0) {
|
||||
if (url.indexOf("?") < 0) {
|
||||
sb.append(String.format("?%s=%s", parameters[0].getName(),
|
||||
parameters[0].getValue()));
|
||||
}
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
sb.append(parameters[i].toGetPara());
|
||||
}
|
||||
}
|
||||
return doRequest(new HttpGet(sb.toString()));
|
||||
}
|
||||
|
||||
public Response post(String url) throws WeixinException {
|
||||
return post(url, (Parameter[]) null);
|
||||
}
|
||||
|
||||
public Response post(String url, Parameter... parameters)
|
||||
throws WeixinException {
|
||||
HttpPost method = new HttpPost(url);
|
||||
List<NameValuePair> params = new ArrayList<NameValuePair>();
|
||||
for (Parameter parameter : parameters) {
|
||||
params.add(parameter.toPostPara());
|
||||
}
|
||||
method.setEntity(new UrlEncodedFormEntity(params, Consts.UTF_8));
|
||||
return doRequest(method);
|
||||
}
|
||||
|
||||
public Response post(String url, String body) throws WeixinException {
|
||||
HttpPost method = new HttpPost(url);
|
||||
method.setEntity(new StringEntity(body, ContentType.create(
|
||||
ContentType.APPLICATION_JSON.getMimeType(), Consts.UTF_8)));
|
||||
return doRequest(method);
|
||||
}
|
||||
|
||||
public Response post(String url, byte[] bytes) throws WeixinException {
|
||||
HttpPost method = new HttpPost(url);
|
||||
method.setEntity(new ByteArrayEntity(bytes, ContentType.create(
|
||||
ContentType.MULTIPART_FORM_DATA.getMimeType(), Consts.UTF_8)));
|
||||
return doRequest(method);
|
||||
}
|
||||
|
||||
public Response post(String url, File file) throws WeixinException {
|
||||
HttpPost method = new HttpPost(url);
|
||||
method.setEntity(new FileEntity(file, ContentType.create(
|
||||
ContentType.APPLICATION_OCTET_STREAM.getMimeType(),
|
||||
Consts.UTF_8)));
|
||||
return doRequest(method);
|
||||
}
|
||||
|
||||
public Response post(String url, PartParameter... paramters)
|
||||
throws WeixinException {
|
||||
HttpPost method = new HttpPost(url);
|
||||
MultipartEntity entity = new MultipartEntity();
|
||||
for (PartParameter paramter : paramters) {
|
||||
entity.addPart(paramter.getName(), paramter.getContentBody());
|
||||
}
|
||||
method.setEntity(entity);
|
||||
|
||||
return doRequest(method);
|
||||
}
|
||||
|
||||
protected Response doRequest(HttpRequestBase request)
|
||||
throws WeixinException {
|
||||
try {
|
||||
HttpResponse httpResponse = client.execute(request);
|
||||
StatusLine statusLine = httpResponse.getStatusLine();
|
||||
HttpEntity httpEntity = httpResponse.getEntity();
|
||||
|
||||
int status = statusLine.getStatusCode();
|
||||
if (status != HttpStatus.SC_OK) {
|
||||
throw new WeixinException(status, "request fail");
|
||||
}
|
||||
// 301或者302
|
||||
if (status == HttpStatus.SC_MOVED_PERMANENTLY
|
||||
|| status == HttpStatus.SC_MOVED_TEMPORARILY) {
|
||||
throw new WeixinException(status, String.format(
|
||||
"the page was redirected to %s",
|
||||
httpResponse.getFirstHeader("location")));
|
||||
}
|
||||
byte[] data = EntityUtils.toByteArray(httpEntity);
|
||||
Response response = new Response();
|
||||
response.setBody(data);
|
||||
response.setStatusCode(status);
|
||||
response.setStatusText(statusLine.getReasonPhrase());
|
||||
response.setStream(new ByteArrayInputStream(data));
|
||||
response.setText(StringUtils.join(data));
|
||||
|
||||
Header contentType = httpResponse
|
||||
.getFirstHeader(HttpHeaders.CONTENT_TYPE);
|
||||
if (contentType.getValue().contains(
|
||||
ContentType.APPLICATION_JSON.getMimeType())
|
||||
|| contentType.getValue().contains(
|
||||
ContentType.TEXT_PLAIN.getMimeType())) {
|
||||
BaseResult result = response.getAsResult();
|
||||
if (result.getErrcode() != 0) {
|
||||
throw new WeixinException(result.getErrcode(),
|
||||
result.getErrmsg());
|
||||
}
|
||||
}
|
||||
EntityUtils.consume(httpEntity);
|
||||
return response;
|
||||
} catch (IOException e) {
|
||||
throw new WeixinException(e.getMessage());
|
||||
} finally {
|
||||
request.releaseConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.foxinmy.weixin4j.http;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
|
||||
public class Parameter {
|
||||
|
||||
private final static String CHARSET = StandardCharsets.UTF_8.name();
|
||||
|
||||
private String name;
|
||||
private String value;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Parameter() {
|
||||
|
||||
}
|
||||
|
||||
public Parameter(String name, String value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String toGetPara() {
|
||||
try {
|
||||
return String.format("&%s=%s", name, URLEncoder.encode(value, CHARSET));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return String.format("&%s=%s", name, value);
|
||||
}
|
||||
}
|
||||
|
||||
public NameValuePair toPostPara() {
|
||||
try {
|
||||
return new BasicNameValuePair(name, URLEncoder.encode(value, CHARSET));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return new BasicNameValuePair(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[Parameter name=%s, value=%s]", name, value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.foxinmy.weixin4j.http;
|
||||
|
||||
import org.apache.http.entity.mime.content.ContentBody;
|
||||
|
||||
public class PartParameter {
|
||||
private String name;
|
||||
private ContentBody contentBody;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public ContentBody getContentBody() {
|
||||
return contentBody;
|
||||
}
|
||||
|
||||
public void setContentBody(ContentBody contentBody) {
|
||||
this.contentBody = contentBody;
|
||||
}
|
||||
|
||||
public PartParameter(String name, ContentBody contentBody) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.contentBody = contentBody;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PartParameter [name=" + name + ", contentBody=" + contentBody + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
基于HttpClient封装的针对微信公众平台、微信企业号API的HttpRequest
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.foxinmy.weixin4j.http;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Node;
|
||||
import org.dom4j.io.SAXReader;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
|
||||
public class Response {
|
||||
|
||||
private String text;
|
||||
private int statusCode;
|
||||
private String statusText;
|
||||
private byte[] body;
|
||||
private InputStream stream;
|
||||
|
||||
public Response() {
|
||||
}
|
||||
|
||||
public Response(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public String getAsString() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public BaseResult getAsResult() {
|
||||
return JSON.parseObject(text, BaseResult.class);
|
||||
}
|
||||
|
||||
public JSONObject getAsJson() {
|
||||
return JSON.parseObject(text);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getAsObject(Class<? extends Serializable> clazz) {
|
||||
return (T) JSON.parseObject(text, clazz);
|
||||
}
|
||||
|
||||
public Object getAsXml() {
|
||||
XStream xs = new XStream();
|
||||
xs.autodetectAnnotations(true);
|
||||
return xs.fromXML(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* <a href=
|
||||
* "http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E5%8F%A3%E9%A2%91%E7%8E%87%E9%99%90%E5%88%B6%E8%AF%B4%E6%98%8E"
|
||||
* >全局返回码</a> {"errcode":45009,"errmsg":"api freq out of limit"}
|
||||
*
|
||||
* @return
|
||||
* @throws DocumentException
|
||||
*/
|
||||
public BaseResult getBaseError() throws DocumentException {
|
||||
BaseResult result = getAsResult();
|
||||
if (result.getErrcode() != 0) {
|
||||
SAXReader reader = new SAXReader();
|
||||
Document doc = reader.read(Thread.currentThread()
|
||||
.getContextClassLoader().getResourceAsStream("error.xml"));
|
||||
Node node = doc.getRootElement().selectSingleNode(
|
||||
String.format("error[@code='%d']", result.getErrcode()));
|
||||
if (node != null) {
|
||||
result.setText(node.getStringValue());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
public void setStatusCode(int statusCode) {
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
public String getStatusText() {
|
||||
return statusText;
|
||||
}
|
||||
|
||||
public void setStatusText(String statusText) {
|
||||
this.statusText = statusText;
|
||||
}
|
||||
|
||||
public byte[] getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(byte[] body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public InputStream getStream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
public void setStream(InputStream stream) {
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[Response text=").append(text);
|
||||
sb.append(", statusCode=").append(statusCode);
|
||||
sb.append(", statusText=").append(statusText).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.foxinmy.weixin4j.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token,正常情况下access_token有效期为7200秒,
|
||||
* 重复获取将导致上次获取的access_token失效
|
||||
*
|
||||
* @className Token
|
||||
* @author jy.hu
|
||||
* @date 2014年4月5日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token">获取token</a>
|
||||
*/
|
||||
@XStreamAlias("app-token")
|
||||
public class Token implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@JSONField(name = "access_token")
|
||||
private String accessToken;
|
||||
@JSONField(name = "expires_in")
|
||||
private int expiresIn;
|
||||
private String openid;
|
||||
private long time;
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void setAccessToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
public int getExpiresIn() {
|
||||
return expiresIn;
|
||||
}
|
||||
|
||||
public void setExpiresIn(int expiresIn) {
|
||||
this.expiresIn = expiresIn;
|
||||
}
|
||||
|
||||
public String getOpenid() {
|
||||
return openid;
|
||||
}
|
||||
|
||||
public void setOpenid(String openid) {
|
||||
this.openid = openid;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(long time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Token) {
|
||||
return accessToken.equals(((Token) obj).getAccessToken());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Token [accessToken=" + accessToken + ", expiresIn=" + expiresIn + ", openid=" + openid + ", time=" + time + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.foxinmy.weixin4j.msg;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.Writer;
|
||||
|
||||
import com.foxinmy.weixin4j.type.MessageType;
|
||||
import com.foxinmy.weixin4j.util.ClassUtil;
|
||||
import com.foxinmy.weixin4j.xml.XStream;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
|
||||
import com.thoughtworks.xstream.io.json.JsonWriter;
|
||||
|
||||
/**
|
||||
* 普通消息基类
|
||||
* <p>
|
||||
* <font color="red">回复图片等多媒体消息时需要预先上传多媒体文件到微信服务器,
|
||||
* 假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试</font>
|
||||
* </p>
|
||||
*
|
||||
* @className BaseMessage
|
||||
* @author jy.hu
|
||||
* @date 2014年4月6日
|
||||
* @since JDK 1.7
|
||||
*/
|
||||
public class BaseMessage implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7761192742840031607L;
|
||||
private final static XStream xmlStream = new XStream();
|
||||
private final static XStream jsonStream = new XStream(
|
||||
new JsonHierarchicalStreamDriver() {
|
||||
public HierarchicalStreamWriter createWriter(Writer writer) {
|
||||
return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE);
|
||||
}
|
||||
});
|
||||
|
||||
@XStreamAlias("ToUserName")
|
||||
private String toUserName; // 开发者微信号
|
||||
@XStreamAlias("FromUserName")
|
||||
private String fromUserName; // 发送方帐号(一个OpenID)
|
||||
@XStreamAlias("CreateTime")
|
||||
private long createTime = System.currentTimeMillis(); // 消息创建时间 (整型)
|
||||
@XStreamAlias("MsgType")
|
||||
private MessageType msgType; // 消息类型
|
||||
@XStreamAlias("MsgId")
|
||||
private long msgId; // 消息ID
|
||||
|
||||
static {
|
||||
Class<?>[] classes = ClassUtil.getClasses(
|
||||
TextMessage.class.getPackage()).toArray(new Class[0]);
|
||||
|
||||
xmlStream.ignoreUnknownElements();
|
||||
xmlStream.autodetectAnnotations(true);
|
||||
xmlStream.processAnnotations(classes);
|
||||
xmlStream.omitField(BaseMessage.class, "msgId");
|
||||
|
||||
jsonStream.setMode(XStream.NO_REFERENCES);
|
||||
jsonStream.autodetectAnnotations(true);
|
||||
jsonStream.processAnnotations(classes);
|
||||
jsonStream.omitField(BaseMessage.class, "msgId");
|
||||
}
|
||||
|
||||
public BaseMessage(MessageType msgType) {
|
||||
this.msgType = msgType;
|
||||
}
|
||||
|
||||
public BaseMessage(MessageType msgType, BaseMessage inMessage) {
|
||||
this(msgType, inMessage.getFromUserName(), inMessage.getToUserName());
|
||||
}
|
||||
|
||||
public BaseMessage(MessageType msgType, String toUserName,
|
||||
String fromUserName) {
|
||||
this.msgType = msgType;
|
||||
this.toUserName = toUserName;
|
||||
this.fromUserName = fromUserName;
|
||||
}
|
||||
|
||||
public String getToUserName() {
|
||||
return toUserName;
|
||||
}
|
||||
|
||||
public void setToUserName(String toUserName) {
|
||||
this.toUserName = toUserName;
|
||||
}
|
||||
|
||||
public String getFromUserName() {
|
||||
return fromUserName;
|
||||
}
|
||||
|
||||
public void setFromUserName(String fromUserName) {
|
||||
this.fromUserName = fromUserName;
|
||||
}
|
||||
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(long createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public MessageType getMsgType() {
|
||||
return msgType;
|
||||
}
|
||||
|
||||
public void setMsgType(MessageType msgType) {
|
||||
this.msgType = msgType;
|
||||
}
|
||||
|
||||
public long getMsgId() {
|
||||
return msgId;
|
||||
}
|
||||
|
||||
public void setMsgId(long msgId) {
|
||||
this.msgId = msgId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof BaseMessage) {
|
||||
return ((BaseMessage) obj).getMsgId() == msgId;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected XStream getXStream() {
|
||||
Class<? extends BaseMessage> targetClass = getMsgType()
|
||||
.getMessageClass();
|
||||
xmlStream.alias("xml", targetClass);
|
||||
return xmlStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息对象转换为微信服务器接受的xml格式消息
|
||||
*
|
||||
* @return xml字符串
|
||||
*/
|
||||
public String toXml() {
|
||||
return getXStream().toXML(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息对象转换为微信服务器接受的json格式字符串
|
||||
*
|
||||
* @return json字符串
|
||||
*/
|
||||
public String toJson() {
|
||||
return jsonStream.toXML(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.foxinmy.weixin4j.msg;
|
||||
|
||||
import com.foxinmy.weixin4j.type.MessageType;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 图片消息
|
||||
*
|
||||
* @className ImageMessage
|
||||
* @author jy.hu
|
||||
* @date 2014年4月6日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E5.9B.BE.E7.89.87.E6.B6.88.E6.81.AF">图片消息</a>
|
||||
*/
|
||||
public class ImageMessage extends BaseMessage {
|
||||
|
||||
private static final long serialVersionUID = 8430800898756567016L;
|
||||
|
||||
public ImageMessage() {
|
||||
super(MessageType.image);
|
||||
}
|
||||
|
||||
@XStreamAlias("PicUrl")
|
||||
private String picUrl; // 图片链接
|
||||
@XStreamAlias("MediaId")
|
||||
private String mediaId; // 图片消息媒体id,可以调用多媒体文件下载接口拉取数据。
|
||||
|
||||
public String getPicUrl() {
|
||||
return picUrl;
|
||||
}
|
||||
|
||||
public String getMediaId() {
|
||||
return mediaId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[ImageMessage ,toUserName=").append(super.getToUserName());
|
||||
sb.append(" ,fromUserName=").append(super.getFromUserName());
|
||||
sb.append(" ,msgType=").append(super.getMsgType().name());
|
||||
sb.append(" ,picUrl=").append(picUrl);
|
||||
sb.append(" ,mediaId=").append(mediaId);
|
||||
sb.append(" ,createTime=").append(super.getCreateTime());
|
||||
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.foxinmy.weixin4j.msg;
|
||||
|
||||
import com.foxinmy.weixin4j.type.MessageType;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 链接消息
|
||||
*
|
||||
* @className LinkMessage
|
||||
* @author jy.hu
|
||||
* @date 2014年4月6日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E9.93.BE.E6.8E.A5.E6.B6.88.E6.81.AF">链接消息</a>
|
||||
*/
|
||||
public class LinkMessage extends BaseMessage {
|
||||
|
||||
private static final long serialVersionUID = 754952745115497030L;
|
||||
|
||||
public LinkMessage() {
|
||||
super(MessageType.link);
|
||||
}
|
||||
|
||||
@XStreamAlias("Title")
|
||||
private String title; // 消息标题
|
||||
@XStreamAlias("Description")
|
||||
private String description; // 消息描述
|
||||
@XStreamAlias("url")
|
||||
private String url; // 消息链接
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[LinkMessage ,toUserName=").append(super.getToUserName());
|
||||
sb.append(" ,fromUserName=").append(super.getFromUserName());
|
||||
sb.append(" ,msgType=").append(super.getMsgType().name());
|
||||
sb.append(" ,title=").append(title);
|
||||
sb.append(" ,description=").append(description);
|
||||
sb.append(" ,url=").append(url);
|
||||
sb.append(" ,createTime=").append(super.getCreateTime());
|
||||
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.foxinmy.weixin4j.msg;
|
||||
|
||||
import com.foxinmy.weixin4j.type.MessageType;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 地理位置消息
|
||||
*
|
||||
* @className LocationMessage
|
||||
* @author jy.hu
|
||||
* @date 2014年4月6日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E6.B6.88.E6.81.AF">地理位置消息</a>
|
||||
*/
|
||||
public class LocationMessage extends BaseMessage {
|
||||
|
||||
private static final long serialVersionUID = 2866021596599237334L;
|
||||
|
||||
public LocationMessage() {
|
||||
super(MessageType.location);
|
||||
}
|
||||
|
||||
@XStreamAlias("Location_X")
|
||||
private double x; // 地理位置维度
|
||||
@XStreamAlias("Location_Y")
|
||||
private double y; // 地理位置经度
|
||||
@XStreamAlias("Scale")
|
||||
private double scale; // 地图缩放大小
|
||||
@XStreamAlias("Label")
|
||||
private String label; // 地理位置信息
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public double getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[LocationMessage ,toUserName=")
|
||||
.append(super.getToUserName());
|
||||
sb.append(" ,fromUserName=").append(super.getFromUserName());
|
||||
sb.append(" ,msgType=").append(super.getMsgType().name());
|
||||
sb.append(" ,location_X=").append(x);
|
||||
sb.append(" ,location_Y=").append(y);
|
||||
sb.append(" ,scale=").append(scale);
|
||||
sb.append(" ,label=").append(label);
|
||||
sb.append(" ,createTime=").append(super.getCreateTime());
|
||||
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
普通消息
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.foxinmy.weixin4j.msg;
|
||||
|
||||
import com.foxinmy.weixin4j.type.MessageType;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 文本消息(接收|回复)
|
||||
*
|
||||
* @className TextMessage
|
||||
* @author jy.hu
|
||||
* @date 2014年4月6日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">接收文本消息</a>
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF#.E5.9B.9E.E5.A4.8D.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">回复文本消息</a>
|
||||
* @see com.foxinmy.weixin4j.msg.BaseMessage
|
||||
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
|
||||
*/
|
||||
public class TextMessage extends BaseMessage {
|
||||
|
||||
private static final long serialVersionUID = -7018053906644190260L;
|
||||
|
||||
public TextMessage() {
|
||||
super(MessageType.text);
|
||||
}
|
||||
|
||||
public TextMessage(String content, BaseMessage inMessage) {
|
||||
super(MessageType.text, inMessage);
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@XStreamAlias("Content")
|
||||
private String content; // 消息内容
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[TextMessage ,toUserName=").append(super.getToUserName());
|
||||
sb.append(" ,fromUserName=").append(super.getFromUserName());
|
||||
sb.append(" ,msgType=").append(super.getMsgType().name());
|
||||
sb.append(" ,content=").append(content);
|
||||
sb.append(" ,createTime=").append(super.getCreateTime());
|
||||
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.foxinmy.weixin4j.msg;
|
||||
|
||||
import com.foxinmy.weixin4j.type.MessageType;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 视频消息
|
||||
*
|
||||
* @className VideoMessage
|
||||
* @author jy.hu
|
||||
* @date 2014年4月6日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E8.A7.86.E9.A2.91.E6.B6.88.E6.81.AF">视频消息</a>
|
||||
*/
|
||||
public class VideoMessage extends BaseMessage {
|
||||
|
||||
private static final long serialVersionUID = -1013075358679078381L;
|
||||
|
||||
public VideoMessage() {
|
||||
super(MessageType.video);
|
||||
}
|
||||
|
||||
@XStreamAlias("MediaId")
|
||||
private String mediaId; // 视频消息媒体id,可以调用多媒体文件下载接口拉取数据。
|
||||
@XStreamAlias("ThumbMediaId")
|
||||
private String thumbMediaId; // 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
|
||||
|
||||
public String getMediaId() {
|
||||
return mediaId;
|
||||
}
|
||||
|
||||
public String getThumbMediaId() {
|
||||
return thumbMediaId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[VideoMessage ,toUserName=").append(super.getToUserName());
|
||||
sb.append(" ,fromUserName=").append(super.getFromUserName());
|
||||
sb.append(" ,msgType=").append(super.getMsgType().name());
|
||||
sb.append(" ,mediaId=").append(mediaId);
|
||||
sb.append(" ,thumbMediaId=").append(thumbMediaId);
|
||||
sb.append(" ,createTime=").append(super.getCreateTime());
|
||||
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.foxinmy.weixin4j.msg;
|
||||
|
||||
import com.foxinmy.weixin4j.type.MessageType;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 语音消息
|
||||
* <p>
|
||||
* 开通语音识别功能,用户每次发送语音给公众号时,微信会在推送的语音消息XML数据包中,赋值到Recongnition字段.
|
||||
* </p>
|
||||
*
|
||||
* @className VoiceMessage
|
||||
* @author jy.hu
|
||||
* @date 2014年4月6日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E8.AF.AD.E9.9F.B3.E6.B6.88.E6.81.AF">语音消息</a>
|
||||
*/
|
||||
public class VoiceMessage extends BaseMessage {
|
||||
|
||||
private static final long serialVersionUID = -7988380977182214003L;
|
||||
|
||||
public VoiceMessage() {
|
||||
super(MessageType.voice);
|
||||
}
|
||||
|
||||
@XStreamAlias("MediaId")
|
||||
private String mediaId; // 语音消息媒体id,可以调用多媒体文件下载接口拉取数据。
|
||||
@XStreamAlias("Format")
|
||||
private String format; // 语音格式,如amr,speex等
|
||||
|
||||
@XStreamAlias("Recognition")
|
||||
private String recognition; // 语音识别结果,UTF8编码
|
||||
|
||||
public String getRecognition() {
|
||||
return recognition;
|
||||
}
|
||||
|
||||
public String getMediaId() {
|
||||
return mediaId;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[VoiceMessage ,toUserName=").append(super.getToUserName());
|
||||
sb.append(" ,fromUserName=").append(super.getFromUserName());
|
||||
sb.append(" ,msgType=").append(super.getMsgType().name());
|
||||
sb.append(" ,mediaId=").append(mediaId);
|
||||
sb.append(" ,format=").append(format);
|
||||
sb.append(" ,recognition=").append(recognition);
|
||||
sb.append(" ,createTime=").append(super.getCreateTime());
|
||||
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.foxinmy.weixin4j.msg.event;
|
||||
|
||||
import com.foxinmy.weixin4j.msg.BaseMessage;
|
||||
import com.foxinmy.weixin4j.type.EventType;
|
||||
import com.foxinmy.weixin4j.type.MessageType;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 事件消息基类
|
||||
* @className EventMessage
|
||||
* @author jy.hu
|
||||
* @date 2014年4月6日
|
||||
* @since JDK 1.7
|
||||
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81">事件推送</a>
|
||||
*/
|
||||
public class EventMessage extends BaseMessage {
|
||||
|
||||
private static final long serialVersionUID = 7703667223814088865L;
|
||||
|
||||
public EventMessage(EventType eventType) {
|
||||
super(MessageType.event);
|
||||
this.eventType = eventType;
|
||||
}
|
||||
|
||||
@XStreamAlias("Event")
|
||||
private EventType eventType;
|
||||
|
||||
public EventType getEventType() {
|
||||
return eventType;
|
||||
}
|
||||
|
||||
public void setEventType(EventType eventType) {
|
||||
this.eventType = eventType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[EventMessage ,toUserName=").append(super.getToUserName());
|
||||
sb.append(" ,fromUserName=").append(super.getFromUserName());
|
||||
sb.append(" ,msgType=").append(super.getMsgType().name());
|
||||
sb.append(" ,eventType=").append(eventType.name());
|
||||
sb.append(" ,createTime=").append(super.getCreateTime());
|
||||
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.foxinmy.weixin4j.msg.event;
|
||||
|
||||
import com.foxinmy.weixin4j.type.EventType;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 上报地理位置事件
|
||||
*
|
||||
* @className LocationEventMessage
|
||||
* @author jy.hu
|
||||
* @date 2014年4月6日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E4.B8.8A.E6.8A.A5.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E4.BA.8B.E4.BB.B6">上报地理位置事件</a>
|
||||
*/
|
||||
public class LocationEventMessage extends EventMessage {
|
||||
|
||||
private static final long serialVersionUID = -2030716800669824861L;
|
||||
|
||||
public LocationEventMessage() {
|
||||
super(EventType.location);
|
||||
}
|
||||
|
||||
@XStreamAlias("Latitude")
|
||||
private String latitude;// 地理位置纬度
|
||||
@XStreamAlias("Longitude")
|
||||
private String longitude;// 地理位置经度
|
||||
@XStreamAlias("Precision")
|
||||
private String precision;// 地理位置精度
|
||||
|
||||
public String getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public String getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
public String getPrecision() {
|
||||
return precision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[LocationEventMessage ,toUserName=").append(
|
||||
super.getToUserName());
|
||||
sb.append(" ,fromUserName=").append(super.getFromUserName());
|
||||
sb.append(" ,msgType=").append(super.getMsgType().name());
|
||||
sb.append(" ,eventType=").append(super.getEventType().name());
|
||||
sb.append(" ,longitude=").append(longitude);
|
||||
sb.append(" ,latitude=").append(latitude);
|
||||
sb.append(" ,precision=").append(precision);
|
||||
sb.append(" ,createTime=").append(super.getCreateTime());
|
||||
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.foxinmy.weixin4j.msg.event;
|
||||
|
||||
import com.foxinmy.weixin4j.type.EventType;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 群发消息事件推送
|
||||
*
|
||||
* @className MassEventMessage
|
||||
* @author jy
|
||||
* @date 2014年4月27日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3#.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81.E7.BE.A4.E5.8F.91.E7.BB.93.E6.9E.9C">群发回调</a>
|
||||
*/
|
||||
public class MassEventMessage extends EventMessage {
|
||||
|
||||
private static final long serialVersionUID = -1660543255873723895L;
|
||||
|
||||
public MassEventMessage() {
|
||||
super(EventType.massendjobfinish);
|
||||
}
|
||||
|
||||
@XStreamAlias("Status")
|
||||
private String status;
|
||||
@XStreamAlias("TotalCount")
|
||||
private int totalCount;
|
||||
@XStreamAlias("FilterCount")
|
||||
private int filterCount;
|
||||
@XStreamAlias("SentCount")
|
||||
private int sentCount;
|
||||
@XStreamAlias("ErrorCount")
|
||||
private int errorCount;
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public int getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public int getFilterCount() {
|
||||
return filterCount;
|
||||
}
|
||||
|
||||
public int getSentCount() {
|
||||
return sentCount;
|
||||
}
|
||||
|
||||
public int getErrorCount() {
|
||||
return errorCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[MassEventMessage ,toUserName=").append(
|
||||
super.getToUserName());
|
||||
sb.append(" ,fromUserName=").append(super.getFromUserName());
|
||||
sb.append(" ,msgType=").append(super.getMsgType().name());
|
||||
sb.append(" ,eventType=").append(super.getEventType().name());
|
||||
sb.append(" ,status=").append(status);
|
||||
sb.append(" ,totalCount=").append(totalCount);
|
||||
sb.append(" ,filterCount=").append(filterCount);
|
||||
sb.append(" ,sentCount=").append(sentCount);
|
||||
sb.append(" ,errorCount=").append(errorCount);
|
||||
sb.append(" ,createTime=").append(super.getCreateTime());
|
||||
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
事件消息
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.foxinmy.weixin4j.msg.event;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 扫描二维码事件
|
||||
*
|
||||
* @className ScanEventMessage
|
||||
* @author jy.hu
|
||||
* @date 2014年4月6日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E6.89.AB.E6.8F.8F.E5.B8.A6.E5.8F.82.E6.95.B0.E4.BA.8C.E7.BB.B4.E7.A0.81.E4.BA.8B.E4.BB.B6">扫描二维码事件</a>
|
||||
*/
|
||||
public class ScanEventMessage extends EventMessage {
|
||||
|
||||
public ScanEventMessage() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 8078674062833071562L;
|
||||
private static final String PARA_PREFIX = "qrscene_";
|
||||
|
||||
@XStreamAlias("EventKey")
|
||||
private String eventKey; // 事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id
|
||||
@XStreamAlias("Ticket")
|
||||
private String ticket; // 二维码的ticket,可用来换取二维码图片
|
||||
|
||||
public String getEventKey() {
|
||||
return eventKey;
|
||||
}
|
||||
|
||||
public String getTicket() {
|
||||
return ticket;
|
||||
}
|
||||
|
||||
public String getParameter() {
|
||||
return eventKey.replace(PARA_PREFIX, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[ScanEventMessage ,toUserName=").append(
|
||||
super.getToUserName());
|
||||
sb.append(" ,fromUserName=").append(super.getFromUserName());
|
||||
sb.append(" ,msgType=").append(super.getMsgType().name());
|
||||
sb.append(" ,eventType=").append(super.getEventType().name());
|
||||
sb.append(" ,eventKey=").append(eventKey);
|
||||
sb.append(" ,ticket=").append(ticket);
|
||||
sb.append(" ,createTime=").append(super.getCreateTime());
|
||||
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.foxinmy.weixin4j.msg.event;
|
||||
|
||||
|
||||
/**
|
||||
* 关注/取消关注事件
|
||||
* <font color="red">包括直接关注与扫描关注</font>
|
||||
* @className ScribeEventMessage
|
||||
* @author jy.hu
|
||||
* @date 2014年4月6日
|
||||
* @since JDK 1.7
|
||||
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E5.85.B3.E6.B3.A8.2F.E5.8F.96.E6.B6.88.E5.85.B3.E6.B3.A8.E4.BA.8B.E4.BB.B6">关注/取消关注事件</a>
|
||||
*/
|
||||
public class ScribeEventMessage extends ScanEventMessage {
|
||||
|
||||
private static final long serialVersionUID = -6846321620262204915L;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[ScribeEventMessage ,toUserName=").append(super.getToUserName());
|
||||
sb.append(" ,fromUserName=").append(super.getFromUserName());
|
||||
sb.append(" ,msgType=").append(super.getMsgType().name());
|
||||
sb.append(" ,eventType=").append(super.getEventType().name());
|
||||
sb.append(" ,eventKey=").append(super.getEventKey());
|
||||
sb.append(" ,ticket=").append(super.getTicket());
|
||||
sb.append(" ,createTime=").append(super.getCreateTime());
|
||||
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.foxinmy.weixin4j.msg.event;
|
||||
|
||||
import com.foxinmy.weixin4j.type.EventType;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 模板消息事件推送
|
||||
*
|
||||
* @className TemplatesendjobfinishMessage
|
||||
* @author jy
|
||||
* @date 2014年9月19日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF%E6%8E%A5%E5%8F%A3">模板消息事件推送</a>
|
||||
*/
|
||||
public class TemplatesendjobfinishMessage extends EventMessage {
|
||||
|
||||
private static final long serialVersionUID = -2903359365988594012L;
|
||||
|
||||
public TemplatesendjobfinishMessage() {
|
||||
super(EventType.templatesendjobfinish);
|
||||
}
|
||||
|
||||
@XStreamAlias("Status")
|
||||
private String status; // 推送状态
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TemplatesendjobfinishMessage [status=" + status + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.foxinmy.weixin4j.msg.event.menu;
|
||||
|
||||
import com.foxinmy.weixin4j.msg.event.EventMessage;
|
||||
import com.foxinmy.weixin4j.type.EventType;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 自定义菜单事件(view|click)
|
||||
*
|
||||
* @className MenuEventMessage
|
||||
* @author jy.hu
|
||||
* @date 2014年4月6日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E7.82.B9.E5.87.BB.E8.8F.9C.E5.8D.95.E6.8B.89.E5.8F.96.E6.B6.88.E6.81.AF.E6.97.B6.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">菜单事件</a>
|
||||
*/
|
||||
public class MenuEventMessage extends EventMessage {
|
||||
|
||||
private static final long serialVersionUID = -1049672447995366063L;
|
||||
|
||||
public MenuEventMessage() {
|
||||
super(EventType.click);
|
||||
}
|
||||
|
||||
@XStreamAlias("EventKey")
|
||||
private String eventKey; // 事件KEY值,与自定义菜单接口中KEY值对应
|
||||
|
||||
public String getEventKey() {
|
||||
return eventKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[MenuEventMessage ,toUserName=").append(
|
||||
super.getToUserName());
|
||||
sb.append(" ,fromUserName=").append(super.getFromUserName());
|
||||
sb.append(" ,msgType=").append(super.getMsgType().name());
|
||||
sb.append(" ,eventType=").append(super.getEventType().name());
|
||||
sb.append(" ,eventKey=").append(eventKey);
|
||||
sb.append(" ,createTime=").append(super.getCreateTime());
|
||||
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package com.foxinmy.weixin4j.msg.event.menu;
|
||||
|
||||
import com.foxinmy.weixin4j.type.EventType;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 弹出地理位置选择器的事件推送
|
||||
*
|
||||
* @className MenuLocationEventMessage
|
||||
* @author jy
|
||||
* @date 2014年9月30日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#location_select.EF.BC.9A.E5.BC.B9.E5.87.BA.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E9.80.89.E6.8B.A9.E5.99.A8.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">弹出地理位置选择事件推送</a>
|
||||
*/
|
||||
public class MenuLocationEventMessage extends MenuEventMessage {
|
||||
|
||||
private static final long serialVersionUID = 145223888272819563L;
|
||||
|
||||
public MenuLocationEventMessage() {
|
||||
super.setEventType(EventType.location_select);
|
||||
}
|
||||
|
||||
@XStreamAlias("SendLocationInfo")
|
||||
private LocationInfo locationInfo;
|
||||
|
||||
public LocationInfo getLocationInfo() {
|
||||
return locationInfo;
|
||||
}
|
||||
|
||||
public static class LocationInfo {
|
||||
@XStreamAlias("Location_X")
|
||||
private double x; // 地理位置维度
|
||||
@XStreamAlias("Location_Y")
|
||||
private double y; // 地理位置经度
|
||||
@XStreamAlias("Scale")
|
||||
private double scale; // 地图缩放大小
|
||||
@XStreamAlias("Label")
|
||||
private String label; // 地理位置信息
|
||||
@XStreamAlias("Poiname")
|
||||
private String poiname;
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public double getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public String getPoiname() {
|
||||
return poiname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LocationInfo [x=" + x + ", y=" + y + ", scale=" + scale
|
||||
+ ", label=" + label + ", poiname=" + poiname + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MenuLocationEventMessage [locationInfo=" + locationInfo + "]";
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.foxinmy.weixin4j.msg.event.menu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 弹出拍照或者相册发图的事件推送(pic_sysphoto|pic_photo_or_album|pic_weixin)
|
||||
*
|
||||
* @className MenuPhotoEventMessage
|
||||
* @author jy
|
||||
* @date 2014年9月30日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#pic_sysphoto.EF.BC.9A.E5.BC.B9.E5.87.BA.E7.B3.BB.E7.BB.9F.E6.8B.8D.E7.85.A7.E5.8F.91.E5.9B.BE.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">弹出系统拍照发图的事件推送</a>
|
||||
*/
|
||||
public class MenuPhotoEventMessage extends MenuEventMessage {
|
||||
|
||||
private static final long serialVersionUID = 3142350663022709730L;
|
||||
|
||||
@XStreamAlias("SendPicsInfo")
|
||||
private PictureInfo pictureInfo;
|
||||
|
||||
public PictureInfo getPictureInfo() {
|
||||
return pictureInfo;
|
||||
}
|
||||
|
||||
public static class PictureInfo {
|
||||
@XStreamAlias("Count")
|
||||
private int count;
|
||||
@XStreamAlias("PicList")
|
||||
private List<PictureItem> items;
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public List<PictureItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PictureInfo [count=" + count + ", items=" + items + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@XStreamAlias("item")
|
||||
public static class PictureItem {
|
||||
@XStreamAlias("PicMd5Sum")
|
||||
private String md5;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PictureItem [md5=" + md5 + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MenuPhotoEventMessage [pictureInfo=" + pictureInfo + "]";
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.foxinmy.weixin4j.msg.event.menu;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
/**
|
||||
* 扫码推事件(scancode_push|scancode_waitmsg)
|
||||
*
|
||||
* @className MenuScanPushEventMessage
|
||||
* @author jy
|
||||
* @date 2014年9月30日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#scancode_push.EF.BC.9A.E6.89.AB.E7.A0.81.E6.8E.A8.E4.BA.8B.E4.BB.B6.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">扫码推事件的事件推送</a>
|
||||
*/
|
||||
public class MenuScanEventMessage extends MenuEventMessage {
|
||||
|
||||
private static final long serialVersionUID = 3142350663022709730L;
|
||||
|
||||
@XStreamAlias("ScanCodeInfo")
|
||||
private ScanInfo scanInfo;
|
||||
|
||||
public ScanInfo getScanInfo() {
|
||||
return scanInfo;
|
||||
}
|
||||
|
||||
public static class ScanInfo {
|
||||
@XStreamAlias("ScanType")
|
||||
private String type;
|
||||
@XStreamAlias("ScanResult")
|
||||
private String result;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ScanInfo [type=" + type + ", result=" + result + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MenuScanPushEventMessage [scanInfo=" + scanInfo + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
底部菜单消息
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.foxinmy.weixin4j.token;
|
||||
|
||||
import com.foxinmy.weixin4j.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* 获取config.properties中的appid&appsecret信息
|
||||
*
|
||||
* @className AbstractTokenApi
|
||||
* @author jy
|
||||
* @date 2014年10月6日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public abstract class AbstractTokenApi implements TokenApi {
|
||||
|
||||
protected String getAppid() {
|
||||
return ConfigUtil.getValue("app_id");
|
||||
}
|
||||
|
||||
protected String getAppsecret() {
|
||||
return ConfigUtil.getValue("app_secret");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.foxinmy.weixin4j.token;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Calendar;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
import com.foxinmy.weixin4j.http.HttpRequest;
|
||||
import com.foxinmy.weixin4j.http.Response;
|
||||
import com.foxinmy.weixin4j.model.Token;
|
||||
import com.foxinmy.weixin4j.util.ConfigUtil;
|
||||
import com.foxinmy.weixin4j.xml.XStream;
|
||||
|
||||
/**
|
||||
* 基于文件保存的Token获取类
|
||||
*
|
||||
* @className FileTokenApi
|
||||
* @author jy.hu
|
||||
* @date 2014年9月27日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token">获取token说明</a>
|
||||
* @see com.foxinmy.weixin4j.model.Token
|
||||
*/
|
||||
public class FileTokenApi extends AbstractTokenApi {
|
||||
|
||||
private final HttpRequest request = new HttpRequest();
|
||||
|
||||
private final String appid;
|
||||
private final String appsecret;
|
||||
|
||||
public FileTokenApi() {
|
||||
this.appid = getAppid();
|
||||
this.appsecret = getAppsecret();
|
||||
}
|
||||
|
||||
public FileTokenApi(String appid, String appsecret) {
|
||||
this.appid = appid;
|
||||
this.appsecret = appsecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token
|
||||
* <p>
|
||||
* 正常情况下返回{"access_token":"ACCESS_TOKEN","expires_in":7200},否则抛出异常.
|
||||
* </p>
|
||||
*
|
||||
* @return token对象
|
||||
* @throws WeixinException
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token">获取token说明</a>
|
||||
* @see com.foxinmy.weixin4j.model.Token
|
||||
*/
|
||||
@Override
|
||||
public Token getToken() throws WeixinException {
|
||||
if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) {
|
||||
throw new IllegalArgumentException(
|
||||
"appid or appsecret not be null!");
|
||||
}
|
||||
XStream xstream = new XStream();
|
||||
xstream.autodetectAnnotations(true);
|
||||
xstream.processAnnotations(Token.class);
|
||||
File token_file = new File(String.format("%s/token_%s.xml",
|
||||
ConfigUtil.getValue("token_path"), appid));
|
||||
Token token = null;
|
||||
Calendar ca = Calendar.getInstance();
|
||||
long now_time = ca.getTimeInMillis();
|
||||
try {
|
||||
String api_token_uri = String.format(
|
||||
ConfigUtil.getValue("api_token_uri"), appid, appsecret);
|
||||
Response response = null;
|
||||
if (token_file.exists()) {
|
||||
token = (Token) xstream.fromXML(token_file);
|
||||
|
||||
long expise_time = token.getTime()
|
||||
+ (token.getExpiresIn() * 1000) - 3;
|
||||
if (expise_time > now_time) {
|
||||
return token;
|
||||
}
|
||||
response = request.get(api_token_uri);
|
||||
} else {
|
||||
response = request.get(api_token_uri);
|
||||
try {
|
||||
token_file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
token_file.getParentFile().mkdirs();
|
||||
}
|
||||
}
|
||||
token = response.getAsObject(Token.class);
|
||||
token.setTime(now_time);
|
||||
token.setOpenid(appid);
|
||||
xstream.toXML(token, new FileOutputStream(token_file));
|
||||
} catch (IOException e) {
|
||||
;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Token的实现
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.foxinmy.weixin4j.token;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
import com.foxinmy.weixin4j.http.HttpRequest;
|
||||
import com.foxinmy.weixin4j.model.Token;
|
||||
import com.foxinmy.weixin4j.util.ConfigUtil;
|
||||
|
||||
/**
|
||||
* 基于redis保存的Token获取类
|
||||
*
|
||||
* @className RedisTokenApi
|
||||
* @author jy.hu
|
||||
* @date 2014年9月27日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token">获取token说明</a>
|
||||
* @see com.foxinmy.weixin4j.model.Token
|
||||
*/
|
||||
public class RedisTokenApi extends AbstractTokenApi {
|
||||
|
||||
private final HttpRequest request = new HttpRequest();
|
||||
|
||||
private final String appid;
|
||||
private final String appsecret;
|
||||
private JedisPool jedisPool;
|
||||
|
||||
public RedisTokenApi() {
|
||||
this.appid = getAppid();
|
||||
this.appsecret = getAppsecret();
|
||||
}
|
||||
|
||||
public RedisTokenApi(String appid, String appsecret) {
|
||||
this(appid, appsecret, "localhost", 6379);
|
||||
}
|
||||
|
||||
public RedisTokenApi(String appid, String appsecret, String host, int port) {
|
||||
this.appid = appid;
|
||||
this.appsecret = appsecret;
|
||||
JedisPoolConfig poolConfig = new JedisPoolConfig();
|
||||
poolConfig.setMaxTotal(50);
|
||||
poolConfig.setMaxIdle(5);
|
||||
poolConfig.setMaxWaitMillis(2000);
|
||||
poolConfig.setTestOnBorrow(false);
|
||||
poolConfig.setTestOnReturn(true);
|
||||
this.jedisPool = new JedisPool(poolConfig, host, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token getToken() throws WeixinException {
|
||||
if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) {
|
||||
throw new IllegalArgumentException(
|
||||
"appid or appsecret not be null!");
|
||||
}
|
||||
Token token = null;
|
||||
Jedis jedis = null;
|
||||
try {
|
||||
jedis = jedisPool.getResource();
|
||||
String key = String.format("token:%s", appid);
|
||||
String accessToken = jedis.get(key);
|
||||
if (StringUtils.isBlank(accessToken)) {
|
||||
String api_token_uri = String.format(
|
||||
ConfigUtil.getValue("api_token_uri"), appid, appsecret);
|
||||
token = request.get(api_token_uri).getAsObject(Token.class);
|
||||
jedis.setex(key, token.getExpiresIn() - 3,
|
||||
token.getAccessToken());
|
||||
} else {
|
||||
token = new Token();
|
||||
token.setAccessToken(accessToken);
|
||||
token.setExpiresIn(jedis.ttl(key).intValue());
|
||||
}
|
||||
token.setTime(System.currentTimeMillis());
|
||||
token.setOpenid(appid);
|
||||
} catch (Exception e) {
|
||||
jedisPool.returnBrokenResource(jedis);
|
||||
} finally {
|
||||
jedisPool.returnResource(jedis);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.foxinmy.weixin4j.token;
|
||||
|
||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
import com.foxinmy.weixin4j.model.Token;
|
||||
|
||||
/**
|
||||
* 获取Token接口
|
||||
*
|
||||
* @className TokenApi
|
||||
* @author jy.hu
|
||||
* @date 2014年9月27日
|
||||
* @since JDK 1.7
|
||||
* @see com.foxinmy.weixin4j.model.Token
|
||||
* @see com.foxinmy.weixin4j.token.AbstractTokenApi
|
||||
* @see com.foxinmy.weixin4j.token.FileTokenApi
|
||||
* @see com.foxinmy.weixin4j.token.RedisTokenApi
|
||||
*/
|
||||
public interface TokenApi {
|
||||
public Token getToken() throws WeixinException;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.foxinmy.weixin4j.type;
|
||||
|
||||
/**
|
||||
* 自定义菜单类型 <br/>
|
||||
* <font color="red">scancode_push 到 location_selec
|
||||
* 仅支持微信iPhone5.4.1以上版本,和Android5 .4以上版本的微信用户 旧版本微信用户点击后将没有回应
|
||||
* 开发者也不能正常接收到事件推送。</font>
|
||||
*
|
||||
* @className ButtonType
|
||||
* @author jy
|
||||
* @date 2014年9月30日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3">按钮类型</a>
|
||||
*/
|
||||
public enum ButtonType {
|
||||
/**
|
||||
* 点击推事件 用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event
|
||||
* 的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互;
|
||||
*/
|
||||
click,
|
||||
/**
|
||||
* 跳转URL 用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的网页URL,可与网页授权获取用户基本信息接口结合,获得用户基本信息。
|
||||
*/
|
||||
view,
|
||||
/**
|
||||
* 扫码推事件 用户点击按钮后,微信客户端将调起扫一扫工具,完成扫码操作后显示扫描结果(如果是URL,将进入URL),且会将扫码的结果传给开发者,
|
||||
* 开发者可以下发消息。
|
||||
*/
|
||||
scancode_push,
|
||||
/**
|
||||
* 扫码推事件且弹出“消息接收中”提示框用户点击按钮后,微信客户端将调起扫一扫工具,完成扫码操作后,将扫码的结果传给开发者,同时收起扫一扫工具,
|
||||
* 然后弹出“消息接收中”提示框,随后可能会收到开发者下发的消息。
|
||||
*/
|
||||
scancode_waitmsg,
|
||||
/**
|
||||
* 弹出系统拍照发图用户点击按钮后,微信客户端将调起系统相机,完成拍照操作后,会将拍摄的相片发送给开发者,并推送事件给开发者,同时收起系统相机,
|
||||
* 随后可能会收到开发者下发的消息。
|
||||
*/
|
||||
pic_sysphoto,
|
||||
/**
|
||||
* 弹出拍照或者相册发图用户点击按钮后,微信客户端将弹出选择器供用户选择“拍照”或者“从手机相册选择”。用户选择后即走其他两种流程。
|
||||
*/
|
||||
pic_photo_or_albu,
|
||||
/**
|
||||
* 弹出微信相册发图器用户点击按钮后,微信客户端将调起微信相册,完成选择操作后,将选择的相片发送给开发者的服务器,并推送事件给开发者,同时收起相册,
|
||||
* 随后可能会收到开发者下发的消息。
|
||||
*/
|
||||
pic_weixin,
|
||||
/**
|
||||
* 弹出地理位置选择器用户点击按钮后,微信客户端将调起地理位置选择工具,完成选择操作后,将选择的地理位置发送给开发者的服务器,同时收起位置选择工具,
|
||||
* 随后可能会收到开发者下发的消息。
|
||||
*/
|
||||
location_select;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.foxinmy.weixin4j.type;
|
||||
|
||||
import com.foxinmy.weixin4j.msg.event.EventMessage;
|
||||
import com.foxinmy.weixin4j.msg.event.LocationEventMessage;
|
||||
import com.foxinmy.weixin4j.msg.event.MassEventMessage;
|
||||
import com.foxinmy.weixin4j.msg.event.ScanEventMessage;
|
||||
import com.foxinmy.weixin4j.msg.event.ScribeEventMessage;
|
||||
import com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage;
|
||||
import com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage;
|
||||
import com.foxinmy.weixin4j.msg.event.menu.MenuLocationEventMessage;
|
||||
import com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage;
|
||||
import com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage;
|
||||
|
||||
/**
|
||||
* 事件类型
|
||||
*
|
||||
* @className EventType
|
||||
* @author jy
|
||||
* @date 2014年9月30日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public enum EventType {
|
||||
subscribe(ScribeEventMessage.class), unsubscribe(ScribeEventMessage.class), scan(
|
||||
ScanEventMessage.class), scancode_push(MenuScanEventMessage.class), view(
|
||||
MenuEventMessage.class), scancode_waitmsg(
|
||||
MenuScanEventMessage.class), pic_sysphoto(
|
||||
MenuPhotoEventMessage.class), pic_photo_or_album(
|
||||
MenuPhotoEventMessage.class), pic_weixin(
|
||||
MenuPhotoEventMessage.class), location_select(
|
||||
MenuLocationEventMessage.class), click(MenuEventMessage.class), location(
|
||||
LocationEventMessage.class), massendjobfinish(
|
||||
MassEventMessage.class), templatesendjobfinish(
|
||||
TemplatesendjobfinishMessage.class);
|
||||
|
||||
private Class<? extends EventMessage> eventClass;
|
||||
|
||||
EventType(Class<? extends EventMessage> eventClass) {
|
||||
this.eventClass = eventClass;
|
||||
}
|
||||
|
||||
public Class<? extends EventMessage> getEventClass() {
|
||||
return eventClass;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.foxinmy.weixin4j.type;
|
||||
|
||||
/**
|
||||
* 上传的媒体类型<br/>
|
||||
* 图片(image): 128K,支持JPG格式<br/>
|
||||
* 语音(voice):256K,播放长度不超过60s,支持AMR\MP3格式<br/>
|
||||
* 视频(video):1MB,支持MP4格式<br/>
|
||||
* 缩略图(thumb):64KB,支持JPG格式<br/>
|
||||
* <p>
|
||||
* <font color='red'>媒体文件在后台保存时间为3天,即3天后media_id失效</font>
|
||||
* <p/>
|
||||
*
|
||||
* @author jy.hu
|
||||
* @date 2014年4月2日
|
||||
* @since JDK 1.7
|
||||
*/
|
||||
public enum MediaType {
|
||||
image("image/jpeg", "jpg"), voice("binary/octet-stream", "amr"), vedio(
|
||||
"binary/octet-stream", "mp4"), thumb("image/jpeg", "jpg"), text(
|
||||
"application/json", ""), music("binary/octet-stream", "mp3"), news(
|
||||
"application/json", ""), mpnews("application/json", ""), mpvideo(
|
||||
"binary/octet-stream", "");
|
||||
|
||||
MediaType(String contentType, String formatType) {
|
||||
this.contentType = contentType;
|
||||
this.formatType = formatType;
|
||||
}
|
||||
|
||||
private String contentType;
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
private String formatType;
|
||||
|
||||
public String getFormatType() {
|
||||
return formatType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.foxinmy.weixin4j.type;
|
||||
|
||||
import com.foxinmy.weixin4j.msg.BaseMessage;
|
||||
import com.foxinmy.weixin4j.msg.ImageMessage;
|
||||
import com.foxinmy.weixin4j.msg.LinkMessage;
|
||||
import com.foxinmy.weixin4j.msg.LocationMessage;
|
||||
import com.foxinmy.weixin4j.msg.TextMessage;
|
||||
import com.foxinmy.weixin4j.msg.VideoMessage;
|
||||
import com.foxinmy.weixin4j.msg.VoiceMessage;
|
||||
import com.foxinmy.weixin4j.msg.event.EventMessage;
|
||||
|
||||
/**
|
||||
*
|
||||
* 消息类型
|
||||
*
|
||||
* @author jy.hu
|
||||
*
|
||||
*/
|
||||
public enum MessageType {
|
||||
text(TextMessage.class), image(ImageMessage.class), voice(
|
||||
VoiceMessage.class), video(VideoMessage.class), location(
|
||||
LocationMessage.class), link(LinkMessage.class), event(
|
||||
EventMessage.class), signature(null);
|
||||
private Class<? extends BaseMessage> messageClass;
|
||||
|
||||
MessageType(Class<? extends BaseMessage> messageClass) {
|
||||
this.messageClass = messageClass;
|
||||
}
|
||||
|
||||
public void setMessageClass(Class<? extends BaseMessage> messageClass) {
|
||||
this.messageClass = messageClass;
|
||||
}
|
||||
|
||||
public Class<? extends BaseMessage> getMessageClass() {
|
||||
return messageClass;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
消息类型、事件类型等枚举
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.foxinmy.weixin4j.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.net.URL;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ClassUtil {
|
||||
|
||||
public static Set<Class<?>> getClasses(Package _package) {
|
||||
ClassLoader classLoader = Thread.currentThread()
|
||||
.getContextClassLoader();
|
||||
String subPath = _package.getName().replace(".", File.separator);
|
||||
URL fullPath = classLoader.getResource(subPath);
|
||||
File dir = new File(fullPath.getPath());
|
||||
return findClasses(dir, _package.getName());
|
||||
}
|
||||
|
||||
private static Set<Class<?>> findClasses(File dir, String packageName) {
|
||||
Set<Class<?>> classes = new HashSet<Class<?>>();
|
||||
File[] files = dir.listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File file, String name) {
|
||||
return file.isDirectory() || file.getName().endsWith(".class");
|
||||
}
|
||||
});
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
classes.addAll(findClasses(file,
|
||||
packageName + "." + file.getName()));
|
||||
} else {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(packageName + "."
|
||||
+ file.getName().replace(".class", ""));
|
||||
if (clazz.isInterface()) {
|
||||
continue;
|
||||
}
|
||||
classes.add(clazz);
|
||||
} catch (ClassNotFoundException e) {
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.foxinmy.weixin4j.util;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ConfigUtil {
|
||||
public ConfigUtil() {
|
||||
}
|
||||
|
||||
private static Properties props = new Properties();
|
||||
static {
|
||||
try {
|
||||
props.load(Thread.currentThread().getContextClassLoader()
|
||||
.getResourceAsStream("weixin.properties"));
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getValue(String key) {
|
||||
String url = props.getProperty(key);
|
||||
Pattern p = Pattern.compile("(\\{[^\\}]*\\})");
|
||||
Matcher m = p.matcher(url);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
String sub = null;
|
||||
while (m.find()) {
|
||||
sub = m.group();
|
||||
m.appendReplacement(sb,
|
||||
getValue(sub.substring(1, sub.length() - 1)));
|
||||
}
|
||||
m.appendTail(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(getValue("api_token_uri"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.foxinmy.weixin4j.util;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* IOUtil
|
||||
*
|
||||
* @className IOUtil
|
||||
* @author jy.hu
|
||||
* @date 2014年9月22日
|
||||
* @since JDK 1.7
|
||||
* @see org.apache.commons.io.IOUtils
|
||||
*/
|
||||
public class IOUtil {
|
||||
|
||||
private static final int EOF = -1;
|
||||
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
|
||||
|
||||
public static byte[] toByteArray(Reader input) throws IOException {
|
||||
return toByteArray(input, Charset.defaultCharset());
|
||||
}
|
||||
|
||||
public static byte[] toByteArray(Reader input, Charset encoding) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
copy(input, output, encoding);
|
||||
return output.toByteArray();
|
||||
}
|
||||
|
||||
public static void copy(Reader input, OutputStream output, Charset encoding) throws IOException {
|
||||
OutputStreamWriter out = new OutputStreamWriter(output, encoding);
|
||||
copyLarge(input, out, new char[DEFAULT_BUFFER_SIZE]);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
public static byte[] toByteArray(InputStream input) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
copyLarge(input, output, new byte[DEFAULT_BUFFER_SIZE]);
|
||||
return output.toByteArray();
|
||||
}
|
||||
|
||||
private static long copyLarge(InputStream input, OutputStream output, byte[] buffer) throws IOException {
|
||||
long count = 0;
|
||||
int n = 0;
|
||||
while (EOF != (n = input.read(buffer))) {
|
||||
output.write(buffer, 0, n);
|
||||
count += n;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static long copyLarge(Reader input, Writer output, char[] buffer) throws IOException {
|
||||
long count = 0;
|
||||
int n = 0;
|
||||
while (EOF != (n = input.read(buffer))) {
|
||||
output.write(buffer, 0, n);
|
||||
count += n;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package com.foxinmy.weixin4j.util;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.DocumentHelper;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.foxinmy.weixin4j.msg.BaseMessage;
|
||||
import com.foxinmy.weixin4j.type.EventType;
|
||||
import com.foxinmy.weixin4j.type.MessageType;
|
||||
import com.foxinmy.weixin4j.xml.XStream;
|
||||
|
||||
public class MessageUtil {
|
||||
|
||||
private final static Logger log = LoggerFactory
|
||||
.getLogger(MessageUtil.class);
|
||||
|
||||
/**
|
||||
* 验证微信签名
|
||||
*
|
||||
* @param token
|
||||
* 开发者填写的token
|
||||
* @param echostr
|
||||
* 随机字符串
|
||||
* @param timestamp
|
||||
* 时间戳
|
||||
* @param nonce
|
||||
* 随机数
|
||||
* @param signature
|
||||
* 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数
|
||||
* @return 开发者通过检验signature对请求进行相关校验。若确认此次GET请求来自微信服务器
|
||||
* 请原样返回echostr参数内容,则接入生效 成为开发者成功,否则接入失败
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97">接入指南</a>
|
||||
*/
|
||||
public static String signature(String token, String echostr,
|
||||
String timestamp, String nonce, String signature) {
|
||||
if (StringUtils.isBlank(token)) {
|
||||
log.error("signature fail : token is null!");
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.isBlank(echostr) || StringUtils.isBlank(timestamp)
|
||||
|| StringUtils.isBlank(nonce)) {
|
||||
log.error("signature fail : invalid parameter!");
|
||||
return null;
|
||||
}
|
||||
String _signature = null;
|
||||
try {
|
||||
String[] a = { token, timestamp, nonce };
|
||||
Arrays.sort(a);
|
||||
StringBuilder sb = new StringBuilder(3);
|
||||
for (String str : a) {
|
||||
sb.append(str);
|
||||
}
|
||||
_signature = DigestUtils.sha1Hex(sb.toString());
|
||||
} catch (Exception e) {
|
||||
log.error("signature error", e);
|
||||
}
|
||||
if (signature.equals(_signature)) {
|
||||
return echostr;
|
||||
} else {
|
||||
log.error("signature fail : invalid signature!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对应的mapping key
|
||||
*
|
||||
* @param xmlMsg
|
||||
* @return
|
||||
* @throws DocumentException
|
||||
* @see com.foxinmy.weixin4j.server.WeixinActionMapping
|
||||
*/
|
||||
public static String getMappingKey(String xmlMsg) throws DocumentException {
|
||||
Document doc = DocumentHelper.parseText(xmlMsg);
|
||||
String msgType = doc.selectSingleNode("/xml/MsgType").getStringValue();
|
||||
if (msgType.equalsIgnoreCase(MessageType.event.name())) {
|
||||
msgType += "_"
|
||||
+ doc.selectSingleNode("/xml/Event").getStringValue();
|
||||
}
|
||||
return msgType;
|
||||
}
|
||||
|
||||
/**
|
||||
* xml消息转换为消息对象
|
||||
*
|
||||
* @param xmlMsg
|
||||
* 消息字符串
|
||||
* @return 消息对象
|
||||
* @throws DocumentException
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AA%8C%E8%AF%81%E6%B6%88%E6%81%AF%E7%9C%9F%E5%AE%9E%E6%80%A7">验证消息的合法性</a>
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF">普通消息</a>
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81">事件触发</a>
|
||||
* @see com.foxinmy.weixin4j.type.MessageType
|
||||
* @see com.feican.weixin.msg.BaeMessage
|
||||
* @see com.foxinmy.weixin4j.msg.TextMessage
|
||||
* @see com.foxinmy.weixin4j.msg.ImageMessage
|
||||
* @see com.foxinmy.weixin4j.msg.VoiceMessage
|
||||
* @see com.foxinmy.weixin4j.msg.VideoMessage
|
||||
* @see com.foxinmy.weixin4j.msg.LocationMessage
|
||||
* @see com.foxinmy.weixin4j.msg.LinkMessage
|
||||
* @see com.foxinmy.weixin4j.msg.event.ScribeEventMessage
|
||||
* @see com.foxinmy.weixin4j.msg.event.ScanEventMessage
|
||||
* @see com.foxinmy.weixin4j.msg.event.LocationEventMessage
|
||||
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage
|
||||
*/
|
||||
public static BaseMessage xml2msg(String xmlMsg) throws DocumentException {
|
||||
Document doc = DocumentHelper.parseText(xmlMsg);
|
||||
String type = doc.selectSingleNode("/xml/MsgType").getStringValue();
|
||||
if (StringUtils.isBlank(type)) {
|
||||
return null;
|
||||
}
|
||||
MessageType messageType = MessageType.valueOf(type.toLowerCase());
|
||||
Class<? extends BaseMessage> messageClass = messageType
|
||||
.getMessageClass();
|
||||
if (messageType == MessageType.event) {
|
||||
type = doc.selectSingleNode("/xml/Event").getStringValue();
|
||||
messageClass = EventType.valueOf(type.toLowerCase())
|
||||
.getEventClass();
|
||||
}
|
||||
XStream xstream = new XStream();
|
||||
xstream.ignoreUnknownElements();
|
||||
xstream.autodetectAnnotations(true);
|
||||
xstream.processAnnotations(messageClass);
|
||||
xstream.alias("xml", messageClass);
|
||||
return xstream.fromXML(xmlMsg, messageClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* xml消息转换为消息对象
|
||||
*
|
||||
* @param inputStream
|
||||
* 带消息字符串的输入流
|
||||
* @return 消息对象
|
||||
* @throws DocumentException
|
||||
* @see {@link com.foxinmy.weixin4j.util.MessageUtil#xml2msg(String)}
|
||||
*/
|
||||
public static BaseMessage xml2msg(InputStream inputStream)
|
||||
throws DocumentException {
|
||||
SAXReader reader = new SAXReader();
|
||||
Document doc = reader.read(inputStream);
|
||||
return xml2msg(doc.asXML());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.foxinmy.weixin4j.util;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 随机码工具类
|
||||
* @className RandomUtil
|
||||
* @author jy
|
||||
* @date 2014年10月22日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class RandomUtil {
|
||||
|
||||
private static final String ALLCHAR = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
private static final String LETTERCHAR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
private static final String NUMBERCHAR = "0123456789";
|
||||
|
||||
// 返回一个定长的随机字符串(包含数字和大小写字母)
|
||||
public static String generateString(int length) {
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < length; i++) {
|
||||
sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// 返回一个定长的随机纯数字字符串(只包含数字)
|
||||
public static String generateStringByNumberChar(int length) {
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < length; i++) {
|
||||
sb.append(NUMBERCHAR.charAt(random.nextInt(NUMBERCHAR.length())));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// 返回一个定长的随机纯字母字符串(只包含大小写字母)
|
||||
public static String generateStringByLetterCharr(int length) {
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < length; i++) {
|
||||
sb.append(LETTERCHAR.charAt(random.nextInt(LETTERCHAR.length())));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// 返回一个定长的随机纯大写字母字符串(只包含大小写字母)
|
||||
public static String generateLowerString(int length) {
|
||||
return generateStringByLetterCharr(length).toLowerCase();
|
||||
}
|
||||
|
||||
// 返回一个定长的随机纯小写字母字符串(只包含大小写字母)
|
||||
public static String generateUpperString(int length) {
|
||||
return generateStringByLetterCharr(length).toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机获取UUID字符串(无中划线)
|
||||
*
|
||||
* @return UUID字符串
|
||||
*/
|
||||
public static String getUUID() {
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
return uuid.substring(0, 8) + uuid.substring(9, 13)
|
||||
+ uuid.substring(14, 18) + uuid.substring(19, 23)
|
||||
+ uuid.substring(24);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(System.nanoTime());
|
||||
System.out.println(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
添加<![CDATA[]>支持
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.foxinmy.weixin4j.xml;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Writer;
|
||||
|
||||
import com.thoughtworks.xstream.core.util.QuickWriter;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
|
||||
import com.thoughtworks.xstream.io.xml.Xpp3Driver;
|
||||
|
||||
public class XStream extends com.thoughtworks.xstream.XStream {
|
||||
|
||||
public XStream() {
|
||||
|
||||
super(new Xpp3Driver() {
|
||||
|
||||
@Override
|
||||
public HierarchicalStreamWriter createWriter(Writer out) {
|
||||
return new PrettyPrintWriter(out) {
|
||||
|
||||
@Override
|
||||
protected void writeText(QuickWriter writer, String text) {
|
||||
writer.write("<![CDATA[");
|
||||
writer.write(text);
|
||||
writer.write("]]>");
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
public XStream(HierarchicalStreamDriver hierarchicalStreamDriver) {
|
||||
super(hierarchicalStreamDriver);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T fromXML(String xml, Class<T> t) {
|
||||
return (T) super.fromXML(xml);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T fromXML(InputStream inputStream, Class<T> t) {
|
||||
return (T) super.fromXML(inputStream);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user