| @@ -19,7 +19,7 @@ public class WxConsts { | |||||
| public static final String XML_MSG_LINK = "link"; | public static final String XML_MSG_LINK = "link"; | ||||
| public static final String XML_MSG_EVENT = "event"; | public static final String XML_MSG_EVENT = "event"; | ||||
| public static final String XML_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; | public static final String XML_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; | ||||
| /////////////////////// | /////////////////////// | ||||
| // 主动发送消息(即客服消息)的消息类型 | // 主动发送消息(即客服消息)的消息类型 | ||||
| /////////////////////// | /////////////////////// | ||||
| @@ -33,7 +33,7 @@ public class WxConsts { | |||||
| public static final String CUSTOM_MSG_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; | public static final String CUSTOM_MSG_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; | ||||
| public static final String CUSTOM_MSG_SAFE_NO = "0"; | public static final String CUSTOM_MSG_SAFE_NO = "0"; | ||||
| public static final String CUSTOM_MSG_SAFE_YES = "1"; | public static final String CUSTOM_MSG_SAFE_YES = "1"; | ||||
| /////////////////////// | /////////////////////// | ||||
| // 群发消息的消息类型 | // 群发消息的消息类型 | ||||
| /////////////////////// | /////////////////////// | ||||
| @@ -42,7 +42,7 @@ public class WxConsts { | |||||
| public static final String MASS_MSG_VOICE = "voice"; | public static final String MASS_MSG_VOICE = "voice"; | ||||
| public static final String MASS_MSG_IMAGE = "image"; | public static final String MASS_MSG_IMAGE = "image"; | ||||
| public static final String MASS_MSG_VIDEO = "mpvideo"; | public static final String MASS_MSG_VIDEO = "mpvideo"; | ||||
| /////////////////////// | /////////////////////// | ||||
| // 群发消息后微信端推送给服务器的反馈消息 | // 群发消息后微信端推送给服务器的反馈消息 | ||||
| /////////////////////// | /////////////////////// | ||||
| @@ -57,25 +57,11 @@ public class WxConsts { | |||||
| public static final String MASS_ST_涉嫌版权 = "err(20013)"; | public static final String MASS_ST_涉嫌版权 = "err(20013)"; | ||||
| public static final String MASS_ST_涉嫌互推_互相宣传 = "err(22000)"; | public static final String MASS_ST_涉嫌互推_互相宣传 = "err(22000)"; | ||||
| public static final String MASS_ST_涉嫌其他 = "err(21000)"; | public static final String MASS_ST_涉嫌其他 = "err(21000)"; | ||||
| /** | /** | ||||
| * 群发反馈消息代码所对应的文字描述 | * 群发反馈消息代码所对应的文字描述 | ||||
| */ | */ | ||||
| public static final Map<String, String> MASS_ST_2_DESC = new HashMap<String, String>(); | 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_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_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_CARD_SKU_REMIND = "card_sku_remind"; // 库存报警 | ||||
| public static final String EVT_KF_CREATE_SESSION = "kf_create_session"; // 客服接入会话 | 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_CLOSE_SESSION = "kf_close_session"; // 客服关闭会话 | ||||
| public static final String EVT_KF_SWITCH_SESSION = "kf_switch_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_VIDEO = "video"; | ||||
| public static final String MEDIA_THUMB = "thumb"; | public static final String MEDIA_THUMB = "thumb"; | ||||
| public static final String MEDIA_FILE = "file"; | 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_MP3 = "mp3"; | ||||
| public static final String FILE_AMR = "amr"; | public static final String FILE_AMR = "amr"; | ||||
| public static final String FILE_MP4 = "mp4"; | 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_VIEW = "view"; | ||||
| /** 扫码推事件 */ | |||||
| /** | |||||
| * 扫码推事件 | |||||
| */ | |||||
| public static final String BUTTON_SCANCODE_PUSH = "scancode_push"; | public static final String BUTTON_SCANCODE_PUSH = "scancode_push"; | ||||
| /** 扫码推事件且弹出“消息接收中”提示框 */ | |||||
| /** | |||||
| * 扫码推事件且弹出“消息接收中”提示框 | |||||
| */ | |||||
| public static final String BUTTON_SCANCODE_WAITMSG = "scancode_waitmsg"; | public static final String BUTTON_SCANCODE_WAITMSG = "scancode_waitmsg"; | ||||
| /** 弹出系统拍照发图 */ | |||||
| /** | |||||
| * 弹出系统拍照发图 | |||||
| */ | |||||
| public static final String BUTTON_PIC_SYSPHOTO = "pic_sysphoto"; | 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_PHOTO_OR_ALBUM = "pic_photo_or_album"; | ||||
| /** 弹出微信相册发图器 */ | |||||
| /** | |||||
| * 弹出微信相册发图器 | |||||
| */ | |||||
| public static final String BUTTON_PIC_WEIXIN = "pic_weixin"; | public static final String BUTTON_PIC_WEIXIN = "pic_weixin"; | ||||
| /** 弹出地理位置选择器 */ | |||||
| /** | |||||
| * 弹出地理位置选择器 | |||||
| */ | |||||
| public static final String BUTTON_LOCATION_SELECT = "location_select"; | public static final String BUTTON_LOCATION_SELECT = "location_select"; | ||||
| /** 下发消息(除文本消息) */ | |||||
| /** | |||||
| * 下发消息(除文本消息) | |||||
| */ | |||||
| public static final String BUTTON_MEDIA_ID = "media_id"; | public static final String BUTTON_MEDIA_ID = "media_id"; | ||||
| /** 跳转图文消息URL */ | |||||
| /** | |||||
| * 跳转图文消息URL | |||||
| */ | |||||
| public static final String BUTTON_VIEW_LIMITED = "view_limited"; | public static final String BUTTON_VIEW_LIMITED = "view_limited"; | ||||
| /** | |||||
| * 不弹出授权页面,直接跳转,只能获取用户openid | |||||
| */ | |||||
| public static final String OAUTH2_SCOPE_BASE = "snsapi_base"; | |||||
| /////////////////////// | /////////////////////// | ||||
| // oauth2网页授权的scope | // oauth2网页授权的scope | ||||
| /////////////////////// | /////////////////////// | ||||
| /** 不弹出授权页面,直接跳转,只能获取用户openid */ | |||||
| public static final String OAUTH2_SCOPE_BASE = "snsapi_base"; | |||||
| /** 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息 */ | |||||
| /** | |||||
| * 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息 | |||||
| */ | |||||
| public static final String OAUTH2_SCOPE_USER_INFO = "snsapi_userinfo"; | 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_VOICE = "voice"; | ||||
| public static final String MATERIAL_IMAGE = "image"; | public static final String MATERIAL_IMAGE = "image"; | ||||
| public static final String MATERIAL_VIDEO = "video"; | 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> | * <h2>公众号的排重方式</h2> | ||||
| * | |||||
| * <p> | |||||
| * <p>普通消息:关于重试的消息排重,推荐使用msgid排重。<a href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html">文档参考</a>。</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>事件消息:关于重试的消息排重,推荐使用FromUserName + CreateTime 排重。<a href="http://mp.weixin.qq.com/wiki/2/5baf56ce4947d35003b86a9805634b1e.html">文档参考</a></p> | ||||
| * | |||||
| * <p> | |||||
| * <h2>企业号的排重方式</h2> | * <h2>企业号的排重方式</h2> | ||||
| * | |||||
| * <p> | |||||
| * 官方文档完全没有写,参照公众号的方式排重。 | * 官方文档完全没有写,参照公众号的方式排重。 | ||||
| * | |||||
| * <p> | |||||
| * <p>或者可以采取更简单的方式,如果有MsgId就用MsgId排重,如果没有就用FromUserName+CreateTime排重</p> | * <p>或者可以采取更简单的方式,如果有MsgId就用MsgId排重,如果没有就用FromUserName+CreateTime排重</p> | ||||
| * | |||||
| * @param messageId messageId需要根据上面讲的方式构造 | * @param messageId messageId需要根据上面讲的方式构造 | ||||
| * @return 如果是重复消息,返回true,否则返回false | * @return 如果是重复消息,返回true,否则返回false | ||||
| */ | */ | ||||
| @@ -46,7 +46,8 @@ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChec | |||||
| /** | /** | ||||
| * WxMsgIdInMemoryDuplicateChecker构造函数 | * WxMsgIdInMemoryDuplicateChecker构造函数 | ||||
| * @param timeToLive 一个消息ID在内存的过期时间:毫秒 | |||||
| * | |||||
| * @param timeToLive 一个消息ID在内存的过期时间:毫秒 | |||||
| * @param clearPeriod 每隔多少周期检查消息ID是否过期:毫秒 | * @param clearPeriod 每隔多少周期检查消息ID是否过期:毫秒 | ||||
| */ | */ | ||||
| public WxMessageInMemoryDuplicateChecker(Long timeToLive, Long clearPeriod) { | public WxMessageInMemoryDuplicateChecker(Long timeToLive, Long clearPeriod) { | ||||
| @@ -8,9 +8,13 @@ public class WxAccessToken implements Serializable { | |||||
| private static final long serialVersionUID = 8709719312922168909L; | private static final long serialVersionUID = 8709719312922168909L; | ||||
| private String accessToken; | private String accessToken; | ||||
| private int expiresIn = -1; | private int expiresIn = -1; | ||||
| public static WxAccessToken fromJson(String json) { | |||||
| return WxGsonBuilder.create().fromJson(json, WxAccessToken.class); | |||||
| } | |||||
| public String getAccessToken() { | public String getAccessToken() { | ||||
| return accessToken; | return accessToken; | ||||
| } | } | ||||
| @@ -27,8 +31,4 @@ public class WxAccessToken implements Serializable { | |||||
| this.expiresIn = expiresIn; | this.expiresIn = expiresIn; | ||||
| } | } | ||||
| public static WxAccessToken fromJson(String json) { | |||||
| return WxGsonBuilder.create().fromJson(json, WxAccessToken.class); | |||||
| } | |||||
| } | } | ||||
| @@ -9,7 +9,7 @@ public class WxJsapiSignature implements Serializable { | |||||
| private static final long serialVersionUID = -1116808193154384804L; | private static final long serialVersionUID = -1116808193154384804L; | ||||
| private String appid; | private String appid; | ||||
| private String noncestr; | private String noncestr; | ||||
| private long timestamp; | private long timestamp; | ||||
| @@ -51,11 +51,11 @@ public class WxJsapiSignature implements Serializable { | |||||
| } | } | ||||
| public String getAppid() { | public String getAppid() { | ||||
| return appid; | |||||
| return appid; | |||||
| } | } | ||||
| public void setAppid(String appid) { | public void setAppid(String appid) { | ||||
| this.appid = appid; | |||||
| this.appid = appid; | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,5 +1,7 @@ | |||||
| package me.chanjar.weixin.common.bean; | package me.chanjar.weixin.common.bean; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
| import java.io.InputStream; | import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | import java.io.InputStreamReader; | ||||
| import java.io.Serializable; | import java.io.Serializable; | ||||
| @@ -7,12 +9,10 @@ import java.nio.charset.StandardCharsets; | |||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||
| import java.util.List; | import java.util.List; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
| /** | /** | ||||
| * 企业号菜单 | * 企业号菜单 | ||||
| * @author Daniel Qian | |||||
| * | * | ||||
| * @author Daniel Qian | |||||
| */ | */ | ||||
| public class WxMenu implements Serializable { | public class WxMenu implements Serializable { | ||||
| @@ -21,26 +21,6 @@ public class WxMenu implements Serializable { | |||||
| private List<WxMenuButton> buttons = new ArrayList<WxMenuButton>(); | private List<WxMenuButton> buttons = new ArrayList<WxMenuButton>(); | ||||
| private WxMenuRule matchRule; | private WxMenuRule matchRule; | ||||
| public List<WxMenuButton> getButtons() { | |||||
| return buttons; | |||||
| } | |||||
| public void setButtons(List<WxMenuButton> buttons) { | |||||
| this.buttons = buttons; | |||||
| } | |||||
| public WxMenuRule getMatchRule() { | |||||
| return matchRule; | |||||
| } | |||||
| public void setMatchRule(WxMenuRule matchRule) { | |||||
| this.matchRule = matchRule; | |||||
| } | |||||
| public String toJson() { | |||||
| return WxGsonBuilder.create().toJson(this); | |||||
| } | |||||
| /** | /** | ||||
| * 要用 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化 | * 要用 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化 | ||||
| @@ -58,11 +38,31 @@ public class WxMenu implements Serializable { | |||||
| return WxGsonBuilder.create().fromJson(new InputStreamReader(is, StandardCharsets.UTF_8), WxMenu.class); | return WxGsonBuilder.create().fromJson(new InputStreamReader(is, StandardCharsets.UTF_8), WxMenu.class); | ||||
| } | } | ||||
| public List<WxMenuButton> getButtons() { | |||||
| return buttons; | |||||
| } | |||||
| public void setButtons(List<WxMenuButton> buttons) { | |||||
| this.buttons = buttons; | |||||
| } | |||||
| public WxMenuRule getMatchRule() { | |||||
| return matchRule; | |||||
| } | |||||
| public void setMatchRule(WxMenuRule matchRule) { | |||||
| this.matchRule = matchRule; | |||||
| } | |||||
| public String toJson() { | |||||
| return WxGsonBuilder.create().toJson(this); | |||||
| } | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return "WxMenu{" + | return "WxMenu{" + | ||||
| "buttons=" + buttons + | |||||
| '}'; | |||||
| "buttons=" + buttons + | |||||
| '}'; | |||||
| } | } | ||||
| public static class WxMenuButton { | public static class WxMenuButton { | ||||
| @@ -71,7 +71,7 @@ public class WxMenu implements Serializable { | |||||
| private String name; | private String name; | ||||
| private String key; | private String key; | ||||
| private String url; | private String url; | ||||
| private List<WxMenuButton> subButtons = new ArrayList<WxMenuButton>(); | private List<WxMenuButton> subButtons = new ArrayList<WxMenuButton>(); | ||||
| public String getType() { | public String getType() { | ||||
| @@ -117,15 +117,15 @@ public class WxMenu implements Serializable { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return "WxMenuButton{" + | return "WxMenuButton{" + | ||||
| "type='" + type + '\'' + | |||||
| ", name='" + name + '\'' + | |||||
| ", key='" + key + '\'' + | |||||
| ", url='" + url + '\'' + | |||||
| ", subButtons=" + subButtons + | |||||
| '}'; | |||||
| "type='" + type + '\'' + | |||||
| ", name='" + name + '\'' + | |||||
| ", key='" + key + '\'' + | |||||
| ", url='" + url + '\'' + | |||||
| ", subButtons=" + subButtons + | |||||
| '}'; | |||||
| } | } | ||||
| } | } | ||||
| public static class WxMenuRule { | public static class WxMenuRule { | ||||
| private String tagId; | private String tagId; | ||||
| private String sex; | private String sex; | ||||
| @@ -134,51 +134,51 @@ public class WxMenu implements Serializable { | |||||
| private String city; | private String city; | ||||
| private String clientPlatformType; | private String clientPlatformType; | ||||
| private String language; | private String language; | ||||
| public String getTagId() { | public String getTagId() { | ||||
| return tagId; | return tagId; | ||||
| } | } | ||||
| public void setTagId(String tagId) { | public void setTagId(String tagId) { | ||||
| this.tagId = tagId; | this.tagId = tagId; | ||||
| } | } | ||||
| public String getSex() { | public String getSex() { | ||||
| return sex; | return sex; | ||||
| } | } | ||||
| public void setSex(String sex) { | public void setSex(String sex) { | ||||
| this.sex = sex; | this.sex = sex; | ||||
| } | } | ||||
| public String getCountry() { | public String getCountry() { | ||||
| return country; | return country; | ||||
| } | } | ||||
| public void setCountry(String country) { | public void setCountry(String country) { | ||||
| this.country = country; | this.country = country; | ||||
| } | } | ||||
| public String getProvince() { | public String getProvince() { | ||||
| return province; | return province; | ||||
| } | } | ||||
| public void setProvince(String province) { | public void setProvince(String province) { | ||||
| this.province = province; | this.province = province; | ||||
| } | } | ||||
| public String getCity() { | public String getCity() { | ||||
| return city; | return city; | ||||
| } | } | ||||
| public void setCity(String city) { | public void setCity(String city) { | ||||
| this.city = city; | this.city = city; | ||||
| } | } | ||||
| public String getClientPlatformType() { | public String getClientPlatformType() { | ||||
| return clientPlatformType; | return clientPlatformType; | ||||
| } | } | ||||
| public void setClientPlatformType(String clientPlatformType) { | public void setClientPlatformType(String clientPlatformType) { | ||||
| this.clientPlatformType = clientPlatformType; | this.clientPlatformType = clientPlatformType; | ||||
| } | } | ||||
| @@ -194,15 +194,15 @@ public class WxMenu implements Serializable { | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return "matchrule:{" + | 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,19 +6,28 @@ import java.io.Serializable; | |||||
| /** | /** | ||||
| * 微信错误码说明,请阅读: <a href="http://mp.weixin.qq.com/wiki/10/6380dc743053a91c544ffd2b7c959166.html">全局返回码说明</a> | * 微信错误码说明,请阅读: <a href="http://mp.weixin.qq.com/wiki/10/6380dc743053a91c544ffd2b7c959166.html">全局返回码说明</a> | ||||
| * @author Daniel Qian | |||||
| * | * | ||||
| * @author Daniel Qian | |||||
| */ | */ | ||||
| public class WxError implements Serializable { | public class WxError implements Serializable { | ||||
| private static final long serialVersionUID = 7869786563361406291L; | private static final long serialVersionUID = 7869786563361406291L; | ||||
| private int errorCode; | private int errorCode; | ||||
| private String errorMsg; | private String errorMsg; | ||||
| private String json; | 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() { | public int getErrorCode() { | ||||
| return errorCode; | return errorCode; | ||||
| } | } | ||||
| @@ -43,43 +52,34 @@ public class WxError implements Serializable { | |||||
| this.json = json; | this.json = json; | ||||
| } | } | ||||
| public static WxError fromJson(String json) { | |||||
| WxError error = WxGsonBuilder.create().fromJson(json, WxError.class); | |||||
| return error; | |||||
| } | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| if(json != null){ | |||||
| if (json != null) { | |||||
| return json; | return json; | ||||
| } | } | ||||
| return "错误: Code=" + errorCode + ", Msg=" + errorMsg; | return "错误: Code=" + errorCode + ", Msg=" + errorMsg; | ||||
| } | } | ||||
| public static Builder newBuilder(){ | |||||
| return new Builder(); | |||||
| } | |||||
| public static class Builder{ | |||||
| public static class Builder { | |||||
| private int errorCode; | private int errorCode; | ||||
| private String errorMsg; | private String errorMsg; | ||||
| public Builder setErrorCode(int errorCode) { | public Builder setErrorCode(int errorCode) { | ||||
| this.errorCode = errorCode; | this.errorCode = errorCode; | ||||
| return this; | return this; | ||||
| } | } | ||||
| public Builder setErrorMsg(String errorMsg) { | public Builder setErrorMsg(String errorMsg) { | ||||
| this.errorMsg = errorMsg; | this.errorMsg = errorMsg; | ||||
| return this; | return this; | ||||
| } | } | ||||
| public WxError build(){ | |||||
| public WxError build() { | |||||
| WxError wxError = new WxError(); | WxError wxError = new WxError(); | ||||
| wxError.setErrorCode(this.errorCode); | wxError.setErrorCode(this.errorCode); | ||||
| wxError.setErrorMsg(this.errorMsg); | wxError.setErrorMsg(this.errorMsg); | ||||
| return wxError; | return wxError; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -6,12 +6,16 @@ import java.io.Serializable; | |||||
| public class WxMediaUploadResult implements Serializable { | public class WxMediaUploadResult implements Serializable { | ||||
| private static final long serialVersionUID = 330834334738622341L; | private static final long serialVersionUID = 330834334738622341L; | ||||
| private String type; | private String type; | ||||
| private String mediaId; | private String mediaId; | ||||
| private String thumbMediaId; | private String thumbMediaId; | ||||
| private long createdAt; | private long createdAt; | ||||
| public static WxMediaUploadResult fromJson(String json) { | |||||
| return WxGsonBuilder.create().fromJson(json, WxMediaUploadResult.class); | |||||
| } | |||||
| public String getType() { | public String getType() { | ||||
| return type; | return type; | ||||
| } | } | ||||
| @@ -44,14 +48,10 @@ public class WxMediaUploadResult implements Serializable { | |||||
| this.thumbMediaId = thumbMediaId; | this.thumbMediaId = thumbMediaId; | ||||
| } | } | ||||
| public static WxMediaUploadResult fromJson(String json) { | |||||
| return WxGsonBuilder.create().fromJson(json, WxMediaUploadResult.class); | |||||
| } | |||||
| @Override | @Override | ||||
| public String toString() { | public String toString() { | ||||
| return "WxUploadResult [type=" + type + ", media_id=" + mediaId + ", thumb_media_id=" + thumbMediaId | return "WxUploadResult [type=" + type + ", media_id=" + mediaId + ", thumb_media_id=" + thumbMediaId | ||||
| + ", created_at=" + createdAt + "]"; | |||||
| + ", created_at=" + createdAt + "]"; | |||||
| } | } | ||||
| } | } | ||||
| @@ -5,7 +5,7 @@ import me.chanjar.weixin.common.bean.result.WxError; | |||||
| public class WxErrorException extends Exception { | public class WxErrorException extends Exception { | ||||
| private static final long serialVersionUID = -6357149550353160810L; | private static final long serialVersionUID = -6357149550353160810L; | ||||
| private WxError error; | private WxError error; | ||||
| public WxErrorException(WxError error) { | public WxErrorException(WxError error) { | ||||
| @@ -17,5 +17,5 @@ public class WxErrorException extends Exception { | |||||
| return error; | return error; | ||||
| } | } | ||||
| } | } | ||||
| @@ -26,6 +26,6 @@ package me.chanjar.weixin.common.session; | |||||
| public class Constants { | 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(); | WxSession getSession(); | ||||
| /** | |||||
| * Return the <code>isValid</code> flag for this session. | |||||
| */ | |||||
| boolean isValid(); | |||||
| /** | /** | ||||
| * Set the <code>isValid</code> flag for this session. | * Set the <code>isValid</code> flag for this session. | ||||
| * | * | ||||
| @@ -15,11 +20,6 @@ public interface InternalSession { | |||||
| */ | */ | ||||
| void setValid(boolean isValid); | void setValid(boolean isValid); | ||||
| /** | |||||
| * Return the <code>isValid</code> flag for this session. | |||||
| */ | |||||
| boolean isValid(); | |||||
| /** | /** | ||||
| * Return the session identifier for this session. | * Return the session identifier for this session. | ||||
| */ | */ | ||||
| @@ -7,11 +7,10 @@ public interface InternalSessionManager { | |||||
| * specified session id (if any); otherwise return <code>null</code>. | * specified session id (if any); otherwise return <code>null</code>. | ||||
| * | * | ||||
| * @param id The session id for the session to be returned | * @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); | InternalSession findSession(String id); | ||||
| @@ -23,10 +22,10 @@ public interface InternalSessionManager { | |||||
| * <code>null</code>. | * <code>null</code>. | ||||
| * | * | ||||
| * @param sessionId The session id which should be used to create the | * @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); | InternalSession createSession(String sessionId); | ||||
| @@ -40,8 +39,8 @@ public interface InternalSessionManager { | |||||
| /** | /** | ||||
| * Remove this Session from the active Sessions for this Manager. | * 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); | void remove(InternalSession session, boolean update); | ||||
| @@ -59,6 +58,7 @@ public interface InternalSessionManager { | |||||
| * @return number of sessions active | * @return number of sessions active | ||||
| */ | */ | ||||
| int getActiveSessions(); | int getActiveSessions(); | ||||
| /** | /** | ||||
| * Get a session from the recycled ones or create a new empty one. | * Get a session from the recycled ones or create a new empty one. | ||||
| * The PersistentManager manager does not need to create session data | * The PersistentManager manager does not need to create session data | ||||
| @@ -88,6 +88,7 @@ public interface InternalSessionManager { | |||||
| * 要和{@link #setBackgroundProcessorDelay(int)}联合起来看 | * 要和{@link #setBackgroundProcessorDelay(int)}联合起来看 | ||||
| * 如果把这个数字设置为6(默认),那么就是说manager要等待 6 * backgroundProcessorDay的时间才会清理过期session | * 如果把这个数字设置为6(默认),那么就是说manager要等待 6 * backgroundProcessorDay的时间才会清理过期session | ||||
| * </pre> | * </pre> | ||||
| * | |||||
| * @param processExpiresFrequency the new manager checks frequency | * @param processExpiresFrequency the new manager checks frequency | ||||
| */ | */ | ||||
| void setProcessExpiresFrequency(int processExpiresFrequency); | void setProcessExpiresFrequency(int processExpiresFrequency); | ||||
| @@ -97,6 +98,7 @@ public interface InternalSessionManager { | |||||
| * Set the manager background processor delay | * Set the manager background processor delay | ||||
| * 设置manager sleep几秒,尝试执行一次background操作(清理过期session) | * 设置manager sleep几秒,尝试执行一次background操作(清理过期session) | ||||
| * </pre> | * </pre> | ||||
| * | |||||
| * @param backgroundProcessorDelay | * @param backgroundProcessorDelay | ||||
| */ | */ | ||||
| void setBackgroundProcessorDelay(int backgroundProcessorDelay); | void setBackgroundProcessorDelay(int backgroundProcessorDelay); | ||||
| @@ -106,6 +108,7 @@ public interface InternalSessionManager { | |||||
| * Set the maximum number of active Sessions allowed, or -1 for | * Set the maximum number of active Sessions allowed, or -1 for | ||||
| * no limit. | * no limit. | ||||
| * 设置最大活跃session数,默认无限 | * 设置最大活跃session数,默认无限 | ||||
| * | |||||
| * @param max The new maximum number of sessions | * @param max The new maximum number of sessions | ||||
| */ | */ | ||||
| void setMaxActiveSessions(int max); | void setMaxActiveSessions(int max); | ||||
| @@ -12,7 +12,6 @@ | |||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | # limitations under the License. | ||||
| applicationSession.session.ise=invalid session state | applicationSession.session.ise=invalid session state | ||||
| applicationSession.value.iae=null value | applicationSession.value.iae=null value | ||||
| fileStore.saving=Saving Session {0} to file {1} | fileStore.saving=Saving Session {0} to file {1} | ||||
| @@ -12,17 +12,68 @@ public class StandardSession implements WxSession, InternalSession { | |||||
| * The string manager for this package. | * The string manager for this package. | ||||
| */ | */ | ||||
| protected static final StringManager sm = | 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 | // ------------------------------ WxSession | ||||
| protected Map<String, Object> attributes = new ConcurrentHashMap<String, Object>(); | 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 | @Override | ||||
| public Object getAttribute(String name) { | public Object getAttribute(String name) { | ||||
| if (!isValidInternal()) | if (!isValidInternal()) | ||||
| throw new IllegalStateException | throw new IllegalStateException | ||||
| (sm.getString("sessionImpl.getAttribute.ise")); | |||||
| (sm.getString("sessionImpl.getAttribute.ise")); | |||||
| if (name == null) return null; | if (name == null) return null; | ||||
| @@ -33,7 +84,7 @@ public class StandardSession implements WxSession, InternalSession { | |||||
| public Enumeration<String> getAttributeNames() { | public Enumeration<String> getAttributeNames() { | ||||
| if (!isValidInternal()) | if (!isValidInternal()) | ||||
| throw new IllegalStateException | throw new IllegalStateException | ||||
| (sm.getString("sessionImpl.getAttributeNames.ise")); | |||||
| (sm.getString("sessionImpl.getAttributeNames.ise")); | |||||
| Set<String> names = new HashSet<String>(); | Set<String> names = new HashSet<String>(); | ||||
| names.addAll(attributes.keySet()); | names.addAll(attributes.keySet()); | ||||
| @@ -45,7 +96,7 @@ public class StandardSession implements WxSession, InternalSession { | |||||
| // Name cannot be null | // Name cannot be null | ||||
| if (name == null) | if (name == null) | ||||
| throw new IllegalArgumentException | throw new IllegalArgumentException | ||||
| (sm.getString("sessionImpl.setAttribute.namenull")); | |||||
| (sm.getString("sessionImpl.setAttribute.namenull")); | |||||
| // Null value is the same as removeAttribute() | // Null value is the same as removeAttribute() | ||||
| if (value == null) { | if (value == null) { | ||||
| @@ -56,97 +107,32 @@ public class StandardSession implements WxSession, InternalSession { | |||||
| // Validate our current state | // Validate our current state | ||||
| if (!isValidInternal()) | if (!isValidInternal()) | ||||
| throw new IllegalStateException(sm.getString( | throw new IllegalStateException(sm.getString( | ||||
| "sessionImpl.setAttribute.ise", getIdInternal())); | |||||
| "sessionImpl.setAttribute.ise", getIdInternal())); | |||||
| attributes.put(name, value); | attributes.put(name, value); | ||||
| } | } | ||||
| @Override | @Override | ||||
| public void removeAttribute(String name) { | public void removeAttribute(String name) { | ||||
| removeAttributeInternal(name); | removeAttributeInternal(name); | ||||
| } | } | ||||
| @Override | @Override | ||||
| public void invalidate() { | public void invalidate() { | ||||
| if (!isValidInternal()) | if (!isValidInternal()) | ||||
| throw new IllegalStateException | throw new IllegalStateException | ||||
| (sm.getString("sessionImpl.invalidate.ise")); | |||||
| (sm.getString("sessionImpl.invalidate.ise")); | |||||
| // Cause this session to expire | // Cause this session to expire | ||||
| 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 | @Override | ||||
| public WxSession getSession() { | public WxSession getSession() { | ||||
| if (facade == null){ | |||||
| if (facade == null) { | |||||
| facade = new StandardSessionFacade(this); | facade = new StandardSessionFacade(this); | ||||
| } | } | ||||
| return (facade); | return (facade); | ||||
| @@ -161,16 +147,6 @@ public class StandardSession implements WxSession, InternalSession { | |||||
| return this.isValid; | 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 | @Override | ||||
| public boolean isValid() { | public boolean isValid() { | ||||
| if (!this.isValid) { | if (!this.isValid) { | ||||
| @@ -197,6 +173,16 @@ public class StandardSession implements WxSession, InternalSession { | |||||
| return this.isValid; | 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 | @Override | ||||
| public String getIdInternal() { | public String getIdInternal() { | ||||
| return (this.id); | return (this.id); | ||||
| @@ -13,60 +13,26 @@ import java.util.concurrent.atomic.AtomicBoolean; | |||||
| */ | */ | ||||
| public class StandardSessionManager implements WxSessionManager, InternalSessionManager { | public class StandardSessionManager implements WxSessionManager, InternalSessionManager { | ||||
| protected final Logger log = LoggerFactory.getLogger(StandardSessionManager.class); | |||||
| protected static final StringManager sm = | protected static final StringManager sm = | ||||
| StringManager.getManager(Constants.Package); | |||||
| StringManager.getManager(Constants.Package); | |||||
| /** | /** | ||||
| * The set of currently active Sessions for this Manager, keyed by | |||||
| * session identifier. | |||||
| * The descriptive name of this Manager implementation (for logging). | |||||
| */ | */ | ||||
| protected Map<String, InternalSession> sessions = new ConcurrentHashMap<String, InternalSession>(); | |||||
| @Override | |||||
| public WxSession getSession(String sessionId) { | |||||
| return getSession(sessionId, true); | |||||
| } | |||||
| @Override | |||||
| public WxSession getSession(String sessionId, boolean create) { | |||||
| if (sessionId == null) { | |||||
| throw new IllegalStateException | |||||
| (sm.getString("sessionManagerImpl.getSession.ise")); | |||||
| } | |||||
| InternalSession session = findSession(sessionId); | |||||
| if ((session != null) && !session.isValid()) { | |||||
| session = null; | |||||
| } | |||||
| if (session != null) { | |||||
| session.access(); | |||||
| return session.getSession(); | |||||
| } | |||||
| // Create a new session if requested and the response is not committed | |||||
| if (!create) { | |||||
| return (null); | |||||
| } | |||||
| session = createSession(sessionId); | |||||
| if (session == null) { | |||||
| return null; | |||||
| } | |||||
| session.access(); | |||||
| return session.getSession(); | |||||
| } | |||||
| 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 | // -------------------------------------- InternalSessionManager | ||||
| /** | /** | ||||
| * The descriptive name of this Manager implementation (for logging). | |||||
| * The set of currently active Sessions for this Manager, keyed by | |||||
| * session identifier. | |||||
| */ | */ | ||||
| private static final String name = "SessionManagerImpl"; | |||||
| protected Map<String, InternalSession> sessions = new ConcurrentHashMap<String, InternalSession>(); | |||||
| /** | /** | ||||
| * The maximum number of active Sessions allowed, or -1 for no limit. | * The maximum number of active Sessions allowed, or -1 for no limit. | ||||
| */ | */ | ||||
| @@ -84,22 +50,13 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||||
| protected int maxInactiveInterval = 30 * 60; | protected int maxInactiveInterval = 30 * 60; | ||||
| // Number of sessions created by this manager | // Number of sessions created by this manager | ||||
| protected long sessionCounter=0; | |||||
| protected volatile int maxActive=0; | |||||
| private final Object maxActiveUpdateLock = new Object(); | |||||
| protected long sessionCounter = 0; | |||||
| protected volatile int maxActive = 0; | |||||
| /** | /** | ||||
| * Processing time during session expiration. | * Processing time during session expiration. | ||||
| */ | */ | ||||
| protected long processingTime = 0; | protected long processingTime = 0; | ||||
| /** | |||||
| * Iteration count for background processing. | |||||
| */ | |||||
| private int count = 0; | |||||
| /** | /** | ||||
| * Frequency of the session expiration, and related manager operations. | * Frequency of the session expiration, and related manager operations. | ||||
| * Manager operations will be done once for the specified amount of | * Manager operations will be done once for the specified amount of | ||||
| @@ -107,16 +64,50 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||||
| * checks will occur). | * checks will occur). | ||||
| */ | */ | ||||
| protected int processExpiresFrequency = 6; | protected int processExpiresFrequency = 6; | ||||
| /** | /** | ||||
| * background processor delay in seconds | * background processor delay in seconds | ||||
| */ | */ | ||||
| protected int backgroundProcessorDelay = 10; | protected int backgroundProcessorDelay = 10; | ||||
| /** | /** | ||||
| * 后台清理线程是否已经开启 | |||||
| * Iteration count for background processing. | |||||
| */ | */ | ||||
| private final AtomicBoolean backgroundProcessStarted = new AtomicBoolean(false); | |||||
| private int count = 0; | |||||
| @Override | |||||
| public WxSession getSession(String sessionId) { | |||||
| return getSession(sessionId, true); | |||||
| } | |||||
| @Override | |||||
| public WxSession getSession(String sessionId, boolean create) { | |||||
| if (sessionId == null) { | |||||
| throw new IllegalStateException | |||||
| (sm.getString("sessionManagerImpl.getSession.ise")); | |||||
| } | |||||
| InternalSession session = findSession(sessionId); | |||||
| if ((session != null) && !session.isValid()) { | |||||
| session = null; | |||||
| } | |||||
| if (session != null) { | |||||
| session.access(); | |||||
| return session.getSession(); | |||||
| } | |||||
| // Create a new session if requested and the response is not committed | |||||
| if (!create) { | |||||
| return (null); | |||||
| } | |||||
| session = createSession(sessionId); | |||||
| if (session == null) { | |||||
| return null; | |||||
| } | |||||
| session.access(); | |||||
| return session.getSession(); | |||||
| } | |||||
| @Override | @Override | ||||
| public void remove(InternalSession session) { | public void remove(InternalSession session) { | ||||
| @@ -131,7 +122,6 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||||
| } | } | ||||
| @Override | @Override | ||||
| public InternalSession findSession(String id) { | public InternalSession findSession(String id) { | ||||
| @@ -145,15 +135,15 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||||
| public InternalSession createSession(String sessionId) { | public InternalSession createSession(String sessionId) { | ||||
| if (sessionId == null) { | if (sessionId == null) { | ||||
| throw new IllegalStateException | throw new IllegalStateException | ||||
| (sm.getString("sessionManagerImpl.createSession.ise")); | |||||
| (sm.getString("sessionManagerImpl.createSession.ise")); | |||||
| } | } | ||||
| if ((maxActiveSessions >= 0) && | if ((maxActiveSessions >= 0) && | ||||
| (getActiveSessions() >= maxActiveSessions)) { | |||||
| (getActiveSessions() >= maxActiveSessions)) { | |||||
| rejectedSessions++; | rejectedSessions++; | ||||
| throw new TooManyActiveSessionsException( | throw new TooManyActiveSessionsException( | ||||
| sm.getString("sessionManagerImpl.createSession.tmase"), | |||||
| maxActiveSessions); | |||||
| sm.getString("sessionManagerImpl.createSession.tmase"), | |||||
| maxActiveSessions); | |||||
| } | } | ||||
| // Recycle or create a Session instance | // Recycle or create a Session instance | ||||
| @@ -216,14 +206,14 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||||
| sessions.put(session.getIdInternal(), session); | sessions.put(session.getIdInternal(), session); | ||||
| int size = getActiveSessions(); | int size = getActiveSessions(); | ||||
| if( size > maxActive ) { | |||||
| synchronized(maxActiveUpdateLock) { | |||||
| if( size > maxActive ) { | |||||
| if (size > maxActive) { | |||||
| synchronized (maxActiveUpdateLock) { | |||||
| if (size > maxActive) { | |||||
| maxActive = size; | maxActive = size; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| @@ -251,19 +241,19 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||||
| long timeNow = System.currentTimeMillis(); | long timeNow = System.currentTimeMillis(); | ||||
| InternalSession sessions[] = findSessions(); | 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); | log.debug("Start expire sessions {} at {} sessioncount {}", getName(), timeNow, sessions.length); | ||||
| for (int i = 0; i < sessions.length; i++) { | for (int i = 0; i < sessions.length; i++) { | ||||
| if (sessions[i]!=null && !sessions[i].isValid()) { | |||||
| if (sessions[i] != null && !sessions[i].isValid()) { | |||||
| expireHere++; | expireHere++; | ||||
| } | } | ||||
| } | } | ||||
| long timeEnd = System.currentTimeMillis(); | long timeEnd = System.currentTimeMillis(); | ||||
| if(log.isDebugEnabled()) | |||||
| if (log.isDebugEnabled()) | |||||
| log.debug("End expire sessions {} processingTime {} expired sessions: {}", getName(), timeEnd - timeNow, expireHere); | 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. | * reached and the server is refusing to create any new sessions. | ||||
| */ | */ | ||||
| public class TooManyActiveSessionsException | 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); | |||||
| 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; | |||||
| } | |||||
| /** | |||||
| * 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; | |||||
| } | |||||
| /** | |||||
| * 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>Checks if a CharSequence is whitespace, empty ("") or null.</p> | ||||
| * | |||||
| * <p> | |||||
| * <pre> | * <pre> | ||||
| * StringUtils.isBlank(null) = true | * StringUtils.isBlank(null) = true | ||||
| * StringUtils.isBlank("") = true | * StringUtils.isBlank("") = true | ||||
| @@ -16,9 +16,8 @@ public class StringUtils { | |||||
| * StringUtils.isBlank(" bob ") = false | * StringUtils.isBlank(" bob ") = false | ||||
| * </pre> | * </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 | * @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) | * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence) | ||||
| */ | */ | ||||
| public static boolean isBlank(CharSequence cs) { | 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>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p> | ||||
| * | |||||
| * <p> | |||||
| * <pre> | * <pre> | ||||
| * StringUtils.isNotBlank(null) = false | * StringUtils.isNotBlank(null) = false | ||||
| * StringUtils.isNotBlank("") = false | * StringUtils.isNotBlank("") = false | ||||
| @@ -45,10 +44,9 @@ public class StringUtils { | |||||
| * StringUtils.isNotBlank(" bob ") = true | * StringUtils.isNotBlank(" bob ") = true | ||||
| * </pre> | * </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 | * @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) | * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence) | ||||
| */ | */ | ||||
| public static boolean isNotBlank(CharSequence cs) { | public static boolean isNotBlank(CharSequence cs) { | ||||
| @@ -57,7 +55,7 @@ public class StringUtils { | |||||
| /** | /** | ||||
| * <p>Checks if a CharSequence is empty ("") or null.</p> | * <p>Checks if a CharSequence is empty ("") or null.</p> | ||||
| * | |||||
| * <p> | |||||
| * <pre> | * <pre> | ||||
| * StringUtils.isEmpty(null) = true | * StringUtils.isEmpty(null) = true | ||||
| * StringUtils.isEmpty("") = true | * StringUtils.isEmpty("") = true | ||||
| @@ -65,12 +63,12 @@ public class StringUtils { | |||||
| * StringUtils.isEmpty("bob") = false | * StringUtils.isEmpty("bob") = false | ||||
| * StringUtils.isEmpty(" bob ") = false | * StringUtils.isEmpty(" bob ") = false | ||||
| * </pre> | * </pre> | ||||
| * | |||||
| * <p> | |||||
| * <p>NOTE: This method changed in Lang version 2.0. | * <p>NOTE: This method changed in Lang version 2.0. | ||||
| * It no longer trims the CharSequence. | * It no longer trims the CharSequence. | ||||
| * That functionality is available in isBlank().</p> | * 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 | * @return {@code true} if the CharSequence is empty or null | ||||
| * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) | * @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>Checks if a CharSequence is not empty ("") and not null.</p> | ||||
| * | |||||
| * <p> | |||||
| * <pre> | * <pre> | ||||
| * StringUtils.isNotEmpty(null) = false | * StringUtils.isNotEmpty(null) = false | ||||
| * StringUtils.isNotEmpty("") = false | * StringUtils.isNotEmpty("") = false | ||||
| @@ -89,7 +87,7 @@ public class StringUtils { | |||||
| * StringUtils.isNotEmpty(" bob ") = true | * StringUtils.isNotEmpty(" bob ") = true | ||||
| * </pre> | * </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 | * @return {@code true} if the CharSequence is not empty and not null | ||||
| * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence) | * @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; | import java.util.ArrayList; | ||||
| public class ByteGroup { | public class ByteGroup { | ||||
| ArrayList<Byte> byteContainer = new ArrayList<Byte>(); | |||||
| ArrayList<Byte> byteContainer = new ArrayList<Byte>(); | |||||
| public byte[] toBytes() { | 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(); | |||||
| } | |||||
| } | } | ||||
| @@ -1,6 +1,6 @@ | |||||
| /** | /** | ||||
| * 对公众平台发送给公众账号的消息加解密示例代码. | * 对公众平台发送给公众账号的消息加解密示例代码. | ||||
| * | |||||
| * | |||||
| * @copyright Copyright (c) 1998-2014 Tencent Inc. | * @copyright Copyright (c) 1998-2014 Tencent Inc. | ||||
| */ | */ | ||||
| @@ -16,53 +16,53 @@ import java.util.Arrays; | |||||
| */ | */ | ||||
| public class PKCS7Encoder { | 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; | package me.chanjar.weixin.common.util.crypto; | ||||
| import org.apache.commons.codec.digest.DigestUtils; | |||||
| import java.security.NoSuchAlgorithmException; | import java.security.NoSuchAlgorithmException; | ||||
| import java.util.Arrays; | import java.util.Arrays; | ||||
| import org.apache.commons.codec.digest.DigestUtils; | |||||
| /** | /** | ||||
| * Created by Daniel Qian on 14/10/19. | * Created by Daniel Qian on 14/10/19. | ||||
| */ | */ | ||||
| @@ -37,4 +37,4 @@ public class SHA1 { | |||||
| } | } | ||||
| return DigestUtils.sha1Hex(sb.toString()); | return DigestUtils.sha1Hex(sb.toString()); | ||||
| } | } | ||||
| } | |||||
| } | |||||
| @@ -2,6 +2,10 @@ | |||||
| * 对公众平台发送给公众账号的消息加解密示例代码. | * 对公众平台发送给公众账号的消息加解密示例代码. | ||||
| * | * | ||||
| * @copyright Copyright (c) 1998-2014 Tencent Inc. | * @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 | * @param appidOrCorpid 公众平台appid/corpid | ||||
| */ | */ | ||||
| public WxCryptUtil(String token, String encodingAesKey, | public WxCryptUtil(String token, String encodingAesKey, | ||||
| String appidOrCorpid) { | |||||
| String appidOrCorpid) { | |||||
| this.token = token; | this.token = token; | ||||
| this.appidOrCorpid = appidOrCorpid; | this.appidOrCorpid = appidOrCorpid; | ||||
| this.aesKey = Base64.decodeBase64(encodingAesKey + "="); | 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> | * <ol> | ||||
| @@ -107,7 +150,7 @@ public class WxCryptUtil { | |||||
| byte[] randomStringBytes = randomStr.getBytes(CHARSET); | byte[] randomStringBytes = randomStr.getBytes(CHARSET); | ||||
| byte[] plainTextBytes = plainText.getBytes(CHARSET); | byte[] plainTextBytes = plainText.getBytes(CHARSET); | ||||
| byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder( | byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder( | ||||
| plainTextBytes.length); | |||||
| plainTextBytes.length); | |||||
| byte[] appIdBytes = appidOrCorpid.getBytes(CHARSET); | byte[] appIdBytes = appidOrCorpid.getBytes(CHARSET); | ||||
| // randomStr + networkBytesOrder + text + appid | // randomStr + networkBytesOrder + text + appid | ||||
| @@ -157,7 +200,7 @@ public class WxCryptUtil { | |||||
| * @return 解密后的原文 | * @return 解密后的原文 | ||||
| */ | */ | ||||
| public String decrypt(String msgSignature, String timeStamp, String nonce, | public String decrypt(String msgSignature, String timeStamp, String nonce, | ||||
| String encryptedXml) { | |||||
| String encryptedXml) { | |||||
| // 密钥,公众账号的app corpSecret | // 密钥,公众账号的app corpSecret | ||||
| // 提取密文 | // 提取密文 | ||||
| String cipherText = extractEncryptPart(encryptedXml); | String cipherText = extractEncryptPart(encryptedXml); | ||||
| @@ -190,7 +233,7 @@ public class WxCryptUtil { | |||||
| Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); | Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); | ||||
| SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES"); | SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES"); | ||||
| IvParameterSpec iv = new IvParameterSpec( | IvParameterSpec iv = new IvParameterSpec( | ||||
| Arrays.copyOfRange(aesKey, 0, 16)); | |||||
| Arrays.copyOfRange(aesKey, 0, 16)); | |||||
| cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); | cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); | ||||
| // 使用BASE64对密文进行解码 | // 使用BASE64对密文进行解码 | ||||
| @@ -213,9 +256,9 @@ public class WxCryptUtil { | |||||
| int xmlLength = bytesNetworkOrder2Number(networkOrder); | int xmlLength = bytesNetworkOrder2Number(networkOrder); | ||||
| xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), | xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), | ||||
| CHARSET); | |||||
| CHARSET); | |||||
| from_appid = new String( | from_appid = new String( | ||||
| Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); | |||||
| Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); | |||||
| } catch (Exception e) { | } catch (Exception e) { | ||||
| throw new RuntimeException(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数组 | * 将一个数字转换成生成4个字节的网络字节序bytes数组 | ||||
| * | * | ||||
| @@ -308,24 +324,12 @@ public class WxCryptUtil { | |||||
| * @return 生成的xml字符串 | * @return 生成的xml字符串 | ||||
| */ | */ | ||||
| private String generateXml(String encrypt, String signature, String timestamp, | private String generateXml(String encrypt, String signature, String timestamp, | ||||
| String nonce) { | |||||
| String nonce) { | |||||
| String format = "<xml>\n" + "<Encrypt><![CDATA[%1$s]]></Encrypt>\n" | 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); | 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 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 { | public static File createTmpFile(InputStream inputStream, String name, String ext, File tmpDirFile) throws IOException { | ||||
| FileOutputStream fos = null; | FileOutputStream fos = null; | ||||
| try { | try { | ||||
| File tmpFile; | File tmpFile; | ||||
| if (tmpDirFile == null) { | if (tmpDirFile == null) { | ||||
| tmpFile = File.createTempFile(name, '.' + ext); | |||||
| tmpFile = File.createTempFile(name, '.' + ext); | |||||
| } else { | } else { | ||||
| tmpFile = File.createTempFile(name, '.' + ext, tmpDirFile); | tmpFile = File.createTempFile(name, '.' + ext, tmpDirFile); | ||||
| } | } | ||||
| @@ -51,12 +52,13 @@ public class FileUtils { | |||||
| /** | /** | ||||
| * 创建临时文件 | * 创建临时文件 | ||||
| * | |||||
| * @param inputStream | * @param inputStream | ||||
| * @param name 文件名 | |||||
| * @param ext 扩展名 | |||||
| * @param name 文件名 | |||||
| * @param ext 扩展名 | |||||
| */ | */ | ||||
| public static File createTmpFile(InputStream inputStream, String name, String ext) throws IOException { | public static File createTmpFile(InputStream inputStream, String name, String ext) throws IOException { | ||||
| return createTmpFile(inputStream, name, ext, null); | return createTmpFile(inputStream, name, ext, null); | ||||
| } | } | ||||
| } | } | ||||
| @@ -10,36 +10,42 @@ public interface ApacheHttpClientBuilder { | |||||
| /** | /** | ||||
| * 构建httpclient实例 | * 构建httpclient实例 | ||||
| * | |||||
| * @return new instance of CloseableHttpClient | * @return new instance of CloseableHttpClient | ||||
| */ | */ | ||||
| CloseableHttpClient build(); | CloseableHttpClient build(); | ||||
| /** | /** | ||||
| * 代理服务器地址 | * 代理服务器地址 | ||||
| * | |||||
| * @param httpProxyHost | * @param httpProxyHost | ||||
| */ | */ | ||||
| ApacheHttpClientBuilder httpProxyHost(String httpProxyHost); | ApacheHttpClientBuilder httpProxyHost(String httpProxyHost); | ||||
| /** | /** | ||||
| * 代理服务器端口 | * 代理服务器端口 | ||||
| * | |||||
| * @param httpProxyPort | * @param httpProxyPort | ||||
| */ | */ | ||||
| ApacheHttpClientBuilder httpProxyPort(int httpProxyPort); | ApacheHttpClientBuilder httpProxyPort(int httpProxyPort); | ||||
| /** | /** | ||||
| * 代理服务器用户名 | * 代理服务器用户名 | ||||
| * | |||||
| * @param httpProxyUsername | * @param httpProxyUsername | ||||
| */ | */ | ||||
| ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername); | ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername); | ||||
| /** | /** | ||||
| * 代理服务器密码 | * 代理服务器密码 | ||||
| * | |||||
| * @param httpProxyPassword | * @param httpProxyPassword | ||||
| */ | */ | ||||
| ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword); | ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword); | ||||
| /** | /** | ||||
| * ssl连接socket工厂 | * ssl连接socket工厂 | ||||
| * | |||||
| * @param sslConnectionSocketFactory | * @param sslConnectionSocketFactory | ||||
| */ | */ | ||||
| ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory); | ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory); | ||||
| @@ -94,7 +94,7 @@ public class DefaultApacheHttpHttpClientBuilder implements ApacheHttpClientBuild | |||||
| return this; | return this; | ||||
| } | } | ||||
| public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory){ | |||||
| public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory) { | |||||
| this.sslConnectionSocketFactory = sslConnectionSocketFactory; | this.sslConnectionSocketFactory = sslConnectionSocketFactory; | ||||
| return this; | return this; | ||||
| } | } | ||||
| @@ -103,18 +103,18 @@ public class DefaultApacheHttpHttpClientBuilder implements ApacheHttpClientBuild | |||||
| return idleConnectionMonitorThread; | return idleConnectionMonitorThread; | ||||
| } | } | ||||
| private void prepare(){ | |||||
| private void prepare() { | |||||
| Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() | 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 = new PoolingHttpClientConnectionManager(registry); | ||||
| connectionManager.setMaxTotal(maxTotalConn); | connectionManager.setMaxTotal(maxTotalConn); | ||||
| connectionManager.setDefaultMaxPerRoute(maxConnPerHost); | connectionManager.setDefaultMaxPerRoute(maxConnPerHost); | ||||
| connectionManager.setDefaultSocketConfig( | connectionManager.setDefaultSocketConfig( | ||||
| SocketConfig.copy(SocketConfig.DEFAULT) | |||||
| .setSoTimeout(soTimeout) | |||||
| .build() | |||||
| SocketConfig.copy(SocketConfig.DEFAULT) | |||||
| .setSoTimeout(soTimeout) | |||||
| .build() | |||||
| ); | ); | ||||
| idleConnectionMonitorThread = new IdleConnectionMonitorThread(connectionManager, idleConnTimeout, checkWaitTime); | idleConnectionMonitorThread = new IdleConnectionMonitorThread(connectionManager, idleConnTimeout, checkWaitTime); | ||||
| @@ -122,22 +122,22 @@ public class DefaultApacheHttpHttpClientBuilder implements ApacheHttpClientBuild | |||||
| idleConnectionMonitorThread.start(); | idleConnectionMonitorThread.start(); | ||||
| httpClientBuilder = HttpClients.custom() | 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)) { | if (StringUtils.isNotBlank(httpProxyHost) && StringUtils.isNotBlank(httpProxyUsername)) { | ||||
| // 使用代理服务器 需要用户认证的代理服务器 | // 使用代理服务器 需要用户认证的代理服务器 | ||||
| CredentialsProvider credsProvider = new BasicCredentialsProvider(); | CredentialsProvider credsProvider = new BasicCredentialsProvider(); | ||||
| credsProvider.setCredentials( | credsProvider.setCredentials( | ||||
| new AuthScope(httpProxyHost, httpProxyPort), | |||||
| new UsernamePasswordCredentials(httpProxyUsername, httpProxyPassword)); | |||||
| new AuthScope(httpProxyHost, httpProxyPort), | |||||
| new UsernamePasswordCredentials(httpProxyUsername, httpProxyPassword)); | |||||
| httpClientBuilder.setDefaultCredentialsProvider(credsProvider); | httpClientBuilder.setDefaultCredentialsProvider(credsProvider); | ||||
| } | } | ||||
| @@ -148,7 +148,7 @@ public class DefaultApacheHttpHttpClientBuilder implements ApacheHttpClientBuild | |||||
| } | } | ||||
| public CloseableHttpClient build() { | public CloseableHttpClient build() { | ||||
| if(!prepared){ | |||||
| if (!prepared) { | |||||
| prepare(); | prepare(); | ||||
| prepared = true; | prepared = true; | ||||
| } | } | ||||
| @@ -1,8 +1,5 @@ | |||||
| package me.chanjar.weixin.common.util.http; | package me.chanjar.weixin.common.util.http; | ||||
| import java.io.IOException; | |||||
| import java.io.InputStream; | |||||
| import org.apache.http.HttpEntity; | import org.apache.http.HttpEntity; | ||||
| import org.apache.http.HttpResponse; | import org.apache.http.HttpResponse; | ||||
| import org.apache.http.StatusLine; | import org.apache.http.StatusLine; | ||||
| @@ -10,10 +7,13 @@ import org.apache.http.client.HttpResponseException; | |||||
| import org.apache.http.client.ResponseHandler; | import org.apache.http.client.ResponseHandler; | ||||
| import org.apache.http.util.EntityUtils; | import org.apache.http.util.EntityUtils; | ||||
| import java.io.IOException; | |||||
| import java.io.InputStream; | |||||
| public class InputStreamResponseHandler implements ResponseHandler<InputStream> { | public class InputStreamResponseHandler implements ResponseHandler<InputStream> { | ||||
| public static final ResponseHandler<InputStream> INSTANCE = new InputStreamResponseHandler(); | public static final ResponseHandler<InputStream> INSTANCE = new InputStreamResponseHandler(); | ||||
| public InputStream handleResponse(final HttpResponse response) throws IOException { | public InputStream handleResponse(final HttpResponse response) throws IOException { | ||||
| final StatusLine statusLine = response.getStatusLine(); | final StatusLine statusLine = response.getStatusLine(); | ||||
| final HttpEntity entity = response.getEntity(); | final HttpEntity entity = response.getEntity(); | ||||
| @@ -18,39 +18,39 @@ import java.io.IOException; | |||||
| */ | */ | ||||
| public class JoddGetRequestExecutor implements RequestExecutor<String, String> { | 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> { | 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(); | |||||
| 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; | |||||
| @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; | |||||
| } | |||||
| } | } | ||||
| @@ -6,7 +6,6 @@ import me.chanjar.weixin.common.util.StringUtils; | |||||
| import me.chanjar.weixin.common.util.fs.FileUtils; | import me.chanjar.weixin.common.util.fs.FileUtils; | ||||
| import org.apache.http.Header; | import org.apache.http.Header; | ||||
| import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||
| import org.apache.http.client.ClientProtocolException; | |||||
| import org.apache.http.client.config.RequestConfig; | import org.apache.http.client.config.RequestConfig; | ||||
| import org.apache.http.client.methods.CloseableHttpResponse; | import org.apache.http.client.methods.CloseableHttpResponse; | ||||
| import org.apache.http.client.methods.HttpGet; | import org.apache.http.client.methods.HttpGet; | ||||
| @@ -21,11 +20,11 @@ import java.util.regex.Pattern; | |||||
| /** | /** | ||||
| * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File | * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File | ||||
| * @author Daniel Qian | |||||
| * | * | ||||
| * @author Daniel Qian | |||||
| */ | */ | ||||
| public class MediaDownloadRequestExecutor implements RequestExecutor<File, String> { | public class MediaDownloadRequestExecutor implements RequestExecutor<File, String> { | ||||
| private File tmpDirFile; | private File tmpDirFile; | ||||
| public MediaDownloadRequestExecutor() { | public MediaDownloadRequestExecutor() { | ||||
| @@ -36,7 +35,7 @@ public class MediaDownloadRequestExecutor implements RequestExecutor<File, Strin | |||||
| super(); | super(); | ||||
| this.tmpDirFile = tmpDirFile; | this.tmpDirFile = tmpDirFile; | ||||
| } | } | ||||
| @Override | @Override | ||||
| public File execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { | public File execute(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, String queryParam) throws WxErrorException, IOException { | ||||
| @@ -46,7 +45,7 @@ public class MediaDownloadRequestExecutor implements RequestExecutor<File, Strin | |||||
| } | } | ||||
| uri += uri.endsWith("?") ? queryParam : '&' + queryParam; | uri += uri.endsWith("?") ? queryParam : '&' + queryParam; | ||||
| } | } | ||||
| HttpGet httpGet = new HttpGet(uri); | HttpGet httpGet = new HttpGet(uri); | ||||
| if (httpProxy != null) { | if (httpProxy != null) { | ||||
| RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); | RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); | ||||
| @@ -74,7 +73,7 @@ public class MediaDownloadRequestExecutor implements RequestExecutor<File, Strin | |||||
| File localFile = FileUtils.createTmpFile(inputStream, name_ext[0], name_ext[1], tmpDirFile); | File localFile = FileUtils.createTmpFile(inputStream, name_ext[0], name_ext[1], tmpDirFile); | ||||
| return localFile; | return localFile; | ||||
| }finally { | |||||
| } finally { | |||||
| httpGet.releaseConnection(); | httpGet.releaseConnection(); | ||||
| } | } | ||||
| @@ -88,5 +87,5 @@ public class MediaDownloadRequestExecutor implements RequestExecutor<File, Strin | |||||
| String fileName = m.group(1); | String fileName = m.group(1); | ||||
| return fileName; | return fileName; | ||||
| } | } | ||||
| } | } | ||||
| @@ -5,7 +5,6 @@ import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | |||||
| import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import org.apache.http.HttpEntity; | import org.apache.http.HttpEntity; | ||||
| import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||
| import org.apache.http.client.ClientProtocolException; | |||||
| import org.apache.http.client.config.RequestConfig; | import org.apache.http.client.config.RequestConfig; | ||||
| import org.apache.http.client.methods.CloseableHttpResponse; | import org.apache.http.client.methods.CloseableHttpResponse; | ||||
| import org.apache.http.client.methods.HttpPost; | import org.apache.http.client.methods.HttpPost; | ||||
| @@ -19,8 +18,8 @@ import java.io.IOException; | |||||
| /** | /** | ||||
| * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String | * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String | ||||
| * @author Daniel Qian | |||||
| * | * | ||||
| * @author Daniel Qian | |||||
| */ | */ | ||||
| public class MediaUploadRequestExecutor implements RequestExecutor<WxMediaUploadResult, File> { | public class MediaUploadRequestExecutor implements RequestExecutor<WxMediaUploadResult, File> { | ||||
| @@ -33,10 +32,10 @@ public class MediaUploadRequestExecutor implements RequestExecutor<WxMediaUpload | |||||
| } | } | ||||
| if (file != null) { | if (file != null) { | ||||
| HttpEntity entity = MultipartEntityBuilder | HttpEntity entity = MultipartEntityBuilder | ||||
| .create() | |||||
| .addBinaryBody("media", file) | |||||
| .setMode(HttpMultipartMode.RFC6532) | |||||
| .build(); | |||||
| .create() | |||||
| .addBinaryBody("media", file) | |||||
| .setMode(HttpMultipartMode.RFC6532) | |||||
| .build(); | |||||
| httpPost.setEntity(entity); | httpPost.setEntity(entity); | ||||
| httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); | httpPost.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString()); | ||||
| } | } | ||||
| @@ -47,7 +46,7 @@ public class MediaUploadRequestExecutor implements RequestExecutor<WxMediaUpload | |||||
| throw new WxErrorException(error); | throw new WxErrorException(error); | ||||
| } | } | ||||
| return WxMediaUploadResult.fromJson(responseContent); | return WxMediaUploadResult.fromJson(responseContent); | ||||
| }finally { | |||||
| } finally { | |||||
| httpPost.releaseConnection(); | httpPost.releaseConnection(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,12 +1,11 @@ | |||||
| package me.chanjar.weixin.common.util.http; | 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.HttpHost; | ||||
| import org.apache.http.client.ClientProtocolException; | import org.apache.http.client.ClientProtocolException; | ||||
| import org.apache.http.impl.client.CloseableHttpClient; | import org.apache.http.impl.client.CloseableHttpClient; | ||||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||||
| import java.io.IOException; | |||||
| /** | /** | ||||
| * http请求执行器 | * http请求执行器 | ||||
| @@ -17,11 +16,10 @@ import me.chanjar.weixin.common.exception.WxErrorException; | |||||
| public interface RequestExecutor<T, E> { | public interface RequestExecutor<T, E> { | ||||
| /** | /** | ||||
| * | |||||
| * @param httpclient 传入的httpClient | * @param httpclient 传入的httpClient | ||||
| * @param httpProxy http代理对象,如果没有配置代理则为空 | |||||
| * @param uri uri | |||||
| * @param data 数据 | |||||
| * @param httpProxy http代理对象,如果没有配置代理则为空 | |||||
| * @param uri uri | |||||
| * @param data 数据 | |||||
| * @throws WxErrorException | * @throws WxErrorException | ||||
| * @throws ClientProtocolException | * @throws ClientProtocolException | ||||
| * @throws IOException | * @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.bean.result.WxError; | ||||
| import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||
| import org.apache.http.client.ClientProtocolException; | |||||
| import org.apache.http.client.config.RequestConfig; | import org.apache.http.client.config.RequestConfig; | ||||
| import org.apache.http.client.methods.CloseableHttpResponse; | import org.apache.http.client.methods.CloseableHttpResponse; | ||||
| import org.apache.http.client.methods.HttpGet; | import org.apache.http.client.methods.HttpGet; | ||||
| @@ -13,8 +12,8 @@ import java.io.IOException; | |||||
| /** | /** | ||||
| * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String | * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String | ||||
| * @author Daniel Qian | |||||
| * | * | ||||
| * @author Daniel Qian | |||||
| */ | */ | ||||
| public class SimpleGetRequestExecutor implements RequestExecutor<String, String> { | public class SimpleGetRequestExecutor implements RequestExecutor<String, String> { | ||||
| @@ -39,7 +38,7 @@ public class SimpleGetRequestExecutor implements RequestExecutor<String, String> | |||||
| throw new WxErrorException(error); | throw new WxErrorException(error); | ||||
| } | } | ||||
| return responseContent; | return responseContent; | ||||
| }finally { | |||||
| } finally { | |||||
| httpGet.releaseConnection(); | httpGet.releaseConnection(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -4,7 +4,6 @@ import me.chanjar.weixin.common.bean.result.WxError; | |||||
| import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import org.apache.http.Consts; | import org.apache.http.Consts; | ||||
| import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||
| import org.apache.http.client.ClientProtocolException; | |||||
| import org.apache.http.client.config.RequestConfig; | import org.apache.http.client.config.RequestConfig; | ||||
| import org.apache.http.client.methods.CloseableHttpResponse; | import org.apache.http.client.methods.CloseableHttpResponse; | ||||
| import org.apache.http.client.methods.HttpPost; | import org.apache.http.client.methods.HttpPost; | ||||
| @@ -15,8 +14,8 @@ import java.io.IOException; | |||||
| /** | /** | ||||
| * 简单的POST请求执行器,请求的参数是String, 返回的结果也是String | * 简单的POST请求执行器,请求的参数是String, 返回的结果也是String | ||||
| * @author Daniel Qian | |||||
| * | * | ||||
| * @author Daniel Qian | |||||
| */ | */ | ||||
| public class SimplePostRequestExecutor implements RequestExecutor<String, String> { | public class SimplePostRequestExecutor implements RequestExecutor<String, String> { | ||||
| @@ -40,7 +39,7 @@ public class SimplePostRequestExecutor implements RequestExecutor<String, String | |||||
| throw new WxErrorException(error); | throw new WxErrorException(error); | ||||
| } | } | ||||
| return responseContent; | return responseContent; | ||||
| }finally { | |||||
| } finally { | |||||
| httpPost.releaseConnection(); | httpPost.releaseConnection(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,7 +1,5 @@ | |||||
| package me.chanjar.weixin.common.util.http; | package me.chanjar.weixin.common.util.http; | ||||
| import java.io.IOException; | |||||
| import org.apache.http.Consts; | import org.apache.http.Consts; | ||||
| import org.apache.http.HttpEntity; | import org.apache.http.HttpEntity; | ||||
| import org.apache.http.HttpResponse; | import org.apache.http.HttpResponse; | ||||
| @@ -10,15 +8,17 @@ import org.apache.http.client.HttpResponseException; | |||||
| import org.apache.http.client.ResponseHandler; | import org.apache.http.client.ResponseHandler; | ||||
| import org.apache.http.util.EntityUtils; | import org.apache.http.util.EntityUtils; | ||||
| import java.io.IOException; | |||||
| /** | /** | ||||
| * copy from {@link org.apache.http.impl.client.BasicResponseHandler} | * copy from {@link org.apache.http.impl.client.BasicResponseHandler} | ||||
| * @author Daniel Qian | |||||
| * | * | ||||
| * @author Daniel Qian | |||||
| */ | */ | ||||
| public class Utf8ResponseHandler implements ResponseHandler<String> { | public class Utf8ResponseHandler implements ResponseHandler<String> { | ||||
| public static final ResponseHandler<String> INSTANCE = new Utf8ResponseHandler(); | public static final ResponseHandler<String> INSTANCE = new Utf8ResponseHandler(); | ||||
| public String handleResponse(final HttpResponse response) throws IOException { | public String handleResponse(final HttpResponse response) throws IOException { | ||||
| final StatusLine statusLine = response.getStatusLine(); | final StatusLine statusLine = response.getStatusLine(); | ||||
| final HttpEntity entity = response.getEntity(); | final HttpEntity entity = response.getEntity(); | ||||
| @@ -15,101 +15,101 @@ import com.google.gson.JsonObject; | |||||
| public class GsonHelper { | public class GsonHelper { | ||||
| public static boolean isNull(JsonElement element) { | |||||
| return element == null || element.isJsonNull(); | |||||
| } | |||||
| 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 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 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 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 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 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 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 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 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 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 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 boolean isNull(JsonElement element) { | |||||
| return element == null || element.isJsonNull(); | |||||
| } | |||||
| 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 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 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 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 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 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 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 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 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 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 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; | |||||
| } | |||||
| } | } | ||||
| @@ -14,9 +14,7 @@ import me.chanjar.weixin.common.bean.WxAccessToken; | |||||
| import java.lang.reflect.Type; | import java.lang.reflect.Type; | ||||
| /** | /** | ||||
| * | |||||
| * @author Daniel Qian | * @author Daniel Qian | ||||
| * | |||||
| */ | */ | ||||
| public class WxAccessTokenAdapter implements JsonDeserializer<WxAccessToken> { | public class WxAccessTokenAdapter implements JsonDeserializer<WxAccessToken> { | ||||
| @@ -32,5 +30,5 @@ public class WxAccessTokenAdapter implements JsonDeserializer<WxAccessToken> { | |||||
| } | } | ||||
| return accessToken; | return accessToken; | ||||
| } | } | ||||
| } | } | ||||
| @@ -14,9 +14,7 @@ import me.chanjar.weixin.common.bean.result.WxError; | |||||
| import java.lang.reflect.Type; | import java.lang.reflect.Type; | ||||
| /** | /** | ||||
| * | |||||
| * @author Daniel Qian | * @author Daniel Qian | ||||
| * | |||||
| */ | */ | ||||
| public class WxErrorAdapter implements JsonDeserializer<WxError> { | public class WxErrorAdapter implements JsonDeserializer<WxError> { | ||||
| @@ -33,5 +31,5 @@ public class WxErrorAdapter implements JsonDeserializer<WxError> { | |||||
| wxError.setJson(json.toString()); | wxError.setJson(json.toString()); | ||||
| return wxError; | return wxError; | ||||
| } | } | ||||
| } | } | ||||
| @@ -2,9 +2,9 @@ package me.chanjar.weixin.common.util.json; | |||||
| import com.google.gson.Gson; | import com.google.gson.Gson; | ||||
| import com.google.gson.GsonBuilder; | 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.WxMenu; | ||||
| import me.chanjar.weixin.common.bean.result.WxError; | import me.chanjar.weixin.common.bean.result.WxError; | ||||
| import me.chanjar.weixin.common.bean.WxAccessToken; | |||||
| import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | ||||
| public class WxGsonBuilder { | public class WxGsonBuilder { | ||||
| @@ -14,9 +14,7 @@ import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | |||||
| import java.lang.reflect.Type; | import java.lang.reflect.Type; | ||||
| /** | /** | ||||
| * | |||||
| * @author Daniel Qian | * @author Daniel Qian | ||||
| * | |||||
| */ | */ | ||||
| public class WxMediaUploadResultAdapter implements JsonDeserializer<WxMediaUploadResult> { | public class WxMediaUploadResultAdapter implements JsonDeserializer<WxMediaUploadResult> { | ||||
| @@ -38,5 +36,5 @@ public class WxMediaUploadResultAdapter implements JsonDeserializer<WxMediaUploa | |||||
| } | } | ||||
| return uploadResult; | return uploadResult; | ||||
| } | } | ||||
| } | } | ||||
| @@ -8,22 +8,13 @@ | |||||
| */ | */ | ||||
| package me.chanjar.weixin.common.util.json; | 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 me.chanjar.weixin.common.bean.WxMenu; | ||||
| import java.lang.reflect.Type; | import java.lang.reflect.Type; | ||||
| /** | /** | ||||
| * | |||||
| * @author Daniel Qian | * @author Daniel Qian | ||||
| * | |||||
| */ | */ | ||||
| public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializer<WxMenu> { | public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializer<WxMenu> { | ||||
| @@ -36,11 +27,11 @@ public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializ | |||||
| buttonArray.add(buttonJson); | buttonArray.add(buttonJson); | ||||
| } | } | ||||
| json.add("button", buttonArray); | json.add("button", buttonArray); | ||||
| if (menu.getMatchRule() != null) { | if (menu.getMatchRule() != null) { | ||||
| json.add("matchrule", convertToJson(menu.getMatchRule())); | json.add("matchrule", convertToJson(menu.getMatchRule())); | ||||
| } | } | ||||
| return json; | return json; | ||||
| } | } | ||||
| @@ -60,15 +51,15 @@ public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializ | |||||
| return buttonJson; | return buttonJson; | ||||
| } | } | ||||
| protected JsonObject convertToJson(WxMenu.WxMenuRule menuRule){ | |||||
| protected JsonObject convertToJson(WxMenu.WxMenuRule menuRule) { | |||||
| JsonObject matchRule = new JsonObject(); | 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; | return matchRule; | ||||
| } | } | ||||
| @@ -96,7 +87,7 @@ public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializ | |||||
| } | } | ||||
| return menu; | return menu; | ||||
| } | } | ||||
| protected WxMenu.WxMenuButton convertFromJson(JsonObject json) { | protected WxMenu.WxMenuButton convertFromJson(JsonObject json) { | ||||
| WxMenu.WxMenuButton button = new WxMenu.WxMenuButton(); | WxMenu.WxMenuButton button = new WxMenu.WxMenuButton(); | ||||
| button.setName(GsonHelper.getString(json, "name")); | button.setName(GsonHelper.getString(json, "name")); | ||||
| @@ -18,30 +18,24 @@ | |||||
| package me.chanjar.weixin.common.util.res; | package me.chanjar.weixin.common.util.res; | ||||
| import java.text.MessageFormat; | 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 | * An internationalization / localization helper class which reduces | ||||
| * the bother of handling ResourceBundles and takes care of the | * the bother of handling ResourceBundles and takes care of the | ||||
| * common cases of message formating which otherwise require the | * common cases of message formating which otherwise require the | ||||
| * creation of Object arrays and such. | * creation of Object arrays and such. | ||||
| * | |||||
| * <p> | |||||
| * <p>The StringManager operates on a package basis. One StringManager | * <p>The StringManager operates on a package basis. One StringManager | ||||
| * per package can be created and accessed via the getManager method | * per package can be created and accessed via the getManager method | ||||
| * call. | * call. | ||||
| * | |||||
| * <p> | |||||
| * <p>The StringManager will look for a ResourceBundle named by | * <p>The StringManager will look for a ResourceBundle named by | ||||
| * the package name given plus the suffix of "LocalStrings". In | * the package name given plus the suffix of "LocalStrings". In | ||||
| * practice, this means that the localized information will be contained | * practice, this means that the localized information will be contained | ||||
| * in a LocalStrings.properties file located in the package | * in a LocalStrings.properties file located in the package | ||||
| * directory of the classpath. | * directory of the classpath. | ||||
| * | |||||
| * <p> | |||||
| * <p>Please see the documentation for java.util.ResourceBundle for | * <p>Please see the documentation for java.util.ResourceBundle for | ||||
| * more information. | * more information. | ||||
| * | * | ||||
| @@ -52,152 +46,80 @@ import java.util.ResourceBundle; | |||||
| */ | */ | ||||
| public class StringManager { | public class StringManager { | ||||
| private static int LOCALE_CACHE_SIZE = 10; | |||||
| /** | |||||
| * 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; | |||||
| 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; | |||||
| /** | |||||
| * 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 { | 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; | |||||
| } | |||||
| 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; | |||||
| } | |||||
| // -------------------------------------------------------------- | |||||
| // 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) { | |||||
| } | |||||
| /** | |||||
| * 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) { | |||||
| /* | /* | ||||
| * Don't want the HashMap to be expanded beyond LOCALE_CACHE_SIZE. | * Don't want the HashMap to be expanded beyond LOCALE_CACHE_SIZE. | ||||
| * Expansion occurs when size() exceeds capacity. Therefore keep | * 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 | * 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; | package me.chanjar.weixin.common.util.xml; | ||||
| import java.io.Writer; | |||||
| import com.thoughtworks.xstream.XStream; | import com.thoughtworks.xstream.XStream; | ||||
| import com.thoughtworks.xstream.core.util.QuickWriter; | import com.thoughtworks.xstream.core.util.QuickWriter; | ||||
| import com.thoughtworks.xstream.io.HierarchicalStreamWriter; | 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.NullPermission; | ||||
| import com.thoughtworks.xstream.security.PrimitiveTypePermission; | import com.thoughtworks.xstream.security.PrimitiveTypePermission; | ||||
| import java.io.Writer; | |||||
| public class XStreamInitializer { | public class XStreamInitializer { | ||||
| public static XStream getInstance() { | public static XStream getInstance() { | ||||
| @@ -22,6 +22,7 @@ public class XStreamInitializer { | |||||
| protected String SUFFIX_CDATA = "]]>"; | protected String SUFFIX_CDATA = "]]>"; | ||||
| protected String PREFIX_MEDIA_ID = "<MediaId>"; | protected String PREFIX_MEDIA_ID = "<MediaId>"; | ||||
| protected String SUFFIX_MEDIA_ID = "</MediaId>"; | protected String SUFFIX_MEDIA_ID = "</MediaId>"; | ||||
| @Override | @Override | ||||
| protected void writeText(QuickWriter writer, String text) { | protected void writeText(QuickWriter writer, String text) { | ||||
| if (text.startsWith(PREFIX_CDATA) && text.endsWith(SUFFIX_CDATA)) { | if (text.startsWith(PREFIX_CDATA) && text.endsWith(SUFFIX_CDATA)) { | ||||
| @@ -14,5 +14,5 @@ public class WxAccessTokenTest { | |||||
| Assert.assertTrue(wxError.getExpiresIn() == 7200); | Assert.assertTrue(wxError.getExpiresIn() == 7200); | ||||
| } | } | ||||
| } | } | ||||
| @@ -15,7 +15,7 @@ public class WxErrorTest { | |||||
| Assert.assertEquals(wxError.getErrorMsg(), "invalid openid"); | Assert.assertEquals(wxError.getErrorMsg(), "invalid openid"); | ||||
| } | } | ||||
| public void testFromBadJson1() { | public void testFromBadJson1() { | ||||
| String json = "{ \"errcode\": 40003, \"errmsg\": \"invalid openid\", \"media_id\": \"12323423dsfafsf232f\" }"; | String json = "{ \"errcode\": 40003, \"errmsg\": \"invalid openid\", \"media_id\": \"12323423dsfafsf232f\" }"; | ||||
| @@ -24,7 +24,7 @@ public class WxErrorTest { | |||||
| Assert.assertEquals(wxError.getErrorMsg(), "invalid openid"); | Assert.assertEquals(wxError.getErrorMsg(), "invalid openid"); | ||||
| } | } | ||||
| public void testFromBadJson2() { | public void testFromBadJson2() { | ||||
| String json = "{\"access_token\":\"ACCESS_TOKEN\",\"expires_in\":7200}"; | String json = "{\"access_token\":\"ACCESS_TOKEN\",\"expires_in\":7200}"; | ||||
| @@ -33,5 +33,5 @@ public class WxErrorTest { | |||||
| Assert.assertEquals(wxError.getErrorMsg(), null); | Assert.assertEquals(wxError.getErrorMsg(), null); | ||||
| } | } | ||||
| } | } | ||||
| @@ -8,51 +8,51 @@ import org.testng.annotations.Test; | |||||
| @Test | @Test | ||||
| public class WxMenuTest { | public class WxMenuTest { | ||||
| @Test(dataProvider="wxReturnMenu") | |||||
| @Test(dataProvider = "wxReturnMenu") | |||||
| public void testFromJson(String json) { | public void testFromJson(String json) { | ||||
| WxMenu menu = WxMenu.fromJson(json); | WxMenu menu = WxMenu.fromJson(json); | ||||
| Assert.assertEquals(menu.getButtons().size(), 3); | Assert.assertEquals(menu.getButtons().size(), 3); | ||||
| } | } | ||||
| @Test(dataProvider="wxPushMenu") | |||||
| @Test(dataProvider = "wxPushMenu") | |||||
| public void testToJson(String json) { | public void testToJson(String json) { | ||||
| WxMenu menu = new WxMenu(); | WxMenu menu = new WxMenu(); | ||||
| WxMenuButton button1 = new WxMenuButton(); | WxMenuButton button1 = new WxMenuButton(); | ||||
| button1.setType("click"); | button1.setType("click"); | ||||
| button1.setName("今日歌曲"); | button1.setName("今日歌曲"); | ||||
| button1.setKey("V1001_TODAY_MUSIC"); | button1.setKey("V1001_TODAY_MUSIC"); | ||||
| WxMenuButton button2 = new WxMenuButton(); | WxMenuButton button2 = new WxMenuButton(); | ||||
| button2.setType("click"); | button2.setType("click"); | ||||
| button2.setName("歌手简介"); | button2.setName("歌手简介"); | ||||
| button2.setKey("V1001_TODAY_SINGER"); | button2.setKey("V1001_TODAY_SINGER"); | ||||
| WxMenuButton button3 = new WxMenuButton(); | WxMenuButton button3 = new WxMenuButton(); | ||||
| button3.setName("菜单"); | button3.setName("菜单"); | ||||
| menu.getButtons().add(button1); | menu.getButtons().add(button1); | ||||
| menu.getButtons().add(button2); | menu.getButtons().add(button2); | ||||
| menu.getButtons().add(button3); | menu.getButtons().add(button3); | ||||
| WxMenuButton button31 = new WxMenuButton(); | WxMenuButton button31 = new WxMenuButton(); | ||||
| button31.setType("view"); | button31.setType("view"); | ||||
| button31.setName("搜索"); | button31.setName("搜索"); | ||||
| button31.setUrl("http://www.soso.com/"); | button31.setUrl("http://www.soso.com/"); | ||||
| WxMenuButton button32 = new WxMenuButton(); | WxMenuButton button32 = new WxMenuButton(); | ||||
| button32.setType("view"); | button32.setType("view"); | ||||
| button32.setName("视频"); | button32.setName("视频"); | ||||
| button32.setUrl("http://v.qq.com/"); | button32.setUrl("http://v.qq.com/"); | ||||
| WxMenuButton button33 = new WxMenuButton(); | WxMenuButton button33 = new WxMenuButton(); | ||||
| button33.setType("click"); | button33.setType("click"); | ||||
| button33.setName("赞一下我们"); | button33.setName("赞一下我们"); | ||||
| button33.setKey("V1001_GOOD"); | button33.setKey("V1001_GOOD"); | ||||
| button3.getSubButtons().add(button31); | button3.getSubButtons().add(button31); | ||||
| button3.getSubButtons().add(button32); | button3.getSubButtons().add(button32); | ||||
| button3.getSubButtons().add(button33); | button3.getSubButtons().add(button33); | ||||
| Assert.assertEquals(menu.toJson(), json); | Assert.assertEquals(menu.toJson(), json); | ||||
| } | } | ||||
| @@ -78,82 +78,82 @@ public class WxMenuTest { | |||||
| Assert.assertEquals(menu.toJson(), json); | Assert.assertEquals(menu.toJson(), json); | ||||
| } | } | ||||
| @DataProvider | @DataProvider | ||||
| public Object[][] wxReturnMenu() { | public Object[][] wxReturnMenu() { | ||||
| Object[][] res = menuJson(); | |||||
| Object[][] res = menuJson(); | |||||
| String json = "{ \"menu\" : " + res[0][0] + " }"; | 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() { | 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 } | |||||
| 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} | |||||
| }; | }; | ||||
| } | } | ||||
| @DataProvider(name = "wxAddConditionalMenu") | @DataProvider(name = "wxAddConditionalMenu") | ||||
| public Object[][] addConditionalMenuJson(){ | |||||
| public Object[][] addConditionalMenuJson() { | |||||
| String json = | 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[][]{ | return new Object[][]{ | ||||
| new Object[]{json} | |||||
| new Object[]{json} | |||||
| }; | }; | ||||
| } | } | ||||
| } | } | ||||
| @@ -10,8 +10,8 @@ public class SessionTest { | |||||
| @DataProvider | @DataProvider | ||||
| public Object[][] getSessionManager() { | 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 class WxMessageInMemoryDuplicateCheckerTest { | ||||
| public void test() throws InterruptedException { | 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); | WxMessageInMemoryDuplicateChecker checker = new WxMessageInMemoryDuplicateChecker(2000l, 1000l); | ||||
| // 第一次检查 | // 第一次检查 | ||||
| @@ -69,7 +69,7 @@ public class WxCryptUtilTest { | |||||
| } | } | ||||
| public void testValidateSignatureError() throws ParserConfigurationException, SAXException, | public void testValidateSignatureError() throws ParserConfigurationException, SAXException, | ||||
| IOException { | |||||
| IOException { | |||||
| try { | try { | ||||
| WxCryptUtil pc = new WxCryptUtil(token, encodingAesKey, appId); | WxCryptUtil pc = new WxCryptUtil(token, encodingAesKey, appId); | ||||
| String afterEncrpt = pc.encrypt(replyMsg); | String afterEncrpt = pc.encrypt(replyMsg); | ||||