diff --git a/README.md b/README.md index 0fc0712b..78fc33e6 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,14 @@ tencent weixin platform java sdk 微信公众平台开发工具包 http://mp.wei > 如果不想使用这种方式可以去掉pom.xml的resources节点最后一个子节点 -> 并修改src/main/java/com/foxinmy/weixin4j/util/WeixinConfig类相关代码以便正确获取api的uri. +> 并修改src/main/java/com/foxinmy/weixin4j/util/ConfigUtil类相关代码以便正确获取api的uri. -接下来 ------- -> netty服务. - -> 消息分发. +更新LOG +------- +2014-10-27 + 1).用netty构建http服务器并支持消息分发 + + 接下来 + ----- + maven多模块分离 + 微信支付模块引入 diff --git a/pom.xml b/pom.xml index 79c6bbea..ffdf7644 100644 --- a/pom.xml +++ b/pom.xml @@ -32,14 +32,15 @@ src/main/resources - *.* + logback.xml src/main/java - **/config.properties + **/*.properties **/error.xml + **/README.md @@ -145,6 +146,11 @@ jedis ${jedis.version} + + io.netty + netty-all + ${netty.version} + @@ -160,6 +166,7 @@ 1.7.3 1.1.6 2.6.0 + 4.0.23.Final UTF-8 diff --git a/src/main/java/com/foxinmy/weixin4j/WeixinProxy.java b/src/main/java/com/foxinmy/weixin4j/WeixinProxy.java index 0453a9cc..72e75ba6 100644 --- a/src/main/java/com/foxinmy/weixin4j/WeixinProxy.java +++ b/src/main/java/com/foxinmy/weixin4j/WeixinProxy.java @@ -1,6 +1,7 @@ package com.foxinmy.weixin4j; import java.io.File; +import java.io.IOException; import java.util.List; import com.alibaba.fastjson.JSONObject; @@ -15,6 +16,7 @@ import com.foxinmy.weixin4j.api.UserApi; import com.foxinmy.weixin4j.api.token.FileTokenApi; import com.foxinmy.weixin4j.api.token.TokenApi; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.model.Button; import com.foxinmy.weixin4j.model.CustomRecord; import com.foxinmy.weixin4j.model.Following; @@ -23,7 +25,6 @@ import com.foxinmy.weixin4j.model.MpArticle; import com.foxinmy.weixin4j.model.QRParameter; import com.foxinmy.weixin4j.model.User; import com.foxinmy.weixin4j.model.UserToken; -import com.foxinmy.weixin4j.msg.BaseResult; import com.foxinmy.weixin4j.msg.model.Article; import com.foxinmy.weixin4j.msg.model.BaseMsg; import com.foxinmy.weixin4j.msg.notify.BaseNotify; @@ -47,7 +48,7 @@ public class WeixinProxy { private final GroupApi groupApi; private final MenuApi menuApi; private final QrApi qrApi; - private final TmplApi templApi; + private final TmplApi tmplApi; /** * 默认采用文件存放Token跟配置文件中的appi信息 @@ -74,7 +75,7 @@ public class WeixinProxy { this.groupApi = new GroupApi(tokenApi); this.menuApi = new MenuApi(tokenApi); this.qrApi = new QrApi(tokenApi); - this.templApi = new TmplApi(tokenApi); + this.tmplApi = new TmplApi(tokenApi); } /** @@ -90,12 +91,13 @@ public class WeixinProxy { * 媒体类型 * @return 上传到微信服务器返回的媒体标识 * @throws WeixinException + * @throws IOException * @see 上传下载说明 * @see com.foxinmy.weixin4j.type.MediaType */ public String uploadMedia(File file, MediaType mediaType) - throws WeixinException { + throws WeixinException, IOException { return mediaApi.uploadMedia(file, mediaType); } @@ -127,12 +129,13 @@ public class WeixinProxy { * 媒体类型 * @return 写入硬盘后的文件对象 * @throws WeixinException + * @throws IOException * @see 上传下载说明 * @see com.foxinmy.weixin4j.type.MediaType */ public File downloadMedia(String mediaId, MediaType mediaType) - throws WeixinException { + throws WeixinException, IOException { return mediaApi.downloadMedia(mediaId, mediaType); } @@ -464,9 +467,9 @@ public class WeixinProxy { * @see 设置用户备注名 */ - public BaseResult updateUserRemark(String openId, String remark) + public BaseResult remarkUserName(String openId, String remark) throws WeixinException { - return userApi.updateUserRemark(openId, remark); + return userApi.remarkUserName(openId, remark); } /** @@ -625,11 +628,12 @@ public class WeixinProxy { * 二维码参数 * @return 硬盘存储的文件对象 * @throws WeixinException + * @throws IOException * @see 二维码 * @see com.foxinmy.weixin4j.model.QRParameter */ - public File getQR(QRParameter parameter) throws WeixinException { + public File getQR(QRParameter parameter) throws WeixinException, IOException { return qrApi.getQR(parameter); } @@ -644,8 +648,8 @@ public class WeixinProxy { * @see com.foxinmy.weixin4j.msg.out.TemplateMessage * @seee com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage */ - public BaseResult sendTplMessage(TemplateMessage tplMessage) + public BaseResult sendTmplMessage(TemplateMessage tplMessage) throws WeixinException { - return templApi.sendTplMessage(tplMessage); + return tmplApi.sendTmplMessage(tplMessage); } } diff --git a/src/main/java/com/foxinmy/weixin4j/api/GroupApi.java b/src/main/java/com/foxinmy/weixin4j/api/GroupApi.java index ed024bbd..58acc50d 100644 --- a/src/main/java/com/foxinmy/weixin4j/api/GroupApi.java +++ b/src/main/java/com/foxinmy/weixin4j/api/GroupApi.java @@ -5,10 +5,10 @@ import java.util.List; import com.alibaba.fastjson.JSON; import com.foxinmy.weixin4j.api.token.TokenApi; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.model.Group; import com.foxinmy.weixin4j.model.Token; -import com.foxinmy.weixin4j.msg.BaseResult; import com.foxinmy.weixin4j.util.ConfigUtil; /** diff --git a/src/main/java/com/foxinmy/weixin4j/api/MassApi.java b/src/main/java/com/foxinmy/weixin4j/api/MassApi.java index be0c994d..ddefc335 100644 --- a/src/main/java/com/foxinmy/weixin4j/api/MassApi.java +++ b/src/main/java/com/foxinmy/weixin4j/api/MassApi.java @@ -6,10 +6,10 @@ import java.util.List; import com.alibaba.fastjson.JSONObject; import com.foxinmy.weixin4j.api.token.TokenApi; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.model.MpArticle; import com.foxinmy.weixin4j.model.Token; -import com.foxinmy.weixin4j.msg.BaseResult; import com.foxinmy.weixin4j.type.MediaType; import com.foxinmy.weixin4j.util.ConfigUtil; diff --git a/src/main/java/com/foxinmy/weixin4j/api/MediaApi.java b/src/main/java/com/foxinmy/weixin4j/api/MediaApi.java index 21e4fb4b..a1a29484 100644 --- a/src/main/java/com/foxinmy/weixin4j/api/MediaApi.java +++ b/src/main/java/com/foxinmy/weixin4j/api/MediaApi.java @@ -1,6 +1,5 @@ package com.foxinmy.weixin4j.api; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -49,37 +48,16 @@ public class MediaApi extends BaseApi { * 媒体类型 * @return 上传到微信服务器返回的媒体标识 * @throws WeixinException + * @throws IOException + * @throws * @see 上传下载说明 * @see com.foxinmy.weixin4j.type.MediaType */ public String uploadMedia(File file, MediaType mediaType) - throws WeixinException { - byte[] b = null; - ByteArrayOutputStream out = null; - FileInputStream in = null; - try { - in = new FileInputStream(file); - b = IOUtil.toByteArray(in); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - ; - } - } - if (in != null) { - try { - in.close(); - } catch (IOException e) { - ; - } - } - } - return uploadMedia(file.getName(), b, mediaType); + throws WeixinException, IOException { + byte[] datas = IOUtil.toByteArray(new FileInputStream(file)); + return uploadMedia(file.getName(), datas, mediaType); } /** @@ -116,40 +94,30 @@ public class MediaApi extends BaseApi { * 媒体类型 * @return 写入硬盘后的文件对象 * @throws WeixinException + * @throws IOException * @see 上传下载说明 * @see com.foxinmy.weixin4j.type.MediaType */ public File downloadMedia(String mediaId, MediaType mediaType) - throws WeixinException { + throws WeixinException, IOException { String media_path = ConfigUtil.getValue("media_path"); - String filename = mediaId + mediaType.getFormatType(); + byte[] datas = downloadMediaData(mediaId, mediaType); + String filename = mediaId + "." + mediaType.getFormatType(); File file = new File(media_path + File.separator + filename); if (file.exists()) { return file; } FileOutputStream out = null; try { - try { - file.createNewFile(); - } catch (IOException e) { - file.getParentFile().mkdirs(); - file.createNewFile(); - } - out = new FileOutputStream(file); - byte[] b = downloadMediaData(mediaId, mediaType); - out.write(b); + file.createNewFile(); } catch (IOException e) { - - } finally { - try { - if (out != null) { - out.close(); - } - } catch (IOException e) { - - } + file.getParentFile().mkdirs(); + file.createNewFile(); } + out = new FileOutputStream(file); + out.write(datas); + out.close(); return file; } diff --git a/src/main/java/com/foxinmy/weixin4j/api/MenuApi.java b/src/main/java/com/foxinmy/weixin4j/api/MenuApi.java index 7e063a04..fe488718 100644 --- a/src/main/java/com/foxinmy/weixin4j/api/MenuApi.java +++ b/src/main/java/com/foxinmy/weixin4j/api/MenuApi.java @@ -6,10 +6,10 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.foxinmy.weixin4j.api.token.TokenApi; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.model.Button; import com.foxinmy.weixin4j.model.Token; -import com.foxinmy.weixin4j.msg.BaseResult; import com.foxinmy.weixin4j.util.ConfigUtil; /** diff --git a/src/main/java/com/foxinmy/weixin4j/api/NotifyApi.java b/src/main/java/com/foxinmy/weixin4j/api/NotifyApi.java index 1ca09cc7..7a40d7ca 100644 --- a/src/main/java/com/foxinmy/weixin4j/api/NotifyApi.java +++ b/src/main/java/com/foxinmy/weixin4j/api/NotifyApi.java @@ -6,10 +6,10 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.foxinmy.weixin4j.api.token.TokenApi; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.model.CustomRecord; import com.foxinmy.weixin4j.model.Token; -import com.foxinmy.weixin4j.msg.BaseResult; import com.foxinmy.weixin4j.msg.model.Article; import com.foxinmy.weixin4j.msg.model.BaseMsg; import com.foxinmy.weixin4j.msg.notify.ArticleNotify; diff --git a/src/main/java/com/foxinmy/weixin4j/api/QrApi.java b/src/main/java/com/foxinmy/weixin4j/api/QrApi.java index d006b3dc..01263254 100644 --- a/src/main/java/com/foxinmy/weixin4j/api/QrApi.java +++ b/src/main/java/com/foxinmy/weixin4j/api/QrApi.java @@ -1,6 +1,7 @@ package com.foxinmy.weixin4j.api; import java.io.File; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; @@ -19,7 +20,8 @@ import com.foxinmy.weixin4j.util.ConfigUtil; * @author jy.hu * @date 2014年9月25日 * @since JDK 1.7 - * @see 二维码支持 + * @see 二维码支持 */ public class QrApi extends BaseApi { @@ -40,7 +42,9 @@ public class QrApi extends BaseApi { public byte[] getQRData(QRParameter parameter) throws WeixinException { Token token = tokenApi.getToken(); String qr_uri = ConfigUtil.getValue("qr_ticket_uri"); - Response response = request.post(String.format(qr_uri, token.getAccessToken()), parameter.toJson()); + Response response = request.post( + String.format(qr_uri, token.getAccessToken()), + parameter.toJson()); String ticket = response.getAsJson().getString("ticket"); qr_uri = ConfigUtil.getValue("qr_image_uri"); response = request.get(String.format(qr_uri, ticket)); @@ -59,8 +63,10 @@ public class QrApi extends BaseApi { * @throws WeixinException * @see {@link com.foxinmy.weixin4j.api.QrApi#getQR(QRParameter)} */ - public byte[] getQRData(int sceneId, int expireSeconds) throws WeixinException { - QRParameter parameter = new QRParameter(sceneId, QRType.TEMPORARY, expireSeconds); + public byte[] getQRData(int sceneId, int expireSeconds) + throws WeixinException { + QRParameter parameter = new QRParameter(sceneId, QRType.TEMPORARY, + expireSeconds); if (expireSeconds <= 0) { parameter.setQrType(QRType.PERMANENCE); } @@ -77,39 +83,31 @@ public class QrApi extends BaseApi { * 二维码参数 * @return 硬盘存储的文件对象 * @throws WeixinException + * @throws FileNotFoundException * @see 二维码 * @see com.foxinmy.weixin4j.model.QRParameter */ - public File getQR(QRParameter parameter) throws WeixinException { + public File getQR(QRParameter parameter) throws WeixinException, + IOException { String qr_path = ConfigUtil.getValue("qr_path"); - String filename = String.format("%s_%d_%d.jpg", parameter.getQrType().name(), parameter.getSceneId(), parameter.getExpireSeconds()); + String filename = String.format("%s_%d_%d.jpg", parameter.getQrType() + .name(), parameter.getSceneId(), parameter.getExpireSeconds()); File file = new File(qr_path + File.separator + filename); if (parameter.getQrType() == QRType.PERMANENCE && file.exists()) { return file; } + byte[] datas = getQRData(parameter); FileOutputStream out = null; try { - try { - file.createNewFile(); - } catch (IOException e) { - file.getParentFile().mkdirs(); - file.createNewFile(); - } - out = new FileOutputStream(file); - byte[] b = getQRData(parameter); - out.write(b); + file.createNewFile(); } catch (IOException e) { - ; - } finally { - try { - if (out != null) { - out.close(); - } - } catch (IOException e) { - ; - } + file.getParentFile().mkdirs(); + file.createNewFile(); } + out = new FileOutputStream(file); + out.write(datas); + out.close(); return file; } } diff --git a/src/main/java/com/foxinmy/weixin4j/api/TmplApi.java b/src/main/java/com/foxinmy/weixin4j/api/TmplApi.java index caf45555..6b794da7 100644 --- a/src/main/java/com/foxinmy/weixin4j/api/TmplApi.java +++ b/src/main/java/com/foxinmy/weixin4j/api/TmplApi.java @@ -2,9 +2,9 @@ package com.foxinmy.weixin4j.api; import com.foxinmy.weixin4j.api.token.TokenApi; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.model.Token; -import com.foxinmy.weixin4j.msg.BaseResult; import com.foxinmy.weixin4j.msg.out.TemplateMessage; import com.foxinmy.weixin4j.util.ConfigUtil; @@ -36,7 +36,7 @@ public class TmplApi extends BaseApi { * @see com.foxinmy.weixin4j.msg.out.TemplateMessage * @seee com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage */ - public BaseResult sendTplMessage(TemplateMessage tplMessage) + public BaseResult sendTmplMessage(TemplateMessage tplMessage) throws WeixinException { Token token = tokenApi.getToken(); String template_send_uri = ConfigUtil.getValue("template_send_uri"); diff --git a/src/main/java/com/foxinmy/weixin4j/api/UserApi.java b/src/main/java/com/foxinmy/weixin4j/api/UserApi.java index 8ce55535..08d400d2 100644 --- a/src/main/java/com/foxinmy/weixin4j/api/UserApi.java +++ b/src/main/java/com/foxinmy/weixin4j/api/UserApi.java @@ -7,12 +7,12 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.foxinmy.weixin4j.api.token.TokenApi; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.BaseResult; import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.model.Following; import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.User; import com.foxinmy.weixin4j.model.UserToken; -import com.foxinmy.weixin4j.msg.BaseResult; import com.foxinmy.weixin4j.util.ConfigUtil; /** @@ -166,7 +166,7 @@ public class UserApi extends BaseApi { * @see 设置用户备注名 */ - public BaseResult updateUserRemark(String openId, String remark) + public BaseResult remarkUserName(String openId, String remark) throws WeixinException { String updateremark_uri = ConfigUtil.getValue("updateremark_uri"); Token token = tokenApi.getToken(); diff --git a/src/main/java/com/foxinmy/weixin4j/config.properties b/src/main/java/com/foxinmy/weixin4j/config.properties index f0f037a2..d115a0c2 100644 --- a/src/main/java/com/foxinmy/weixin4j/config.properties +++ b/src/main/java/com/foxinmy/weixin4j/config.properties @@ -2,7 +2,7 @@ app_id=wx4ab8f8de58159a57 app_secret=1d4eb0f4bf556aaed539f30ed05ca795 app_openId=gh_22b350df957b -app_token=carsonliu13450438112 +app_token=wexintoken # ---------------------------------------------------------------------------- # api\u9996\u9875 @@ -15,7 +15,6 @@ api_base_url=https://api.weixin.qq.com/cgi-bin mp_base_url=https://mp.weixin.qq.com/cgi-bin file_base_url=http://file.api.weixin.qq.com/cgi-bin - # \u7f51\u9875\u6388\u6743\u83b7\u53d6\u7528\u6237\u4fe1\u606f user_auth_uri=https://open.weixin.qq.com/connect/oauth2/authorize?appid={app_id}&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect sns_user_token_uri=https://api.weixin.qq.com/sns/oauth2/access_token?appid={app_id}&secret={app_secret}&code=%s&grant_type=authorization_code @@ -25,15 +24,13 @@ sns_user_info_uri=https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid= api_user_info_uri={api_base_url}/user/info?access_token=%s&openid=%s&lang=zh_CN # \u83b7\u53d6\u6211\u7684token api_token_uri={api_base_url}/token?grant_type=client_credential&appid=%s&secret=%s - # \u83b7\u53d6\u4e8c\u7ef4\u7801 qr_ticket_uri={api_base_url}/qrcode/create?access_token=%s qr_image_uri={mp_base_url}/showqrcode?ticket=%s - # \u4e0a\u4f20\u5a92\u4f53\u6587\u4ef6 file_upload_uri={file_base_url}/media/upload?access_token=%s&type=%s +# \u4e0b\u8f7d\u5a92\u4f53\u6587\u4ef6 file_download_uri={file_base_url}/media/get?access_token=%s&media_id=%s - # \u53d1\u9001\u5ba2\u670d\u6d88\u606f custom_notify_uri={api_base_url}/message/custom/send?access_token=%s # \u521b\u5efa\u5206\u7ec4 @@ -73,10 +70,9 @@ updateremark_uri={api_base_url}/user/info/updateremark?access_token=%s # \u6a21\u677f\u6d88\u606f template_send_uri={api_base_url}/message/template/send?access_token=%s - # token\u5b58\u653e\u8def\u5f84 token_path=/tmp/weixin/token # \u4e8c\u7ef4\u7801\u4fdd\u5b58\u8def\u5f84 qr_path=/tmp/weixin/qr # \u5a92\u4f53\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84 -media_path=/tmp/weixin/media +media_path=/tmp/weixin/media \ No newline at end of file diff --git a/src/main/java/com/foxinmy/weixin4j/exception/WeixinException.java b/src/main/java/com/foxinmy/weixin4j/exception/WeixinException.java index 4e19f162..2933f61a 100644 --- a/src/main/java/com/foxinmy/weixin4j/exception/WeixinException.java +++ b/src/main/java/com/foxinmy/weixin4j/exception/WeixinException.java @@ -2,6 +2,7 @@ package com.foxinmy.weixin4j.exception; /** * 调用微信接口抛出的异常 + * * @className WeixinException * @author jy.hu * @date 2014年4月10日 @@ -29,10 +30,15 @@ public class WeixinException extends Exception { } public int getErrorCode() { - return this.errorCode; + return errorCode; } public String getErrorMsg() { - return this.errorMsg; + return errorMsg; + } + + @Override + public String getMessage() { + return this.errorCode + "," + this.errorMsg; } } diff --git a/src/main/java/com/foxinmy/weixin4j/msg/BaseResult.java b/src/main/java/com/foxinmy/weixin4j/http/BaseResult.java similarity index 92% rename from src/main/java/com/foxinmy/weixin4j/msg/BaseResult.java rename to src/main/java/com/foxinmy/weixin4j/http/BaseResult.java index 0e46f846..c19b7e46 100644 --- a/src/main/java/com/foxinmy/weixin4j/msg/BaseResult.java +++ b/src/main/java/com/foxinmy/weixin4j/http/BaseResult.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.msg; +package com.foxinmy.weixin4j.http; import java.io.Serializable; diff --git a/src/main/java/com/foxinmy/weixin4j/http/HttpRequest.java b/src/main/java/com/foxinmy/weixin4j/http/HttpRequest.java index 9ecee3e8..087eaca9 100644 --- a/src/main/java/com/foxinmy/weixin4j/http/HttpRequest.java +++ b/src/main/java/com/foxinmy/weixin4j/http/HttpRequest.java @@ -2,6 +2,7 @@ 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; @@ -33,7 +34,6 @@ import org.apache.http.params.CoreProtocolPNames; import org.apache.http.util.EntityUtils; import com.foxinmy.weixin4j.exception.WeixinException; -import com.foxinmy.weixin4j.msg.BaseResult; /** * 调用微信相关接口的HttpRequest,对于其他请求可能并不试用 @@ -51,7 +51,8 @@ public class HttpRequest { this(150, 100, 10000, 10000); } - public HttpRequest(int maxConPerRoute, int maxTotal, int socketTimeout, int connectionTimeout) { + public HttpRequest(int maxConPerRoute, int maxTotal, int socketTimeout, + int connectionTimeout) { PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager(); // 指定IP并发最大数 connectionManager.setDefaultMaxPerRoute(maxConPerRoute); @@ -59,25 +60,35 @@ public class HttpRequest { 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); + 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 { + 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())); + 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()); @@ -90,7 +101,8 @@ public class HttpRequest { return post(url, (Parameter[]) null); } - public Response post(String url, Parameter... parameters) throws WeixinException { + public Response post(String url, Parameter... parameters) + throws WeixinException { HttpPost method = new HttpPost(url); List params = new ArrayList(); for (Parameter parameter : parameters) { @@ -102,23 +114,28 @@ public class HttpRequest { 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))); + 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))); + 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))); + 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 { + public Response post(String url, PartParameter... paramters) + throws WeixinException { HttpPost method = new HttpPost(url); MultipartEntity entity = new MultipartEntity(); for (PartParameter paramter : paramters) { @@ -129,7 +146,8 @@ public class HttpRequest { return doRequest(method); } - protected Response doRequest(HttpRequestBase request) throws WeixinException { + protected Response doRequest(HttpRequestBase request) + throws WeixinException { try { HttpResponse httpResponse = client.execute(request); StatusLine statusLine = httpResponse.getStatusLine(); @@ -140,8 +158,11 @@ public class HttpRequest { 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"))); + 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(); @@ -151,16 +172,21 @@ public class HttpRequest { response.setStream(new ByteArrayInputStream(data)); response.setText(StringUtils.newStringUtf8(data)); - Header contentType = httpResponse.getFirstHeader(HttpHeaders.CONTENT_TYPE); - if (contentType.getValue().contains(ContentType.APPLICATION_JSON.getMimeType())) { + 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()); + throw new WeixinException(result.getErrcode(), + result.getErrmsg()); } } EntityUtils.consume(httpEntity); return response; - } catch (Exception e) { + } catch (IOException e) { throw new WeixinException(e.getMessage()); } finally { request.releaseConnection(); diff --git a/src/main/java/com/foxinmy/weixin4j/http/Response.java b/src/main/java/com/foxinmy/weixin4j/http/Response.java index b1b2e274..e555bcad 100644 --- a/src/main/java/com/foxinmy/weixin4j/http/Response.java +++ b/src/main/java/com/foxinmy/weixin4j/http/Response.java @@ -11,7 +11,6 @@ import org.dom4j.io.SAXReader; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.foxinmy.weixin4j.WeixinProxy; -import com.foxinmy.weixin4j.msg.BaseResult; import com.thoughtworks.xstream.XStream; public class Response { diff --git a/src/main/java/com/foxinmy/weixin4j/msg/BaseMessage.java b/src/main/java/com/foxinmy/weixin4j/msg/BaseMessage.java index dbfe975a..7016b775 100644 --- a/src/main/java/com/foxinmy/weixin4j/msg/BaseMessage.java +++ b/src/main/java/com/foxinmy/weixin4j/msg/BaseMessage.java @@ -4,6 +4,7 @@ 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; @@ -25,8 +26,14 @@ import com.thoughtworks.xstream.io.json.JsonWriter; public class BaseMessage implements Serializable { private static final long serialVersionUID = 7761192742840031607L; - private static XStream xstream; - + 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") @@ -38,10 +45,21 @@ public class BaseMessage implements Serializable { @XStreamAlias("MsgId") private long msgId; // 消息ID - static{ - xstream = new XStream(); + 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; } @@ -108,11 +126,8 @@ public class BaseMessage implements Serializable { protected XStream getXStream() { Class targetClass = getMsgType() .getMessageClass(); - xstream.alias("xml", targetClass); - xstream.autodetectAnnotations(true); - xstream.processAnnotations(targetClass); - xstream.omitField(BaseMessage.class, "msgId"); - return xstream; + xmlStream.alias("xml", targetClass); + return xmlStream; } /** @@ -121,13 +136,7 @@ public class BaseMessage implements Serializable { * @return xml字符串 */ public String toXml() { - Class targetClass = getMsgType() - .getMessageClass(); - xstream.alias("xml", targetClass); - xstream.autodetectAnnotations(true); - xstream.processAnnotations(targetClass); - xstream.omitField(BaseMessage.class, "msgId"); - return xstream.toXML(this); + return getXStream().toXML(this); } /** @@ -136,15 +145,6 @@ public class BaseMessage implements Serializable { * @return json字符串 */ public String toJson() { - XStream xstream = new XStream(new JsonHierarchicalStreamDriver() { - public HierarchicalStreamWriter createWriter(Writer writer) { - return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE); - } - }); - xstream.setMode(XStream.NO_REFERENCES); - xstream.autodetectAnnotations(true); - xstream.processAnnotations(getMsgType().getMessageClass()); - xstream.omitField(BaseMessage.class, "msgId"); - return xstream.toXML(this); + return jsonStream.toXML(this); } } diff --git a/src/main/java/com/foxinmy/weixin4j/msg/model/BaseMsg.java b/src/main/java/com/foxinmy/weixin4j/msg/model/BaseMsg.java index 61b5648c..f7d35981 100644 --- a/src/main/java/com/foxinmy/weixin4j/msg/model/BaseMsg.java +++ b/src/main/java/com/foxinmy/weixin4j/msg/model/BaseMsg.java @@ -3,7 +3,9 @@ package com.foxinmy.weixin4j.msg.model; import java.io.Serializable; import java.io.Writer; +import com.foxinmy.weixin4j.msg.notify.BaseNotify; import com.foxinmy.weixin4j.type.MediaType; +import com.foxinmy.weixin4j.util.ClassUtil; import com.foxinmy.weixin4j.xml.XStream; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver; @@ -11,6 +13,18 @@ import com.thoughtworks.xstream.io.json.JsonWriter; public abstract class BaseMsg implements Serializable { private static final long serialVersionUID = 1L; + private final static XStream xstream = new XStream( + new JsonHierarchicalStreamDriver() { + public HierarchicalStreamWriter createWriter(Writer writer) { + return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE); + } + }); + static { + xstream.setMode(XStream.NO_REFERENCES); + xstream.autodetectAnnotations(true); + xstream.processAnnotations(ClassUtil.getClasses( + BaseNotify.class.getPackage()).toArray(new Class[0])); + } public abstract MediaType getMediaType(); @@ -20,14 +34,6 @@ public abstract class BaseMsg implements Serializable { * @return {"touser": "to","msgtype": "text","text": {"content": "123"}} */ public String toNotifyJson() { - XStream xstream = new XStream(new JsonHierarchicalStreamDriver() { - public HierarchicalStreamWriter createWriter(Writer writer) { - return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE); - } - }); - xstream.setMode(XStream.NO_REFERENCES); - xstream.autodetectAnnotations(true); - xstream.processAnnotations(this.getClass()); return xstream.toXML(this); } } diff --git a/src/main/java/com/foxinmy/weixin4j/msg/out/ArticleMessage.java b/src/main/java/com/foxinmy/weixin4j/msg/out/ArticleMessage.java index 9c3737a7..aa439b54 100644 --- a/src/main/java/com/foxinmy/weixin4j/msg/out/ArticleMessage.java +++ b/src/main/java/com/foxinmy/weixin4j/msg/out/ArticleMessage.java @@ -1,7 +1,6 @@ package com.foxinmy.weixin4j.msg.out; import java.util.LinkedList; -import java.util.List; import com.foxinmy.weixin4j.msg.BaseMessage; import com.foxinmy.weixin4j.msg.model.Article; @@ -35,19 +34,14 @@ public class ArticleMessage extends BaseMessage { @XStreamAlias("Articles") private LinkedList
articles; - public List
getArticles() { - return this.articles; - } - public void pushArticle(String title, String desc, String picUrl, String url) { - if ((count + 1) > MAX_ARTICLE_COUNT) { - return; - } if (this.articles == null) { this.articles = new LinkedList
(); } + if ((articles.size() + 1) > MAX_ARTICLE_COUNT) { + return; + } this.articles.add(new Article(title, desc, picUrl, url)); - count++; } public void pushFirstArticle(String title, String desc, String picUrl, @@ -67,10 +61,11 @@ public class ArticleMessage extends BaseMessage { } public Article removeLastArticle() { + Article article = null; if (this.articles != null) { - return this.articles.removeLast(); + article = this.articles.removeLast(); } - return null; + return article; } public Article removeFirstArticle() { @@ -86,6 +81,7 @@ public class ArticleMessage extends BaseMessage { @Override public String toXml() { + this.count = articles.size(); XStream xstream = getXStream(); xstream.alias("item", Article.class); xstream.aliasField("Title", Article.class, "title"); @@ -101,7 +97,7 @@ public class ArticleMessage extends BaseMessage { sb.append("[ArticleMessage ,toUserName=").append(super.getToUserName()); sb.append(" ,fromUserName=").append(super.getFromUserName()); sb.append(" ,msgType=").append(super.getMsgType().name()); - sb.append(" ,articles=").append(getArticles().toString()); + sb.append(" ,articles=").append(this.articles.toString()); sb.append(" ,createTime=").append(super.getCreateTime()); sb.append(" ,msgId=").append(super.getMsgId()).append("]"); return sb.toString(); diff --git a/src/main/java/com/foxinmy/weixin4j/msg/out/ImageMessage.java b/src/main/java/com/foxinmy/weixin4j/msg/out/ImageMessage.java index fb58ecb8..4b4361ce 100644 --- a/src/main/java/com/foxinmy/weixin4j/msg/out/ImageMessage.java +++ b/src/main/java/com/foxinmy/weixin4j/msg/out/ImageMessage.java @@ -23,8 +23,7 @@ public class ImageMessage extends BaseMessage { private static final long serialVersionUID = 6998255203997554731L; public ImageMessage(BaseMessage inMessage) { - super(MessageType.image, inMessage); - super.getMsgType().setMessageClass(ImageMessage.class); + this(null, inMessage); } public ImageMessage(String mediaId, BaseMessage inMessage) { diff --git a/src/main/java/com/foxinmy/weixin4j/msg/out/TemplateMessage.java b/src/main/java/com/foxinmy/weixin4j/msg/out/TemplateMessage.java index 3721504b..b394f86e 100644 --- a/src/main/java/com/foxinmy/weixin4j/msg/out/TemplateMessage.java +++ b/src/main/java/com/foxinmy/weixin4j/msg/out/TemplateMessage.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.Map; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; /** * 模板消息 @@ -13,7 +14,7 @@ import com.alibaba.fastjson.JSON; * @author jy * @date 2014年9月29日 * @since JDK 1.7 - * @see + * @see 模板消息 */ public class TemplateMessage implements Serializable { @@ -29,11 +30,13 @@ public class TemplateMessage implements Serializable { this.data.put(key, new Item(value)); } - public TemplateMessage(String touser, String template_id, String url) { + public TemplateMessage(String touser, String template_id, String title, + String url) { this.touser = touser; this.template_id = template_id; this.url = url; this.data = new HashMap(); + pushData("first", title); } private static class Item implements Serializable { @@ -111,6 +114,7 @@ public class TemplateMessage implements Serializable { + ", data=" + data + "]"; } + @JSONField(serialize = false) public String toJson() { return JSON.toJSONString(this); } diff --git a/src/main/java/com/foxinmy/weixin4j/msg/out/VoiceMessage.java b/src/main/java/com/foxinmy/weixin4j/msg/out/VoiceMessage.java index dcac1046..9f61e558 100644 --- a/src/main/java/com/foxinmy/weixin4j/msg/out/VoiceMessage.java +++ b/src/main/java/com/foxinmy/weixin4j/msg/out/VoiceMessage.java @@ -24,8 +24,7 @@ public class VoiceMessage extends BaseMessage { private static final long serialVersionUID = -7944926238652243793L; public VoiceMessage(BaseMessage inMessage) { - super(MessageType.voice, inMessage); - super.getMsgType().setMessageClass(VoiceMessage.class); + this(null, inMessage); } public VoiceMessage(String mediaId, BaseMessage inMessage) { diff --git a/src/main/java/com/foxinmy/weixin4j/WeixinExecutor.java b/src/main/java/com/foxinmy/weixin4j/spider/WeixinExecutor.java similarity index 65% rename from src/main/java/com/foxinmy/weixin4j/WeixinExecutor.java rename to src/main/java/com/foxinmy/weixin4j/spider/WeixinExecutor.java index 9fd61b87..1f7bbf85 100644 --- a/src/main/java/com/foxinmy/weixin4j/WeixinExecutor.java +++ b/src/main/java/com/foxinmy/weixin4j/spider/WeixinExecutor.java @@ -1,8 +1,9 @@ -package com.foxinmy.weixin4j; +package com.foxinmy.weixin4j.spider; import java.io.Serializable; import java.net.URI; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -37,11 +38,16 @@ import org.slf4j.LoggerFactory; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.foxinmy.weixin4j.util.IOUtil; +import com.foxinmy.weixin4j.util.RandomUtil; /** - * 用于微信公众号绑定(模拟登录|启用开发者模式|修改服务器配置|修改回调地址|创建自定义菜单) + * 模拟微信WEB登陆 * - * @className WeixinBind + *

+ * (模拟登录|启用开发者模式|修改服务器配置|修改回调地址|创建自定义菜单....more) + *

+ * + * @className WeixinExecutor * @author jy * @date 2014年8月15日 * @since JDK 1.7 @@ -53,7 +59,8 @@ public class WeixinExecutor implements Serializable { private final Logger logger = LoggerFactory.getLogger(getClass()); - private final static Charset charset = Charset.forName("utf-8"); + private final static Charset charset = StandardCharsets.UTF_8; + private final static Map accountMap = new HashMap() { private static final long serialVersionUID = 1L; @@ -65,6 +72,7 @@ public class WeixinExecutor implements Serializable { put("微信号", "weixinNo"); put("类型", "accountType"); put("认证情况", "weixinVerify"); + put("主体信息", "bodyInfo"); put("介绍", "introduce"); put("所在地址", "address"); put("二维码", "qrcodeUrl"); @@ -91,7 +99,8 @@ public class WeixinExecutor implements Serializable { // 当要求输入验证码时,cookie需带上 private String sig; - public WeixinExecutor(String backurl, String pushurl, String token, String uname, String pwd, String imgcode, String sig) { + public WeixinExecutor(String backurl, String pushurl, String token, + String uname, String pwd, String imgcode, String sig) { this.backurl = backurl; this.pushurl = pushurl; this.token = token; @@ -105,19 +114,31 @@ public class WeixinExecutor implements Serializable { weixin.put("host", "mp.weixin.qq.com"); weixin.put("base", "https://mp.weixin.qq.com"); weixin.put("auth", "https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN"); - weixin.put("call", "https://mp.weixin.qq.com/advanced/callbackprofile?t=ajax-response&token=%s&lang=zh_CN"); - weixin.put("start", "https://mp.weixin.qq.com/misc/skeyform?form=advancedswitchform"); - weixin.put("back", "https://mp.weixin.qq.com/merchant/myservice?action=set_oauth_domain&f=json"); - weixin.put("verifycode", "https://mp.weixin.qq.com/cgi-bin/verifycode?username=" + uname + "&r=%s"); + weixin.put( + "call", + "https://mp.weixin.qq.com/advanced/callbackprofile?t=ajax-response&token=%s&lang=zh_CN"); + weixin.put("start", + "https://mp.weixin.qq.com/misc/skeyform?form=advancedswitchform"); + weixin.put("back", + "https://mp.weixin.qq.com/merchant/myservice?action=set_oauth_domain&f=json"); + weixin.put("verifycode", + "https://mp.weixin.qq.com/cgi-bin/verifycode?username=" + uname + + "&r=%s"); + weixin.put("bedeveloper", + "https://mp.weixin.qq.com/advanced/advanced?action=agreement"); List headers = new ArrayList(); headers.add(new BasicHeader("Origin", weixin.getString("base"))); headers.add(new BasicHeader("Connection", "keep-alive")); - headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36")); + headers.add(new BasicHeader( + "User-Agent", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36")); client = new DefaultHttpClient(); - client.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY); - client.getParams().setBooleanParameter("http.protocol.single-cookie-header", true); + client.getParams().setParameter(ClientPNames.COOKIE_POLICY, + CookiePolicy.BROWSER_COMPATIBILITY); + client.getParams().setBooleanParameter( + "http.protocol.single-cookie-header", true); client.getParams().setParameter(ClientPNames.DEFAULT_HEADERS, headers); host = new HttpHost(weixin.getString("host"), -1, "https"); @@ -158,7 +179,8 @@ public class WeixinExecutor implements Serializable { try { List parameters = new ArrayList(); parameters.add(new BasicNameValuePair("username", uname)); - parameters.add(new BasicNameValuePair("pwd", DigestUtils.md5Hex(pwd.getBytes()))); + parameters.add(new BasicNameValuePair("pwd", DigestUtils.md5Hex(pwd + .getBytes()))); parameters.add(new BasicNameValuePair("f", "json")); parameters.add(new BasicNameValuePair("imgcode", imgcode)); if (!StringUtil.isBlank(imgcode)) { @@ -169,15 +191,18 @@ public class WeixinExecutor implements Serializable { HttpResponse response = client.execute(host, method); HttpEntity entity = response.getEntity(); - Document root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base")); + Document root = Jsoup.parse(entity.getContent(), charset.name(), + weixin.getString("base")); StatusLine line = response.getStatusLine(); - logger.info("step1_login--->status={},body=\n{}", line, root.toString()); + logger.info("step1_login--->status={},body=\n{}", line, + root.toString()); if (line.getStatusCode() == HttpStatus.SC_OK) { JSONObject body = JSON.parseObject(root.body().text()); String msg = ""; int code = 0; - switch (body.getJSONObject("base_resp").getIntValue("ret")) { + switch (body.getIntValue("ret") + + body.getJSONObject("base_resp").getIntValue("ret")) { case -1: msg = "系统错误,请稍候再试。"; code = -1; @@ -223,20 +248,32 @@ public class WeixinExecutor implements Serializable { break; } if (code == 0) { - weixin.put("urlToken", getQueryMap(body.getString("redirect_url")).get("token")); - weixin.put("indexUrl", String.format("%s%s", weixin.getString("base"), body.getString("redirect_url"))); + weixin.put( + "urlToken", + getQueryMap(body.getString("redirect_url")).get( + "token")); + weixin.put("indexUrl", String.format("%s%s", + weixin.getString("base"), + body.getString("redirect_url"))); weixin.put("step", "1"); } else { if (code == 104 || code == 105) { // 下载验证码 - HttpGet get = new HttpGet(String.format(weixin.getString("verifycode"), System.currentTimeMillis())); + HttpGet get = new HttpGet(String.format( + weixin.getString("verifycode"), + System.currentTimeMillis())); get.setHeaders(method.getAllHeaders()); response = client.execute(host, get); StringBuffer base64 = new StringBuffer(); - base64.append("data:").append(response.getFirstHeader("Content-Type").getValue()).append(";base64,"); - base64.append(new String(Base64.encodeBase64(IOUtil.toByteArray(response.getEntity().getContent())), charset)); + base64.append("data:") + .append(response.getFirstHeader("Content-Type") + .getValue()).append(";base64,"); + base64.append(new String( + Base64.encodeBase64(IOUtil.toByteArray(response + .getEntity().getContent())), charset)); weixin.put("verifydata", base64.toString()); - List cookieList = client.getCookieStore().getCookies(); + List cookieList = client.getCookieStore() + .getCookies(); for (Cookie cookie : cookieList) { if (cookie.getName().equals("sig")) { weixin.put("sig", cookie.getValue()); @@ -274,38 +311,46 @@ public class WeixinExecutor implements Serializable { HttpResponse response = client.execute(host, method); HttpEntity entity = response.getEntity(); - Document root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base")); + Document root = Jsoup.parse(entity.getContent(), charset.name(), + weixin.getString("base")); StatusLine line = response.getStatusLine(); - logger.info("step2_setting--->status={},body=\n{}", line, root.toString()); + logger.info("step2_setting--->status={},body=\n{}", line, + root.toString()); if (line.getStatusCode() == HttpStatus.SC_OK) { - Element ele = root.getElementById("menuBar").getElementsByTag("dl").last(); + Element ele = root.getElementById("menuBar") + .getElementsByTag("dl").last(); url = ele.getElementsByTag("a").last().absUrl("href"); weixin.put("developerUrl", url); method.addHeader("Referer", url); - url = ele.previousElementSibling().getElementsByTag("a").first().absUrl("href"); + url = ele.previousElementSibling().getElementsByTag("a") + .first().absUrl("href"); weixin.put("settingUrl", url); method.setURI(URI.create(url)); response = client.execute(host, method); entity = response.getEntity(); - root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base")); + root = Jsoup.parse(entity.getContent(), charset.name(), + weixin.getString("base")); line = response.getStatusLine(); weixin.put("step", "2-1"); // 公众号配置页面 if (line.getStatusCode() == HttpStatus.SC_OK) { - Elements eles = root.getElementById("settingArea").getElementsByTag("li"); + Elements eles = root.getElementById("settingArea") + .getElementsByTag("li"); String key, value; for (Element element : eles) { key = element.getElementsByTag("h4").first().text(); - ele = element.getElementsByClass("meta_content").first(); + ele = element.getElementsByClass("meta_content") + .first(); if (ele.children().isEmpty()) { value = ele.text(); } else { if (ele.child(0).tagName().equalsIgnoreCase("a")) { value = ele.child(0).absUrl("href"); - } else if (ele.child(0).tagName().equalsIgnoreCase("img")) { + } else if (ele.child(0).tagName() + .equalsIgnoreCase("img")) { value = ele.child(0).absUrl("src"); } else { value = ele.text(); @@ -313,14 +358,18 @@ public class WeixinExecutor implements Serializable { } weixin.put(accountMap.get(key), value); } - weixin.put("isVerify", weixin.getString("weixinVerify").contains("微信认证")); - weixin.put("isService", weixin.getString("accountType").contains("服务号")); - weixin.put("isSubscribe", weixin.getString("accountType").contains("订阅号")); + weixin.put("isVerify", weixin.getString("weixinVerify") + .contains("微信认证")); + weixin.put("isService", weixin.getString("accountType") + .contains("服务号")); + weixin.put("isSubscribe", weixin.getString("accountType") + .contains("订阅号")); value = weixin.getString("qrcodeUrl"); method.setURI(URI.create(value)); response = client.execute(host, method); - weixin.put("qrcodeData", IOUtil.toByteArray(response.getEntity().getContent())); + weixin.put("qrcodeData", IOUtil.toByteArray(response + .getEntity().getContent())); weixin.put("step", "2-2"); // 开发者页面 @@ -329,26 +378,83 @@ public class WeixinExecutor implements Serializable { response = client.execute(host, method); entity = response.getEntity(); - root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base")); + root = Jsoup.parse(entity.getContent(), charset.name(), + weixin.getString("base")); line = response.getStatusLine(); if (line.getStatusCode() == HttpStatus.SC_OK) { + // 还没有成为开发者 2014.10-06 jy.hu + // 触发成为开发者动作 + ele = root.getElementById("js_toBeDeveloper"); + if (ele != null && ele.hasText()) { + HttpPost post = new HttpPost(URI.create(weixin + .getString("bedeveloper"))); + post.addHeader("Referer", url); + List parameters = new ArrayList(); + parameters = new ArrayList(); + parameters.add(new BasicNameValuePair("token", + weixin.getString("urlToken"))); + parameters.add(new BasicNameValuePair("f", "json")); + parameters.add(new BasicNameValuePair("ajax", "1")); + parameters.add(new BasicNameValuePair("lang", + "zh_CN")); + parameters.add(new BasicNameValuePair("random", + System.currentTimeMillis() + "")); + + post.setEntity(new UrlEncodedFormEntity(parameters, + charset)); + response = client.execute(host, post); + entity = response.getEntity(); + root = Jsoup.parse(entity.getContent(), + charset.name(), weixin.getString("base")); + line = response.getStatusLine(); + logger.info( + "step2_bedeveloper--->status={},body=\n{}", + line, root.toString()); + if (line.getStatusCode() == HttpStatus.SC_OK) { + JSONObject body = JSON.parseObject(root.body() + .text()); + if (body.getIntValue("ret") == 0) { + method.addHeader("Referer", url); + method.setURI(URI.create(weixin + .getString("developerUrl"))); + + response = client.execute(host, method); + entity = response.getEntity(); + root = Jsoup.parse(entity.getContent(), + charset.name(), + weixin.getString("base")); + } else { + weixin.put("code", "-100"); + weixin.put("msg", "成为开发者失败!"); + return; + } + } + } // 初始化状态 // 配置未启用状态 // 配置已启用状态 eles = root.getElementsByClass("developer_info_opr"); if (eles != null && eles.hasText()) { - weixin.put("developerModifyUrl", eles.first().children().last().absUrl("href")); - weixin.put("status", eles.first().children().first().text().contains("启用") ? "READY" : "RUNNING"); + weixin.put("developerModifyUrl", eles.first() + .children().first().absUrl("href")); + weixin.put("status", + eles.text().contains("启用") ? "READY" + : "RUNNING"); } else { weixin.put("status", "INIT"); } - // appid&appsecret - if (weixin.getBooleanValue("isService") || (weixin.getBooleanValue("isSubscribe") && weixin.getBooleanValue("isVerify"))) { - eles = root.getElementsByClass("developer_info_item").first().children().last().getElementsByClass("frm_controls"); + if (weixin.getBooleanValue("isService") + || (weixin.getBooleanValue("isSubscribe") && weixin + .getBooleanValue("isVerify"))) { + eles = root + .getElementsByClass("developer_info_item") + .first().children().last() + .getElementsByClass("frm_controls"); weixin.put("appId", eles.first().text()); - weixin.put("appSecret", eles.last().text().replace("重置", "").trim()); + weixin.put("appSecret", + eles.last().text().replace("重置", "").trim()); } weixin.put("step", "2-3"); } @@ -376,24 +482,35 @@ public class WeixinExecutor implements Serializable { * step3:填写配置 */ private void step3_setting() { - HttpPost method = new HttpPost(String.format(weixin.getString("call"), weixin.getString("urlToken"))); + HttpPost method = new HttpPost(String.format(weixin.getString("call"), + weixin.getString("urlToken"))); try { List parameters = new ArrayList(); parameters.add(new BasicNameValuePair("url", pushurl)); parameters.add(new BasicNameValuePair("callback_token", token)); + // EncodingAESKey | 消息加解密方式(明文0,兼容1,安全2) + parameters.add(new BasicNameValuePair("encoding_aeskey", RandomUtil + .generateString(43))); + parameters + .add(new BasicNameValuePair("callback_encrypt_mode", "0")); + parameters.add(new BasicNameValuePair("operation_seq", RandomUtil + .generateStringByNumberChar(9))); method.setEntity(new UrlEncodedFormEntity(parameters, charset)); method.addHeader("Referer", weixin.getString("developerModifyUrl")); HttpResponse response = client.execute(host, method); HttpEntity entity = response.getEntity(); - Document root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base")); + Document root = Jsoup.parse(entity.getContent(), charset.name(), + weixin.getString("base")); StatusLine line = response.getStatusLine(); - logger.info("step3_setting--->status={},body=\n{}", line, root.toString()); + logger.info("step3_setting--->status={},body=\n{}", line, + root.toString()); if (line.getStatusCode() == HttpStatus.SC_OK) { JSONObject body = JSON.parseObject(root.body().text()); String msg = ""; int code = 0; - switch (body.getIntValue("ret")) { + switch (body.getIntValue("ret") + + body.getJSONObject("base_resp").getIntValue("ret")) { case -201: msg = "无效的URL"; code = 200; @@ -437,25 +554,32 @@ public class WeixinExecutor implements Serializable { // 触发启用按钮 if (!weixin.getString("status").equals("RUNNING")) { parameters = new ArrayList(); - parameters.add(new BasicNameValuePair("token", weixin.getString("urlToken"))); + parameters.add(new BasicNameValuePair("token", weixin + .getString("urlToken"))); parameters.add(new BasicNameValuePair("f", "json")); parameters.add(new BasicNameValuePair("ajax", "1")); parameters.add(new BasicNameValuePair("flag", "1")); parameters.add(new BasicNameValuePair("type", "2")); parameters.add(new BasicNameValuePair("lang", "zh_CN")); - parameters.add(new BasicNameValuePair("random", System.currentTimeMillis() + "")); + parameters.add(new BasicNameValuePair("random", System + .currentTimeMillis() + "")); - method.setEntity(new UrlEncodedFormEntity(parameters, charset)); + method.setEntity(new UrlEncodedFormEntity(parameters, + charset)); method.setURI(URI.create(weixin.getString("start"))); response = client.execute(host, method); entity = response.getEntity(); - root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base")); + root = Jsoup.parse(entity.getContent(), charset.name(), + weixin.getString("base")); line = response.getStatusLine(); - logger.info("step3_setting--->status={},body=\n{}", line, root.toString()); + logger.info("step3_setting--->status={},body=\n{}", + line, root.toString()); if (line.getStatusCode() == HttpStatus.SC_OK) { body = JSON.parseObject(root.body().text()); - if (body.getIntValue("ret") != 0 || body.getJSONObject("base_resp").getIntValue("ret") != 0) { + if (body.getIntValue("ret") + + body.getJSONObject("base_resp") + .getIntValue("ret") != 0) { weixin.put("code", 300); weixin.put("msg", "启用开发者模式失败,请稍后再试!"); } @@ -492,23 +616,29 @@ public class WeixinExecutor implements Serializable { List parameters = new ArrayList(); parameters.add(new BasicNameValuePair("domain", backurl)); - parameters.add(new BasicNameValuePair("token", weixin.getString("urlToken"))); + parameters.add(new BasicNameValuePair("token", weixin + .getString("urlToken"))); parameters.add(new BasicNameValuePair("f", "json")); parameters.add(new BasicNameValuePair("ajax", "1")); parameters.add(new BasicNameValuePair("flag", "1")); parameters.add(new BasicNameValuePair("lang", "zh_CN")); - parameters.add(new BasicNameValuePair("random", System.currentTimeMillis() + "")); + parameters.add(new BasicNameValuePair("random", System + .currentTimeMillis() + "")); method.setEntity(new UrlEncodedFormEntity(parameters, charset)); method.addHeader("Referer", weixin.getString("developerUrl")); HttpResponse response = client.execute(host, method); HttpEntity entity = response.getEntity(); - Document root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base")); + Document root = Jsoup.parse(entity.getContent(), + charset.name(), weixin.getString("base")); StatusLine line = response.getStatusLine(); - logger.info("step4_back--->status={},body=\n{}", line, root.toString()); + logger.info("step4_back--->status={},body=\n{}", line, + root.toString()); if (line.getStatusCode() == HttpStatus.SC_OK) { JSONObject body = JSON.parseObject(root.body().text()); - if (body.getIntValue("ret") != 0 || body.getJSONObject("base_resp").getIntValue("ret") != 0) { + if (body.getIntValue("ret") + + body.getJSONObject("base_resp") + .getIntValue("ret") != 0) { weixin.put("code", "400"); weixin.put("msg", "修改授权回调地址失败!"); } diff --git a/src/main/java/com/foxinmy/weixin4j/type/MessageType.java b/src/main/java/com/foxinmy/weixin4j/type/MessageType.java index a883d993..933365b6 100644 --- a/src/main/java/com/foxinmy/weixin4j/type/MessageType.java +++ b/src/main/java/com/foxinmy/weixin4j/type/MessageType.java @@ -27,7 +27,9 @@ public enum MessageType { EventMessage.class), // 发送的消息类型 music(MusicMessage.class), news(ArticleMessage.class), transfer_customer_service( - TransferMessage.class); + TransferMessage.class), + // 微信消息认证 + signature(null); private Class messageClass; MessageType(Class messageClass) { diff --git a/src/main/java/com/foxinmy/weixin4j/util/MessageUtil.java b/src/main/java/com/foxinmy/weixin4j/util/MessageUtil.java index 82a23ef3..275287b9 100644 --- a/src/main/java/com/foxinmy/weixin4j/util/MessageUtil.java +++ b/src/main/java/com/foxinmy/weixin4j/util/MessageUtil.java @@ -18,12 +18,15 @@ import com.foxinmy.weixin4j.type.MessageType; import com.foxinmy.weixin4j.xml.XStream; public class MessageUtil { - - private final static Logger log = LoggerFactory.getLogger(MessageUtil.class); + + private final static Logger log = LoggerFactory + .getLogger(MessageUtil.class); /** * 验证微信签名 * + * @param token + * 开发者填写的token * @param echostr * 随机字符串 * @param timestamp @@ -37,19 +40,20 @@ public class MessageUtil { * @see 接入指南 */ - public static String signature(String echostr, String timestamp, String nonce, String signature) { - String app_token = ConfigUtil.getValue("app_token"); - if (StringUtil.isBlank(app_token)) { + public static String signature(String token, String echostr, + String timestamp, String nonce, String signature) { + if (StringUtil.isBlank(token)) { log.error("signature fail : token is null!"); return null; } - if (StringUtil.isBlank(echostr) || StringUtil.isBlank(timestamp) || StringUtil.isBlank(nonce)) { + if (StringUtil.isBlank(echostr) || StringUtil.isBlank(timestamp) + || StringUtil.isBlank(nonce)) { log.error("signature fail : invalid parameter!"); return null; } String _signature = null; try { - String[] a = { app_token, timestamp, nonce }; + String[] a = { token, timestamp, nonce }; Arrays.sort(a); StringBuilder sb = new StringBuilder(3); for (String str : a) { @@ -67,13 +71,27 @@ public class MessageUtil { } } + /** + * 获取对应的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 xml + * @param xmlMsg * 消息字符串 * @return 消息对象 * @throws DocumentException @@ -96,26 +114,26 @@ public class MessageUtil { * @see com.foxinmy.weixin4j.msg.event.LocationEventMessage * @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage */ - public static BaseMessage xml2msg(String xml) throws DocumentException { - if (StringUtil.isBlank(xml)) - return null; - Document doc = DocumentHelper.parseText(xml); + public static BaseMessage xml2msg(String xmlMsg) throws DocumentException { + Document doc = DocumentHelper.parseText(xmlMsg); String type = doc.selectSingleNode("/xml/MsgType").getStringValue(); if (StringUtil.isBlank(type)) { return null; } - XStream xstream = new XStream(); MessageType messageType = MessageType.valueOf(type.toLowerCase()); - Class messageClass = messageType.getMessageClass(); + Class messageClass = messageType + .getMessageClass(); if (messageType == MessageType.event) { type = doc.selectSingleNode("/xml/Event").getStringValue(); - messageClass = EventType.valueOf(type.toLowerCase()).getEventClass(); + messageClass = EventType.valueOf(type.toLowerCase()) + .getEventClass(); } - xstream.alias("xml", messageClass); + XStream xstream = new XStream(); xstream.ignoreUnknownElements(); xstream.autodetectAnnotations(true); xstream.processAnnotations(messageClass); - return xstream.fromXML(doc.asXML(), messageClass); + xstream.alias("xml", messageClass); + return xstream.fromXML(xmlMsg, messageClass); } /** @@ -125,9 +143,10 @@ public class MessageUtil { * 带消息字符串的输入流 * @return 消息对象 * @throws DocumentException - * @see {@link com.foxinmy.weixin4j.WeixinProxy#xml2msg(String)} + * @see {@link com.foxinmy.weixin4j.util.MessageUtil#xml2msg(String)} */ - public static BaseMessage xml2msg(InputStream inputStream) throws DocumentException { + public static BaseMessage xml2msg(InputStream inputStream) + throws DocumentException { SAXReader reader = new SAXReader(); Document doc = reader.read(inputStream); return xml2msg(doc.asXML()); diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index da383837..63fb5da0 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -25,12 +25,11 @@ - /tmp/weixin/log/%d{yyyy-MM-dd}.log + /tmp/weixin/weixin.%d{yyyy-MM-dd}.log 30 - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n @@ -55,7 +54,7 @@ - + diff --git a/src/test/java/com/foxinmy/weixin4j/test/ButtonTest.java b/src/test/java/com/foxinmy/weixin4j/test/ButtonTest.java deleted file mode 100644 index 4a811a6c..00000000 --- a/src/test/java/com/foxinmy/weixin4j/test/ButtonTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.foxinmy.weixin4j.test; - -import java.util.ArrayList; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; - -import com.foxinmy.weixin4j.WeixinProxy; -import com.foxinmy.weixin4j.exception.WeixinException; -import com.foxinmy.weixin4j.model.Button; -import com.foxinmy.weixin4j.type.ButtonType; - -/** - * 自定义菜单测试 - * @className ButtonTest - * @author jy.hu - * @date 2014年4月10日 - * @since JDK 1.7 - */ -public class ButtonTest { - private WeixinProxy weixinProxy; - - @Before - public void init() { - weixinProxy = new WeixinProxy(); - } - - @Test - public void create() { - List