新增MessageConverter

This commit is contained in:
jinyu
2016-07-21 14:44:28 +08:00
parent f62985f69d
commit 57669927a7
66 changed files with 1210 additions and 968 deletions
@@ -18,8 +18,8 @@ import java.util.Map;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.message.XmlResult;
import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
import com.foxinmy.weixin4j.http.weixin.XmlResult;
import com.foxinmy.weixin4j.model.Consts;
import com.foxinmy.weixin4j.model.WeixinPayAccount;
import com.foxinmy.weixin4j.payment.mch.APPPayRequest;
@@ -746,7 +746,7 @@ public class PayApi extends MchApi {
String param = XmlStream.map2xml(map);
WeixinResponse response = weixinExecutor.post(
getRequestUri("interface_report_uri"), param);
return response.getAsXmlResult();
return response.getAsXml();
}
/**
@@ -22,24 +22,20 @@ public class FileCacheStorager<T extends Cacheable> implements CacheStorager<T>
private final String SEPARATOR = File.separator;
public FileCacheStorager(String path) {
this.tmpdir = new File(String.format("%s%sweixin4j_token_temp",
path, SEPARATOR));
this.tmpdir = new File(String.format("%s%s%s", path, SEPARATOR, ALLKEY));
this.tmpdir.mkdirs();
}
@Override
public T lookup(String key) {
File cacheFile = new File(String.format("%s%s%s",
tmpdir.getAbsolutePath(), SEPARATOR, key));
File cacheFile = new File(String.format("%s%s%s", tmpdir.getAbsolutePath(), SEPARATOR, key));
try {
if (cacheFile.exists()) {
T cache = SerializationUtils.deserialize(new FileInputStream(
cacheFile));
T cache = SerializationUtils.deserialize(new FileInputStream(cacheFile));
if (cache.getCreateTime() < 0) {
return cache;
}
if ((cache.getCreateTime() + cache.getExpires() - CUTMS) > System
.currentTimeMillis()) {
if ((cache.getCreateTime() + cache.getExpires() - CUTMS) > System.currentTimeMillis()) {
return cache;
}
}
@@ -52,10 +48,8 @@ public class FileCacheStorager<T extends Cacheable> implements CacheStorager<T>
@Override
public void caching(String key, T cache) {
try {
SerializationUtils.serialize(
cache,
new FileOutputStream(new File(String.format("%s%s%s",
tmpdir.getAbsolutePath(), SEPARATOR, key))));
SerializationUtils.serialize(cache,
new FileOutputStream(new File(String.format("%s%s%s", tmpdir.getAbsolutePath(), SEPARATOR, key))));
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -64,12 +58,10 @@ public class FileCacheStorager<T extends Cacheable> implements CacheStorager<T>
@Override
public T evict(String key) {
T cache = null;
File cacheFile = new File(String.format("%s%s%s",
tmpdir.getAbsolutePath(), SEPARATOR, key));
File cacheFile = new File(String.format("%s%s%s", tmpdir.getAbsolutePath(), SEPARATOR, key));
try {
if (cacheFile.exists()) {
cache = SerializationUtils.deserialize(new FileInputStream(
cacheFile));
cache = SerializationUtils.deserialize(new FileInputStream(cacheFile));
cacheFile.delete();
}
} catch (IOException e) {
@@ -18,8 +18,7 @@ import com.whalin.MemCached.SockIOPool;
* @since JDK 1.6
* @see
*/
public class MemcacheCacheStorager<T extends Cacheable> implements
CacheStorager<T> {
public class MemcacheCacheStorager<T extends Cacheable> implements CacheStorager<T> {
private final MemCachedClient mc;
@@ -30,7 +29,13 @@ public class MemcacheCacheStorager<T extends Cacheable> implements
public MemcacheCacheStorager(MemcachePoolConfig poolConfig) {
mc = new MemCachedClient();
poolConfig.initSocketIO();
mc.set(ALLKEY, new HashSet<String>());
init();
}
private void init() {
if (!mc.keyExists(ALLKEY)) {
mc.set(ALLKEY, new HashSet<String>());
}
}
@SuppressWarnings("unchecked")
@@ -43,9 +48,7 @@ public class MemcacheCacheStorager<T extends Cacheable> implements
@Override
public void caching(String key, T cache) {
if (cache.getCreateTime() > 0l) {
mc.set(key,
cache,
new Date(cache.getCreateTime() + cache.getExpires() - CUTMS));
mc.set(key, cache, new Date(cache.getCreateTime() + cache.getExpires() - CUTMS));
} else {
mc.set(key, cache);
}
@@ -10,17 +10,15 @@ import com.foxinmy.weixin4j.logging.InternalLoggerFactory;
public abstract class AbstractHttpClient implements HttpClient {
protected final InternalLogger logger = InternalLoggerFactory
.getInstance(getClass());
protected final InternalLogger logger = InternalLoggerFactory.getInstance(getClass());
@Override
public HttpResponse get(String url) throws HttpClientException {
return execute(HttpMethod.GET, url);
}
@Override
public HttpResponse get(String url, URLParameter... parameters)
throws HttpClientException {
public HttpResponse get(String url, URLParameter... parameters) throws HttpClientException {
return execute(HttpMethod.GET, url, parameters);
}
@@ -30,8 +28,7 @@ public abstract class AbstractHttpClient implements HttpClient {
}
@Override
public HttpHeaders head(String url, URLParameter... parameters)
throws HttpClientException {
public HttpHeaders head(String url, URLParameter... parameters) throws HttpClientException {
return execute(HttpMethod.HEAD, url, parameters).getHeaders();
}
@@ -41,8 +38,7 @@ public abstract class AbstractHttpClient implements HttpClient {
}
@Override
public HttpResponse post(String url, URLParameter... parameters)
throws HttpClientException {
public HttpResponse post(String url, URLParameter... parameters) throws HttpClientException {
HttpEntity entity = null;
if (parameters != null && parameters.length > 0) {
entity = new FormUrlEntity(Arrays.asList(parameters));
@@ -51,8 +47,7 @@ public abstract class AbstractHttpClient implements HttpClient {
}
@Override
public HttpResponse post(String url, HttpEntity entity)
throws HttpClientException {
public HttpResponse post(String url, HttpEntity entity) throws HttpClientException {
HttpRequest request = new HttpRequest(HttpMethod.POST, url);
request.setEntity(entity);
return execute(request);
@@ -64,8 +59,7 @@ public abstract class AbstractHttpClient implements HttpClient {
}
@Override
public void put(String url, URLParameter... parameters)
throws HttpClientException {
public void put(String url, URLParameter... parameters) throws HttpClientException {
execute(HttpMethod.PUT, url, parameters);
}
@@ -75,8 +69,7 @@ public abstract class AbstractHttpClient implements HttpClient {
}
@Override
public void delete(String url, URLParameter... parameters)
throws HttpClientException {
public void delete(String url, URLParameter... parameters) throws HttpClientException {
execute(HttpMethod.DELETE, url, parameters);
}
@@ -86,20 +79,17 @@ public abstract class AbstractHttpClient implements HttpClient {
}
@Override
public Set<HttpMethod> options(String url, URLParameter... parameters)
throws HttpClientException {
HttpHeaders headers = execute(HttpMethod.OPTIONS, url, parameters)
.getHeaders();
public Set<HttpMethod> options(String url, URLParameter... parameters) throws HttpClientException {
HttpHeaders headers = execute(HttpMethod.OPTIONS, url, parameters).getHeaders();
return headers.getAllow();
}
protected HttpResponse execute(HttpMethod method, String url)
throws HttpClientException {
protected HttpResponse execute(HttpMethod method, String url) throws HttpClientException {
return execute(new HttpRequest(method, url));
}
protected HttpResponse execute(HttpMethod method, String url,
URLParameter... parameters) throws HttpClientException {
protected HttpResponse execute(HttpMethod method, String url, URLParameter... parameters)
throws HttpClientException {
StringBuilder buf = new StringBuilder(url);
if (parameters != null && parameters.length > 0) {
if (url.indexOf("?") < 0) {
@@ -113,27 +103,20 @@ public abstract class AbstractHttpClient implements HttpClient {
}
protected boolean hasError(HttpStatus status) {
return (status.series() == HttpStatus.Series.CLIENT_ERROR || status
.series() == HttpStatus.Series.SERVER_ERROR);
return (status.series() == HttpStatus.Series.CLIENT_ERROR || status.series() == HttpStatus.Series.SERVER_ERROR);
}
protected void handleResponse(HttpResponse response)
throws HttpClientException {
protected void handleResponse(HttpResponse response) throws HttpClientException {
HttpStatus status = response.getStatus();
HttpHeaders headers = response.getHeaders();
String contentType = headers.getFirst(HttpHeaders.CONTENT_TYPE);
boolean jsonResult = contentType != null
&& contentType.contains(ContentType.APPLICATION_JSON
.getMimeType());
if (!jsonResult && hasError(status)) {
MimeType resultType = MimeType.valueOf(headers.getFirst(HttpHeaders.CONTENT_TYPE));
if (!MimeType.APPLICATION_JSON.includes(resultType) && hasError(status)) {
switch (status.series()) {
case CLIENT_ERROR:
case SERVER_ERROR:
throw new HttpClientException(String.format("%d %s",
status.getStatusCode(), status.getStatusText()));
throw new HttpClientException(String.format("%d %s", status.getStatusCode(), status.getStatusText()));
default:
throw new HttpClientException("Unknown status code [" + status
+ "]");
throw new HttpClientException("Unknown status code [" + status + "]");
}
}
}
@@ -2,7 +2,6 @@ package com.foxinmy.weixin4j.http;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.List;
import java.util.Locale;
@@ -21,48 +20,32 @@ public final class ContentType implements Serializable {
private static final long serialVersionUID = 1544245878894784980L;
public static final ContentType APPLICATION_ATOM_XML = create(
"application/atom+xml", Consts.UTF_8);
public static final ContentType APPLICATION_FORM_URLENCODED = create(
"application/x-www-form-urlencoded", Consts.UTF_8);
public static final ContentType APPLICATION_JSON = create(
"application/json", Consts.UTF_8);
public static final ContentType APPLICATION_OCTET_STREAM = create(
"application/octet-stream", (Charset) null);
public static final ContentType APPLICATION_SVG_XML = create(
"application/svg+xml", Consts.UTF_8);
public static final ContentType APPLICATION_XHTML_XML = create(
"application/xhtml+xml", Consts.UTF_8);
public static final ContentType APPLICATION_XML = create("application/xml",
Consts.UTF_8);
public static final ContentType MULTIPART_FORM_DATA = create(
"multipart/form-data", Consts.UTF_8);
public static final ContentType TEXT_HTML = create("text/html",
Consts.UTF_8);
public static final ContentType TEXT_PLAIN = create("text/plain",
Consts.UTF_8);
public static final ContentType IMAGE_JPG = create("image/jpg",
Consts.UTF_8);
public static final ContentType AUDIO_MP3 = create("audio/mp3",
Consts.UTF_8);
public static final ContentType VIDEO_MPEG4 = create("video/mpeg4",
Consts.UTF_8);
public static final ContentType TEXT_XML = create("text/xml", Consts.UTF_8);
public static final ContentType WILDCARD = create("*/*", (Charset) null);
// defaults
public static final ContentType DEFAULT_TEXT = TEXT_PLAIN;
public static final ContentType DEFAULT_BINARY = APPLICATION_OCTET_STREAM;
private final String mimeType;
private final MimeType mimeType;
private final Charset charset;
private static final Charset DEFAULT_CHARSET = Consts.UTF_8;
ContentType(final String mimeType, final Charset charset) {
public static final ContentType APPLICATION_FORM_URLENCODED;
public static final ContentType MULTIPART_FORM_DATA;
public static final ContentType DEFAULT_BINARY;
public static final ContentType DEFAULT_TEXT;
static {
APPLICATION_FORM_URLENCODED = new ContentType(MimeType.APPLICATION_FORM_URLENCODED);
MULTIPART_FORM_DATA = new ContentType(MimeType.MULTIPART_FORM_DATA);
DEFAULT_BINARY = new ContentType(MimeType.APPLICATION_OCTET_STREAM);
DEFAULT_TEXT = new ContentType(MimeType.TEXT_PLAIN);
}
ContentType(final MimeType mimeType) {
this(mimeType, DEFAULT_CHARSET);
}
ContentType(final MimeType mimeType, final Charset charset) {
this.mimeType = mimeType;
this.charset = charset;
}
public String getMimeType() {
public MimeType getMimeType() {
return this.mimeType;
}
@@ -73,7 +56,7 @@ public final class ContentType implements Serializable {
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(this.mimeType);
buf.append(this.mimeType.toString());
if (this.charset != null) {
buf.append("; charset=");
buf.append(this.charset.name());
@@ -102,8 +85,18 @@ public final class ContentType implements Serializable {
return true;
}
public static ContentType create(final String mimeType,
final Charset charset) {
public static ContentType create(final MimeType mimeType, final Charset charset) {
if (mimeType == null) {
throw new IllegalArgumentException("MIME type may not be null");
}
return new ContentType(mimeType, charset);
}
public static ContentType create(final String mimeType) {
return create(MimeType.valueOf(mimeType), (Charset) null);
}
public static ContentType create(final String mimeType, final Charset charset) {
if (mimeType == null) {
throw new IllegalArgumentException("MIME type may not be null");
}
@@ -112,21 +105,8 @@ public final class ContentType implements Serializable {
throw new IllegalArgumentException("MIME type may not be empty");
}
if (!valid(type)) {
throw new IllegalArgumentException(
"MIME type may not contain reserved characters");
throw new IllegalArgumentException("MIME type may not contain reserved characters");
}
return new ContentType(type, charset);
}
public static ContentType create(final String mimeType) {
return new ContentType(mimeType, (Charset) null);
}
public static ContentType create(final String mimeType, final String charset)
throws UnsupportedCharsetException {
return create(
mimeType,
(charset != null && charset.length() > 0) ? Charset
.forName(charset) : null);
return new ContentType(MimeType.valueOf(type), charset);
}
}
@@ -25,7 +25,6 @@ public interface HttpResponse extends HttpMessage {
* @return
*/
HttpStatus getStatus();
/**
* 响应内容
*
@@ -0,0 +1,160 @@
package com.foxinmy.weixin4j.http;
import java.io.Serializable;
import java.util.Locale;
import com.foxinmy.weixin4j.util.StringUtil;
/**
* MIME type
*
* @className MimeType
* @author jinyu
* @date Jul 20, 2016
* @since JDK 1.8
*/
public class MimeType implements Serializable {
private static final long serialVersionUID = 4430596628682058362L;
private static final String WILDCARD_TYPE = "*";
private final String type;
private final String subType;
public static final MimeType APPLICATION_FORM_URLENCODED;
public static final MimeType APPLICATION_JSON;
public static final MimeType APPLICATION_OCTET_STREAM;
public static final MimeType APPLICATION_XML;
public static final MimeType MULTIPART_FORM_DATA;
public static final MimeType TEXT_HTML;
public static final MimeType TEXT_PLAIN;
public static final MimeType IMAGE_JPG;
public static final MimeType AUDIO_MP3;
public static final MimeType VIDEO_MPEG4;
public static final MimeType TEXT_XML;
static {
APPLICATION_FORM_URLENCODED = valueOf("application/x-www-form-urlencoded");
APPLICATION_JSON = valueOf("application/json");
APPLICATION_OCTET_STREAM = valueOf("application/octet-stream");
APPLICATION_XML = valueOf("application/xml");
MULTIPART_FORM_DATA = MimeType.valueOf("multipart/form-data");
TEXT_HTML = valueOf("text/html");
TEXT_PLAIN = valueOf("text/plain");
IMAGE_JPG = valueOf("image/jpg");
AUDIO_MP3 = valueOf("audio/mp3");
VIDEO_MPEG4 = valueOf("video/mpeg4");
TEXT_XML = valueOf("text/xml");
}
public MimeType(String type) {
this(type, WILDCARD_TYPE);
}
public MimeType(String type, String subType) {
this.type = type.toLowerCase(Locale.ENGLISH);
this.subType = subType.toLowerCase(Locale.ENGLISH);
}
public String getType() {
return type;
}
public String getSubType() {
return subType;
}
public boolean isWildcardType() {
return WILDCARD_TYPE.equals(getType());
}
public boolean isWildcardSubtype() {
return WILDCARD_TYPE.equals(getSubType()) || getSubType().startsWith("*+");
}
public static MimeType valueOf(String value) {
if (StringUtil.isBlank(value)) {
return null;
}
String mimeType = StringUtil.tokenizeToStringArray(value, ";")[0].trim().toLowerCase(Locale.ENGLISH);
if (WILDCARD_TYPE.equals(mimeType)) {
mimeType = "*/*";
}
int subIndex = mimeType.indexOf('/');
if (subIndex == -1) {
throw new IllegalArgumentException(mimeType + ":does not contain '/'");
}
if (subIndex == mimeType.length() - 1) {
throw new IllegalArgumentException(mimeType + ":does not contain subtype after '/'");
}
String type = mimeType.substring(0, subIndex);
String subType = mimeType.substring(subIndex + 1, mimeType.length());
if (WILDCARD_TYPE.equals(type) && !WILDCARD_TYPE.equals(subType)) {
throw new IllegalArgumentException(mimeType + ":wildcard type is legal only in '*/*' (all mime types)");
}
return new MimeType(type, subType);
}
/**
* reference of apache Spring Web
*/
public boolean includes(MimeType other) {
if (other == null) {
return false;
}
if (this.isWildcardType()) {
// */* includes anything
return true;
} else if (getType().equals(other.getType())) {
if (getSubType().equals(other.getSubType())) {
return true;
}
if (this.isWildcardSubtype()) {
// wildcard with suffix, e.g. application/*+xml
int thisPlusIdx = getSubType().indexOf('+');
if (thisPlusIdx == -1) {
return true;
} else {
// application/*+xml includes application/soap+xml
int otherPlusIdx = other.getSubType().indexOf('+');
if (otherPlusIdx != -1) {
String thisSubtypeNoSuffix = getSubType().substring(0, thisPlusIdx);
String thisSubtypeSuffix = getSubType().substring(thisPlusIdx + 1);
String otherSubtypeSuffix = other.getSubType().substring(otherPlusIdx + 1);
if (thisSubtypeSuffix.equals(otherSubtypeSuffix) && WILDCARD_TYPE.equals(thisSubtypeNoSuffix)) {
return true;
}
}
}
}
}
return false;
}
@Override
public String toString() {
return String.format("%s/%s", this.type, this.subType);
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof MimeType)) {
return false;
}
MimeType otherType = (MimeType) other;
return this.type.equalsIgnoreCase(otherType.type) && this.subType.equalsIgnoreCase(otherType.subType);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((subType == null) ? 0 : subType.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
}
@@ -148,7 +148,7 @@ public class SimpleHttpClient extends AbstractHttpClient implements HttpClient {
}
if (httpEntity.getContentType() != null) {
connection.setRequestProperty(HttpHeaders.CONTENT_TYPE,
httpEntity.getContentType().getMimeType());
httpEntity.getContentType().toString());
}
logger.debug("entity >> " + httpEntity.getContentType() + "("
+ httpEntity.getContentLength() + "byte)");
@@ -137,6 +137,7 @@ public class MultipartEntity implements HttpEntity {
return !isRepeatable();
}
@Override
public long getContentLength() {
if (this.dirty) {
this.length = this.multipart.getTotalLength();
@@ -145,6 +146,7 @@ public class MultipartEntity implements HttpEntity {
return this.length;
}
@Override
public ContentType getContentType() {
return ContentType.MULTIPART_FORM_DATA;
}
@@ -157,12 +159,14 @@ public class MultipartEntity implements HttpEntity {
}
}
@Override
public InputStream getContent() throws IOException,
UnsupportedOperationException {
throw new UnsupportedOperationException(
"Multipart form entity does not implement #getContent()");
}
@Override
public void writeTo(final OutputStream outstream) throws IOException {
this.multipart.writeTo(outstream);
outstream.flush();
@@ -0,0 +1,95 @@
package com.foxinmy.weixin4j.http.message;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.foxinmy.weixin4j.http.HttpResponse;
import com.foxinmy.weixin4j.http.MimeType;
import com.foxinmy.weixin4j.model.Consts;
public abstract class AbstractMessageConverter implements MessageConverter {
protected Charset charset = Consts.UTF_8;
private List<MimeType> supportedMimeTypes;
protected AbstractMessageConverter() {
this.supportedMimeTypes = Collections.emptyList();
}
protected AbstractMessageConverter(MimeType supportedMimeType) {
setSupportedMediaTypes(Collections.singletonList(supportedMimeType));
}
protected AbstractMessageConverter(MimeType... supportedMimeTypes) {
setSupportedMediaTypes(Arrays.asList(supportedMimeTypes));
}
public void setSupportedMediaTypes(List<MimeType> supportedMimeTypes) {
this.supportedMimeTypes = new ArrayList<MimeType>(supportedMimeTypes);
}
public Charset getCharset() {
return charset;
}
public void setCharset(Charset charset) {
this.charset = charset;
}
@Override
public List<MimeType> supportedMimeTypes() {
return Collections.unmodifiableList(this.supportedMimeTypes);
}
@Override
public boolean canConvert(Class<?> clazz, HttpResponse response) {
MimeType mimeType = MimeType.valueOf(response.getHeaders().getContentType());
byte[] content = response.getContent();
return supports(clazz, mimeType) || supports(clazz, content);
}
/**
* 满足其中一个supports
*
* @param clazz
* 转换类型
* @param mimeType
* 媒体类型
* @return 支持标识
*/
protected boolean supports(Class<?> clazz, MimeType mimeType) {
if (mimeType == null) {
return true;
}
for (MimeType supportedMediaType : supportedMimeTypes()) {
if (supportedMediaType.includes(mimeType)) {
return true;
}
}
return false;
}
/**
* 满足其中一个supports
*
* @param clazz
* 转换类型
* @param content
* 内容数据
* @return 支持标识
*/
protected abstract boolean supports(Class<?> clazz, byte[] content);
@Override
public <T> T convert(Class<? extends T> clazz, HttpResponse response) throws IOException {
return convertInternal(clazz, response.getBody());
}
protected abstract <T> T convertInternal(Class<? extends T> clazz, InputStream body) throws IOException;
}
@@ -0,0 +1,74 @@
package com.foxinmy.weixin4j.http.message;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import com.alibaba.fastjson.annotation.JSONField;
/**
* 调用接口的返回
*
* @className ApiResult
* @author jinyu(foxinmy@gmail.com)
* @date 2014年9月24日
* @since JDK 1.6
* @see <a href=
* "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433747234&token=&lang=zh_CN">公众平台全局返回码说明</a>
* @see <a href=
* "http://qydev.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>
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ApiResult implements Serializable {
private static final long serialVersionUID = -6185313616955051150L;
/**
* 调用接口返回码,通信标识
*/
@XmlElement(name = "return_code")
@JSONField(name = "errcode")
private String returnCode;
/**
* 调用接口返回消息,如非 空,为错误原因 可能为空
*/
@XmlElement(name = "return_msg")
@JSONField(name = "errmsg")
private String returnMsg;
public ApiResult() {
this.returnCode = "0";
this.returnMsg = "OK";
}
public ApiResult(String returnCode, String returnMsg) {
this.returnCode = returnCode;
this.returnMsg = returnMsg;
}
public String getReturnCode() {
return returnCode;
}
public String getReturnMsg() {
return returnMsg;
}
public void setReturnCode(String returnCode) {
this.returnCode = returnCode;
}
public void setReturnMsg(String returnMsg) {
this.returnMsg = returnMsg;
}
@Override
public String toString() {
return "returnCode=" + returnCode + ", returnMsg=" + returnMsg;
}
}
@@ -0,0 +1,55 @@
package com.foxinmy.weixin4j.http.message;
import java.io.IOException;
import java.io.InputStream;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.http.HttpHeaders;
import com.foxinmy.weixin4j.http.HttpResponse;
import com.foxinmy.weixin4j.http.MimeType;
import com.foxinmy.weixin4j.util.FileUtil;
import com.foxinmy.weixin4j.util.IOUtil;
import com.foxinmy.weixin4j.util.RegexUtil;
/**
* JSON 转换
*
* @className JsonMessageConverter
* @author jinyu
* @date Jul 20, 2016
* @since JDK 1.8
*/
public class JsonMessageConverter extends AbstractMessageConverter {
public static final JsonMessageConverter GLOBAL = new JsonMessageConverter();
private static final String JSO = "json";
private static final int BRACE = 1 << '{';
private static final int BRACKET = 1 << '[';
private static final int MASK = BRACE | BRACKET;
public JsonMessageConverter() {
super(MimeType.APPLICATION_JSON, new MimeType("application", "*+json"));
}
@Override
public boolean canConvert(Class<?> clazz, HttpResponse response) {
if (!super.canConvert(clazz, response)) {
String disposition = response.getHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION);
String fileName = RegexUtil.regexFileNameFromContentDispositionHeader(disposition);
return (fileName != null && FileUtil.getFileExtension(fileName).equalsIgnoreCase(JSO));
}
return true;
}
@Override
protected boolean supports(Class<?> clazz, byte[] content) {
return (MASK & (1 << content[0])) != 0;
}
@Override
protected <T> T convertInternal(Class<? extends T> clazz, InputStream body) throws IOException {
byte[] bytes = IOUtil.toByteArray(body);
return JSON.parseObject(bytes, 0, bytes.length, charset.newDecoder(), clazz);
}
}
@@ -0,0 +1,48 @@
package com.foxinmy.weixin4j.http.message;
import java.io.IOException;
import java.util.List;
import com.foxinmy.weixin4j.http.HttpResponse;
import com.foxinmy.weixin4j.http.MimeType;
/**
* 消息转换接口
*
* @className MessageConverter
* @author jinyu
* @date Jul 20, 2016
* @since JDK 1.8
* @see
*/
public interface MessageConverter {
/**
* 获取可以转换的媒体类型
*
* @return 媒体列表
*/
public List<MimeType> supportedMimeTypes();
/**
* 是否可以转换
*
* @param clazz
* 转换类型
* @param response
* 响应对象
* @return 是否标识
*/
public boolean canConvert(Class<?> clazz, HttpResponse response);
/**
* 转换消息
*
* @param clazz
* 转换类型
* @param response
* 响应对象
* @throws IOException
* @return 消息对象
*/
public <T> T convert(Class<? extends T> clazz, HttpResponse response) throws IOException;
}
@@ -0,0 +1,51 @@
package com.foxinmy.weixin4j.http.message;
import java.io.IOException;
import java.io.InputStream;
import com.foxinmy.weixin4j.http.HttpHeaders;
import com.foxinmy.weixin4j.http.HttpResponse;
import com.foxinmy.weixin4j.http.MimeType;
import com.foxinmy.weixin4j.util.FileUtil;
import com.foxinmy.weixin4j.util.RegexUtil;
import com.foxinmy.weixin4j.xml.XmlStream;
/**
* XML 转换
*
* @className XmlMessageConverter
* @author jinyu
* @date Jul 20, 2016
* @since JDK 1.8
*/
public class XmlMessageConverter extends AbstractMessageConverter {
public static final XmlMessageConverter GLOBAL = new XmlMessageConverter();
private static final String XML = "xml";
private static final int BRACKET = '<';
public XmlMessageConverter() {
super(MimeType.APPLICATION_XML, MimeType.TEXT_XML, new MimeType("application", "*+xml"));
}
@Override
public boolean canConvert(Class<?> clazz, HttpResponse response) {
if (!super.canConvert(clazz, response)) {
String disposition = response.getHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION);
String fileName = RegexUtil.regexFileNameFromContentDispositionHeader(disposition);
return (fileName != null && FileUtil.getFileExtension(fileName).equalsIgnoreCase(XML));
}
return true;
}
@Override
protected boolean supports(Class<?> clazz, byte[] content) {
return BRACKET == content[0];
}
@Override
protected <T> T convertInternal(Class<? extends T> clazz, InputStream body) throws IOException {
return XmlStream.fromXML(body, clazz);
}
}
@@ -1,6 +1,4 @@
package com.foxinmy.weixin4j.http.weixin;
import java.io.Serializable;
package com.foxinmy.weixin4j.http.message;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
@@ -20,22 +18,10 @@ import com.alibaba.fastjson.annotation.JSONField;
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class XmlResult implements Serializable {
public class XmlResult extends ApiResult {
private static final long serialVersionUID = -6185313616955051150L;
/**
* 此字段是通信标识,非交易 标识,交易是否成功需要查 result_code 来判断非空
*/
@XmlElement(name = "return_code")
@JSONField(name = "return_code")
private String returnCode;
/**
* 返回信息,如非 ,为错误原因 可能为空
*/
@XmlElement(name = "return_msg")
@JSONField(name = "return_msg")
private String returnMsg;
/**
* 业务结果SUCCESS/FAIL 非空
*/
@@ -55,20 +41,11 @@ public class XmlResult implements Serializable {
@JSONField(name = "err_code_des")
private String errCodeDes;
public XmlResult() {
protected XmlResult() {
}
public XmlResult(String returnCode, String returnMsg) {
this.returnCode = returnCode;
this.returnMsg = returnMsg;
}
public String getReturnCode() {
return returnCode;
}
public String getReturnMsg() {
return returnMsg;
super(returnCode, returnMsg);
}
public String getResultCode() {
@@ -83,14 +60,6 @@ public class XmlResult implements Serializable {
return errCodeDes;
}
public void setReturnCode(String returnCode) {
this.returnCode = returnCode;
}
public void setReturnMsg(String returnMsg) {
this.returnMsg = returnMsg;
}
public void setResultCode(String resultCode) {
this.resultCode = resultCode;
}
@@ -105,8 +74,6 @@ public class XmlResult implements Serializable {
@Override
public String toString() {
return "returnCode=" + returnCode + ", returnMsg=" + returnMsg
+ ", resultCode=" + resultCode + ", errCode=" + errCode
+ ", errCodeDes=" + errCodeDes;
return super.toString() + ", resultCode=" + resultCode + ", errCode=" + errCode + ", errCodeDes=" + errCodeDes;
}
}
@@ -1,69 +0,0 @@
package com.foxinmy.weixin4j.http.weixin;
import java.io.Serializable;
import com.alibaba.fastjson.annotation.JSONField;
/**
* 调用接口返回JSON格式
*
* @className JsonResult
* @author jinyu(foxinmy@gmail.com)
* @date 2014年9月24日
* @since JDK 1.6
* @see <a
* href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433747234&token=&lang=zh_CN">公众平台全局返回码说明</a>
* @see <a
* href="http://qydev.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
+ "]";
}
}
@@ -1,13 +1,11 @@
package com.foxinmy.weixin4j.http.weixin;
import java.io.IOException;
import java.util.Map;
import com.alibaba.fastjson.JSONException;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.ContentType;
import com.foxinmy.weixin4j.http.HttpClient;
import com.foxinmy.weixin4j.http.HttpClientException;
import com.foxinmy.weixin4j.http.HttpHeaders;
import com.foxinmy.weixin4j.http.HttpMethod;
import com.foxinmy.weixin4j.http.HttpParams;
import com.foxinmy.weixin4j.http.HttpRequest;
@@ -19,10 +17,12 @@ import com.foxinmy.weixin4j.http.entity.FormUrlEntity;
import com.foxinmy.weixin4j.http.entity.HttpEntity;
import com.foxinmy.weixin4j.http.entity.StringEntity;
import com.foxinmy.weixin4j.http.factory.HttpClientFactory;
import com.foxinmy.weixin4j.http.message.ApiResult;
import com.foxinmy.weixin4j.http.message.XmlMessageConverter;
import com.foxinmy.weixin4j.http.message.XmlResult;
import com.foxinmy.weixin4j.logging.InternalLogger;
import com.foxinmy.weixin4j.logging.InternalLoggerFactory;
import com.foxinmy.weixin4j.model.Consts;
import com.foxinmy.weixin4j.xml.XmlStream;
/**
* 负责微信请求的执行
@@ -35,8 +35,9 @@ import com.foxinmy.weixin4j.xml.XmlStream;
*/
public class WeixinRequestExecutor {
protected final InternalLogger logger = InternalLoggerFactory
.getInstance(getClass());
protected final InternalLogger logger = InternalLoggerFactory.getInstance(getClass());
private static final String SUCCESS_CODE = ",0,success,";
protected final HttpClient httpClient;
protected final HttpParams httpParams;
@@ -55,8 +56,7 @@ public class WeixinRequestExecutor {
return doRequest(request);
}
public WeixinResponse get(String url, Map<String, String> parameters)
throws WeixinException {
public WeixinResponse get(String url, Map<String, String> parameters) throws WeixinException {
StringBuilder buf = new StringBuilder(url);
if (parameters != null && !parameters.isEmpty()) {
if (url.indexOf("?") < 0) {
@@ -81,10 +81,8 @@ public class WeixinRequestExecutor {
return doRequest(request);
}
public WeixinResponse post(String url, FormBodyPart... bodyParts)
throws WeixinException {
MultipartEntity entity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE, null, Consts.UTF_8);
public WeixinResponse post(String url, FormBodyPart... bodyParts) throws WeixinException {
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, null, Consts.UTF_8);
for (FormBodyPart bodyPart : bodyParts) {
entity.addPart(bodyPart);
}
@@ -93,85 +91,35 @@ public class WeixinRequestExecutor {
return doRequest(request);
}
protected WeixinResponse doRequest(HttpRequest request)
throws WeixinException {
protected WeixinResponse doRequest(HttpRequest request) throws WeixinException {
request.setParams(httpParams);
try {
logger.info("weixin request >> " + request.getMethod() + " "
+ request.getURI().toString());
logger.info("weixin request >> " + request.getMethod() + " " + request.getURI().toString());
HttpResponse httpResponse = httpClient.execute(request);
HttpHeaders headers = httpResponse.getHeaders();
WeixinResponse response = new WeixinResponse(httpResponse);
logger.info("weixin response << " + httpResponse.getProtocol()
+ httpResponse.getStatus() + ":" + response.getAsString());
String contentType = headers.getFirst(HttpHeaders.CONTENT_TYPE);
String disposition = headers
.getFirst(HttpHeaders.CONTENT_DISPOSITION);
// json
if (contentType
.contains(ContentType.APPLICATION_JSON.getMimeType())
|| (disposition != null && disposition.indexOf(".json") > 0)) {
checkJson(response);
} else if (contentType.contains(ContentType.TEXT_XML.getMimeType())) {
checkXml(response);
} else if (contentType.contains(ContentType.TEXT_PLAIN
.getMimeType())
|| contentType
.contains(ContentType.TEXT_HTML.getMimeType())) {
try {
checkJson(response);
return response;
} catch (JSONException e) {
;
}
try {
checkXml(response);
return response;
} catch (IllegalArgumentException ex) {
;
}
throw new WeixinException(response.getAsString());
}
logger.info("weixin response << " + httpResponse.getProtocol() + httpResponse.getStatus() + ":"
+ response.getAsString());
handlResponse(response);
return response;
} catch (HttpClientException e) {
throw new WeixinException(e);
}
}
protected void checkJson(WeixinResponse response) throws WeixinException {
JsonResult jsonResult = response.getAsJsonResult();
response.setJsonResult(true);
if (jsonResult.getCode() != 0) {
throw new WeixinException(Integer.toString(jsonResult.getCode()),
jsonResult.getDesc());
protected void handlResponse(WeixinResponse response) throws WeixinException {
ApiResult result = response.getAsResult();
if (!SUCCESS_CODE.contains(String.format(",%s,", result.getReturnCode().toLowerCase()))) {
throw new WeixinException(result.getReturnCode(), result.getReturnMsg());
}
}
protected void checkXml(WeixinResponse response) throws WeixinException {
String xmlContent = response.getAsString();
if (xmlContent.length() != xmlContent.replaceFirst("<retcode>",
"<return_code>").length()) {
// <?xml><root><data..../data></root>
xmlContent = xmlContent.replaceFirst("<root>", "<xml>")
.replaceFirst("<retcode>", "<return_code>")
.replaceFirst("</retcode>", "</return_code>")
.replaceFirst("<retmsg>", "<return_msg>")
.replaceFirst("</retmsg>", "</return_msg>")
.replaceFirst("</root>", "</xml>");
}
XmlResult xmlResult = XmlStream.fromXML(xmlContent, XmlResult.class);
response.setText(xmlContent);
response.setXmlResult(true);
if ("0".equals(xmlResult.getReturnCode())) {
return;
}
if (!Consts.SUCCESS.equalsIgnoreCase(xmlResult.getReturnCode())) {
throw new WeixinException(xmlResult.getReturnCode(),
xmlResult.getReturnMsg());
}
if (!Consts.SUCCESS.equalsIgnoreCase(xmlResult.getResultCode())) {
throw new WeixinException(xmlResult.getErrCode(),
xmlResult.getErrCodeDes());
if (XmlMessageConverter.GLOBAL.canConvert(XmlResult.class, response)) {
try {
XmlResult xmlResult = XmlMessageConverter.GLOBAL.convert(XmlResult.class, response);
if (!SUCCESS_CODE.contains(xmlResult.getResultCode())) {
throw new WeixinException(xmlResult.getErrCode(), xmlResult.getErrCodeDes());
}
} catch (IOException e) {
;
}
}
}
@@ -1,6 +1,9 @@
package com.foxinmy.weixin4j.http.weixin;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
@@ -8,73 +11,102 @@ import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.http.HttpHeaders;
import com.foxinmy.weixin4j.http.HttpResponse;
import com.foxinmy.weixin4j.http.HttpStatus;
import com.foxinmy.weixin4j.http.HttpVersion;
import com.foxinmy.weixin4j.http.message.ApiResult;
import com.foxinmy.weixin4j.http.message.JsonMessageConverter;
import com.foxinmy.weixin4j.http.message.MessageConverter;
import com.foxinmy.weixin4j.http.message.XmlMessageConverter;
import com.foxinmy.weixin4j.http.message.XmlResult;
import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.xml.XmlStream;
public class WeixinResponse {
/**
* 调用微信接口响应
*
* @className WeixinResponse
* @author jinyu
* @date Jul 21, 2016
* @since JDK 1.6
*/
public class WeixinResponse implements HttpResponse {
private boolean isJsonResult;
private boolean isXmlResult;
private volatile String text;
private final HttpResponse response;
private static List<MessageConverter> messageConverters = new ArrayList<MessageConverter>();
private final TypeReference<ApiResult> APIRESULT_CLAZZ = new TypeReference<ApiResult>() {
};
private final TypeReference<XmlResult> XMLRESULT_CLAZZ = new TypeReference<XmlResult>() {
};
static {
messageConverters.add(new JsonMessageConverter());
messageConverters.add(new XmlMessageConverter());
}
public WeixinResponse(HttpResponse response) {
this.response = response;
}
public void setJsonResult(boolean isJsonResult) {
this.isJsonResult = isJsonResult;
}
public void setXmlResult(boolean isXmlResult) {
this.isXmlResult = isXmlResult;
}
public String getAsString() {
if (text == null) {
text = StringUtil.newStringUtf8(response.getContent());
text = StringUtil.newStringUtf8(getContent());
}
return text;
}
public void setText(String text) {
this.text = text;
}
public JsonResult getAsJsonResult() {
return JSON.parseObject(getAsString(), JsonResult.class);
public ApiResult getAsResult() {
return getAsObject(APIRESULT_CLAZZ);
}
public JSONObject getAsJson() {
return JSON.parseObject(getAsString());
}
public XmlResult getAsXml() {
return getAsObject(XMLRESULT_CLAZZ);
}
@SuppressWarnings("unchecked")
public <T> T getAsObject(TypeReference<T> typeReference) {
if (isJsonResult) {
return JSON.parseObject(getAsString(), typeReference);
Class<T> clazz = (Class<T>) typeReference.getType();
for (MessageConverter messageConverter : messageConverters) {
if (messageConverter.canConvert(clazz, response)) {
try {
return messageConverter.convert(clazz, response);
} catch (IOException e) {
throw new RuntimeException("IO error on convert to " + typeReference, e);
}
}
}
if (isXmlResult) {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) typeReference.getType();
return XmlStream.fromXML(getAsString(), clazz);
}
return null;
}
public XmlResult getAsXmlResult() {
return XmlStream.fromXML(getAsString(), XmlResult.class);
throw new RuntimeException("cannot convert to " + typeReference);
}
@Override
public HttpHeaders getHeaders() {
return response.getHeaders();
}
@Override
public HttpStatus getStatus() {
return response.getStatus();
}
@Override
public byte[] getContent() {
return response.getContent();
}
@Override
public InputStream getBody() {
return response.getBody();
}
@Override
public HttpVersion getProtocol() {
return response.getProtocol();
}
@Override
public void close() {
response.close();
}
}
@@ -12,7 +12,7 @@ import com.foxinmy.weixin4j.api.CouponApi;
import com.foxinmy.weixin4j.api.CustomsApi;
import com.foxinmy.weixin4j.api.PayApi;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.XmlResult;
import com.foxinmy.weixin4j.http.message.XmlResult;
import com.foxinmy.weixin4j.model.Pageable;
import com.foxinmy.weixin4j.model.WeixinPayAccount;
import com.foxinmy.weixin4j.payment.coupon.CouponDetail;
@@ -6,7 +6,7 @@ import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.http.weixin.XmlResult;
import com.foxinmy.weixin4j.http.message.XmlResult;
import com.foxinmy.weixin4j.type.SignType;
/**
@@ -11,7 +11,7 @@ import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.http.weixin.XmlResult;
import com.foxinmy.weixin4j.http.message.XmlResult;
import com.foxinmy.weixin4j.type.RedpacketSendType;
import com.foxinmy.weixin4j.type.RedpacketStatus;
import com.foxinmy.weixin4j.type.RedpacketType;
@@ -1,19 +1,22 @@
package com.foxinmy.weixin4j.type;
import com.foxinmy.weixin4j.http.ContentType;
import com.foxinmy.weixin4j.http.MimeType;
/**
* 上传的媒体类型</br>
* <p>
* 公众平台上传限制:</br> 图片(image): 2MB,支持bmp/png/jpeg/jpg/gif格式</br>
* 公众平台上传限制:</br>
* 图片(image): 2MB,支持bmp/png/jpeg/jpg/gif格式</br>
* 语音(voice):2MB,播放长度不超过60s,支持mp3/wma/wav/amr格式</br>
* 视频(video):10MB,支持rm/rmvb/wmv/avi/mpg/mpeg/mp4格式</br>
* 缩略图(thumb):64KB,支持JPG格式</br>
* </p>
* <p>
* 企业号上传限制:</br> 图片(image:1MB,支持bmp/png/jpeg/jpg/gif格式</br>
* 企业号上传限制:</br>
* 图片(image:1MB,支持bmp/png/jpeg/jpg/gif格式</br>
* 语音(voice):2MB,播放长度不超过60s,支持mp3/wma/wav/amr格式</br>
* 视频(video):10MB,支持rm/rmvb/wmv/avi/mpg/mpeg/mp4格式</br> 普通文件(file):20MB</br>
* 视频(video):10MB,支持rm/rmvb/wmv/avi/mpg/mpeg/mp4格式</br>
* 普通文件(file):20MB</br>
* </p>
* <p>
* <font color='red'>临时媒体文件在后台保存时间为3天,即3天后media_id失效</font>
@@ -24,18 +27,16 @@ import com.foxinmy.weixin4j.http.ContentType;
* @since JDK 1.6
*/
public enum MediaType {
image(ContentType.IMAGE_JPG), voice(ContentType.AUDIO_MP3), video(
ContentType.VIDEO_MPEG4), thumb(ContentType.IMAGE_JPG), file(
ContentType.MULTIPART_FORM_DATA), news(
ContentType.MULTIPART_FORM_DATA);
image(MimeType.IMAGE_JPG), voice(MimeType.AUDIO_MP3), video(MimeType.VIDEO_MPEG4), thumb(MimeType.IMAGE_JPG), file(
MimeType.MULTIPART_FORM_DATA), news(MimeType.MULTIPART_FORM_DATA);
MediaType(ContentType contentType) {
this.contentType = contentType;
MediaType(MimeType mimeType) {
this.mimeType = mimeType;
}
private ContentType contentType;
private MimeType mimeType;
public ContentType getContentType() {
return contentType;
public MimeType getMimeType() {
return mimeType;
}
}
@@ -1,7 +1,10 @@
package com.foxinmy.weixin4j.util;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import com.foxinmy.weixin4j.model.Consts;
@@ -62,9 +65,7 @@ public final class StringUtil {
return str;
}
return new StringBuilder(strLen)
.append(Character.toLowerCase(firstChar))
.append(str.substring(1)).toString();
return new StringBuilder(strLen).append(Character.toLowerCase(firstChar)).append(str.substring(1)).toString();
}
public static String capitalize(final String str) {
@@ -78,13 +79,10 @@ public final class StringUtil {
// already capitalized
return str;
}
return new StringBuilder(strLen)
.append(Character.toTitleCase(firstChar))
.append(str.substring(1)).toString();
return new StringBuilder(strLen).append(Character.toTitleCase(firstChar)).append(str.substring(1)).toString();
}
public static String substringBefore(final String str,
final String separator) {
public static String substringBefore(final String str, final String separator) {
if (isEmpty(str) || separator == null) {
return str;
}
@@ -119,8 +117,7 @@ public final class StringUtil {
return join(array, separator, 0, array.length);
}
public static String join(final Object[] array, final char separator,
final int startIndex, final int endIndex) {
public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
@@ -187,8 +184,7 @@ public final class StringUtil {
return join(array, separator, 0, array.length);
}
public static String join(final int[] array, final char separator,
final int startIndex, final int endIndex) {
public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
@@ -234,4 +230,28 @@ public final class StringUtil {
return clazz.getName();
}
}
public static String[] tokenizeToStringArray(String str, String delimiters) {
return tokenizeToStringArray(str, delimiters, true, true);
}
public static String[] tokenizeToStringArray(String str, String delimiters, boolean trimTokens,
boolean ignoreEmptyTokens) {
if (str == null) {
return null;
}
StringTokenizer st = new StringTokenizer(str, delimiters);
List<String> tokens = new ArrayList<String>();
while (st.hasMoreTokens()) {
String token = st.nextToken();
if (trimTokens) {
token = token.trim();
}
if (!ignoreEmptyTokens || token.length() > 0) {
tokens.add(token);
}
}
return tokens.toArray(new String[tokens.size()]);
}
}
@@ -69,7 +69,7 @@ public final class XmlStream {
unmarshaller = jaxbContext.createUnmarshaller();
messageUnmarshaller.put(clazz, unmarshaller);
} catch (JAXBException e) {
throw new IllegalArgumentException(e);
throw new RuntimeException(e);
}
}
try {
@@ -83,7 +83,7 @@ public final class XmlStream {
return (T) unmarshaller.unmarshal(source);
}
} catch (Exception e) {
throw new IllegalArgumentException(e);
throw new RuntimeException(e);
} finally {
if (content != null) {
try {
@@ -11,7 +11,7 @@ import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.exception.WeixinPayException;
import com.foxinmy.weixin4j.http.weixin.XmlResult;
import com.foxinmy.weixin4j.http.message.XmlResult;
import com.foxinmy.weixin4j.model.WeixinPayAccount;
import com.foxinmy.weixin4j.payment.WeixinPayProxy;
import com.foxinmy.weixin4j.payment.mch.MchPayPackage;
@@ -45,7 +45,7 @@ public class PayTest {
static {
ACCOUNT = new WeixinPayAccount("appid", "paysignkey", "mchid");
SIGNATURE = new WeixinPaymentSignature(ACCOUNT.getPaySignKey());
PAY = new WeixinPayProxy(new Weixin4jSettings(ACCOUNT));
PAY = new WeixinPayProxy(new Weixin4jSettings<WeixinPayAccount>(ACCOUNT));
}
/**
* 商户证书文件