mirror of
				https://gitee.com/binary/weixin-java-tools.git
				synced 2025-10-31 02:28:25 +08:00 
			
		
		
		
	code clean up for common module
This commit is contained in:
		| @ -62,20 +62,6 @@ public class WxConsts { | ||||
|    * 群发反馈消息代码所对应的文字描述 | ||||
|    */ | ||||
|   public static final Map<String, String> MASS_ST_2_DESC = new HashMap<String, String>(); | ||||
|   static { | ||||
|     MASS_ST_2_DESC.put(MASS_ST_SUCCESS, "发送成功"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_FAIL, "发送失败"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌广告, "涉嫌广告"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌政治, "涉嫌政治"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌社会, "涉嫌社会"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌色情, "涉嫌色情"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌违法犯罪, "涉嫌违法犯罪"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌欺诈, "涉嫌欺诈"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌版权, "涉嫌版权"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌互推_互相宣传, "涉嫌互推_互相宣传"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌其他, "涉嫌其他"); | ||||
|   } | ||||
|    | ||||
|   /////////////////////// | ||||
|   // 微信端推送过来的事件类型 | ||||
|   /////////////////////// | ||||
| @ -103,11 +89,9 @@ public class WxConsts { | ||||
|   public static final String EVT_USER_VIEW_CARD = "user_view_card"; | ||||
|   public static final String EVT_USER_ENTER_SESSION_FROM_CARD = "user_enter_session_from_card"; | ||||
|   public static final String EVT_CARD_SKU_REMIND = "card_sku_remind"; // 库存报警 | ||||
|  | ||||
|   public static final String EVT_KF_CREATE_SESSION = "kf_create_session"; // 客服接入会话 | ||||
|   public static final String EVT_KF_CLOSE_SESSION = "kf_close_session"; // 客服关闭会话 | ||||
|   public static final String EVT_KF_SWITCH_SESSION = "kf_switch_session"; // 客服转接会话 | ||||
|  | ||||
|   /////////////////////// | ||||
|   // 上传多媒体文件的类型 | ||||
|   /////////////////////// | ||||
| @ -116,7 +100,6 @@ public class WxConsts { | ||||
|   public static final String MEDIA_VIDEO = "video"; | ||||
|   public static final String MEDIA_THUMB = "thumb"; | ||||
|   public static final String MEDIA_FILE = "file"; | ||||
|    | ||||
|   /////////////////////// | ||||
|   // 文件类型 | ||||
|   /////////////////////// | ||||
| @ -124,40 +107,63 @@ public class WxConsts { | ||||
|   public static final String FILE_MP3 = "mp3"; | ||||
|   public static final String FILE_AMR = "amr"; | ||||
|   public static final String FILE_MP4 = "mp4"; | ||||
|   /** | ||||
|    * 点击推事件 | ||||
|    */ | ||||
|   public static final String BUTTON_CLICK = "click"; | ||||
|  | ||||
|  | ||||
|   /////////////////////// | ||||
|   // 自定义菜单的按钮类型 | ||||
|   /////////////////////// | ||||
|   /** 点击推事件 */ | ||||
|   public static final String BUTTON_CLICK = "click"; | ||||
|   /** 跳转URL */ | ||||
|   /** | ||||
|    * 跳转URL | ||||
|    */ | ||||
|   public static final String BUTTON_VIEW = "view"; | ||||
|   /** 扫码推事件 */ | ||||
|   /** | ||||
|    * 扫码推事件 | ||||
|    */ | ||||
|   public static final String BUTTON_SCANCODE_PUSH = "scancode_push"; | ||||
|   /** 扫码推事件且弹出“消息接收中”提示框 */ | ||||
|   /** | ||||
|    * 扫码推事件且弹出“消息接收中”提示框 | ||||
|    */ | ||||
|   public static final String BUTTON_SCANCODE_WAITMSG = "scancode_waitmsg"; | ||||
|   /** 弹出系统拍照发图 */ | ||||
|   /** | ||||
|    * 弹出系统拍照发图 | ||||
|    */ | ||||
|   public static final String BUTTON_PIC_SYSPHOTO = "pic_sysphoto"; | ||||
|   /** 弹出拍照或者相册发图 */ | ||||
|   /** | ||||
|    * 弹出拍照或者相册发图 | ||||
|    */ | ||||
|   public static final String BUTTON_PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; | ||||
|   /** 弹出微信相册发图器 */ | ||||
|   /** | ||||
|    * 弹出微信相册发图器 | ||||
|    */ | ||||
|   public static final String BUTTON_PIC_WEIXIN = "pic_weixin"; | ||||
|   /** 弹出地理位置选择器 */ | ||||
|   /** | ||||
|    * 弹出地理位置选择器 | ||||
|    */ | ||||
|   public static final String BUTTON_LOCATION_SELECT = "location_select"; | ||||
|   /** 下发消息(除文本消息) */ | ||||
|   /** | ||||
|    * 下发消息(除文本消息) | ||||
|    */ | ||||
|   public static final String BUTTON_MEDIA_ID = "media_id"; | ||||
|   /** 跳转图文消息URL */ | ||||
|   /** | ||||
|    * 跳转图文消息URL | ||||
|    */ | ||||
|   public static final String BUTTON_VIEW_LIMITED = "view_limited"; | ||||
|   /** | ||||
|    * 不弹出授权页面,直接跳转,只能获取用户openid | ||||
|    */ | ||||
|   public static final String OAUTH2_SCOPE_BASE = "snsapi_base"; | ||||
|  | ||||
|   /////////////////////// | ||||
|   // oauth2网页授权的scope | ||||
|   /////////////////////// | ||||
|   /** 不弹出授权页面,直接跳转,只能获取用户openid */ | ||||
|   public static final String OAUTH2_SCOPE_BASE = "snsapi_base"; | ||||
|   /** 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息 */ | ||||
|   /** | ||||
|    * 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息 | ||||
|    */ | ||||
|   public static final String OAUTH2_SCOPE_USER_INFO = "snsapi_userinfo"; | ||||
|  | ||||
|   /////////////////////// | ||||
|   // 永久素材类型 | ||||
|   /////////////////////// | ||||
| @ -165,4 +171,18 @@ public class WxConsts { | ||||
|   public static final String MATERIAL_VOICE = "voice"; | ||||
|   public static final String MATERIAL_IMAGE = "image"; | ||||
|   public static final String MATERIAL_VIDEO = "video"; | ||||
|  | ||||
|   static { | ||||
|     MASS_ST_2_DESC.put(MASS_ST_SUCCESS, "发送成功"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_FAIL, "发送失败"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌广告, "涉嫌广告"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌政治, "涉嫌政治"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌社会, "涉嫌社会"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌色情, "涉嫌色情"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌违法犯罪, "涉嫌违法犯罪"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌欺诈, "涉嫌欺诈"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌版权, "涉嫌版权"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌互推_互相宣传, "涉嫌互推_互相宣传"); | ||||
|     MASS_ST_2_DESC.put(MASS_ST_涉嫌其他, "涉嫌其他"); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -10,15 +10,16 @@ public interface WxMessageDuplicateChecker { | ||||
|  | ||||
|   /** | ||||
|    * <h2>公众号的排重方式</h2> | ||||
|    * | ||||
|    * <p> | ||||
|    * <p>普通消息:关于重试的消息排重,推荐使用msgid排重。<a href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html">文档参考</a>。</p> | ||||
|    * <p>事件消息:关于重试的消息排重,推荐使用FromUserName + CreateTime 排重。<a href="http://mp.weixin.qq.com/wiki/2/5baf56ce4947d35003b86a9805634b1e.html">文档参考</a></p> | ||||
|    * | ||||
|    * <p> | ||||
|    * <h2>企业号的排重方式</h2> | ||||
|    * | ||||
|    * <p> | ||||
|    * 官方文档完全没有写,参照公众号的方式排重。 | ||||
|    * | ||||
|    * <p> | ||||
|    * <p>或者可以采取更简单的方式,如果有MsgId就用MsgId排重,如果没有就用FromUserName+CreateTime排重</p> | ||||
|    * | ||||
|    * @param messageId messageId需要根据上面讲的方式构造 | ||||
|    * @return 如果是重复消息,返回true,否则返回false | ||||
|    */ | ||||
|  | ||||
| @ -46,7 +46,8 @@ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChec | ||||
|  | ||||
|   /** | ||||
|    * WxMsgIdInMemoryDuplicateChecker构造函数 | ||||
|    * @param timeToLive 一个消息ID在内存的过期时间:毫秒 | ||||
|    * | ||||
|    * @param timeToLive  一个消息ID在内存的过期时间:毫秒 | ||||
|    * @param clearPeriod 每隔多少周期检查消息ID是否过期:毫秒 | ||||
|    */ | ||||
|   public WxMessageInMemoryDuplicateChecker(Long timeToLive, Long clearPeriod) { | ||||
|  | ||||
| @ -11,6 +11,10 @@ public class WxAccessToken implements Serializable { | ||||
|  | ||||
|   private int expiresIn = -1; | ||||
|  | ||||
|   public static WxAccessToken fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxAccessToken.class); | ||||
|   } | ||||
|  | ||||
|   public String getAccessToken() { | ||||
|     return accessToken; | ||||
|   } | ||||
| @ -27,8 +31,4 @@ public class WxAccessToken implements Serializable { | ||||
|     this.expiresIn = expiresIn; | ||||
|   } | ||||
|  | ||||
|   public static WxAccessToken fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxAccessToken.class); | ||||
|   } | ||||
|    | ||||
| } | ||||
|  | ||||
| @ -51,11 +51,11 @@ public class WxJsapiSignature implements Serializable { | ||||
|   } | ||||
|  | ||||
|   public String getAppid() { | ||||
| 	  return appid; | ||||
|     return appid; | ||||
|   } | ||||
|  | ||||
|   public void setAppid(String appid) { | ||||
| 	  this.appid = appid; | ||||
|     this.appid = appid; | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,7 @@ | ||||
| package me.chanjar.weixin.common.bean; | ||||
|  | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
|  | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.io.Serializable; | ||||
| @ -7,12 +9,10 @@ import java.nio.charset.StandardCharsets; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
|  | ||||
| /** | ||||
|  * 企业号菜单 | ||||
|  * @author Daniel Qian | ||||
|  * | ||||
|  * @author Daniel Qian | ||||
|  */ | ||||
| public class WxMenu implements Serializable { | ||||
|  | ||||
| @ -22,6 +22,22 @@ public class WxMenu implements Serializable { | ||||
|  | ||||
|   private WxMenuRule matchRule; | ||||
|  | ||||
|   /** | ||||
|    * 要用 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化 | ||||
|    * 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu | ||||
|    */ | ||||
|   public static WxMenu fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMenu.class); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 要用 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化 | ||||
|    * 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu | ||||
|    */ | ||||
|   public static WxMenu fromJson(InputStream is) { | ||||
|     return WxGsonBuilder.create().fromJson(new InputStreamReader(is, StandardCharsets.UTF_8), WxMenu.class); | ||||
|   } | ||||
|  | ||||
|   public List<WxMenuButton> getButtons() { | ||||
|     return buttons; | ||||
|   } | ||||
| @ -42,27 +58,11 @@ public class WxMenu implements Serializable { | ||||
|     return WxGsonBuilder.create().toJson(this); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 要用 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化 | ||||
|    * 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu | ||||
|    */ | ||||
|   public static WxMenu fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMenu.class); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 要用 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化 | ||||
|    * 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu | ||||
|    */ | ||||
|   public static WxMenu fromJson(InputStream is) { | ||||
|     return WxGsonBuilder.create().fromJson(new InputStreamReader(is, StandardCharsets.UTF_8), WxMenu.class); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String toString() { | ||||
|     return "WxMenu{" + | ||||
|         "buttons=" + buttons + | ||||
|         '}'; | ||||
|             "buttons=" + buttons + | ||||
|             '}'; | ||||
|   } | ||||
|  | ||||
|   public static class WxMenuButton { | ||||
| @ -117,12 +117,12 @@ public class WxMenu implements Serializable { | ||||
|     @Override | ||||
|     public String toString() { | ||||
|       return "WxMenuButton{" + | ||||
|           "type='" + type + '\'' + | ||||
|           ", name='" + name + '\'' + | ||||
|           ", key='" + key + '\'' + | ||||
|           ", url='" + url + '\'' + | ||||
|           ", subButtons=" + subButtons + | ||||
|           '}'; | ||||
|               "type='" + type + '\'' + | ||||
|               ", name='" + name + '\'' + | ||||
|               ", key='" + key + '\'' + | ||||
|               ", url='" + url + '\'' + | ||||
|               ", subButtons=" + subButtons + | ||||
|               '}'; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @ -194,14 +194,14 @@ public class WxMenu implements Serializable { | ||||
|     @Override | ||||
|     public String toString() { | ||||
|       return "matchrule:{" + | ||||
|           "tag_id='" + tagId + '\'' + | ||||
|           ", sex='" + sex + '\'' + | ||||
|           ", country" + country + '\'' + | ||||
|           ", province" + province + '\'' + | ||||
|           ", city" + city + '\'' + | ||||
|           ", client_platform_type" + clientPlatformType + '\'' + | ||||
|           ", language" + language + '\'' + | ||||
|           "}"; | ||||
|               "tag_id='" + tagId + '\'' + | ||||
|               ", sex='" + sex + '\'' + | ||||
|               ", country" + country + '\'' + | ||||
|               ", province" + province + '\'' + | ||||
|               ", city" + city + '\'' + | ||||
|               ", client_platform_type" + clientPlatformType + '\'' + | ||||
|               ", language" + language + '\'' + | ||||
|               "}"; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  | ||||
| @ -6,8 +6,8 @@ import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 微信错误码说明,请阅读: <a href="http://mp.weixin.qq.com/wiki/10/6380dc743053a91c544ffd2b7c959166.html">全局返回码说明</a> | ||||
|  * @author Daniel Qian | ||||
|  * | ||||
|  * @author Daniel Qian | ||||
|  */ | ||||
| public class WxError implements Serializable { | ||||
|  | ||||
| @ -19,6 +19,15 @@ public class WxError implements Serializable { | ||||
|  | ||||
|   private String json; | ||||
|  | ||||
|   public static WxError fromJson(String json) { | ||||
|     WxError error = WxGsonBuilder.create().fromJson(json, WxError.class); | ||||
|     return error; | ||||
|   } | ||||
|  | ||||
|   public static Builder newBuilder() { | ||||
|     return new Builder(); | ||||
|   } | ||||
|  | ||||
|   public int getErrorCode() { | ||||
|     return errorCode; | ||||
|   } | ||||
| @ -43,24 +52,15 @@ public class WxError implements Serializable { | ||||
|     this.json = json; | ||||
|   } | ||||
|  | ||||
|   public static WxError fromJson(String json) { | ||||
|     WxError error = WxGsonBuilder.create().fromJson(json, WxError.class); | ||||
|     return error; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String toString() { | ||||
|     if(json != null){ | ||||
|     if (json != null) { | ||||
|       return json; | ||||
|     } | ||||
|     return "错误: Code=" + errorCode + ", Msg=" + errorMsg; | ||||
|   } | ||||
|  | ||||
|   public static Builder newBuilder(){ | ||||
|     return new Builder(); | ||||
|   } | ||||
|    | ||||
|   public static class Builder{ | ||||
|   public static class Builder { | ||||
|     private int errorCode; | ||||
|     private String errorMsg; | ||||
|  | ||||
| @ -74,7 +74,7 @@ public class WxError implements Serializable { | ||||
|       return this; | ||||
|     } | ||||
|  | ||||
|     public WxError build(){ | ||||
|     public WxError build() { | ||||
|       WxError wxError = new WxError(); | ||||
|       wxError.setErrorCode(this.errorCode); | ||||
|       wxError.setErrorMsg(this.errorMsg); | ||||
|  | ||||
| @ -12,6 +12,10 @@ public class WxMediaUploadResult implements Serializable { | ||||
|   private String thumbMediaId; | ||||
|   private long createdAt; | ||||
|  | ||||
|   public static WxMediaUploadResult fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMediaUploadResult.class); | ||||
|   } | ||||
|  | ||||
|   public String getType() { | ||||
|     return type; | ||||
|   } | ||||
| @ -44,14 +48,10 @@ public class WxMediaUploadResult implements Serializable { | ||||
|     this.thumbMediaId = thumbMediaId; | ||||
|   } | ||||
|  | ||||
|   public static WxMediaUploadResult fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMediaUploadResult.class); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String toString() { | ||||
|     return "WxUploadResult [type=" + type + ", media_id=" + mediaId + ", thumb_media_id=" + thumbMediaId | ||||
|         + ", created_at=" + createdAt + "]"; | ||||
|             + ", created_at=" + createdAt + "]"; | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -26,6 +26,6 @@ package me.chanjar.weixin.common.session; | ||||
|  | ||||
| public class Constants { | ||||
|  | ||||
|     public static final String Package = "me.chanjar.weixin.common.session"; | ||||
|   public static final String Package = "me.chanjar.weixin.common.session"; | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -8,6 +8,11 @@ public interface InternalSession { | ||||
|    */ | ||||
|   WxSession getSession(); | ||||
|  | ||||
|   /** | ||||
|    * Return the <code>isValid</code> flag for this session. | ||||
|    */ | ||||
|   boolean isValid(); | ||||
|  | ||||
|   /** | ||||
|    * Set the <code>isValid</code> flag for this session. | ||||
|    * | ||||
| @ -15,11 +20,6 @@ public interface InternalSession { | ||||
|    */ | ||||
|   void setValid(boolean isValid); | ||||
|  | ||||
|   /** | ||||
|    * Return the <code>isValid</code> flag for this session. | ||||
|    */ | ||||
|   boolean isValid(); | ||||
|  | ||||
|   /** | ||||
|    * Return the session identifier for this session. | ||||
|    */ | ||||
|  | ||||
| @ -7,11 +7,10 @@ public interface InternalSessionManager { | ||||
|    * specified session id (if any); otherwise return <code>null</code>. | ||||
|    * | ||||
|    * @param id The session id for the session to be returned | ||||
|    * | ||||
|    * @exception IllegalStateException if a new session cannot be | ||||
|    *  instantiated for any reason | ||||
|    * @exception java.io.IOException if an input/output error occurs while | ||||
|    *  processing this request | ||||
|    * @throws IllegalStateException if a new session cannot be | ||||
|    *                               instantiated for any reason | ||||
|    * @throws java.io.IOException   if an input/output error occurs while | ||||
|    *                               processing this request | ||||
|    */ | ||||
|   InternalSession findSession(String id); | ||||
|  | ||||
| @ -23,10 +22,10 @@ public interface InternalSessionManager { | ||||
|    * <code>null</code>. | ||||
|    * | ||||
|    * @param sessionId The session id which should be used to create the | ||||
|    *  new session; if <code>null</code>, a new session id will be | ||||
|    *  generated | ||||
|    * @exception IllegalStateException if a new session cannot be | ||||
|    *  instantiated for any reason | ||||
|    *                  new session; if <code>null</code>, a new session id will be | ||||
|    *                  generated | ||||
|    * @throws IllegalStateException if a new session cannot be | ||||
|    *                               instantiated for any reason | ||||
|    */ | ||||
|   InternalSession createSession(String sessionId); | ||||
|  | ||||
| @ -40,8 +39,8 @@ public interface InternalSessionManager { | ||||
|   /** | ||||
|    * Remove this Session from the active Sessions for this Manager. | ||||
|    * | ||||
|    * @param session   Session to be removed | ||||
|    * @param update    Should the expiration statistics be updated | ||||
|    * @param session Session to be removed | ||||
|    * @param update  Should the expiration statistics be updated | ||||
|    */ | ||||
|   void remove(InternalSession session, boolean update); | ||||
|  | ||||
| @ -59,6 +58,7 @@ public interface InternalSessionManager { | ||||
|    * @return number of sessions active | ||||
|    */ | ||||
|   int getActiveSessions(); | ||||
|  | ||||
|   /** | ||||
|    * Get a session from the recycled ones or create a new empty one. | ||||
|    * The PersistentManager manager does not need to create session data | ||||
| @ -88,6 +88,7 @@ public interface InternalSessionManager { | ||||
|    * 要和{@link #setBackgroundProcessorDelay(int)}联合起来看 | ||||
|    * 如果把这个数字设置为6(默认),那么就是说manager要等待 6 * backgroundProcessorDay的时间才会清理过期session | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param processExpiresFrequency the new manager checks frequency | ||||
|    */ | ||||
|   void setProcessExpiresFrequency(int processExpiresFrequency); | ||||
| @ -97,6 +98,7 @@ public interface InternalSessionManager { | ||||
|    * Set the manager background processor delay | ||||
|    * 设置manager sleep几秒,尝试执行一次background操作(清理过期session) | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param backgroundProcessorDelay | ||||
|    */ | ||||
|   void setBackgroundProcessorDelay(int backgroundProcessorDelay); | ||||
| @ -106,6 +108,7 @@ public interface InternalSessionManager { | ||||
|    * Set the maximum number of active Sessions allowed, or -1 for | ||||
|    * no limit. | ||||
|    * 设置最大活跃session数,默认无限 | ||||
|    * | ||||
|    * @param max The new maximum number of sessions | ||||
|    */ | ||||
|   void setMaxActiveSessions(int max); | ||||
|  | ||||
| @ -12,7 +12,6 @@ | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| applicationSession.session.ise=invalid session state | ||||
| applicationSession.value.iae=null value | ||||
| fileStore.saving=Saving Session {0} to file {1} | ||||
|  | ||||
| @ -12,17 +12,68 @@ public class StandardSession implements WxSession, InternalSession { | ||||
|    * The string manager for this package. | ||||
|    */ | ||||
|   protected static final StringManager sm = | ||||
|       StringManager.getManager(Constants.Package); | ||||
|  | ||||
|           StringManager.getManager(Constants.Package); | ||||
|   /** | ||||
|    * Type array. | ||||
|    */ | ||||
|   protected static final String EMPTY_ARRAY[] = new String[0]; | ||||
|   // ------------------------------ WxSession | ||||
|   protected Map<String, Object> attributes = new ConcurrentHashMap<String, Object>(); | ||||
|   /** | ||||
|    * The session identifier of this Session. | ||||
|    */ | ||||
|   protected String id = null; | ||||
|   /** | ||||
|    * Flag indicating whether this session is valid or not. | ||||
|    */ | ||||
|   protected volatile boolean isValid = false; | ||||
|   /** | ||||
|    * We are currently processing a session expiration, so bypass | ||||
|    * certain IllegalStateException tests.  NOTE:  This value is not | ||||
|    * included in the serialized version of this object. | ||||
|    */ | ||||
|   protected transient volatile boolean expiring = false; | ||||
|   /** | ||||
|    * The Manager with which this Session is associated. | ||||
|    */ | ||||
|   protected transient InternalSessionManager manager = null; | ||||
|  | ||||
|   // ------------------------------ InternalSession | ||||
|   /** | ||||
|    * The time this session was created, in milliseconds since midnight, | ||||
|    * January 1, 1970 GMT. | ||||
|    */ | ||||
|   protected long creationTime = 0L; | ||||
|   /** | ||||
|    * The current accessed time for this session. | ||||
|    */ | ||||
|   protected volatile long thisAccessedTime = creationTime; | ||||
|   /** | ||||
|    * The default maximum inactive interval for Sessions created by | ||||
|    * this Manager. | ||||
|    */ | ||||
|   protected int maxInactiveInterval = 30 * 60; | ||||
|   /** | ||||
|    * The facade associated with this session.  NOTE:  This value is not | ||||
|    * included in the serialized version of this object. | ||||
|    */ | ||||
|   protected transient StandardSessionFacade facade = null; | ||||
|   /** | ||||
|    * The access count for this session. | ||||
|    */ | ||||
|   protected transient AtomicInteger accessCount = null; | ||||
|  | ||||
|   public StandardSession(InternalSessionManager manager) { | ||||
|     this.manager = manager; | ||||
|     this.accessCount = new AtomicInteger(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public Object getAttribute(String name) { | ||||
|  | ||||
|     if (!isValidInternal()) | ||||
|       throw new IllegalStateException | ||||
|           (sm.getString("sessionImpl.getAttribute.ise")); | ||||
|               (sm.getString("sessionImpl.getAttribute.ise")); | ||||
|  | ||||
|     if (name == null) return null; | ||||
|  | ||||
| @ -33,7 +84,7 @@ public class StandardSession implements WxSession, InternalSession { | ||||
|   public Enumeration<String> getAttributeNames() { | ||||
|     if (!isValidInternal()) | ||||
|       throw new IllegalStateException | ||||
|           (sm.getString("sessionImpl.getAttributeNames.ise")); | ||||
|               (sm.getString("sessionImpl.getAttributeNames.ise")); | ||||
|  | ||||
|     Set<String> names = new HashSet<String>(); | ||||
|     names.addAll(attributes.keySet()); | ||||
| @ -45,7 +96,7 @@ public class StandardSession implements WxSession, InternalSession { | ||||
|     // Name cannot be null | ||||
|     if (name == null) | ||||
|       throw new IllegalArgumentException | ||||
|           (sm.getString("sessionImpl.setAttribute.namenull")); | ||||
|               (sm.getString("sessionImpl.setAttribute.namenull")); | ||||
|  | ||||
|     // Null value is the same as removeAttribute() | ||||
|     if (value == null) { | ||||
| @ -56,97 +107,32 @@ public class StandardSession implements WxSession, InternalSession { | ||||
|     // Validate our current state | ||||
|     if (!isValidInternal()) | ||||
|       throw new IllegalStateException(sm.getString( | ||||
|           "sessionImpl.setAttribute.ise", getIdInternal())); | ||||
|               "sessionImpl.setAttribute.ise", getIdInternal())); | ||||
|  | ||||
|     attributes.put(name, value); | ||||
|  | ||||
|   } | ||||
|  | ||||
|  | ||||
|   @Override | ||||
|   public void removeAttribute(String name) { | ||||
|     removeAttributeInternal(name); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   @Override | ||||
|   public void invalidate() { | ||||
|     if (!isValidInternal()) | ||||
|       throw new IllegalStateException | ||||
|           (sm.getString("sessionImpl.invalidate.ise")); | ||||
|               (sm.getString("sessionImpl.invalidate.ise")); | ||||
|  | ||||
|     // Cause this session to expire | ||||
|     expire(); | ||||
|  | ||||
|   } | ||||
|  | ||||
|   // ------------------------------ InternalSession | ||||
|   /** | ||||
|    * The session identifier of this Session. | ||||
|    */ | ||||
|   protected String id = null; | ||||
|  | ||||
|   /** | ||||
|    * Flag indicating whether this session is valid or not. | ||||
|    */ | ||||
|   protected volatile boolean isValid = false; | ||||
|  | ||||
|   /** | ||||
|    * We are currently processing a session expiration, so bypass | ||||
|    * certain IllegalStateException tests.  NOTE:  This value is not | ||||
|    * included in the serialized version of this object. | ||||
|    */ | ||||
|   protected transient volatile boolean expiring = false; | ||||
|  | ||||
|   /** | ||||
|    * The Manager with which this Session is associated. | ||||
|    */ | ||||
|   protected transient InternalSessionManager manager = null; | ||||
|  | ||||
|   /** | ||||
|    * Type array. | ||||
|    */ | ||||
|   protected static final String EMPTY_ARRAY[] = new String[0]; | ||||
|  | ||||
|   /** | ||||
|    * The time this session was created, in milliseconds since midnight, | ||||
|    * January 1, 1970 GMT. | ||||
|    */ | ||||
|   protected long creationTime = 0L; | ||||
|  | ||||
|   /** | ||||
|    * The current accessed time for this session. | ||||
|    */ | ||||
|   protected volatile long thisAccessedTime = creationTime; | ||||
|  | ||||
|   /** | ||||
|    * The default maximum inactive interval for Sessions created by | ||||
|    * this Manager. | ||||
|    */ | ||||
|   protected int maxInactiveInterval = 30 * 60; | ||||
|  | ||||
|   /** | ||||
|    * The facade associated with this session.  NOTE:  This value is not | ||||
|    * included in the serialized version of this object. | ||||
|    */ | ||||
|   protected transient StandardSessionFacade facade = null; | ||||
|  | ||||
|   /** | ||||
|    * The access count for this session. | ||||
|    */ | ||||
|   protected transient AtomicInteger accessCount = null; | ||||
|  | ||||
|  | ||||
|   public StandardSession(InternalSessionManager manager) { | ||||
|     this.manager = manager; | ||||
|     this.accessCount = new AtomicInteger(); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   @Override | ||||
|   public WxSession getSession() { | ||||
|  | ||||
|     if (facade == null){ | ||||
|     if (facade == null) { | ||||
|       facade = new StandardSessionFacade(this); | ||||
|     } | ||||
|     return (facade); | ||||
| @ -161,16 +147,6 @@ public class StandardSession implements WxSession, InternalSession { | ||||
|     return this.isValid; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Set the <code>isValid</code> flag for this session. | ||||
|    * | ||||
|    * @param isValid The new value for the <code>isValid</code> flag | ||||
|    */ | ||||
|   @Override | ||||
|   public void setValid(boolean isValid) { | ||||
|     this.isValid = isValid; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public boolean isValid() { | ||||
|     if (!this.isValid) { | ||||
| @ -197,6 +173,16 @@ public class StandardSession implements WxSession, InternalSession { | ||||
|     return this.isValid; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Set the <code>isValid</code> flag for this session. | ||||
|    * | ||||
|    * @param isValid The new value for the <code>isValid</code> flag | ||||
|    */ | ||||
|   @Override | ||||
|   public void setValid(boolean isValid) { | ||||
|     this.isValid = isValid; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String getIdInternal() { | ||||
|     return (this.id); | ||||
|  | ||||
| @ -13,16 +13,65 @@ import java.util.concurrent.atomic.AtomicBoolean; | ||||
|  */ | ||||
| public class StandardSessionManager implements WxSessionManager, InternalSessionManager { | ||||
|  | ||||
|   protected final Logger log = LoggerFactory.getLogger(StandardSessionManager.class); | ||||
|  | ||||
|   protected static final StringManager sm = | ||||
|       StringManager.getManager(Constants.Package); | ||||
|           StringManager.getManager(Constants.Package); | ||||
|   /** | ||||
|    * The descriptive name of this Manager implementation (for logging). | ||||
|    */ | ||||
|   private static final String name = "SessionManagerImpl"; | ||||
|   protected final Logger log = LoggerFactory.getLogger(StandardSessionManager.class); | ||||
|   private final Object maxActiveUpdateLock = new Object(); | ||||
|   /** | ||||
|    * 后台清理线程是否已经开启 | ||||
|    */ | ||||
|   private final AtomicBoolean backgroundProcessStarted = new AtomicBoolean(false); | ||||
|  | ||||
|  | ||||
|   // -------------------------------------- InternalSessionManager | ||||
|   /** | ||||
|    * The set of currently active Sessions for this Manager, keyed by | ||||
|    * session identifier. | ||||
|    */ | ||||
|   protected Map<String, InternalSession> sessions = new ConcurrentHashMap<String, InternalSession>(); | ||||
|   /** | ||||
|    * The maximum number of active Sessions allowed, or -1 for no limit. | ||||
|    */ | ||||
|   protected int maxActiveSessions = -1; | ||||
|  | ||||
|   /** | ||||
|    * Number of session creations that failed due to maxActiveSessions. | ||||
|    */ | ||||
|   protected int rejectedSessions = 0; | ||||
|  | ||||
|   /** | ||||
|    * The default maximum inactive interval for Sessions created by | ||||
|    * this Manager. | ||||
|    */ | ||||
|   protected int maxInactiveInterval = 30 * 60; | ||||
|  | ||||
|   // Number of sessions created by this manager | ||||
|   protected long sessionCounter = 0; | ||||
|  | ||||
|   protected volatile int maxActive = 0; | ||||
|   /** | ||||
|    * Processing time during session expiration. | ||||
|    */ | ||||
|   protected long processingTime = 0; | ||||
|   /** | ||||
|    * Frequency of the session expiration, and related manager operations. | ||||
|    * Manager operations will be done once for the specified amount of | ||||
|    * backgrondProcess calls (ie, the lower the amount, the most often the | ||||
|    * checks will occur). | ||||
|    */ | ||||
|   protected int processExpiresFrequency = 6; | ||||
|   /** | ||||
|    * background processor delay in seconds | ||||
|    */ | ||||
|   protected int backgroundProcessorDelay = 10; | ||||
|   /** | ||||
|    * Iteration count for background processing. | ||||
|    */ | ||||
|   private int count = 0; | ||||
|  | ||||
|   @Override | ||||
|   public WxSession getSession(String sessionId) { | ||||
| @ -33,7 +82,7 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | ||||
|   public WxSession getSession(String sessionId, boolean create) { | ||||
|     if (sessionId == null) { | ||||
|       throw new IllegalStateException | ||||
|           (sm.getString("sessionManagerImpl.getSession.ise")); | ||||
|               (sm.getString("sessionManagerImpl.getSession.ise")); | ||||
|     } | ||||
|  | ||||
|     InternalSession session = findSession(sessionId); | ||||
| @ -60,64 +109,6 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | ||||
|     return session.getSession(); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   // -------------------------------------- InternalSessionManager | ||||
|   /** | ||||
|    * The descriptive name of this Manager implementation (for logging). | ||||
|    */ | ||||
|   private static final String name = "SessionManagerImpl"; | ||||
|  | ||||
|   /** | ||||
|    * The maximum number of active Sessions allowed, or -1 for no limit. | ||||
|    */ | ||||
|   protected int maxActiveSessions = -1; | ||||
|  | ||||
|   /** | ||||
|    * Number of session creations that failed due to maxActiveSessions. | ||||
|    */ | ||||
|   protected int rejectedSessions = 0; | ||||
|  | ||||
|   /** | ||||
|    * The default maximum inactive interval for Sessions created by | ||||
|    * this Manager. | ||||
|    */ | ||||
|   protected int maxInactiveInterval = 30 * 60; | ||||
|  | ||||
|   // Number of sessions created by this manager | ||||
|   protected long sessionCounter=0; | ||||
|  | ||||
|   protected volatile int maxActive=0; | ||||
|  | ||||
|   private final Object maxActiveUpdateLock = new Object(); | ||||
|  | ||||
|   /** | ||||
|    * Processing time during session expiration. | ||||
|    */ | ||||
|   protected long processingTime = 0; | ||||
|  | ||||
|   /** | ||||
|    * Iteration count for background processing. | ||||
|    */ | ||||
|   private int count = 0; | ||||
|  | ||||
|   /** | ||||
|    * Frequency of the session expiration, and related manager operations. | ||||
|    * Manager operations will be done once for the specified amount of | ||||
|    * backgrondProcess calls (ie, the lower the amount, the most often the | ||||
|    * checks will occur). | ||||
|    */ | ||||
|   protected int processExpiresFrequency = 6; | ||||
|  | ||||
|   /** | ||||
|    * background processor delay in seconds | ||||
|    */ | ||||
|   protected int backgroundProcessorDelay = 10; | ||||
|  | ||||
|   /** | ||||
|    * 后台清理线程是否已经开启 | ||||
|    */ | ||||
|   private final AtomicBoolean backgroundProcessStarted = new AtomicBoolean(false); | ||||
|  | ||||
|   @Override | ||||
|   public void remove(InternalSession session) { | ||||
|     remove(session, false); | ||||
| @ -131,7 +122,6 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | ||||
|   } | ||||
|  | ||||
|  | ||||
|  | ||||
|   @Override | ||||
|   public InternalSession findSession(String id) { | ||||
|  | ||||
| @ -145,15 +135,15 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | ||||
|   public InternalSession createSession(String sessionId) { | ||||
|     if (sessionId == null) { | ||||
|       throw new IllegalStateException | ||||
|           (sm.getString("sessionManagerImpl.createSession.ise")); | ||||
|               (sm.getString("sessionManagerImpl.createSession.ise")); | ||||
|     } | ||||
|  | ||||
|     if ((maxActiveSessions >= 0) && | ||||
|         (getActiveSessions() >= maxActiveSessions)) { | ||||
|             (getActiveSessions() >= maxActiveSessions)) { | ||||
|       rejectedSessions++; | ||||
|       throw new TooManyActiveSessionsException( | ||||
|           sm.getString("sessionManagerImpl.createSession.tmase"), | ||||
|           maxActiveSessions); | ||||
|               sm.getString("sessionManagerImpl.createSession.tmase"), | ||||
|               maxActiveSessions); | ||||
|     } | ||||
|  | ||||
|     // Recycle or create a Session instance | ||||
| @ -216,9 +206,9 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | ||||
|  | ||||
|     sessions.put(session.getIdInternal(), session); | ||||
|     int size = getActiveSessions(); | ||||
|     if( size > maxActive ) { | ||||
|       synchronized(maxActiveUpdateLock) { | ||||
|         if( size > maxActive ) { | ||||
|     if (size > maxActive) { | ||||
|       synchronized (maxActiveUpdateLock) { | ||||
|         if (size > maxActive) { | ||||
|           maxActive = size; | ||||
|         } | ||||
|       } | ||||
| @ -251,19 +241,19 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | ||||
|  | ||||
|     long timeNow = System.currentTimeMillis(); | ||||
|     InternalSession sessions[] = findSessions(); | ||||
|     int expireHere = 0 ; | ||||
|     int expireHere = 0; | ||||
|  | ||||
|     if(log.isDebugEnabled()) | ||||
|     if (log.isDebugEnabled()) | ||||
|       log.debug("Start expire sessions {} at {} sessioncount {}", getName(), timeNow, sessions.length); | ||||
|     for (int i = 0; i < sessions.length; i++) { | ||||
|       if (sessions[i]!=null && !sessions[i].isValid()) { | ||||
|       if (sessions[i] != null && !sessions[i].isValid()) { | ||||
|         expireHere++; | ||||
|       } | ||||
|     } | ||||
|     long timeEnd = System.currentTimeMillis(); | ||||
|     if(log.isDebugEnabled()) | ||||
|     if (log.isDebugEnabled()) | ||||
|       log.debug("End expire sessions {} processingTime {} expired sessions: {}", getName(), timeEnd - timeNow, expireHere); | ||||
|     processingTime += ( timeEnd - timeNow ); | ||||
|     processingTime += (timeEnd - timeNow); | ||||
|  | ||||
|   } | ||||
|  | ||||
|  | ||||
| @ -21,37 +21,34 @@ package me.chanjar.weixin.common.session; | ||||
|  * reached and the server is refusing to create any new sessions. | ||||
|  */ | ||||
| public class TooManyActiveSessionsException | ||||
|     extends IllegalStateException | ||||
| { | ||||
|     private static final long serialVersionUID = 1L; | ||||
|         extends IllegalStateException { | ||||
|   private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * The maximum number of active sessions the server will tolerate. | ||||
|      */ | ||||
|     private final int maxActiveSessions; | ||||
|   /** | ||||
|    * The maximum number of active sessions the server will tolerate. | ||||
|    */ | ||||
|   private final int maxActiveSessions; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new TooManyActiveSessionsException. | ||||
|      *  | ||||
|      * @param message A description for the exception. | ||||
|      * @param maxActive The maximum number of active sessions allowed by the | ||||
|      *                  session manager. | ||||
|      */ | ||||
|     public TooManyActiveSessionsException(String message, | ||||
|                                           int maxActive) | ||||
|     { | ||||
|         super(message); | ||||
|   /** | ||||
|    * Creates a new TooManyActiveSessionsException. | ||||
|    * | ||||
|    * @param message   A description for the exception. | ||||
|    * @param maxActive The maximum number of active sessions allowed by the | ||||
|    *                  session manager. | ||||
|    */ | ||||
|   public TooManyActiveSessionsException(String message, | ||||
|                                         int maxActive) { | ||||
|     super(message); | ||||
|  | ||||
|         maxActiveSessions = maxActive; | ||||
|     } | ||||
|     maxActiveSessions = maxActive; | ||||
|   } | ||||
|  | ||||
|     /** | ||||
|      * Gets the maximum number of sessions allowed by the session manager. | ||||
|      * | ||||
|      * @return The maximum number of sessions allowed by the session manager. | ||||
|      */ | ||||
|     public int getMaxActiveSessions() | ||||
|     { | ||||
|         return maxActiveSessions; | ||||
|     } | ||||
|   /** | ||||
|    * Gets the maximum number of sessions allowed by the session manager. | ||||
|    * | ||||
|    * @return The maximum number of sessions allowed by the session manager. | ||||
|    */ | ||||
|   public int getMaxActiveSessions() { | ||||
|     return maxActiveSessions; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -7,7 +7,7 @@ public class StringUtils { | ||||
|  | ||||
|   /** | ||||
|    * <p>Checks if a CharSequence is whitespace, empty ("") or null.</p> | ||||
|    * | ||||
|    * <p> | ||||
|    * <pre> | ||||
|    * StringUtils.isBlank(null)      = true | ||||
|    * StringUtils.isBlank("")        = true | ||||
| @ -16,9 +16,8 @@ public class StringUtils { | ||||
|    * StringUtils.isBlank("  bob  ") = false | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param cs  the CharSequence to check, may be null | ||||
|    * @param cs the CharSequence to check, may be null | ||||
|    * @return {@code true} if the CharSequence is null, empty or whitespace | ||||
|    * @since 2.0 | ||||
|    * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence) | ||||
|    */ | ||||
|   public static boolean isBlank(CharSequence cs) { | ||||
| @ -36,7 +35,7 @@ public class StringUtils { | ||||
|  | ||||
|   /** | ||||
|    * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p> | ||||
|    * | ||||
|    * <p> | ||||
|    * <pre> | ||||
|    * StringUtils.isNotBlank(null)      = false | ||||
|    * StringUtils.isNotBlank("")        = false | ||||
| @ -45,10 +44,9 @@ public class StringUtils { | ||||
|    * StringUtils.isNotBlank("  bob  ") = true | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param cs  the CharSequence to check, may be null | ||||
|    * @param cs the CharSequence to check, may be null | ||||
|    * @return {@code true} if the CharSequence is | ||||
|    *  not empty and not null and not whitespace | ||||
|    * @since 2.0 | ||||
|    * not empty and not null and not whitespace | ||||
|    * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence) | ||||
|    */ | ||||
|   public static boolean isNotBlank(CharSequence cs) { | ||||
| @ -57,7 +55,7 @@ public class StringUtils { | ||||
|  | ||||
|   /** | ||||
|    * <p>Checks if a CharSequence is empty ("") or null.</p> | ||||
|    * | ||||
|    * <p> | ||||
|    * <pre> | ||||
|    * StringUtils.isEmpty(null)      = true | ||||
|    * StringUtils.isEmpty("")        = true | ||||
| @ -65,12 +63,12 @@ public class StringUtils { | ||||
|    * StringUtils.isEmpty("bob")     = false | ||||
|    * StringUtils.isEmpty("  bob  ") = false | ||||
|    * </pre> | ||||
|    * | ||||
|    * <p> | ||||
|    * <p>NOTE: This method changed in Lang version 2.0. | ||||
|    * It no longer trims the CharSequence. | ||||
|    * That functionality is available in isBlank().</p> | ||||
|    * | ||||
|    * @param cs  the CharSequence to check, may be null | ||||
|    * @param cs the CharSequence to check, may be null | ||||
|    * @return {@code true} if the CharSequence is empty or null | ||||
|    * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) | ||||
|    */ | ||||
| @ -80,7 +78,7 @@ public class StringUtils { | ||||
|  | ||||
|   /** | ||||
|    * <p>Checks if a CharSequence is not empty ("") and not null.</p> | ||||
|    * | ||||
|    * <p> | ||||
|    * <pre> | ||||
|    * StringUtils.isNotEmpty(null)      = false | ||||
|    * StringUtils.isNotEmpty("")        = false | ||||
| @ -89,7 +87,7 @@ public class StringUtils { | ||||
|    * StringUtils.isNotEmpty("  bob  ") = true | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param cs  the CharSequence to check, may be null | ||||
|    * @param cs the CharSequence to check, may be null | ||||
|    * @return {@code true} if the CharSequence is not empty and not null | ||||
|    * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence) | ||||
|    */ | ||||
|  | ||||
| @ -3,24 +3,24 @@ package me.chanjar.weixin.common.util.crypto; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class ByteGroup { | ||||
| 	ArrayList<Byte> byteContainer = new ArrayList<Byte>(); | ||||
|   ArrayList<Byte> byteContainer = new ArrayList<Byte>(); | ||||
|  | ||||
|   public byte[] toBytes() { | ||||
| 		byte[] bytes = new byte[byteContainer.size()]; | ||||
| 		for (int i = 0; i < byteContainer.size(); i++) { | ||||
| 			bytes[i] = byteContainer.get(i); | ||||
| 		} | ||||
| 		return bytes; | ||||
| 	} | ||||
|     byte[] bytes = new byte[byteContainer.size()]; | ||||
|     for (int i = 0; i < byteContainer.size(); i++) { | ||||
|       bytes[i] = byteContainer.get(i); | ||||
|     } | ||||
|     return bytes; | ||||
|   } | ||||
|  | ||||
| 	public ByteGroup addBytes(byte[] bytes) { | ||||
| 		for (byte b : bytes) { | ||||
| 			byteContainer.add(b); | ||||
| 		} | ||||
| 		return this; | ||||
| 	} | ||||
|   public ByteGroup addBytes(byte[] bytes) { | ||||
|     for (byte b : bytes) { | ||||
|       byteContainer.add(b); | ||||
|     } | ||||
|     return this; | ||||
|   } | ||||
|  | ||||
| 	public int size() { | ||||
| 		return byteContainer.size(); | ||||
| 	} | ||||
|   public int size() { | ||||
|     return byteContainer.size(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -16,53 +16,53 @@ import java.util.Arrays; | ||||
|  */ | ||||
| public class PKCS7Encoder { | ||||
|  | ||||
| 	private static final Charset CHARSET = Charset.forName("utf-8"); | ||||
| 	private static final int BLOCK_SIZE = 32; | ||||
|   private static final Charset CHARSET = Charset.forName("utf-8"); | ||||
|   private static final int BLOCK_SIZE = 32; | ||||
|  | ||||
| 	/** | ||||
| 	 * 获得对明文进行补位填充的字节. | ||||
| 	 *  | ||||
| 	 * @param count 需要进行填充补位操作的明文字节个数 | ||||
| 	 * @return 补齐用的字节数组 | ||||
| 	 */ | ||||
| 	public static byte[] encode(int count) { | ||||
| 		// 计算需要填充的位数 | ||||
| 		int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); | ||||
| 		if (amountToPad == 0) { | ||||
| 			amountToPad = BLOCK_SIZE; | ||||
| 		} | ||||
| 		// 获得补位所用的字符 | ||||
| 		char padChr = chr(amountToPad); | ||||
| 		String tmp = new String(); | ||||
| 		for (int index = 0; index < amountToPad; index++) { | ||||
| 			tmp += padChr; | ||||
| 		} | ||||
| 		return tmp.getBytes(CHARSET); | ||||
| 	} | ||||
|   /** | ||||
|    * 获得对明文进行补位填充的字节. | ||||
|    * | ||||
|    * @param count 需要进行填充补位操作的明文字节个数 | ||||
|    * @return 补齐用的字节数组 | ||||
|    */ | ||||
|   public static byte[] encode(int count) { | ||||
|     // 计算需要填充的位数 | ||||
|     int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); | ||||
|     if (amountToPad == 0) { | ||||
|       amountToPad = BLOCK_SIZE; | ||||
|     } | ||||
|     // 获得补位所用的字符 | ||||
|     char padChr = chr(amountToPad); | ||||
|     String tmp = new String(); | ||||
|     for (int index = 0; index < amountToPad; index++) { | ||||
|       tmp += padChr; | ||||
|     } | ||||
|     return tmp.getBytes(CHARSET); | ||||
|   } | ||||
|  | ||||
| 	/** | ||||
| 	 * 删除解密后明文的补位字符 | ||||
| 	 *  | ||||
| 	 * @param decrypted 解密后的明文 | ||||
| 	 * @return 删除补位字符后的明文 | ||||
| 	 */ | ||||
| 	public static byte[] decode(byte[] decrypted) { | ||||
| 		int pad = (int) decrypted[decrypted.length - 1]; | ||||
| 		if (pad < 1 || pad > 32) { | ||||
| 			pad = 0; | ||||
| 		} | ||||
| 		return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad); | ||||
| 	} | ||||
|   /** | ||||
|    * 删除解密后明文的补位字符 | ||||
|    * | ||||
|    * @param decrypted 解密后的明文 | ||||
|    * @return 删除补位字符后的明文 | ||||
|    */ | ||||
|   public static byte[] decode(byte[] decrypted) { | ||||
|     int pad = (int) decrypted[decrypted.length - 1]; | ||||
|     if (pad < 1 || pad > 32) { | ||||
|       pad = 0; | ||||
|     } | ||||
|     return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad); | ||||
|   } | ||||
|  | ||||
| 	/** | ||||
| 	 * 将数字转化成ASCII码对应的字符,用于对明文进行补码 | ||||
| 	 *  | ||||
| 	 * @param a 需要转化的数字 | ||||
| 	 * @return 转化得到的字符 | ||||
| 	 */ | ||||
| 	public static char chr(int a) { | ||||
| 		byte target = (byte) (a & 0xFF); | ||||
| 		return (char) target; | ||||
| 	} | ||||
|   /** | ||||
|    * 将数字转化成ASCII码对应的字符,用于对明文进行补码 | ||||
|    * | ||||
|    * @param a 需要转化的数字 | ||||
|    * @return 转化得到的字符 | ||||
|    */ | ||||
|   public static char chr(int a) { | ||||
|     byte target = (byte) (a & 0xFF); | ||||
|     return (char) target; | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -1,10 +1,10 @@ | ||||
| package me.chanjar.weixin.common.util.crypto; | ||||
|  | ||||
| import org.apache.commons.codec.digest.DigestUtils; | ||||
|  | ||||
| import java.security.NoSuchAlgorithmException; | ||||
| import java.util.Arrays; | ||||
|  | ||||
| import org.apache.commons.codec.digest.DigestUtils; | ||||
|  | ||||
| /** | ||||
|  * Created by Daniel Qian on 14/10/19. | ||||
|  */ | ||||
| @ -37,4 +37,4 @@ public class SHA1 { | ||||
|     } | ||||
|     return DigestUtils.sha1Hex(sb.toString()); | ||||
|   } | ||||
|  } | ||||
| } | ||||
|  | ||||
| @ -2,6 +2,10 @@ | ||||
|  * 对公众平台发送给公众账号的消息加解密示例代码. | ||||
|  * | ||||
|  * @copyright Copyright (c) 1998-2014 Tencent Inc. | ||||
|  * <p> | ||||
|  * 针对org.apache.commons.codec.binary.Base64, | ||||
|  * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) | ||||
|  * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi | ||||
|  */ | ||||
|  | ||||
| // ------------------------------------------------------------------------ | ||||
| @ -62,12 +66,51 @@ public class WxCryptUtil { | ||||
|    * @param appidOrCorpid          公众平台appid/corpid | ||||
|    */ | ||||
|   public WxCryptUtil(String token, String encodingAesKey, | ||||
|       String appidOrCorpid) { | ||||
|                      String appidOrCorpid) { | ||||
|     this.token = token; | ||||
|     this.appidOrCorpid = appidOrCorpid; | ||||
|     this.aesKey = Base64.decodeBase64(encodingAesKey + "="); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 微信公众号支付签名算法(详见:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3) | ||||
|    * @param packageParams 原始参数 | ||||
|    * @param signKey 加密Key(即 商户Key) | ||||
|    * @return 签名字符串 | ||||
|    */ | ||||
|   public static String createSign(Map<String, String> packageParams, | ||||
|                                   String signKey) { | ||||
|     SortedMap<String, String> sortedMap = new TreeMap<String, String>(); | ||||
|     sortedMap.putAll(packageParams); | ||||
|  | ||||
|     List<String> keys = new ArrayList<String>(packageParams.keySet()); | ||||
|     Collections.sort(keys); | ||||
|  | ||||
|     StringBuffer toSign = new StringBuffer(); | ||||
|     for (String key : keys) { | ||||
|       String value = packageParams.get(key); | ||||
|       if (null != value && !"".equals(value) && !"sign".equals(key) | ||||
|               && !"key".equals(key)) { | ||||
|         toSign.append(key + "=" + value + "&"); | ||||
|       } | ||||
|     } | ||||
|     toSign.append("key=" + signKey); | ||||
|     String sign = DigestUtils.md5Hex(toSign.toString()).toUpperCase(); | ||||
|     return sign; | ||||
|   } | ||||
|  | ||||
|   static String extractEncryptPart(String xml) { | ||||
|     try { | ||||
|       DocumentBuilder db = builderLocal.get(); | ||||
|       Document document = db.parse(new InputSource(new StringReader(xml))); | ||||
|  | ||||
|       Element root = document.getDocumentElement(); | ||||
|       return root.getElementsByTagName("Encrypt").item(0).getTextContent(); | ||||
|     } catch (Exception e) { | ||||
|       throw new RuntimeException(e); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 将公众平台回复用户的消息加密打包. | ||||
|    * <ol> | ||||
| @ -107,7 +150,7 @@ public class WxCryptUtil { | ||||
|     byte[] randomStringBytes = randomStr.getBytes(CHARSET); | ||||
|     byte[] plainTextBytes = plainText.getBytes(CHARSET); | ||||
|     byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder( | ||||
|         plainTextBytes.length); | ||||
|             plainTextBytes.length); | ||||
|     byte[] appIdBytes = appidOrCorpid.getBytes(CHARSET); | ||||
|  | ||||
|     // randomStr + networkBytesOrder + text + appid | ||||
| @ -157,7 +200,7 @@ public class WxCryptUtil { | ||||
|    * @return 解密后的原文 | ||||
|    */ | ||||
|   public String decrypt(String msgSignature, String timeStamp, String nonce, | ||||
|       String encryptedXml) { | ||||
|                         String encryptedXml) { | ||||
|     // 密钥,公众账号的app corpSecret | ||||
|     // 提取密文 | ||||
|     String cipherText = extractEncryptPart(encryptedXml); | ||||
| @ -190,7 +233,7 @@ public class WxCryptUtil { | ||||
|       Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); | ||||
|       SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES"); | ||||
|       IvParameterSpec iv = new IvParameterSpec( | ||||
|           Arrays.copyOfRange(aesKey, 0, 16)); | ||||
|               Arrays.copyOfRange(aesKey, 0, 16)); | ||||
|       cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); | ||||
|  | ||||
|       // 使用BASE64对密文进行解码 | ||||
| @ -213,9 +256,9 @@ public class WxCryptUtil { | ||||
|       int xmlLength = bytesNetworkOrder2Number(networkOrder); | ||||
|  | ||||
|       xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), | ||||
|           CHARSET); | ||||
|               CHARSET); | ||||
|       from_appid = new String( | ||||
|           Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); | ||||
|               Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); | ||||
|     } catch (Exception e) { | ||||
|       throw new RuntimeException(e); | ||||
|     } | ||||
| @ -229,33 +272,6 @@ public class WxCryptUtil { | ||||
|  | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 微信公众号支付签名算法(详见:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3) | ||||
|    * @param packageParams 原始参数 | ||||
|    * @param signKey 加密Key(即 商户Key) | ||||
|    * @return 签名字符串 | ||||
|    */ | ||||
|   public static String createSign(Map<String, String> packageParams, | ||||
|       String signKey) { | ||||
|     SortedMap<String, String> sortedMap = new TreeMap<String, String>(); | ||||
|     sortedMap.putAll(packageParams); | ||||
|  | ||||
|     List<String> keys = new ArrayList<String>(packageParams.keySet()); | ||||
|     Collections.sort(keys); | ||||
|  | ||||
|     StringBuffer toSign = new StringBuffer(); | ||||
|     for (String key : keys) { | ||||
|       String value = packageParams.get(key); | ||||
|       if (null != value && !"".equals(value) && !"sign".equals(key) | ||||
|           && !"key".equals(key)) { | ||||
|         toSign.append(key + "=" + value + "&"); | ||||
|       } | ||||
|     } | ||||
|     toSign.append("key=" + signKey); | ||||
|     String sign = DigestUtils.md5Hex(toSign.toString()).toUpperCase(); | ||||
|     return sign; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 将一个数字转换成生成4个字节的网络字节序bytes数组 | ||||
|    * | ||||
| @ -308,24 +324,12 @@ public class WxCryptUtil { | ||||
|    * @return 生成的xml字符串 | ||||
|    */ | ||||
|   private String generateXml(String encrypt, String signature, String timestamp, | ||||
|       String nonce) { | ||||
|                              String nonce) { | ||||
|     String format = "<xml>\n" + "<Encrypt><![CDATA[%1$s]]></Encrypt>\n" | ||||
|         + "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n" | ||||
|         + "<TimeStamp>%3$s</TimeStamp>\n" + "<Nonce><![CDATA[%4$s]]></Nonce>\n" | ||||
|         + "</xml>"; | ||||
|             + "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n" | ||||
|             + "<TimeStamp>%3$s</TimeStamp>\n" + "<Nonce><![CDATA[%4$s]]></Nonce>\n" | ||||
|             + "</xml>"; | ||||
|     return String.format(format, encrypt, signature, timestamp, nonce); | ||||
|   } | ||||
|  | ||||
|   static String extractEncryptPart(String xml) { | ||||
|     try { | ||||
|       DocumentBuilder db = builderLocal.get(); | ||||
|       Document document = db.parse(new InputSource(new StringReader(xml))); | ||||
|  | ||||
|       Element root = document.getDocumentElement(); | ||||
|       return root.getElementsByTagName("Encrypt").item(0).getTextContent(); | ||||
|     } catch (Exception e) { | ||||
|       throw new RuntimeException(e); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -10,17 +10,18 @@ public class FileUtils { | ||||
|  | ||||
|   /** | ||||
|    * 创建临时文件 | ||||
|    * | ||||
|    * @param inputStream | ||||
|    * @param name  文件名 | ||||
|    * @param ext   扩展名 | ||||
|    * @param tmpDirFile   临时文件夹目录 | ||||
|    * @param name        文件名 | ||||
|    * @param ext         扩展名 | ||||
|    * @param tmpDirFile  临时文件夹目录 | ||||
|    */ | ||||
|   public static File createTmpFile(InputStream inputStream, String name, String ext, File tmpDirFile) throws IOException { | ||||
|     FileOutputStream fos = null; | ||||
|     try { | ||||
|       File tmpFile; | ||||
|       if (tmpDirFile == null) { | ||||
|     	  tmpFile = File.createTempFile(name, '.' + ext); | ||||
|         tmpFile = File.createTempFile(name, '.' + ext); | ||||
|       } else { | ||||
|         tmpFile = File.createTempFile(name, '.' + ext, tmpDirFile); | ||||
|       } | ||||
| @ -51,9 +52,10 @@ public class FileUtils { | ||||
|  | ||||
|   /** | ||||
|    * 创建临时文件 | ||||
|    * | ||||
|    * @param inputStream | ||||
|    * @param name  文件名 | ||||
|    * @param ext   扩展名 | ||||
|    * @param name        文件名 | ||||
|    * @param ext         扩展名 | ||||
|    */ | ||||
|   public static File createTmpFile(InputStream inputStream, String name, String ext) throws IOException { | ||||
|     return createTmpFile(inputStream, name, ext, null); | ||||
|  | ||||
| @ -10,36 +10,42 @@ public interface ApacheHttpClientBuilder { | ||||
|  | ||||
|   /** | ||||
|    * 构建httpclient实例 | ||||
|    * | ||||
|    * @return new instance of CloseableHttpClient | ||||
|    */ | ||||
|   CloseableHttpClient build(); | ||||
|  | ||||
|   /** | ||||
|    * 代理服务器地址 | ||||
|    * | ||||
|    * @param httpProxyHost | ||||
|    */ | ||||
|   ApacheHttpClientBuilder httpProxyHost(String httpProxyHost); | ||||
|  | ||||
|   /** | ||||
|    * 代理服务器端口 | ||||
|    * | ||||
|    * @param httpProxyPort | ||||
|    */ | ||||
|   ApacheHttpClientBuilder httpProxyPort(int httpProxyPort); | ||||
|  | ||||
|   /** | ||||
|    * 代理服务器用户名 | ||||
|    * | ||||
|    * @param httpProxyUsername | ||||
|    */ | ||||
|   ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername); | ||||
|  | ||||
|   /** | ||||
|    * 代理服务器密码 | ||||
|    * | ||||
|    * @param httpProxyPassword | ||||
|    */ | ||||
|   ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword); | ||||
|  | ||||
|   /** | ||||
|    * ssl连接socket工厂 | ||||
|    * | ||||
|    * @param sslConnectionSocketFactory | ||||
|    */ | ||||
|   ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory); | ||||
|  | ||||
| @ -94,7 +94,7 @@ public class DefaultApacheHttpHttpClientBuilder implements ApacheHttpClientBuild | ||||
|     return this; | ||||
|   } | ||||
|  | ||||
|   public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory){ | ||||
|   public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory) { | ||||
|     this.sslConnectionSocketFactory = sslConnectionSocketFactory; | ||||
|     return this; | ||||
|   } | ||||
| @ -103,18 +103,18 @@ public class DefaultApacheHttpHttpClientBuilder implements ApacheHttpClientBuild | ||||
|     return idleConnectionMonitorThread; | ||||
|   } | ||||
|  | ||||
|   private void prepare(){ | ||||
|   private void prepare() { | ||||
|     Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() | ||||
|       .register("http", plainConnectionSocketFactory) | ||||
|       .register("https", sslConnectionSocketFactory) | ||||
|       .build(); | ||||
|             .register("http", plainConnectionSocketFactory) | ||||
|             .register("https", sslConnectionSocketFactory) | ||||
|             .build(); | ||||
|     connectionManager = new PoolingHttpClientConnectionManager(registry); | ||||
|     connectionManager.setMaxTotal(maxTotalConn); | ||||
|     connectionManager.setDefaultMaxPerRoute(maxConnPerHost); | ||||
|     connectionManager.setDefaultSocketConfig( | ||||
|       SocketConfig.copy(SocketConfig.DEFAULT) | ||||
|         .setSoTimeout(soTimeout) | ||||
|         .build() | ||||
|             SocketConfig.copy(SocketConfig.DEFAULT) | ||||
|                     .setSoTimeout(soTimeout) | ||||
|                     .build() | ||||
|     ); | ||||
|  | ||||
|     idleConnectionMonitorThread = new IdleConnectionMonitorThread(connectionManager, idleConnTimeout, checkWaitTime); | ||||
| @ -122,22 +122,22 @@ public class DefaultApacheHttpHttpClientBuilder implements ApacheHttpClientBuild | ||||
|     idleConnectionMonitorThread.start(); | ||||
|  | ||||
|     httpClientBuilder = HttpClients.custom() | ||||
|       .setConnectionManager(connectionManager) | ||||
|       .setDefaultRequestConfig( | ||||
|         RequestConfig.custom() | ||||
|           .setSocketTimeout(soTimeout) | ||||
|           .setConnectTimeout(connectionTimeout) | ||||
|           .setConnectionRequestTimeout(connectionRequestTimeout) | ||||
|           .build() | ||||
|       ) | ||||
|       .setRetryHandler(httpRequestRetryHandler); | ||||
|             .setConnectionManager(connectionManager) | ||||
|             .setDefaultRequestConfig( | ||||
|                     RequestConfig.custom() | ||||
|                             .setSocketTimeout(soTimeout) | ||||
|                             .setConnectTimeout(connectionTimeout) | ||||
|                             .setConnectionRequestTimeout(connectionRequestTimeout) | ||||
|                             .build() | ||||
|             ) | ||||
|             .setRetryHandler(httpRequestRetryHandler); | ||||
|  | ||||
|     if (StringUtils.isNotBlank(httpProxyHost) && StringUtils.isNotBlank(httpProxyUsername)) { | ||||
|       // 使用代理服务器 需要用户认证的代理服务器 | ||||
|       CredentialsProvider credsProvider = new BasicCredentialsProvider(); | ||||
|       credsProvider.setCredentials( | ||||
|         new AuthScope(httpProxyHost, httpProxyPort), | ||||
|         new UsernamePasswordCredentials(httpProxyUsername, httpProxyPassword)); | ||||
|               new AuthScope(httpProxyHost, httpProxyPort), | ||||
|               new UsernamePasswordCredentials(httpProxyUsername, httpProxyPassword)); | ||||
|       httpClientBuilder.setDefaultCredentialsProvider(credsProvider); | ||||
|     } | ||||
|  | ||||
| @ -148,7 +148,7 @@ public class DefaultApacheHttpHttpClientBuilder implements ApacheHttpClientBuild | ||||
|   } | ||||
|  | ||||
|   public CloseableHttpClient build() { | ||||
|     if(!prepared){ | ||||
|     if (!prepared) { | ||||
|       prepare(); | ||||
|       prepared = true; | ||||
|     } | ||||
|  | ||||
| @ -1,8 +1,5 @@ | ||||
| package me.chanjar.weixin.common.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; | ||||
| @ -10,6 +7,9 @@ import org.apache.http.client.HttpResponseException; | ||||
| import org.apache.http.client.ResponseHandler; | ||||
| import org.apache.http.util.EntityUtils; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
|  | ||||
| public class InputStreamResponseHandler implements ResponseHandler<InputStream> { | ||||
|  | ||||
|   public static final ResponseHandler<InputStream> INSTANCE = new InputStreamResponseHandler(); | ||||
|  | ||||
| @ -18,39 +18,39 @@ import java.io.IOException; | ||||
|  */ | ||||
| public class JoddGetRequestExecutor implements RequestExecutor<String, String> { | ||||
|  | ||||
|     @Override | ||||
|     public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, | ||||
|         String queryParam) throws WxErrorException, IOException { | ||||
|         if (queryParam != null) { | ||||
|             if (uri.indexOf('?') == -1) { | ||||
|                 uri += '?'; | ||||
|             } | ||||
|             uri += uri.endsWith("?") ? queryParam : '&' + queryParam; | ||||
|         } | ||||
|  | ||||
|         SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); | ||||
|  | ||||
|         if (httpProxy != null) { | ||||
|             ProxyInfo proxyInfoObj = new ProxyInfo( | ||||
|                 ProxyInfo.ProxyType.HTTP, | ||||
|                 httpProxy.getHostName(), | ||||
|                 httpProxy.getPort(), "", ""); | ||||
|             provider.useProxy(proxyInfoObj); | ||||
|         } | ||||
|  | ||||
|         HttpRequest request = HttpRequest.get(uri); | ||||
|         request.method("GET"); | ||||
|         request.charset("UTF-8"); | ||||
|  | ||||
|         HttpResponse response = request.open(provider).send(); | ||||
|         response.charset("UTF-8"); | ||||
|         String result = response.bodyText(); | ||||
|  | ||||
|         WxError error = WxError.fromJson(result); | ||||
|         if (error.getErrorCode() != 0) { | ||||
|             throw new WxErrorException(error); | ||||
|         } | ||||
|         return result; | ||||
|   @Override | ||||
|   public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, | ||||
|                         String queryParam) throws WxErrorException, IOException { | ||||
|     if (queryParam != null) { | ||||
|       if (uri.indexOf('?') == -1) { | ||||
|         uri += '?'; | ||||
|       } | ||||
|       uri += uri.endsWith("?") ? queryParam : '&' + queryParam; | ||||
|     } | ||||
|  | ||||
|     SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); | ||||
|  | ||||
|     if (httpProxy != null) { | ||||
|       ProxyInfo proxyInfoObj = new ProxyInfo( | ||||
|               ProxyInfo.ProxyType.HTTP, | ||||
|               httpProxy.getHostName(), | ||||
|               httpProxy.getPort(), "", ""); | ||||
|       provider.useProxy(proxyInfoObj); | ||||
|     } | ||||
|  | ||||
|     HttpRequest request = HttpRequest.get(uri); | ||||
|     request.method("GET"); | ||||
|     request.charset("UTF-8"); | ||||
|  | ||||
|     HttpResponse response = request.open(provider).send(); | ||||
|     response.charset("UTF-8"); | ||||
|     String result = response.bodyText(); | ||||
|  | ||||
|     WxError error = WxError.fromJson(result); | ||||
|     if (error.getErrorCode() != 0) { | ||||
|       throw new WxErrorException(error); | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -18,33 +18,33 @@ import java.io.IOException; | ||||
|  */ | ||||
| public class JoddPostRequestExecutor implements RequestExecutor<String, String> { | ||||
|  | ||||
|     @Override | ||||
|     public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, | ||||
|         String postEntity) throws WxErrorException, IOException { | ||||
|         SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); | ||||
|   @Override | ||||
|   public String execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, | ||||
|                         String postEntity) throws WxErrorException, IOException { | ||||
|     SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); | ||||
|  | ||||
|         if (httpProxy != null) { | ||||
|             ProxyInfo proxyInfoObj = new ProxyInfo( | ||||
|                 ProxyInfo.ProxyType.HTTP, | ||||
|                 httpProxy.getAddress().getHostAddress(), | ||||
|                 httpProxy.getPort(), "", ""); | ||||
|             provider.useProxy(proxyInfoObj); | ||||
|         } | ||||
|  | ||||
|         HttpRequest request = HttpRequest.get(uri); | ||||
|         request.method("POST"); | ||||
|         request.charset("UTF-8"); | ||||
|         request.bodyText(postEntity); | ||||
|  | ||||
|         HttpResponse response = request.open(provider).send(); | ||||
|         response.charset("UTF-8"); | ||||
|         String result = response.bodyText(); | ||||
|  | ||||
|         WxError error = WxError.fromJson(result); | ||||
|         if (error.getErrorCode() != 0) { | ||||
|             throw new WxErrorException(error); | ||||
|         } | ||||
|         return result; | ||||
|     if (httpProxy != null) { | ||||
|       ProxyInfo proxyInfoObj = new ProxyInfo( | ||||
|               ProxyInfo.ProxyType.HTTP, | ||||
|               httpProxy.getAddress().getHostAddress(), | ||||
|               httpProxy.getPort(), "", ""); | ||||
|       provider.useProxy(proxyInfoObj); | ||||
|     } | ||||
|  | ||||
|     HttpRequest request = HttpRequest.get(uri); | ||||
|     request.method("POST"); | ||||
|     request.charset("UTF-8"); | ||||
|     request.bodyText(postEntity); | ||||
|  | ||||
|     HttpResponse response = request.open(provider).send(); | ||||
|     response.charset("UTF-8"); | ||||
|     String result = response.bodyText(); | ||||
|  | ||||
|     WxError error = WxError.fromJson(result); | ||||
|     if (error.getErrorCode() != 0) { | ||||
|       throw new WxErrorException(error); | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -6,7 +6,6 @@ import me.chanjar.weixin.common.util.StringUtils; | ||||
| import me.chanjar.weixin.common.util.fs.FileUtils; | ||||
| import org.apache.http.Header; | ||||
| import org.apache.http.HttpHost; | ||||
| import org.apache.http.client.ClientProtocolException; | ||||
| import org.apache.http.client.config.RequestConfig; | ||||
| import org.apache.http.client.methods.CloseableHttpResponse; | ||||
| import org.apache.http.client.methods.HttpGet; | ||||
| @ -21,8 +20,8 @@ import java.util.regex.Pattern; | ||||
|  | ||||
| /** | ||||
|  * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File | ||||
|  * @author Daniel Qian | ||||
|  * | ||||
|  * @author Daniel Qian | ||||
|  */ | ||||
| public class MediaDownloadRequestExecutor implements RequestExecutor<File, String> { | ||||
|  | ||||
| @ -74,7 +73,7 @@ public class MediaDownloadRequestExecutor implements RequestExecutor<File, Strin | ||||
|       File localFile = FileUtils.createTmpFile(inputStream, name_ext[0], name_ext[1], tmpDirFile); | ||||
|       return localFile; | ||||
|  | ||||
|     }finally { | ||||
|     } finally { | ||||
|       httpGet.releaseConnection(); | ||||
|     } | ||||
|  | ||||
|  | ||||
| @ -5,7 +5,6 @@ import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | ||||
| import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import org.apache.http.HttpEntity; | ||||
| import org.apache.http.HttpHost; | ||||
| import org.apache.http.client.ClientProtocolException; | ||||
| import org.apache.http.client.config.RequestConfig; | ||||
| import org.apache.http.client.methods.CloseableHttpResponse; | ||||
| import org.apache.http.client.methods.HttpPost; | ||||
| @ -19,8 +18,8 @@ import java.io.IOException; | ||||
|  | ||||
| /** | ||||
|  * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String | ||||
|  * @author Daniel Qian | ||||
|  * | ||||
|  * @author Daniel Qian | ||||
|  */ | ||||
| public class MediaUploadRequestExecutor implements RequestExecutor<WxMediaUploadResult, File> { | ||||
|  | ||||
| @ -33,10 +32,10 @@ public class MediaUploadRequestExecutor implements RequestExecutor<WxMediaUpload | ||||
|     } | ||||
|     if (file != null) { | ||||
|       HttpEntity entity = MultipartEntityBuilder | ||||
|             .create() | ||||
|             .addBinaryBody("media", file) | ||||
|             .setMode(HttpMultipartMode.RFC6532) | ||||
|             .build(); | ||||
|               .create() | ||||
|               .addBinaryBody("media", file) | ||||
|               .setMode(HttpMultipartMode.RFC6532) | ||||
|               .build(); | ||||
|       httpPost.setEntity(entity); | ||||
|       httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); | ||||
|     } | ||||
| @ -47,7 +46,7 @@ public class MediaUploadRequestExecutor implements RequestExecutor<WxMediaUpload | ||||
|         throw new WxErrorException(error); | ||||
|       } | ||||
|       return WxMediaUploadResult.fromJson(responseContent); | ||||
|     }finally { | ||||
|     } finally { | ||||
|       httpPost.releaseConnection(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @ -1,12 +1,11 @@ | ||||
| package me.chanjar.weixin.common.util.http; | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import org.apache.http.HttpHost; | ||||
| import org.apache.http.client.ClientProtocolException; | ||||
| import org.apache.http.impl.client.CloseableHttpClient; | ||||
|  | ||||
| import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import java.io.IOException; | ||||
|  | ||||
| /** | ||||
|  * http请求执行器 | ||||
| @ -17,11 +16,10 @@ import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| public interface RequestExecutor<T, E> { | ||||
|  | ||||
|   /** | ||||
|    * | ||||
|    * @param httpclient 传入的httpClient | ||||
|    * @param httpProxy http代理对象,如果没有配置代理则为空 | ||||
|    * @param uri       uri | ||||
|    * @param data      数据 | ||||
|    * @param httpProxy  http代理对象,如果没有配置代理则为空 | ||||
|    * @param uri        uri | ||||
|    * @param data       数据 | ||||
|    * @throws WxErrorException | ||||
|    * @throws ClientProtocolException | ||||
|    * @throws IOException | ||||
|  | ||||
| @ -3,7 +3,6 @@ package me.chanjar.weixin.common.util.http; | ||||
| import me.chanjar.weixin.common.bean.result.WxError; | ||||
| import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import org.apache.http.HttpHost; | ||||
| import org.apache.http.client.ClientProtocolException; | ||||
| import org.apache.http.client.config.RequestConfig; | ||||
| import org.apache.http.client.methods.CloseableHttpResponse; | ||||
| import org.apache.http.client.methods.HttpGet; | ||||
| @ -13,8 +12,8 @@ import java.io.IOException; | ||||
|  | ||||
| /** | ||||
|  * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String | ||||
|  * @author Daniel Qian | ||||
|  * | ||||
|  * @author Daniel Qian | ||||
|  */ | ||||
| public class SimpleGetRequestExecutor implements RequestExecutor<String, String> { | ||||
|  | ||||
| @ -39,7 +38,7 @@ public class SimpleGetRequestExecutor implements RequestExecutor<String, String> | ||||
|         throw new WxErrorException(error); | ||||
|       } | ||||
|       return responseContent; | ||||
|     }finally { | ||||
|     } finally { | ||||
|       httpGet.releaseConnection(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @ -4,7 +4,6 @@ import me.chanjar.weixin.common.bean.result.WxError; | ||||
| import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import org.apache.http.Consts; | ||||
| import org.apache.http.HttpHost; | ||||
| import org.apache.http.client.ClientProtocolException; | ||||
| import org.apache.http.client.config.RequestConfig; | ||||
| import org.apache.http.client.methods.CloseableHttpResponse; | ||||
| import org.apache.http.client.methods.HttpPost; | ||||
| @ -15,8 +14,8 @@ import java.io.IOException; | ||||
|  | ||||
| /** | ||||
|  * 简单的POST请求执行器,请求的参数是String, 返回的结果也是String | ||||
|  * @author Daniel Qian | ||||
|  * | ||||
|  * @author Daniel Qian | ||||
|  */ | ||||
| public class SimplePostRequestExecutor implements RequestExecutor<String, String> { | ||||
|  | ||||
| @ -40,7 +39,7 @@ public class SimplePostRequestExecutor implements RequestExecutor<String, String | ||||
|         throw new WxErrorException(error); | ||||
|       } | ||||
|       return responseContent; | ||||
|     }finally { | ||||
|     } finally { | ||||
|       httpPost.releaseConnection(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @ -1,7 +1,5 @@ | ||||
| package me.chanjar.weixin.common.util.http; | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| import org.apache.http.Consts; | ||||
| import org.apache.http.HttpEntity; | ||||
| import org.apache.http.HttpResponse; | ||||
| @ -10,10 +8,12 @@ import org.apache.http.client.HttpResponseException; | ||||
| import org.apache.http.client.ResponseHandler; | ||||
| import org.apache.http.util.EntityUtils; | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| /** | ||||
|  * copy from {@link org.apache.http.impl.client.BasicResponseHandler} | ||||
|  * @author Daniel Qian | ||||
|  * | ||||
|  * @author Daniel Qian | ||||
|  */ | ||||
| public class Utf8ResponseHandler implements ResponseHandler<String> { | ||||
|  | ||||
|  | ||||
| @ -15,101 +15,101 @@ import com.google.gson.JsonObject; | ||||
|  | ||||
| public class GsonHelper { | ||||
|  | ||||
| 	public static boolean isNull(JsonElement element) { | ||||
| 		return element == null || element.isJsonNull(); | ||||
| 	} | ||||
|   public static boolean isNull(JsonElement element) { | ||||
|     return element == null || element.isJsonNull(); | ||||
|   } | ||||
|  | ||||
| 	public static boolean isNotNull(JsonElement element) { | ||||
| 		return !isNull(element); | ||||
| 	} | ||||
|   public static boolean isNotNull(JsonElement element) { | ||||
|     return !isNull(element); | ||||
|   } | ||||
|  | ||||
| 	public static Long getLong(JsonObject json, String property) { | ||||
| 		return getAsLong(json.get(property)); | ||||
| 	} | ||||
|   public static Long getLong(JsonObject json, String property) { | ||||
|     return getAsLong(json.get(property)); | ||||
|   } | ||||
|  | ||||
| 	public static long getPrimitiveLong(JsonObject json, String property) { | ||||
| 		return getAsPrimitiveLong(json.get(property)); | ||||
| 	} | ||||
|   public static long getPrimitiveLong(JsonObject json, String property) { | ||||
|     return getAsPrimitiveLong(json.get(property)); | ||||
|   } | ||||
|  | ||||
| 	public static Integer getInteger(JsonObject json, String property) { | ||||
| 		return getAsInteger(json.get(property)); | ||||
| 	} | ||||
|   public static Integer getInteger(JsonObject json, String property) { | ||||
|     return getAsInteger(json.get(property)); | ||||
|   } | ||||
|  | ||||
| 	public static int getPrimitiveInteger(JsonObject json, String property) { | ||||
| 		return getAsPrimitiveInt(json.get(property)); | ||||
| 	} | ||||
|   public static int getPrimitiveInteger(JsonObject json, String property) { | ||||
|     return getAsPrimitiveInt(json.get(property)); | ||||
|   } | ||||
|  | ||||
| 	public static Double getDouble(JsonObject json, String property) { | ||||
| 		return getAsDouble(json.get(property)); | ||||
| 	} | ||||
|   public static Double getDouble(JsonObject json, String property) { | ||||
|     return getAsDouble(json.get(property)); | ||||
|   } | ||||
|  | ||||
| 	public static double getPrimitiveDouble(JsonObject json, String property) { | ||||
| 		return getAsPrimitiveDouble(json.get(property)); | ||||
| 	} | ||||
|   public static double getPrimitiveDouble(JsonObject json, String property) { | ||||
|     return getAsPrimitiveDouble(json.get(property)); | ||||
|   } | ||||
|  | ||||
| 	public static Float getFloat(JsonObject json, String property) { | ||||
| 		return getAsFloat(json.get(property)); | ||||
| 	} | ||||
|   public static Float getFloat(JsonObject json, String property) { | ||||
|     return getAsFloat(json.get(property)); | ||||
|   } | ||||
|  | ||||
| 	public static float getPrimitiveFloat(JsonObject json, String property) { | ||||
| 		return getAsPrimitiveFloat(json.get(property)); | ||||
| 	} | ||||
|   public static float getPrimitiveFloat(JsonObject json, String property) { | ||||
|     return getAsPrimitiveFloat(json.get(property)); | ||||
|   } | ||||
|  | ||||
| 	public static Boolean getBoolean(JsonObject json, String property) { | ||||
| 		return getAsBoolean(json.get(property)); | ||||
| 	} | ||||
|   public static Boolean getBoolean(JsonObject json, String property) { | ||||
|     return getAsBoolean(json.get(property)); | ||||
|   } | ||||
|  | ||||
| 	public static String getString(JsonObject json, String property) { | ||||
| 		return getAsString(json.get(property)); | ||||
| 	} | ||||
|   public static String getString(JsonObject json, String property) { | ||||
|     return getAsString(json.get(property)); | ||||
|   } | ||||
|  | ||||
| 	public static String getAsString(JsonElement element) { | ||||
| 		return isNull(element) ? null : element.getAsString(); | ||||
| 	} | ||||
|   public static String getAsString(JsonElement element) { | ||||
|     return isNull(element) ? null : element.getAsString(); | ||||
|   } | ||||
|  | ||||
| 	public static Long getAsLong(JsonElement element) { | ||||
| 		return isNull(element) ? null : element.getAsLong(); | ||||
| 	} | ||||
|   public static Long getAsLong(JsonElement element) { | ||||
|     return isNull(element) ? null : element.getAsLong(); | ||||
|   } | ||||
|  | ||||
| 	public static long getAsPrimitiveLong(JsonElement element) { | ||||
| 		Long r = getAsLong(element); | ||||
| 		return r == null ? 0l : r; | ||||
| 	} | ||||
|   public static long getAsPrimitiveLong(JsonElement element) { | ||||
|     Long r = getAsLong(element); | ||||
|     return r == null ? 0l : r; | ||||
|   } | ||||
|  | ||||
| 	public static Integer getAsInteger(JsonElement element) { | ||||
| 		return isNull(element) ? null : element.getAsInt(); | ||||
| 	} | ||||
|   public static Integer getAsInteger(JsonElement element) { | ||||
|     return isNull(element) ? null : element.getAsInt(); | ||||
|   } | ||||
|  | ||||
| 	public static int getAsPrimitiveInt(JsonElement element) { | ||||
| 		Integer r = getAsInteger(element); | ||||
| 		return r == null ? 0 : r; | ||||
| 	} | ||||
|   public static int getAsPrimitiveInt(JsonElement element) { | ||||
|     Integer r = getAsInteger(element); | ||||
|     return r == null ? 0 : r; | ||||
|   } | ||||
|  | ||||
| 	public static Boolean getAsBoolean(JsonElement element) { | ||||
| 		return isNull(element) ? null : element.getAsBoolean(); | ||||
| 	} | ||||
|   public static Boolean getAsBoolean(JsonElement element) { | ||||
|     return isNull(element) ? null : element.getAsBoolean(); | ||||
|   } | ||||
|  | ||||
| 	public static boolean getAsPrimitiveBool(JsonElement element) { | ||||
| 		Boolean r = getAsBoolean(element); | ||||
| 		return r != null && r.booleanValue(); | ||||
| 	} | ||||
|   public static boolean getAsPrimitiveBool(JsonElement element) { | ||||
|     Boolean r = getAsBoolean(element); | ||||
|     return r != null && r.booleanValue(); | ||||
|   } | ||||
|  | ||||
| 	public static Double getAsDouble(JsonElement element) { | ||||
| 		return isNull(element) ? null : element.getAsDouble(); | ||||
| 	} | ||||
|   public static Double getAsDouble(JsonElement element) { | ||||
|     return isNull(element) ? null : element.getAsDouble(); | ||||
|   } | ||||
|  | ||||
| 	public static double getAsPrimitiveDouble(JsonElement element) { | ||||
| 		Double r = getAsDouble(element); | ||||
| 		return r == null ? 0d : r; | ||||
| 	} | ||||
|   public static double getAsPrimitiveDouble(JsonElement element) { | ||||
|     Double r = getAsDouble(element); | ||||
|     return r == null ? 0d : r; | ||||
|   } | ||||
|  | ||||
| 	public static Float getAsFloat(JsonElement element) { | ||||
| 		return isNull(element) ? null : element.getAsFloat(); | ||||
| 	} | ||||
|   public static Float getAsFloat(JsonElement element) { | ||||
|     return isNull(element) ? null : element.getAsFloat(); | ||||
|   } | ||||
|  | ||||
| 	public static float getAsPrimitiveFloat(JsonElement element) { | ||||
| 		Float r = getAsFloat(element); | ||||
| 		return r == null ? 0f : r; | ||||
| 	} | ||||
|   public static float getAsPrimitiveFloat(JsonElement element) { | ||||
|     Float r = getAsFloat(element); | ||||
|     return r == null ? 0f : r; | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -14,9 +14,7 @@ import me.chanjar.weixin.common.bean.WxAccessToken; | ||||
| import java.lang.reflect.Type; | ||||
|  | ||||
| /** | ||||
|  *  | ||||
|  * @author Daniel Qian | ||||
|  * | ||||
|  */ | ||||
| public class WxAccessTokenAdapter implements JsonDeserializer<WxAccessToken> { | ||||
|  | ||||
|  | ||||
| @ -14,9 +14,7 @@ import me.chanjar.weixin.common.bean.result.WxError; | ||||
| import java.lang.reflect.Type; | ||||
|  | ||||
| /** | ||||
|  *  | ||||
|  * @author Daniel Qian | ||||
|  * | ||||
|  */ | ||||
| public class WxErrorAdapter implements JsonDeserializer<WxError> { | ||||
|  | ||||
|  | ||||
| @ -2,9 +2,9 @@ package me.chanjar.weixin.common.util.json; | ||||
|  | ||||
| import com.google.gson.Gson; | ||||
| import com.google.gson.GsonBuilder; | ||||
| import me.chanjar.weixin.common.bean.WxAccessToken; | ||||
| import me.chanjar.weixin.common.bean.WxMenu; | ||||
| import me.chanjar.weixin.common.bean.result.WxError; | ||||
| import me.chanjar.weixin.common.bean.WxAccessToken; | ||||
| import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | ||||
|  | ||||
| public class WxGsonBuilder { | ||||
|  | ||||
| @ -14,9 +14,7 @@ import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | ||||
| import java.lang.reflect.Type; | ||||
|  | ||||
| /** | ||||
|  *  | ||||
|  * @author Daniel Qian | ||||
|  * | ||||
|  */ | ||||
| public class WxMediaUploadResultAdapter implements JsonDeserializer<WxMediaUploadResult> { | ||||
|  | ||||
|  | ||||
| @ -8,22 +8,13 @@ | ||||
|  */ | ||||
| package me.chanjar.weixin.common.util.json; | ||||
|  | ||||
| import com.google.gson.JsonArray; | ||||
| import com.google.gson.JsonDeserializationContext; | ||||
| import com.google.gson.JsonDeserializer; | ||||
| import com.google.gson.JsonElement; | ||||
| import com.google.gson.JsonObject; | ||||
| import com.google.gson.JsonParseException; | ||||
| import com.google.gson.JsonSerializationContext; | ||||
| import com.google.gson.JsonSerializer; | ||||
| import com.google.gson.*; | ||||
| import me.chanjar.weixin.common.bean.WxMenu; | ||||
|  | ||||
| import java.lang.reflect.Type; | ||||
|  | ||||
| /** | ||||
|  *  | ||||
|  * @author Daniel Qian | ||||
|  * | ||||
|  */ | ||||
| public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializer<WxMenu> { | ||||
|  | ||||
| @ -60,15 +51,15 @@ public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializ | ||||
|     return buttonJson; | ||||
|   } | ||||
|  | ||||
|   protected JsonObject convertToJson(WxMenu.WxMenuRule menuRule){ | ||||
|   protected JsonObject convertToJson(WxMenu.WxMenuRule menuRule) { | ||||
|     JsonObject matchRule = new JsonObject(); | ||||
|     matchRule.addProperty("tag_id",menuRule.getTagId()); | ||||
|     matchRule.addProperty("sex",menuRule.getSex()); | ||||
|     matchRule.addProperty("country",menuRule.getCountry()); | ||||
|     matchRule.addProperty("province",menuRule.getProvince()); | ||||
|     matchRule.addProperty("city",menuRule.getCity()); | ||||
|     matchRule.addProperty("client_platform_type",menuRule.getClientPlatformType()); | ||||
|     matchRule.addProperty("language",menuRule.getLanguage()); | ||||
|     matchRule.addProperty("tag_id", menuRule.getTagId()); | ||||
|     matchRule.addProperty("sex", menuRule.getSex()); | ||||
|     matchRule.addProperty("country", menuRule.getCountry()); | ||||
|     matchRule.addProperty("province", menuRule.getProvince()); | ||||
|     matchRule.addProperty("city", menuRule.getCity()); | ||||
|     matchRule.addProperty("client_platform_type", menuRule.getClientPlatformType()); | ||||
|     matchRule.addProperty("language", menuRule.getLanguage()); | ||||
|     return matchRule; | ||||
|   } | ||||
|  | ||||
|  | ||||
| @ -18,30 +18,24 @@ | ||||
| package me.chanjar.weixin.common.util.res; | ||||
|  | ||||
| import java.text.MessageFormat; | ||||
| import java.util.Enumeration; | ||||
| import java.util.Hashtable; | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.Locale; | ||||
| import java.util.Map; | ||||
| import java.util.MissingResourceException; | ||||
| import java.util.ResourceBundle; | ||||
| import java.util.*; | ||||
|  | ||||
| /** | ||||
|  * An internationalization / localization helper class which reduces | ||||
|  * the bother of handling ResourceBundles and takes care of the | ||||
|  * common cases of message formating which otherwise require the | ||||
|  * creation of Object arrays and such. | ||||
|  * | ||||
|  * <p> | ||||
|  * <p>The StringManager operates on a package basis. One StringManager | ||||
|  * per package can be created and accessed via the getManager method | ||||
|  * call. | ||||
|  * | ||||
|  * <p> | ||||
|  * <p>The StringManager will look for a ResourceBundle named by | ||||
|  * the package name given plus the suffix of "LocalStrings". In | ||||
|  * practice, this means that the localized information will be contained | ||||
|  * in a LocalStrings.properties file located in the package | ||||
|  * directory of the classpath. | ||||
|  * | ||||
|  * <p> | ||||
|  * <p>Please see the documentation for java.util.ResourceBundle for | ||||
|  * more information. | ||||
|  * | ||||
| @ -52,152 +46,80 @@ import java.util.ResourceBundle; | ||||
|  */ | ||||
| public class StringManager { | ||||
|  | ||||
|     private static int LOCALE_CACHE_SIZE = 10; | ||||
|   private static final Map<String, Map<Locale, StringManager>> managers = | ||||
|           new Hashtable<String, Map<Locale, StringManager>>(); | ||||
|   private static int LOCALE_CACHE_SIZE = 10; | ||||
|   /** | ||||
|    * The ResourceBundle for this StringManager. | ||||
|    */ | ||||
|   private final ResourceBundle bundle; | ||||
|   private final Locale locale; | ||||
|  | ||||
|     /** | ||||
|      * The ResourceBundle for this StringManager. | ||||
|      */ | ||||
|     private final ResourceBundle bundle; | ||||
|     private final Locale locale; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new StringManager for a given package. This is a | ||||
|      * private method and all access to it is arbitrated by the | ||||
|      * static getManager method call so that only one StringManager | ||||
|      * per package will be created. | ||||
|      * | ||||
|      * @param packageName Name of package to create StringManager for. | ||||
|      */ | ||||
|     private StringManager(String packageName, Locale locale) { | ||||
|         String bundleName = packageName + ".LocalStrings"; | ||||
|         ResourceBundle bnd = null; | ||||
|   /** | ||||
|    * Creates a new StringManager for a given package. This is a | ||||
|    * private method and all access to it is arbitrated by the | ||||
|    * static getManager method call so that only one StringManager | ||||
|    * per package will be created. | ||||
|    * | ||||
|    * @param packageName Name of package to create StringManager for. | ||||
|    */ | ||||
|   private StringManager(String packageName, Locale locale) { | ||||
|     String bundleName = packageName + ".LocalStrings"; | ||||
|     ResourceBundle bnd = null; | ||||
|     try { | ||||
|       bnd = ResourceBundle.getBundle(bundleName, locale); | ||||
|     } catch (MissingResourceException ex) { | ||||
|       // Try from the current loader (that's the case for trusted apps) | ||||
|       // Should only be required if using a TC5 style classloader structure | ||||
|       // where common != shared != server | ||||
|       ClassLoader cl = Thread.currentThread().getContextClassLoader(); | ||||
|       if (cl != null) { | ||||
|         try { | ||||
|             bnd = ResourceBundle.getBundle(bundleName, locale); | ||||
|         } catch( MissingResourceException ex ) { | ||||
|             // Try from the current loader (that's the case for trusted apps) | ||||
|             // Should only be required if using a TC5 style classloader structure | ||||
|             // where common != shared != server | ||||
|             ClassLoader cl = Thread.currentThread().getContextClassLoader(); | ||||
|             if( cl != null ) { | ||||
|                 try { | ||||
|                     bnd = ResourceBundle.getBundle(bundleName, locale, cl); | ||||
|                 } catch(MissingResourceException ex2) { | ||||
|                     // Ignore | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         bundle = bnd; | ||||
|         // Get the actual locale, which may be different from the requested one | ||||
|         if (bundle != null) { | ||||
|             Locale bundleLocale = bundle.getLocale(); | ||||
|             if (bundleLocale.equals(Locale.ROOT)) { | ||||
|                 this.locale = Locale.ENGLISH; | ||||
|             } else { | ||||
|                 this.locale = bundleLocale; | ||||
|             } | ||||
|         } else { | ||||
|             this.locale = null; | ||||
|           bnd = ResourceBundle.getBundle(bundleName, locale, cl); | ||||
|         } catch (MissingResourceException ex2) { | ||||
|           // Ignore | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|         Get a string from the underlying resource bundle or return | ||||
|         null if the String is not found. | ||||
|  | ||||
|         @param key to desired resource String | ||||
|         @return resource String matching <i>key</i> from underlying | ||||
|                 bundle or null if not found. | ||||
|         @throws IllegalArgumentException if <i>key</i> is null. | ||||
|      */ | ||||
|     public String getString(String key) { | ||||
|         if(key == null){ | ||||
|             String msg = "key may not have a null value"; | ||||
|  | ||||
|             throw new IllegalArgumentException(msg); | ||||
|         } | ||||
|  | ||||
|         String str = null; | ||||
|  | ||||
|         try { | ||||
|             // Avoid NPE if bundle is null and treat it like an MRE | ||||
|             if (bundle != null) { | ||||
|                 str = bundle.getString(key); | ||||
|             } | ||||
|         } catch(MissingResourceException mre) { | ||||
|             //bad: shouldn't mask an exception the following way: | ||||
|             //   str = "[cannot find message associated with key '" + key + | ||||
|             //         "' due to " + mre + "]"; | ||||
|             //     because it hides the fact that the String was missing | ||||
|             //     from the calling code. | ||||
|             //good: could just throw the exception (or wrap it in another) | ||||
|             //      but that would probably cause much havoc on existing | ||||
|             //      code. | ||||
|             //better: consistent with container pattern to | ||||
|             //      simply return null.  Calling code can then do | ||||
|             //      a null check. | ||||
|             str = null; | ||||
|         } | ||||
|  | ||||
|         return str; | ||||
|     bundle = bnd; | ||||
|     // Get the actual locale, which may be different from the requested one | ||||
|     if (bundle != null) { | ||||
|       Locale bundleLocale = bundle.getLocale(); | ||||
|       if (bundleLocale.equals(Locale.ROOT)) { | ||||
|         this.locale = Locale.ENGLISH; | ||||
|       } else { | ||||
|         this.locale = bundleLocale; | ||||
|       } | ||||
|     } else { | ||||
|       this.locale = null; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|     /** | ||||
|      * Get a string from the underlying resource bundle and format | ||||
|      * it with the given set of arguments. | ||||
|      * | ||||
|      * @param key | ||||
|      * @param args | ||||
|      */ | ||||
|     public String getString(final String key, final Object... args) { | ||||
|         String value = getString(key); | ||||
|         if (value == null) { | ||||
|             value = key; | ||||
|         } | ||||
|   /** | ||||
|    * Get the StringManager for a particular package. If a manager for | ||||
|    * a package already exists, it will be reused, else a new | ||||
|    * StringManager will be created and returned. | ||||
|    * | ||||
|    * @param packageName The package name | ||||
|    */ | ||||
|   public static final synchronized StringManager getManager( | ||||
|           String packageName) { | ||||
|     return getManager(packageName, Locale.getDefault()); | ||||
|   } | ||||
|  | ||||
|         MessageFormat mf = new MessageFormat(value); | ||||
|         mf.setLocale(locale); | ||||
|         return mf.format(args, new StringBuffer(), null).toString(); | ||||
|     } | ||||
|   /** | ||||
|    * Get the StringManager for a particular package and Locale. If a manager | ||||
|    * for a package/Locale combination already exists, it will be reused, else | ||||
|    * a new StringManager will be created and returned. | ||||
|    * | ||||
|    * @param packageName The package name | ||||
|    * @param locale      The Locale | ||||
|    */ | ||||
|   public static final synchronized StringManager getManager( | ||||
|           String packageName, Locale locale) { | ||||
|  | ||||
|     /** | ||||
|      * Identify the Locale this StringManager is associated with | ||||
|      */ | ||||
|     public Locale getLocale() { | ||||
|         return locale; | ||||
|     } | ||||
|  | ||||
|     // -------------------------------------------------------------- | ||||
|     // STATIC SUPPORT METHODS | ||||
|     // -------------------------------------------------------------- | ||||
|  | ||||
|     private static final Map<String, Map<Locale,StringManager>> managers = | ||||
|         new Hashtable<String, Map<Locale,StringManager>>(); | ||||
|  | ||||
|     /** | ||||
|      * Get the StringManager for a particular package. If a manager for | ||||
|      * a package already exists, it will be reused, else a new | ||||
|      * StringManager will be created and returned. | ||||
|      * | ||||
|      * @param packageName The package name | ||||
|      */ | ||||
|     public static final synchronized StringManager getManager( | ||||
|             String packageName) { | ||||
|         return getManager(packageName, Locale.getDefault()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get the StringManager for a particular package and Locale. If a manager | ||||
|      * for a package/Locale combination already exists, it will be reused, else | ||||
|      * a new StringManager will be created and returned. | ||||
|      * | ||||
|      * @param packageName The package name | ||||
|      * @param locale      The Locale | ||||
|      */ | ||||
|     public static final synchronized StringManager getManager( | ||||
|             String packageName, Locale locale) { | ||||
|  | ||||
|         Map<Locale,StringManager> map = managers.get(packageName); | ||||
|         if (map == null) { | ||||
|     Map<Locale, StringManager> map = managers.get(packageName); | ||||
|     if (map == null) { | ||||
|             /* | ||||
|              * Don't want the HashMap to be expanded beyond LOCALE_CACHE_SIZE. | ||||
|              * Expansion occurs when size() exceeds capacity. Therefore keep | ||||
| @ -206,43 +128,113 @@ public class StringManager { | ||||
|              * for removal needs to use one less than the maximum desired size | ||||
|              * | ||||
|              */ | ||||
|             map = new LinkedHashMap<Locale,StringManager>(LOCALE_CACHE_SIZE, 1, true) { | ||||
|                 private static final long serialVersionUID = 1L; | ||||
|                 @Override | ||||
|                 protected boolean removeEldestEntry( | ||||
|                         Map.Entry<Locale,StringManager> eldest) { | ||||
|                   return size() > (LOCALE_CACHE_SIZE - 1); | ||||
|                 } | ||||
|             }; | ||||
|             managers.put(packageName, map); | ||||
|         } | ||||
|       map = new LinkedHashMap<Locale, StringManager>(LOCALE_CACHE_SIZE, 1, true) { | ||||
|         private static final long serialVersionUID = 1L; | ||||
|  | ||||
|         StringManager mgr = map.get(locale); | ||||
|         if (mgr == null) { | ||||
|             mgr = new StringManager(packageName, locale); | ||||
|             map.put(locale, mgr); | ||||
|         @Override | ||||
|         protected boolean removeEldestEntry( | ||||
|                 Map.Entry<Locale, StringManager> eldest) { | ||||
|           return size() > (LOCALE_CACHE_SIZE - 1); | ||||
|         } | ||||
|         return mgr; | ||||
|       }; | ||||
|       managers.put(packageName, map); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Retrieve the StringManager for a list of Locales. The first StringManager | ||||
|      * found will be returned. | ||||
|      * | ||||
|      * @param requestedLocales the list of Locales | ||||
|      * | ||||
|      * @return the found StringManager or the default StringManager | ||||
|      */ | ||||
|     public static StringManager getManager(String packageName, | ||||
|             Enumeration<Locale> requestedLocales) { | ||||
|         while (requestedLocales.hasMoreElements()) { | ||||
|             Locale locale = requestedLocales.nextElement(); | ||||
|             StringManager result = getManager(packageName, locale); | ||||
|             if (result.getLocale().equals(locale)) { | ||||
|                 return result; | ||||
|             } | ||||
|         } | ||||
|         // Return the default | ||||
|         return getManager(packageName); | ||||
|     StringManager mgr = map.get(locale); | ||||
|     if (mgr == null) { | ||||
|       mgr = new StringManager(packageName, locale); | ||||
|       map.put(locale, mgr); | ||||
|     } | ||||
|     return mgr; | ||||
|   } | ||||
|  | ||||
|   // -------------------------------------------------------------- | ||||
|   // STATIC SUPPORT METHODS | ||||
|   // -------------------------------------------------------------- | ||||
|  | ||||
|   /** | ||||
|    * Retrieve the StringManager for a list of Locales. The first StringManager | ||||
|    * found will be returned. | ||||
|    * | ||||
|    * @param requestedLocales the list of Locales | ||||
|    * @return the found StringManager or the default StringManager | ||||
|    */ | ||||
|   public static StringManager getManager(String packageName, | ||||
|                                          Enumeration<Locale> requestedLocales) { | ||||
|     while (requestedLocales.hasMoreElements()) { | ||||
|       Locale locale = requestedLocales.nextElement(); | ||||
|       StringManager result = getManager(packageName, locale); | ||||
|       if (result.getLocale().equals(locale)) { | ||||
|         return result; | ||||
|       } | ||||
|     } | ||||
|     // Return the default | ||||
|     return getManager(packageName); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get a string from the underlying resource bundle or return | ||||
|    * null if the String is not found. | ||||
|    * | ||||
|    * @param key to desired resource String | ||||
|    * @return resource String matching <i>key</i> from underlying | ||||
|    * bundle or null if not found. | ||||
|    * @throws IllegalArgumentException if <i>key</i> is null. | ||||
|    */ | ||||
|   public String getString(String key) { | ||||
|     if (key == null) { | ||||
|       String msg = "key may not have a null value"; | ||||
|  | ||||
|       throw new IllegalArgumentException(msg); | ||||
|     } | ||||
|  | ||||
|     String str = null; | ||||
|  | ||||
|     try { | ||||
|       // Avoid NPE if bundle is null and treat it like an MRE | ||||
|       if (bundle != null) { | ||||
|         str = bundle.getString(key); | ||||
|       } | ||||
|     } catch (MissingResourceException mre) { | ||||
|       //bad: shouldn't mask an exception the following way: | ||||
|       //   str = "[cannot find message associated with key '" + key + | ||||
|       //         "' due to " + mre + "]"; | ||||
|       //     because it hides the fact that the String was missing | ||||
|       //     from the calling code. | ||||
|       //good: could just throw the exception (or wrap it in another) | ||||
|       //      but that would probably cause much havoc on existing | ||||
|       //      code. | ||||
|       //better: consistent with container pattern to | ||||
|       //      simply return null.  Calling code can then do | ||||
|       //      a null check. | ||||
|       str = null; | ||||
|     } | ||||
|  | ||||
|     return str; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get a string from the underlying resource bundle and format | ||||
|    * it with the given set of arguments. | ||||
|    * | ||||
|    * @param key | ||||
|    * @param args | ||||
|    */ | ||||
|   public String getString(final String key, final Object... args) { | ||||
|     String value = getString(key); | ||||
|     if (value == null) { | ||||
|       value = key; | ||||
|     } | ||||
|  | ||||
|     MessageFormat mf = new MessageFormat(value); | ||||
|     mf.setLocale(locale); | ||||
|     return mf.format(args, new StringBuffer(), null).toString(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Identify the Locale this StringManager is associated with | ||||
|    */ | ||||
|   public Locale getLocale() { | ||||
|     return locale; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,7 +1,5 @@ | ||||
| package me.chanjar.weixin.common.util.xml; | ||||
|  | ||||
| import java.io.Writer; | ||||
|  | ||||
| import com.thoughtworks.xstream.XStream; | ||||
| import com.thoughtworks.xstream.core.util.QuickWriter; | ||||
| import com.thoughtworks.xstream.io.HierarchicalStreamWriter; | ||||
| @ -10,6 +8,8 @@ import com.thoughtworks.xstream.io.xml.XppDriver; | ||||
| import com.thoughtworks.xstream.security.NullPermission; | ||||
| import com.thoughtworks.xstream.security.PrimitiveTypePermission; | ||||
|  | ||||
| import java.io.Writer; | ||||
|  | ||||
| public class XStreamInitializer { | ||||
|  | ||||
|   public static XStream getInstance() { | ||||
| @ -22,6 +22,7 @@ public class XStreamInitializer { | ||||
|           protected String SUFFIX_CDATA = "]]>"; | ||||
|           protected String PREFIX_MEDIA_ID = "<MediaId>"; | ||||
|           protected String SUFFIX_MEDIA_ID = "</MediaId>"; | ||||
|  | ||||
|           @Override | ||||
|           protected void writeText(QuickWriter writer, String text) { | ||||
|             if (text.startsWith(PREFIX_CDATA) && text.endsWith(SUFFIX_CDATA)) { | ||||
|  | ||||
| @ -8,13 +8,13 @@ import org.testng.annotations.Test; | ||||
| @Test | ||||
| public class WxMenuTest { | ||||
|  | ||||
|   @Test(dataProvider="wxReturnMenu") | ||||
|   @Test(dataProvider = "wxReturnMenu") | ||||
|   public void testFromJson(String json) { | ||||
|     WxMenu menu = WxMenu.fromJson(json); | ||||
|     Assert.assertEquals(menu.getButtons().size(), 3); | ||||
|   } | ||||
|  | ||||
|   @Test(dataProvider="wxPushMenu") | ||||
|   @Test(dataProvider = "wxPushMenu") | ||||
|   public void testToJson(String json) { | ||||
|     WxMenu menu = new WxMenu(); | ||||
|     WxMenuButton button1 = new WxMenuButton(); | ||||
| @ -81,78 +81,78 @@ public class WxMenuTest { | ||||
|  | ||||
|   @DataProvider | ||||
|   public Object[][] wxReturnMenu() { | ||||
|     Object[][]  res = menuJson(); | ||||
|     Object[][] res = menuJson(); | ||||
|     String json = "{ \"menu\" : " + res[0][0] + " }"; | ||||
|     return new Object[][] { | ||||
|         new Object[] { json } | ||||
|     return new Object[][]{ | ||||
|             new Object[]{json} | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   @DataProvider(name="wxPushMenu") | ||||
|   @DataProvider(name = "wxPushMenu") | ||||
|   public Object[][] menuJson() { | ||||
|     String json = | ||||
|         "{" | ||||
|             +"\"button\":[" | ||||
|               +"{" | ||||
|                 +"\"type\":\"click\"," | ||||
|                 +"\"name\":\"今日歌曲\"," | ||||
|                 +"\"key\":\"V1001_TODAY_MUSIC\"" | ||||
|               +"}," | ||||
|               +"{" | ||||
|                 +"\"type\":\"click\"," | ||||
|                 +"\"name\":\"歌手简介\"," | ||||
|                 +"\"key\":\"V1001_TODAY_SINGER\"" | ||||
|               +"}," | ||||
|               +"{" | ||||
|                 +"\"name\":\"菜单\"," | ||||
|                 +"\"sub_button\":[" | ||||
|                   +"{" | ||||
|                     +"\"type\":\"view\"," | ||||
|                     +"\"name\":\"搜索\"," | ||||
|                     +"\"url\":\"http://www.soso.com/\"" | ||||
|                   +"}," | ||||
|                   +"{" | ||||
|                     +"\"type\":\"view\"," | ||||
|                     +"\"name\":\"视频\"," | ||||
|                     +"\"url\":\"http://v.qq.com/\"" | ||||
|                   +"}," | ||||
|                   +"{" | ||||
|                   +"\"type\":\"click\"," | ||||
|                   +"\"name\":\"赞一下我们\"," | ||||
|                   +"\"key\":\"V1001_GOOD\"" | ||||
|                   +"}" | ||||
|                 +"]" | ||||
|               +"}" | ||||
|             +"]" | ||||
|         +"}"; | ||||
|     return new Object[][] { | ||||
|         new Object[] { json } | ||||
|             "{" | ||||
|                     + "\"button\":[" | ||||
|                     + "{" | ||||
|                     + "\"type\":\"click\"," | ||||
|                     + "\"name\":\"今日歌曲\"," | ||||
|                     + "\"key\":\"V1001_TODAY_MUSIC\"" | ||||
|                     + "}," | ||||
|                     + "{" | ||||
|                     + "\"type\":\"click\"," | ||||
|                     + "\"name\":\"歌手简介\"," | ||||
|                     + "\"key\":\"V1001_TODAY_SINGER\"" | ||||
|                     + "}," | ||||
|                     + "{" | ||||
|                     + "\"name\":\"菜单\"," | ||||
|                     + "\"sub_button\":[" | ||||
|                     + "{" | ||||
|                     + "\"type\":\"view\"," | ||||
|                     + "\"name\":\"搜索\"," | ||||
|                     + "\"url\":\"http://www.soso.com/\"" | ||||
|                     + "}," | ||||
|                     + "{" | ||||
|                     + "\"type\":\"view\"," | ||||
|                     + "\"name\":\"视频\"," | ||||
|                     + "\"url\":\"http://v.qq.com/\"" | ||||
|                     + "}," | ||||
|                     + "{" | ||||
|                     + "\"type\":\"click\"," | ||||
|                     + "\"name\":\"赞一下我们\"," | ||||
|                     + "\"key\":\"V1001_GOOD\"" | ||||
|                     + "}" | ||||
|                     + "]" | ||||
|                     + "}" | ||||
|                     + "]" | ||||
|                     + "}"; | ||||
|     return new Object[][]{ | ||||
|             new Object[]{json} | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   @DataProvider(name = "wxAddConditionalMenu") | ||||
|   public Object[][] addConditionalMenuJson(){ | ||||
|   public Object[][] addConditionalMenuJson() { | ||||
|     String json = | ||||
|         "{" | ||||
|             +"\"button\":[" | ||||
|             +"{" | ||||
|             +"\"type\":\"click\"," | ||||
|             +"\"name\":\"今日歌曲\"," | ||||
|             +"\"key\":\"V1001_TODAY_MUSIC\"" | ||||
|             +"}" | ||||
|             +"]," | ||||
|             +"\"matchrule\":{" | ||||
|               +"\"group_id\":\"2\"," | ||||
|               +"\"sex\":\"1\"," | ||||
|               +"\"country\":\"中国\"," | ||||
|               +"\"province\":\"广东\"," | ||||
|               +"\"city\":\"广州\"," | ||||
|               +"\"client_platform_type\":\"2\"," | ||||
|               +"\"language\":\"zh_CN\"" | ||||
|             +"}" | ||||
|             +"}"; | ||||
|             "{" | ||||
|                     + "\"button\":[" | ||||
|                     + "{" | ||||
|                     + "\"type\":\"click\"," | ||||
|                     + "\"name\":\"今日歌曲\"," | ||||
|                     + "\"key\":\"V1001_TODAY_MUSIC\"" | ||||
|                     + "}" | ||||
|                     + "]," | ||||
|                     + "\"matchrule\":{" | ||||
|                     + "\"group_id\":\"2\"," | ||||
|                     + "\"sex\":\"1\"," | ||||
|                     + "\"country\":\"中国\"," | ||||
|                     + "\"province\":\"广东\"," | ||||
|                     + "\"city\":\"广州\"," | ||||
|                     + "\"client_platform_type\":\"2\"," | ||||
|                     + "\"language\":\"zh_CN\"" | ||||
|                     + "}" | ||||
|                     + "}"; | ||||
|     return new Object[][]{ | ||||
|         new Object[]{json} | ||||
|             new Object[]{json} | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|  | ||||
| @ -10,8 +10,8 @@ public class SessionTest { | ||||
|   @DataProvider | ||||
|   public Object[][] getSessionManager() { | ||||
|  | ||||
|     return new Object[][] { | ||||
|         new Object[] { new StandardSessionManager() } | ||||
|     return new Object[][]{ | ||||
|             new Object[]{new StandardSessionManager()} | ||||
|     }; | ||||
|  | ||||
|   } | ||||
|  | ||||
| @ -8,7 +8,7 @@ import org.testng.annotations.Test; | ||||
| public class WxMessageInMemoryDuplicateCheckerTest { | ||||
|  | ||||
|   public void test() throws InterruptedException { | ||||
|     Long[] msgIds = new Long[] { 1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l }; | ||||
|     Long[] msgIds = new Long[]{1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l}; | ||||
|     WxMessageInMemoryDuplicateChecker checker = new WxMessageInMemoryDuplicateChecker(2000l, 1000l); | ||||
|  | ||||
|     // 第一次检查 | ||||
|  | ||||
| @ -69,7 +69,7 @@ public class WxCryptUtilTest { | ||||
|   } | ||||
|  | ||||
|   public void testValidateSignatureError() throws ParserConfigurationException, SAXException, | ||||
|       IOException { | ||||
|           IOException { | ||||
|     try { | ||||
|       WxCryptUtil pc = new WxCryptUtil(token, encodingAesKey, appId); | ||||
|       String afterEncrpt = pc.encrypt(replyMsg); | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 BinaryWang
					BinaryWang