diff --git a/src/main/java/chanjarster/weixin/api/WxConsts.java b/src/main/java/chanjarster/weixin/api/WxConsts.java index 0f4fbb8e..d2ae9050 100644 --- a/src/main/java/chanjarster/weixin/api/WxConsts.java +++ b/src/main/java/chanjarster/weixin/api/WxConsts.java @@ -26,7 +26,6 @@ public class WxConsts { public static final String MEDIA_THUMB = "thumb"; public static final String FILE_JPG = "jpeg"; - public static final String FILE_PNG = "png"; public static final String FILE_MP3 = "mp3"; public static final String FILE_ARM = "arm"; public static final String FILE_MP4 = "mp4"; diff --git a/src/main/java/chanjarster/weixin/api/WxService.java b/src/main/java/chanjarster/weixin/api/WxService.java index b39fbf6c..fe37ed15 100644 --- a/src/main/java/chanjarster/weixin/api/WxService.java +++ b/src/main/java/chanjarster/weixin/api/WxService.java @@ -44,6 +44,7 @@ public interface WxService { /** *
* 上传多媒体文件 + * * 上传的多媒体文件有格式和大小限制,如下: * 图片(image): 1M,支持JPG格式 * 语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式 @@ -67,6 +68,18 @@ public interface WxService { */ public WxUploadResult uploadMedia(String mediaType, File file) throws WxErrorException; + /** + *+ * 下载多媒体文件 + * + * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件 + *+ * @params media_id + * @return 保存到本地的临时文件 + * @throws WxErrorException + */ + public File downloadMedia(String media_id) throws WxErrorException; + /** ** 发送客服消息 @@ -75,7 +88,7 @@ public interface WxService { * @param message * @throws WxErrorException */ - public String sendCustomMessage(WxCustomMessage message) throws WxErrorException; + public void sendCustomMessage(WxCustomMessage message) throws WxErrorException; /** *@@ -85,7 +98,7 @@ public interface WxService { * @param menu * @throws WxErrorException */ - public String createMenu(WxMenu menu) throws WxErrorException; + public void createMenu(WxMenu menu) throws WxErrorException; /** *@@ -94,7 +107,7 @@ public interface WxService { ** @throws WxErrorException */ - public String deleteMenu() throws WxErrorException; + public void deleteMenu() throws WxErrorException; /** *diff --git a/src/main/java/chanjarster/weixin/api/WxServiceImpl.java b/src/main/java/chanjarster/weixin/api/WxServiceImpl.java index 51d7421c..f6e4b19f 100644 --- a/src/main/java/chanjarster/weixin/api/WxServiceImpl.java +++ b/src/main/java/chanjarster/weixin/api/WxServiceImpl.java @@ -1,7 +1,6 @@ package chanjarster.weixin.api; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; @@ -10,15 +9,9 @@ import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.lang3.StringUtils; -import org.apache.http.Consts; -import org.apache.http.HttpEntity; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; @@ -29,7 +22,12 @@ import chanjarster.weixin.bean.WxMenu; import chanjarster.weixin.bean.result.WxError; import chanjarster.weixin.bean.result.WxUploadResult; import chanjarster.weixin.exception.WxErrorException; -import chanjarster.weixin.util.Utf8ResponseHandler; +import chanjarster.weixin.util.fs.FileUtil; +import chanjarster.weixin.util.http.MediaDownloadRequestExecutor; +import chanjarster.weixin.util.http.MediaUploadRequestExecutor; +import chanjarster.weixin.util.http.RequestExecutor; +import chanjarster.weixin.util.http.SimpleGetRequestExecutor; +import chanjarster.weixin.util.http.SimplePostRequestExecutor; public class WxServiceImpl implements WxService { @@ -62,7 +60,7 @@ public class WxServiceImpl implements WxService { } } - protected static String bytesToHex(byte[] b) { + protected String bytesToHex(byte[] b) { char hexDigit[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; StringBuffer buf = new StringBuffer(); @@ -110,25 +108,25 @@ public class WxServiceImpl implements WxService { } } - public String sendCustomMessage(WxCustomMessage message) throws WxErrorException { + public void sendCustomMessage(WxCustomMessage message) throws WxErrorException { String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send"; - return post(url, message.toJson()); + execute(new SimplePostRequestExecutor(), url, message.toJson()); } - public String createMenu(WxMenu menu) throws WxErrorException { + public void createMenu(WxMenu menu) throws WxErrorException { String url = "https://api.weixin.qq.com/cgi-bin/menu/create"; - return post(url, menu.toJson()); + execute(new SimplePostRequestExecutor(), url, menu.toJson()); } - public String deleteMenu() throws WxErrorException { + public void deleteMenu() throws WxErrorException { String url = "https://api.weixin.qq.com/cgi-bin/menu/delete"; - return get(url, null); + execute(new SimpleGetRequestExecutor(), url, null); } public WxMenu getMenu() throws WxErrorException { String url = "https://api.weixin.qq.com/cgi-bin/menu/get"; try { - String resultContent = get(url, null); + String resultContent = execute(new SimpleGetRequestExecutor(), url, null); return WxMenu.fromJson(resultContent); } catch (WxErrorException e) { // 46003 不存在的菜单数据 @@ -140,30 +138,28 @@ public class WxServiceImpl implements WxService { } public WxUploadResult uploadMedia(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException { - return uploadMedia(mediaType, createTmpFile(inputStream, fileType)); + return uploadMedia(mediaType,FileUtil.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); } public WxUploadResult uploadMedia(String mediaType, File file) throws WxErrorException { String url = "http://file.api.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; - String json = post(url, file); - return WxUploadResult.fromJson(json); + return execute(new MediaUploadRequestExecutor(), url, file); } - protected String post(String uri, Object data) throws WxErrorException { - return execute("POST", uri, data); - } - - protected String get(String uri, Object data) throws WxErrorException { - return execute("GET", uri, data); + public File downloadMedia(String media_id) throws WxErrorException { + String url = "http://file.api.weixin.qq.com/cgi-bin/media/get"; + return execute(new MediaDownloadRequestExecutor(), url, "media_id=" + media_id); } /** * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 - * @param request - * @return 微信服务端返回的结果 - * @throws WxErrorException + * @param executor + * @param uri + * @param data + * @return + * @throws WxErrorException */ - protected String execute(String method, String uri, Object data) throws WxErrorException { + publicT execute(RequestExecutor executor, String uri, E data) throws WxErrorException { if (StringUtils.isBlank(wxConfigStorage.getAccessToken())) { refreshAccessToken(); } @@ -173,38 +169,9 @@ public class WxServiceImpl implements WxService { uriWithAccessToken += uri.indexOf('?') == -1 ? "?access_token=" + accessToken : "&access_token=" + accessToken; try { - String resultContent = null; - if ("POST".equals(method)) { - HttpPost httpPost = new HttpPost(uriWithAccessToken); - if (data != null) { - if (data instanceof String) { - StringEntity entity = new StringEntity((String)data, Consts.UTF_8); - httpPost.setEntity(entity); - } - if (data instanceof File) { - File file = (File) data; - HttpEntity entity = MultipartEntityBuilder - .create() - .addBinaryBody("media", file) - .build(); - httpPost.setEntity(entity); - httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); - } - } - CloseableHttpResponse response = httpclient.execute(httpPost); - resultContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - } else if ("GET".equals(method)) { - if (data != null) { - if (data instanceof String) { - uriWithAccessToken += uriWithAccessToken.endsWith("&") ? data : '&' + (String)data; - } - } - HttpGet httpGet = new HttpGet(uriWithAccessToken); - CloseableHttpResponse response = httpclient.execute(httpGet); - resultContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - } - - WxError error = WxError.fromJson(resultContent); + return executor.execute(uriWithAccessToken, data); + } catch (WxErrorException e) { + WxError error = e.getError(); /* * 发生以下情况时尝试刷新access_token * 40001 获取access_token时AppSecret错误,或者access_token无效 @@ -212,12 +179,24 @@ public class WxServiceImpl implements WxService { */ if (error.getErrcode() == 42001 || error.getErrcode() == 40001) { refreshAccessToken(); - return execute(method, uri, data); + return execute(executor, uri, data); + } + /** + * -1 系统繁忙, 500ms后重试 + */ + if (error.getErrcode() == -1) { + try { + System.out.println("微信系统繁忙,500ms后重试"); + Thread.sleep(500); + return execute(executor, uri, data); + } catch (InterruptedException e1) { + throw new RuntimeException(e1); + } } if (error.getErrcode() != 0) { throw new WxErrorException(error); } - return resultContent; + return null; } catch (ClientProtocolException e) { throw new RuntimeException(e); } catch (IOException e) { @@ -225,38 +204,8 @@ public class WxServiceImpl implements WxService { } } - protected File createTmpFile(InputStream inputStream, String fileType) throws IOException { - FileOutputStream fos = null; - try { - File tmpFile = File.createTempFile(UUID.randomUUID().toString(), '.' + fileType); - tmpFile.deleteOnExit(); - fos = new FileOutputStream(tmpFile); - int read = 0; - byte[] bytes = new byte[1024 * 100]; - while ((read = inputStream.read(bytes)) != -1) { - fos.write(bytes, 0, read); - } - fos.flush(); - return tmpFile; - } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException e) { - } - } - if (fos != null) { - try { - fos.close(); - } catch (IOException e) { - } - } - } - } - public void setWxConfigStorage(WxConfigStorage wxConfigProvider) { this.wxConfigStorage = wxConfigProvider; } - } diff --git a/src/main/java/chanjarster/weixin/bean/WxAccessToken.java b/src/main/java/chanjarster/weixin/bean/WxAccessToken.java index 90b357d0..8c02f538 100644 --- a/src/main/java/chanjarster/weixin/bean/WxAccessToken.java +++ b/src/main/java/chanjarster/weixin/bean/WxAccessToken.java @@ -1,6 +1,6 @@ package chanjarster.weixin.bean; -import chanjarster.weixin.util.WxGsonBuilder; +import chanjarster.weixin.util.json.WxGsonBuilder; public class WxAccessToken { diff --git a/src/main/java/chanjarster/weixin/bean/WxCustomMessage.java b/src/main/java/chanjarster/weixin/bean/WxCustomMessage.java index 9b41f8bf..2ca24e67 100644 --- a/src/main/java/chanjarster/weixin/bean/WxCustomMessage.java +++ b/src/main/java/chanjarster/weixin/bean/WxCustomMessage.java @@ -3,7 +3,7 @@ package chanjarster.weixin.bean; import java.util.ArrayList; import java.util.List; -import chanjarster.weixin.util.WxGsonBuilder; +import chanjarster.weixin.util.json.WxGsonBuilder; /** * 客服消息 diff --git a/src/main/java/chanjarster/weixin/bean/WxMenu.java b/src/main/java/chanjarster/weixin/bean/WxMenu.java index a1662c7d..be79386c 100644 --- a/src/main/java/chanjarster/weixin/bean/WxMenu.java +++ b/src/main/java/chanjarster/weixin/bean/WxMenu.java @@ -5,7 +5,7 @@ import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; -import chanjarster.weixin.util.WxGsonBuilder; +import chanjarster.weixin.util.json.WxGsonBuilder; /** * 公众号菜单 diff --git a/src/main/java/chanjarster/weixin/bean/WxXmlMessage.java b/src/main/java/chanjarster/weixin/bean/WxXmlMessage.java index a89f649e..71650567 100644 --- a/src/main/java/chanjarster/weixin/bean/WxXmlMessage.java +++ b/src/main/java/chanjarster/weixin/bean/WxXmlMessage.java @@ -9,8 +9,8 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import chanjarster.weixin.util.AdapterCDATA; -import chanjarster.weixin.util.XmlTransformer; +import chanjarster.weixin.util.xml.AdapterCDATA; +import chanjarster.weixin.util.xml.XmlTransformer; /** * diff --git a/src/main/java/chanjarster/weixin/bean/result/WxError.java b/src/main/java/chanjarster/weixin/bean/result/WxError.java index 051a777e..69a4ddef 100644 --- a/src/main/java/chanjarster/weixin/bean/result/WxError.java +++ b/src/main/java/chanjarster/weixin/bean/result/WxError.java @@ -3,7 +3,7 @@ package chanjarster.weixin.bean.result; import java.util.HashMap; import java.util.Map; -import chanjarster.weixin.util.WxGsonBuilder; +import chanjarster.weixin.util.json.WxGsonBuilder; /** * 微信错误码说明 diff --git a/src/main/java/chanjarster/weixin/bean/result/WxUploadResult.java b/src/main/java/chanjarster/weixin/bean/result/WxUploadResult.java index cf605fe9..98bee3e3 100644 --- a/src/main/java/chanjarster/weixin/bean/result/WxUploadResult.java +++ b/src/main/java/chanjarster/weixin/bean/result/WxUploadResult.java @@ -1,6 +1,6 @@ package chanjarster.weixin.bean.result; -import chanjarster.weixin.util.WxGsonBuilder; +import chanjarster.weixin.util.json.WxGsonBuilder; public class WxUploadResult { diff --git a/src/main/java/chanjarster/weixin/util/fs/FileUtil.java b/src/main/java/chanjarster/weixin/util/fs/FileUtil.java new file mode 100644 index 00000000..3faeb4dd --- /dev/null +++ b/src/main/java/chanjarster/weixin/util/fs/FileUtil.java @@ -0,0 +1,47 @@ +package chanjarster.weixin.util.fs; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +public class FileUtil { + + /** + * 创建临时文件 + * @param inputStream + * @param name 文件名 + * @param ext 扩展名 + * @return + * @throws IOException + */ + public static File createTmpFile(InputStream inputStream, String name, String ext) throws IOException { + FileOutputStream fos = null; + try { + File tmpFile = File.createTempFile(name, '.' + ext); + tmpFile.deleteOnExit(); + fos = new FileOutputStream(tmpFile); + int read = 0; + byte[] bytes = new byte[1024 * 100]; + while ((read = inputStream.read(bytes)) != -1) { + fos.write(bytes, 0, read); + } + fos.flush(); + return tmpFile; + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + } + } + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + } + } + } + } + +} diff --git a/src/main/java/chanjarster/weixin/util/http/InputStreamResponseHandler.java b/src/main/java/chanjarster/weixin/util/http/InputStreamResponseHandler.java new file mode 100644 index 00000000..37d57790 --- /dev/null +++ b/src/main/java/chanjarster/weixin/util/http/InputStreamResponseHandler.java @@ -0,0 +1,27 @@ +package chanjarster.weixin.util.http; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.StatusLine; +import org.apache.http.client.HttpResponseException; +import org.apache.http.client.ResponseHandler; +import org.apache.http.util.EntityUtils; + +public class InputStreamResponseHandler implements ResponseHandler{ + + public static final ResponseHandler INSTANCE = new InputStreamResponseHandler(); + + public InputStream handleResponse(final HttpResponse response) throws HttpResponseException, IOException { + final StatusLine statusLine = response.getStatusLine(); + final HttpEntity entity = response.getEntity(); + if (statusLine.getStatusCode() >= 300) { + EntityUtils.consume(entity); + throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); + } + return entity == null ? null : entity.getContent(); + } + +} diff --git a/src/main/java/chanjarster/weixin/util/http/MediaDownloadRequestExecutor.java b/src/main/java/chanjarster/weixin/util/http/MediaDownloadRequestExecutor.java new file mode 100644 index 00000000..46e563d5 --- /dev/null +++ b/src/main/java/chanjarster/weixin/util/http/MediaDownloadRequestExecutor.java @@ -0,0 +1,68 @@ +package chanjarster.weixin.util.http; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.Header; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.entity.ContentType; + +import chanjarster.weixin.bean.result.WxError; +import chanjarster.weixin.exception.WxErrorException; +import chanjarster.weixin.util.fs.FileUtil; + +/** + * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是String + * @author chanjarster + * + */ +public class MediaDownloadRequestExecutor implements RequestExecutor { + + @Override + public File execute(String uri, String queryParam) throws WxErrorException, ClientProtocolException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpGet httpGet = new HttpGet(uri); + CloseableHttpResponse response = httpclient.execute(httpGet); + + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0) { + // 下载媒体文件出错 + if (ContentType.TEXT_PLAIN.getMimeType().equals(contentTypeHeader[0].getValue())) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent)); + } + } + InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response); + + // 视频文件不支持下载 + String fileName = getFileName(response); + if (StringUtils.isBlank(fileName)) { + return null; + } + String[] name_ext = fileName.split("\\."); + File localFile = FileUtil.createTmpFile(inputStream, name_ext[0], name_ext[1]); + return localFile; + } + + protected String getFileName(CloseableHttpResponse response) { + Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); + Pattern p = Pattern.compile(".*filename=\"(.*)\""); + Matcher m = p.matcher(contentDispositionHeader[0].getValue()); + m.matches(); + String fileName = m.group(1); + return fileName; + } + +} diff --git a/src/main/java/chanjarster/weixin/util/http/MediaUploadRequestExecutor.java b/src/main/java/chanjarster/weixin/util/http/MediaUploadRequestExecutor.java new file mode 100644 index 00000000..46287ab1 --- /dev/null +++ b/src/main/java/chanjarster/weixin/util/http/MediaUploadRequestExecutor.java @@ -0,0 +1,44 @@ +package chanjarster.weixin.util.http; + +import java.io.File; +import java.io.IOException; + +import org.apache.http.HttpEntity; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.MultipartEntityBuilder; + +import chanjarster.weixin.bean.result.WxError; +import chanjarster.weixin.bean.result.WxUploadResult; +import chanjarster.weixin.exception.WxErrorException; + +/** + * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String + * @author chanjarster + * + */ +public class MediaUploadRequestExecutor implements RequestExecutor { + + @Override + public WxUploadResult execute(String uri, File file) throws WxErrorException, ClientProtocolException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (file != null) { + HttpEntity entity = MultipartEntityBuilder + .create() + .addBinaryBody("media", file) + .build(); + httpPost.setEntity(entity); + httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); + } + CloseableHttpResponse response = httpclient.execute(httpPost); + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrcode() != 0) { + throw new WxErrorException(error); + } + return WxUploadResult.fromJson(responseContent); + } + +} diff --git a/src/main/java/chanjarster/weixin/util/http/RequestExecutor.java b/src/main/java/chanjarster/weixin/util/http/RequestExecutor.java new file mode 100644 index 00000000..e80bd61c --- /dev/null +++ b/src/main/java/chanjarster/weixin/util/http/RequestExecutor.java @@ -0,0 +1,24 @@ +package chanjarster.weixin.util.http; + +import java.io.IOException; + +import org.apache.http.client.ClientProtocolException; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; + +import chanjarster.weixin.exception.WxErrorException; + +/** + * http请求执行器 + * @author chanjarster + * + * @param 返回值类型 + * @param 请求参数类型 + */ +public interface RequestExecutor { + + public static final CloseableHttpClient httpclient = HttpClients.createDefault(); + + public T execute(String uri, E data) throws WxErrorException, ClientProtocolException, IOException; + +} diff --git a/src/main/java/chanjarster/weixin/util/http/SimpleGetRequestExecutor.java b/src/main/java/chanjarster/weixin/util/http/SimpleGetRequestExecutor.java new file mode 100644 index 00000000..91ac1e58 --- /dev/null +++ b/src/main/java/chanjarster/weixin/util/http/SimpleGetRequestExecutor.java @@ -0,0 +1,37 @@ +package chanjarster.weixin.util.http; + +import java.io.IOException; + +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; + +import chanjarster.weixin.bean.result.WxError; +import chanjarster.weixin.exception.WxErrorException; + +/** + * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String + * @author chanjarster + * + */ +public class SimpleGetRequestExecutor implements RequestExecutor { + + @Override + public String execute(String uri, String queryParam) throws WxErrorException, ClientProtocolException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + HttpGet httpGet = new HttpGet(uri); + CloseableHttpResponse response = httpclient.execute(httpGet); + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrcode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/src/main/java/chanjarster/weixin/util/http/SimplePostRequestExecutor.java b/src/main/java/chanjarster/weixin/util/http/SimplePostRequestExecutor.java new file mode 100644 index 00000000..4f3c5bc4 --- /dev/null +++ b/src/main/java/chanjarster/weixin/util/http/SimplePostRequestExecutor.java @@ -0,0 +1,37 @@ +package chanjarster.weixin.util.http; + +import java.io.IOException; + +import org.apache.http.Consts; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; + +import chanjarster.weixin.bean.result.WxError; +import chanjarster.weixin.exception.WxErrorException; + +/** + * 简单的POST请求执行器,请求的参数是String, 返回的结果也是String + * @author chanjarster + * + */ +public class SimplePostRequestExecutor implements RequestExecutor { + + @Override + public String execute(String uri, String postEntity) throws WxErrorException, ClientProtocolException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (postEntity != null) { + StringEntity entity = new StringEntity(postEntity, Consts.UTF_8); + httpPost.setEntity(entity); + } + CloseableHttpResponse response = httpclient.execute(httpPost); + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + WxError error = WxError.fromJson(responseContent); + if (error.getErrcode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/src/main/java/chanjarster/weixin/util/Utf8ResponseHandler.java b/src/main/java/chanjarster/weixin/util/http/Utf8ResponseHandler.java similarity index 96% rename from src/main/java/chanjarster/weixin/util/Utf8ResponseHandler.java rename to src/main/java/chanjarster/weixin/util/http/Utf8ResponseHandler.java index 9884425d..384205e5 100644 --- a/src/main/java/chanjarster/weixin/util/Utf8ResponseHandler.java +++ b/src/main/java/chanjarster/weixin/util/http/Utf8ResponseHandler.java @@ -1,4 +1,4 @@ -package chanjarster.weixin.util; +package chanjarster.weixin.util.http; import java.io.IOException; diff --git a/src/main/java/chanjarster/weixin/util/GsonHelper.java b/src/main/java/chanjarster/weixin/util/json/GsonHelper.java similarity index 98% rename from src/main/java/chanjarster/weixin/util/GsonHelper.java rename to src/main/java/chanjarster/weixin/util/json/GsonHelper.java index 0b138a5e..7487b9fc 100644 --- a/src/main/java/chanjarster/weixin/util/GsonHelper.java +++ b/src/main/java/chanjarster/weixin/util/json/GsonHelper.java @@ -6,7 +6,7 @@ * arose from modification of the original source, or other redistribution of this source * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. */ -package chanjarster.weixin.util; +package chanjarster.weixin.util.json; import com.google.gson.JsonElement; diff --git a/src/main/java/chanjarster/weixin/util/WxCustomMessageGsonAdapter.java b/src/main/java/chanjarster/weixin/util/json/WxCustomMessageGsonAdapter.java similarity index 98% rename from src/main/java/chanjarster/weixin/util/WxCustomMessageGsonAdapter.java rename to src/main/java/chanjarster/weixin/util/json/WxCustomMessageGsonAdapter.java index b6f0a972..cfe9c289 100644 --- a/src/main/java/chanjarster/weixin/util/WxCustomMessageGsonAdapter.java +++ b/src/main/java/chanjarster/weixin/util/json/WxCustomMessageGsonAdapter.java @@ -6,7 +6,7 @@ * arose from modification of the original source, or other redistribution of this source * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. */ -package chanjarster.weixin.util; +package chanjarster.weixin.util.json; import java.lang.reflect.Type; diff --git a/src/main/java/chanjarster/weixin/util/WxGsonBuilder.java b/src/main/java/chanjarster/weixin/util/json/WxGsonBuilder.java similarity index 93% rename from src/main/java/chanjarster/weixin/util/WxGsonBuilder.java rename to src/main/java/chanjarster/weixin/util/json/WxGsonBuilder.java index 60e17b48..c77fafc6 100644 --- a/src/main/java/chanjarster/weixin/util/WxGsonBuilder.java +++ b/src/main/java/chanjarster/weixin/util/json/WxGsonBuilder.java @@ -1,4 +1,4 @@ -package chanjarster.weixin.util; +package chanjarster.weixin.util.json; import chanjarster.weixin.bean.WxCustomMessage; import chanjarster.weixin.bean.WxMenu; diff --git a/src/main/java/chanjarster/weixin/util/WxMenuGsonAdapter.java b/src/main/java/chanjarster/weixin/util/json/WxMenuGsonAdapter.java similarity index 98% rename from src/main/java/chanjarster/weixin/util/WxMenuGsonAdapter.java rename to src/main/java/chanjarster/weixin/util/json/WxMenuGsonAdapter.java index 020fa2cf..78b6cc74 100644 --- a/src/main/java/chanjarster/weixin/util/WxMenuGsonAdapter.java +++ b/src/main/java/chanjarster/weixin/util/json/WxMenuGsonAdapter.java @@ -6,7 +6,7 @@ * arose from modification of the original source, or other redistribution of this source * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. */ -package chanjarster.weixin.util; +package chanjarster.weixin.util.json; import java.lang.reflect.Type; diff --git a/src/main/java/chanjarster/weixin/util/AdapterCDATA.java b/src/main/java/chanjarster/weixin/util/xml/AdapterCDATA.java similarity index 92% rename from src/main/java/chanjarster/weixin/util/AdapterCDATA.java rename to src/main/java/chanjarster/weixin/util/xml/AdapterCDATA.java index 581fcde4..84b96fdf 100644 --- a/src/main/java/chanjarster/weixin/util/AdapterCDATA.java +++ b/src/main/java/chanjarster/weixin/util/xml/AdapterCDATA.java @@ -1,4 +1,4 @@ -package chanjarster.weixin.util; +package chanjarster.weixin.util.xml; import javax.xml.bind.annotation.adapters.XmlAdapter; diff --git a/src/main/java/chanjarster/weixin/util/XmlTransformer.java b/src/main/java/chanjarster/weixin/util/xml/XmlTransformer.java similarity index 98% rename from src/main/java/chanjarster/weixin/util/XmlTransformer.java rename to src/main/java/chanjarster/weixin/util/xml/XmlTransformer.java index 7f52efa7..081fc67f 100644 --- a/src/main/java/chanjarster/weixin/util/XmlTransformer.java +++ b/src/main/java/chanjarster/weixin/util/xml/XmlTransformer.java @@ -1,4 +1,4 @@ -package chanjarster.weixin.util; +package chanjarster.weixin.util.xml; import java.io.IOException; import java.io.InputStream; diff --git a/src/test/java/chanjarster/weixin/api/WxServiceTest.java b/src/test/java/chanjarster/weixin/api/WxServiceTest.java index 65feaab5..4649a161 100644 --- a/src/test/java/chanjarster/weixin/api/WxServiceTest.java +++ b/src/test/java/chanjarster/weixin/api/WxServiceTest.java @@ -2,6 +2,8 @@ package chanjarster.weixin.api; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; import javax.xml.bind.JAXBException; import javax.xml.bind.annotation.XmlAccessType; @@ -19,14 +21,17 @@ import chanjarster.weixin.bean.WxMenu; import chanjarster.weixin.bean.WxMenu.WxMenuButton; import chanjarster.weixin.bean.result.WxUploadResult; import chanjarster.weixin.exception.WxErrorException; -import chanjarster.weixin.util.XmlTransformer; +import chanjarster.weixin.util.xml.XmlTransformer; public class WxServiceTest { private WxServiceImpl wxService; + private List media_ids = new ArrayList (); + @BeforeTest public void prepare() throws JAXBException { + this.wxService = null; InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml"); WxXmlConfigStorage config = XmlTransformer.fromXml(WxXmlConfigStorage.class, is1); this.wxService = new WxServiceImpl(); @@ -66,32 +71,51 @@ public class WxServiceTest { Assert.assertNotNull(wxService.getMenu()); } - @Test(dependsOnMethods = { "testRefreshAccessToken", "testGetMenu" }, enabled = true) + @Test(dependsOnMethods = { "testRefreshAccessToken", "testGetMenu"}, enabled = true) public void testDeleteMenu() throws WxErrorException { wxService.deleteMenu(); } - @Test(dependsOnMethods = { "testRefreshAccessToken" }, dataProvider="uploadFiles", enabled = true) + @Test(dependsOnMethods = { "testRefreshAccessToken" }, dataProvider="uploadMedia", enabled = true) public void testUploadMedia1(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName); WxUploadResult res = wxService.uploadMedia(mediaType, fileType, inputStream); Assert.assertNotNull(res.getType()); Assert.assertNotNull(res.getCreated_at()); Assert.assertTrue(res.getMedia_id() != null || res.getThumb_media_id() != null); + + if (res.getMedia_id() != null) { + media_ids.add(res.getMedia_id()); + } + if (res.getThumb_media_id() != null) { + media_ids.add(res.getThumb_media_id()); + } } @DataProvider - public Object[][] uploadFiles() { + public Object[][] uploadMedia() { return new Object[][] { - new Object[] { WxConsts.MEDIA_IMAGE, WxConsts.FILE_PNG, "mm.png" }, new Object[] { WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, "mm.jpeg" }, new Object[] { WxConsts.MEDIA_VOICE, WxConsts.FILE_MP3, "mm.mp3" }, new Object[] { WxConsts.MEDIA_VIDEO, WxConsts.FILE_MP4, "mm.mp4" }, - new Object[] { WxConsts.MEDIA_THUMB, WxConsts.FILE_PNG, "mm.png" }, new Object[] { WxConsts.MEDIA_THUMB, WxConsts.FILE_JPG, "mm.jpeg" } }; } + @Test(dependsOnMethods = { "testUploadMedia1" }, dataProvider="downloadMedia") + public void testDownloadMedia(String media_id) throws WxErrorException { + wxService.downloadMedia(media_id); + } + + @DataProvider + public Object[][] downloadMedia() { + Object[][] params = new Object[this.media_ids.size()][]; + for (int i = 0; i < this.media_ids.size(); i++) { + params[i] = new Object[] { this.media_ids.get(i) }; + } + return params; + } + @Test(enabled = true) public void testCheckSignature() throws WxErrorException { String timestamp = "23234235423246"; diff --git a/src/test/resources/mm.png b/src/test/resources/mm.png deleted file mode 100644 index a060d443..00000000 Binary files a/src/test/resources/mm.png and /dev/null differ