@@ -6,7 +6,7 @@ | |||
<modelVersion>4.0.0</modelVersion> | |||
<groupId>com.github.binarywang</groupId> | |||
<artifactId>weixin-java-parent</artifactId> | |||
<version>2.8.0</version> | |||
<version>2.9.0</version> | |||
<packaging>pom</packaging> | |||
<name>WeiXin Java Tools - Parent</name> | |||
<description>微信公众号、企业号上级POM</description> | |||
@@ -80,6 +80,11 @@ | |||
<email>crskyp@gmail.com</email> | |||
<url>https://github.com/crskyp</url> | |||
</developer> | |||
<developer> | |||
<name>007</name> | |||
<email>007gzs@gmail.com</email> | |||
<url>https://github.com/007gzs</url> | |||
</developer> | |||
</developers> | |||
<scm> | |||
@@ -94,6 +99,7 @@ | |||
<module>weixin-java-mp</module> | |||
<module>weixin-java-pay</module> | |||
<module>weixin-java-miniapp</module> | |||
<module>weixin-java-open</module> | |||
<!--module>weixin-java-osgi</module--> | |||
</modules> | |||
@@ -225,6 +231,12 @@ | |||
<version>2.9.0</version> | |||
<scope>provided</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.projectlombok</groupId> | |||
<artifactId>lombok</artifactId> | |||
<version>1.16.18</version> | |||
<scope>compile</scope> | |||
</dependency> | |||
</dependencies> | |||
</dependencyManagement> | |||
@@ -40,7 +40,7 @@ | |||
<property name="allowNonPrintableEscapes" value="true"/> | |||
</module> | |||
<module name="LineLength"> | |||
<property name="max" value="100"/> | |||
<property name="max" value="120"/> | |||
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/> | |||
</module> | |||
<module name="AvoidStarImport"/> | |||
@@ -52,7 +52,7 @@ | |||
</module> | |||
<module name="NeedBraces"/> | |||
<module name="LeftCurly"> | |||
<property name="maxLineLength" value="100"/> | |||
<property name="maxLineLength" value="120"/> | |||
</module> | |||
<module name="RightCurly"> | |||
<property name="id" value="RightCurlySame"/> | |||
@@ -163,9 +163,12 @@ | |||
<module name="OverloadMethodsDeclarationOrder"/> | |||
<module name="VariableDeclarationUsageDistance"/> | |||
<module name="CustomImportOrder"> | |||
<property name="customImportOrderRules" | |||
value="THIRD_PARTY_PACKAGE###SPECIAL_IMPORTS###STANDARD_JAVA_PACKAGE###STATIC"/> | |||
<property name="specialImportsRegExp" value="^javax\."/> | |||
<property name="standardPackageRegExp" value="^java\."/> | |||
<property name="sortImportsInGroupAlphabetically" value="true"/> | |||
<property name="separateLineBetweenGroups" value="true"/> | |||
<property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE"/> | |||
<property name="separateLineBetweenGroups" value="false"/> | |||
</module> | |||
<module name="MethodParamPad"/> | |||
<module name="ParenPad"/> | |||
@@ -7,7 +7,7 @@ | |||
<parent> | |||
<groupId>com.github.binarywang</groupId> | |||
<artifactId>weixin-java-parent</artifactId> | |||
<version>2.8.0</version> | |||
<version>2.9.0</version> | |||
</parent> | |||
<artifactId>weixin-java-common</artifactId> | |||
@@ -74,6 +74,10 @@ | |||
<groupId>com.google.guava</groupId> | |||
<artifactId>guava</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.projectlombok</groupId> | |||
<artifactId>lombok</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>ch.qos.logback</groupId> | |||
@@ -3,187 +3,248 @@ package me.chanjar.weixin.common.api; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
/** | |||
* 微信开发所使用到的常量类. | |||
* | |||
* @author chanjarster & binarywang | |||
*/ | |||
public class WxConsts { | |||
/////////////////////// | |||
// 微信推送过来的消息的类型,和发送给微信xml格式消息的消息类型 | |||
/////////////////////// | |||
public static final String XML_MSG_TEXT = "text"; | |||
public static final String XML_MSG_IMAGE = "image"; | |||
public static final String XML_MSG_VOICE = "voice"; | |||
public static final String XML_MSG_SHORTVIDEO = "shortvideo"; | |||
public static final String XML_MSG_VIDEO = "video"; | |||
public static final String XML_MSG_NEWS = "news"; | |||
public static final String XML_MSG_MUSIC = "music"; | |||
public static final String XML_MSG_LOCATION = "location"; | |||
public static final String XML_MSG_LINK = "link"; | |||
public static final String XML_MSG_EVENT = "event"; | |||
public static final String XML_MSG_DEVICE_TEXT = "device_text"; | |||
public static final String XML_MSG_DEVICE_EVENT = "device_event"; | |||
public static final String XML_MSG_DEVICE_STATUS = "device_status"; | |||
public static final String XML_MSG_HARDWARE = "hardware"; | |||
public static final String XML_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; | |||
/////////////////////// | |||
// 主动发送消息(即客服消息)的消息类型 | |||
/////////////////////// | |||
public static final String CUSTOM_MSG_TEXT = "text";//文本消息 | |||
public static final String CUSTOM_MSG_IMAGE = "image";//图片消息 | |||
public static final String CUSTOM_MSG_VOICE = "voice";//语音消息 | |||
public static final String CUSTOM_MSG_VIDEO = "video";//视频消息 | |||
public static final String CUSTOM_MSG_MUSIC = "music";//音乐消息 | |||
public static final String CUSTOM_MSG_NEWS = "news";//图文消息(点击跳转到外链) | |||
public static final String CUSTOM_MSG_MPNEWS = "mpnews";//图文消息(点击跳转到图文消息页面) | |||
public static final String CUSTOM_MSG_FILE = "file";//发送文件(CP专用) | |||
public static final String CUSTOM_MSG_TEXTCARD = "textcard";//文本卡片消息(CP专用) | |||
public static final String CUSTOM_MSG_WXCARD = "wxcard";//卡券消息 | |||
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_YES = "1"; | |||
/////////////////////// | |||
// 群发消息的消息类型 | |||
/////////////////////// | |||
public static final String MASS_MSG_NEWS = "mpnews"; | |||
public static final String MASS_MSG_TEXT = "text"; | |||
public static final String MASS_MSG_VOICE = "voice"; | |||
public static final String MASS_MSG_IMAGE = "image"; | |||
public static final String MASS_MSG_VIDEO = "mpvideo"; | |||
/////////////////////// | |||
// 群发消息后微信端推送给服务器的反馈消息 | |||
/////////////////////// | |||
public static final String MASS_ST_SUCCESS = "send success"; | |||
public static final String MASS_ST_FAIL = "send fail"; | |||
public static final String MASS_ST_10001 = "err(10001)"; | |||
public static final String MASS_ST_20001 = "err(20001)"; | |||
public static final String MASS_ST_20004 = "err(20004)"; | |||
public static final String MASS_ST_20002 = "err(20002)"; | |||
public static final String MASS_ST_20006 = "err(20006)"; | |||
public static final String MASS_ST_20008 = "err(20008)"; | |||
public static final String MASS_ST_20013 = "err(20013)"; | |||
public static final String MASS_ST_22000 = "err(22000)"; | |||
public static final String MASS_ST_21000 = "err(21000)"; | |||
/** | |||
* 群发反馈消息代码所对应的文字描述 | |||
* 微信推送过来的消息的类型,和发送给微信xml格式消息的消息类型. | |||
*/ | |||
public static final Map<String, String> MASS_ST_2_DESC = new HashMap<>(); | |||
/////////////////////// | |||
// 微信端推送过来的事件类型 | |||
/////////////////////// | |||
public static final String EVT_SUBSCRIBE = "subscribe"; | |||
public static final String EVT_UNSUBSCRIBE = "unsubscribe"; | |||
public static final String EVT_SCAN = "SCAN"; | |||
public static final String EVT_LOCATION = "LOCATION"; | |||
public static final String EVT_CLICK = "CLICK"; | |||
public static final String EVT_VIEW = "VIEW"; | |||
public static final String EVT_MASS_SEND_JOB_FINISH = "MASSSENDJOBFINISH"; | |||
public static final String EVT_SCANCODE_PUSH = "scancode_push"; | |||
public static final String EVT_SCANCODE_WAITMSG = "scancode_waitmsg"; | |||
public static final String EVT_PIC_SYSPHOTO = "pic_sysphoto"; | |||
public static final String EVT_PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; | |||
public static final String EVT_PIC_WEIXIN = "pic_weixin"; | |||
public static final String EVT_LOCATION_SELECT = "location_select"; | |||
public static final String EVT_TEMPLATESENDJOBFINISH = "TEMPLATESENDJOBFINISH"; | |||
public static final String EVT_ENTER_AGENT = "enter_agent"; | |||
/////////////////////// | |||
// 上传多媒体文件的类型 | |||
/////////////////////// | |||
public static final String MEDIA_IMAGE = "image"; | |||
public static final String MEDIA_VOICE = "voice"; | |||
public static final String MEDIA_VIDEO = "video"; | |||
public static final String MEDIA_THUMB = "thumb"; | |||
public static final String MEDIA_FILE = "file"; | |||
public static class XmlMsgType { | |||
public static final String TEXT = "text"; | |||
public static final String IMAGE = "image"; | |||
public static final String VOICE = "voice"; | |||
public static final String SHORTVIDEO = "shortvideo"; | |||
public static final String VIDEO = "video"; | |||
public static final String NEWS = "news"; | |||
public static final String MUSIC = "music"; | |||
public static final String LOCATION = "location"; | |||
public static final String LINK = "link"; | |||
public static final String EVENT = "event"; | |||
public static final String DEVICE_TEXT = "device_text"; | |||
public static final String DEVICE_EVENT = "device_event"; | |||
public static final String DEVICE_STATUS = "device_status"; | |||
public static final String HARDWARE = "hardware"; | |||
public static final String TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; | |||
} | |||
/////////////////////// | |||
// 自定义菜单的按钮类型 | |||
/////////////////////// | |||
/** | |||
* 点击推事件 | |||
*/ | |||
public static final String BUTTON_CLICK = "click"; | |||
/** | |||
* 跳转URL | |||
*/ | |||
public static final String BUTTON_VIEW = "view"; | |||
/** | |||
* 跳转到小程序 | |||
*/ | |||
public static final String BUTTON_MINIPROGRAM = "miniprogram"; | |||
/** | |||
* 扫码推事件 | |||
*/ | |||
public static final String BUTTON_SCANCODE_PUSH = "scancode_push"; | |||
/** | |||
* 扫码推事件且弹出“消息接收中”提示框 | |||
* 主动发送消息(即客服消息)的消息类型. | |||
*/ | |||
public static final String BUTTON_SCANCODE_WAITMSG = "scancode_waitmsg"; | |||
public static class KefuMsgType { | |||
/** | |||
* 文本消息. | |||
*/ | |||
public static final String TEXT = "text"; | |||
/** | |||
* 图片消息. | |||
*/ | |||
public static final String IMAGE = "image"; | |||
/** | |||
* 语音消息. | |||
*/ | |||
public static final String VOICE = "voice"; | |||
/** | |||
* 视频消息. | |||
*/ | |||
public static final String VIDEO = "video"; | |||
/** | |||
* 音乐消息. | |||
*/ | |||
public static final String MUSIC = "music"; | |||
/** | |||
* 图文消息(点击跳转到外链). | |||
*/ | |||
public static final String NEWS = "news"; | |||
/** | |||
* 图文消息(点击跳转到图文消息页面). | |||
*/ | |||
public static final String MPNEWS = "mpnews"; | |||
/** | |||
* 发送文件(CP专用). | |||
*/ | |||
public static final String FILE = "file"; | |||
/** | |||
* 文本卡片消息(CP专用). | |||
*/ | |||
public static final String TEXTCARD = "textcard"; | |||
/** | |||
* 卡券消息. | |||
*/ | |||
public static final String WXCARD = "wxcard"; | |||
/** | |||
* 转发到客服的消息. | |||
*/ | |||
public static final String TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; | |||
} | |||
/** | |||
* 弹出系统拍照发图 | |||
* 表示是否是保密消息,0表示否,1表示是,默认0. | |||
*/ | |||
public static final String BUTTON_PIC_SYSPHOTO = "pic_sysphoto"; | |||
public static class KefuMsgSafe { | |||
public static final String NO = "0"; | |||
public static final String YES = "1"; | |||
} | |||
/** | |||
* 弹出拍照或者相册发图 | |||
* 群发消息的消息类型. | |||
*/ | |||
public static final String BUTTON_PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; | |||
public static class MassMsgType { | |||
public static final String MPNEWS = "mpnews"; | |||
public static final String TEXT = "text"; | |||
public static final String VOICE = "voice"; | |||
public static final String IMAGE = "image"; | |||
public static final String MPVIDEO = "mpvideo"; | |||
} | |||
/** | |||
* 弹出微信相册发图器 | |||
* 群发消息后微信端推送给服务器的反馈消息. | |||
*/ | |||
public static final String BUTTON_PIC_WEIXIN = "pic_weixin"; | |||
public static class MassMsgStatus { | |||
public static final String SEND_SUCCESS = "send success"; | |||
public static final String SEND_FAIL = "send fail"; | |||
public static final String ERR_10001 = "err(10001)"; | |||
public static final String ERR_20001 = "err(20001)"; | |||
public static final String ERR_20004 = "err(20004)"; | |||
public static final String ERR_20002 = "err(20002)"; | |||
public static final String ERR_20006 = "err(20006)"; | |||
public static final String ERR_20008 = "err(20008)"; | |||
public static final String ERR_20013 = "err(20013)"; | |||
public static final String ERR_22000 = "err(22000)"; | |||
public static final String ERR_21000 = "err(21000)"; | |||
/** | |||
* 群发反馈消息代码所对应的文字描述. | |||
*/ | |||
public static final Map<String, String> STATUS_DESC = new HashMap<>(); | |||
static { | |||
STATUS_DESC.put(SEND_SUCCESS, "发送成功"); | |||
STATUS_DESC.put(SEND_FAIL, "发送失败"); | |||
STATUS_DESC.put(ERR_10001, "涉嫌广告"); | |||
STATUS_DESC.put(ERR_20001, "涉嫌政治"); | |||
STATUS_DESC.put(ERR_20004, "涉嫌社会"); | |||
STATUS_DESC.put(ERR_20002, "涉嫌色情"); | |||
STATUS_DESC.put(ERR_20006, "涉嫌违法犯罪"); | |||
STATUS_DESC.put(ERR_20008, "涉嫌欺诈"); | |||
STATUS_DESC.put(ERR_20013, "涉嫌版权"); | |||
STATUS_DESC.put(ERR_22000, "涉嫌互推_互相宣传"); | |||
STATUS_DESC.put(ERR_21000, "涉嫌其他"); | |||
} | |||
} | |||
/** | |||
* 弹出地理位置选择器 | |||
* 微信端推送过来的事件类型. | |||
*/ | |||
public static final String BUTTON_LOCATION_SELECT = "location_select"; | |||
public static class EventType { | |||
public static final String SUBSCRIBE = "subscribe"; | |||
public static final String UNSUBSCRIBE = "unsubscribe"; | |||
public static final String SCAN = "SCAN"; | |||
public static final String LOCATION = "LOCATION"; | |||
public static final String CLICK = "CLICK"; | |||
public static final String VIEW = "VIEW"; | |||
public static final String MASS_SEND_JOB_FINISH = "MASSSENDJOBFINISH"; | |||
public static final String SCANCODE_PUSH = "scancode_push"; | |||
public static final String SCANCODE_WAITMSG = "scancode_waitmsg"; | |||
public static final String PIC_SYSPHOTO = "pic_sysphoto"; | |||
public static final String PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; | |||
public static final String PIC_WEIXIN = "pic_weixin"; | |||
public static final String LOCATION_SELECT = "location_select"; | |||
public static final String TEMPLATE_SEND_JOB_FINISH = "TEMPLATESENDJOBFINISH"; | |||
public static final String ENTER_AGENT = "enter_agent"; | |||
} | |||
/** | |||
* 下发消息(除文本消息) | |||
* 上传多媒体(临时素材)文件的类型. | |||
*/ | |||
public static final String BUTTON_MEDIA_ID = "media_id"; | |||
public static class MediaFileType { | |||
public static final String IMAGE = "image"; | |||
public static final String VOICE = "voice"; | |||
public static final String VIDEO = "video"; | |||
public static final String THUMB = "thumb"; | |||
public static final String FILE = "file"; | |||
} | |||
/** | |||
* 跳转图文消息URL | |||
* 自定义菜单的按钮类型. | |||
*/ | |||
public static final String BUTTON_VIEW_LIMITED = "view_limited"; | |||
public static class MenuButtonType { | |||
/** | |||
* 点击推事件. | |||
*/ | |||
public static final String CLICK = "click"; | |||
/** | |||
* 跳转URL. | |||
*/ | |||
public static final String VIEW = "view"; | |||
/** | |||
* 跳转到小程序. | |||
*/ | |||
public static final String MINIPROGRAM = "miniprogram"; | |||
/** | |||
* 扫码推事件. | |||
*/ | |||
public static final String SCANCODE_PUSH = "scancode_push"; | |||
/** | |||
* 扫码推事件且弹出“消息接收中”提示框. | |||
*/ | |||
public static final String SCANCODE_WAITMSG = "scancode_waitmsg"; | |||
/** | |||
* 弹出系统拍照发图. | |||
*/ | |||
public static final String PIC_SYSPHOTO = "pic_sysphoto"; | |||
/** | |||
* 弹出拍照或者相册发图. | |||
*/ | |||
public static final String PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; | |||
/** | |||
* 弹出微信相册发图器. | |||
*/ | |||
public static final String PIC_WEIXIN = "pic_weixin"; | |||
/** | |||
* 弹出地理位置选择器. | |||
*/ | |||
public static final String LOCATION_SELECT = "location_select"; | |||
/** | |||
* 下发消息(除文本消息). | |||
*/ | |||
public static final String MEDIA_ID = "media_id"; | |||
/** | |||
* 跳转图文消息URL. | |||
*/ | |||
public static final String VIEW_LIMITED = "view_limited"; | |||
} | |||
/** | |||
* 不弹出授权页面,直接跳转,只能获取用户openid | |||
* oauth2网页授权的scope. | |||
*/ | |||
public static final String OAUTH2_SCOPE_BASE = "snsapi_base"; | |||
public static class OAuth2Scope { | |||
/** | |||
* 不弹出授权页面,直接跳转,只能获取用户openid. | |||
*/ | |||
public static final String SNSAPI_BASE = "snsapi_base"; | |||
/** | |||
* 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息. | |||
*/ | |||
public static final String SNSAPI_USERINFO = "snsapi_userinfo"; | |||
} | |||
/////////////////////// | |||
// oauth2网页授权的scope | |||
/////////////////////// | |||
/** | |||
* 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息 | |||
* 网页应用登录授权作用域. | |||
*/ | |||
public static final String OAUTH2_SCOPE_USER_INFO = "snsapi_userinfo"; | |||
public static class QrConnectScope { | |||
public static final String SNSAPI_LOGIN = "snsapi_login"; | |||
} | |||
/** | |||
* 网页应用登录授权作用域 snsapi_login | |||
* 永久素材类型. | |||
*/ | |||
public static final String QRCONNECT_SCOPE_SNSAPI_LOGIN = "snsapi_login"; | |||
/////////////////////// | |||
// 永久素材类型 | |||
/////////////////////// | |||
public static final String MATERIAL_NEWS = "news"; | |||
public static final String MATERIAL_VOICE = "voice"; | |||
public static final String MATERIAL_IMAGE = "image"; | |||
public static final String MATERIAL_VIDEO = "video"; | |||
static { | |||
MASS_ST_2_DESC.put(MASS_ST_SUCCESS, "发送成功"); | |||
MASS_ST_2_DESC.put(MASS_ST_FAIL, "发送失败"); | |||
MASS_ST_2_DESC.put(MASS_ST_10001, "涉嫌广告"); | |||
MASS_ST_2_DESC.put(MASS_ST_20001, "涉嫌政治"); | |||
MASS_ST_2_DESC.put(MASS_ST_20004, "涉嫌社会"); | |||
MASS_ST_2_DESC.put(MASS_ST_20002, "涉嫌色情"); | |||
MASS_ST_2_DESC.put(MASS_ST_20006, "涉嫌违法犯罪"); | |||
MASS_ST_2_DESC.put(MASS_ST_20008, "涉嫌欺诈"); | |||
MASS_ST_2_DESC.put(MASS_ST_20013, "涉嫌版权"); | |||
MASS_ST_2_DESC.put(MASS_ST_22000, "涉嫌互推_互相宣传"); | |||
MASS_ST_2_DESC.put(MASS_ST_21000, "涉嫌其他"); | |||
public static class MaterialType { | |||
public static final String NEWS = "news"; | |||
public static final String VOICE = "voice"; | |||
public static final String IMAGE = "image"; | |||
public static final String VIDEO = "video"; | |||
} | |||
} |
@@ -3,7 +3,7 @@ package me.chanjar.weixin.common.api; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
/** | |||
* WxErrorException处理器 | |||
* WxErrorException处理器. | |||
*/ | |||
public interface WxErrorExceptionHandler { | |||
@@ -2,22 +2,21 @@ package me.chanjar.weixin.common.api; | |||
/** | |||
* <pre> | |||
* 消息重复检查器 | |||
* 消息重复检查器. | |||
* 微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次 | |||
* </pre> | |||
*/ | |||
public interface WxMessageDuplicateChecker { | |||
/** | |||
* 判断消息是否重复. | |||
* <h2>公众号的排重方式</h2> | |||
* <p> | |||
* | |||
* <p>普通消息:关于重试的消息排重,推荐使用msgid排重。<a href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html">文档参考</a>。</p> | |||
* <p>事件消息:关于重试的消息排重,推荐使用FromUserName + CreateTime 排重。<a href="http://mp.weixin.qq.com/wiki/2/5baf56ce4947d35003b86a9805634b1e.html">文档参考</a></p> | |||
* <p> | |||
* | |||
* <h2>企业号的排重方式</h2> | |||
* <p> | |||
* 官方文档完全没有写,参照公众号的方式排重。 | |||
* <p> | |||
* <p>官方文档完全没有写,参照公众号的方式排重。</p> | |||
* <p>或者可以采取更简单的方式,如果有MsgId就用MsgId排重,如果没有就用FromUserName+CreateTime排重</p> | |||
* | |||
* @param messageId messageId需要根据上面讲的方式构造 | |||
@@ -6,46 +6,46 @@ import java.util.concurrent.atomic.AtomicBoolean; | |||
/** | |||
* <pre> | |||
* 默认消息重复检查器 | |||
* 默认消息重复检查器. | |||
* 将每个消息id保存在内存里,每隔5秒清理已经过期的消息id,每个消息id的过期时间是15秒 | |||
* </pre> | |||
*/ | |||
public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChecker { | |||
/** | |||
* 一个消息ID在内存的过期时间:15秒 | |||
* 一个消息ID在内存的过期时间:15秒. | |||
*/ | |||
private final Long timeToLive; | |||
/** | |||
* 每隔多少周期检查消息ID是否过期:5秒 | |||
* 每隔多少周期检查消息ID是否过期:5秒. | |||
*/ | |||
private final Long clearPeriod; | |||
/** | |||
* 消息id->消息时间戳的map | |||
* 消息id->消息时间戳的map. | |||
*/ | |||
private final ConcurrentHashMap<String, Long> msgId2Timestamp = new ConcurrentHashMap<>(); | |||
/** | |||
* 后台清理线程是否已经开启 | |||
* 后台清理线程是否已经开启. | |||
*/ | |||
private final AtomicBoolean backgroundProcessStarted = new AtomicBoolean(false); | |||
/** | |||
* WxMsgIdInMemoryDuplicateChecker构造函数 | |||
* 无参构造方法. | |||
* <pre> | |||
* 一个消息ID在内存的过期时间:15秒 | |||
* 每隔多少周期检查消息ID是否过期:5秒 | |||
* </pre> | |||
*/ | |||
public WxMessageInMemoryDuplicateChecker() { | |||
this.timeToLive = 15 * 1000l; | |||
this.clearPeriod = 5 * 1000l; | |||
this.timeToLive = 15 * 1000L; | |||
this.clearPeriod = 5 * 1000L; | |||
} | |||
/** | |||
* WxMsgIdInMemoryDuplicateChecker构造函数 | |||
* 构造方法. | |||
* | |||
* @param timeToLive 一个消息ID在内存的过期时间:毫秒 | |||
* @param clearPeriod 每隔多少周期检查消息ID是否过期:毫秒 | |||
@@ -66,7 +66,8 @@ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChec | |||
while (true) { | |||
Thread.sleep(WxMessageInMemoryDuplicateChecker.this.clearPeriod); | |||
Long now = System.currentTimeMillis(); | |||
for (Map.Entry<String, Long> entry : WxMessageInMemoryDuplicateChecker.this.msgId2Timestamp.entrySet()) { | |||
for (Map.Entry<String, Long> entry : | |||
WxMessageInMemoryDuplicateChecker.this.msgId2Timestamp.entrySet()) { | |||
if (now - entry.getValue() > WxMessageInMemoryDuplicateChecker.this.timeToLive) { | |||
WxMessageInMemoryDuplicateChecker.this.msgId2Timestamp.entrySet().remove(entry); | |||
} | |||
@@ -1,9 +1,11 @@ | |||
package me.chanjar.weixin.common.bean; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||
import java.io.Serializable; | |||
@Data | |||
public class WxAccessToken implements Serializable { | |||
private static final long serialVersionUID = 8709719312922168909L; | |||
@@ -15,20 +17,4 @@ public class WxAccessToken implements Serializable { | |||
return WxGsonBuilder.create().fromJson(json, WxAccessToken.class); | |||
} | |||
public String getAccessToken() { | |||
return this.accessToken; | |||
} | |||
public void setAccessToken(String accessToken) { | |||
this.accessToken = accessToken; | |||
} | |||
public int getExpiresIn() { | |||
return this.expiresIn; | |||
} | |||
public void setExpiresIn(int expiresIn) { | |||
this.expiresIn = expiresIn; | |||
} | |||
} |
@@ -1,17 +1,18 @@ | |||
package me.chanjar.weixin.common.bean; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import java.io.Serializable; | |||
/** | |||
* 卡券Api签名 | |||
* 卡券Api签名. | |||
* | |||
* @author YuJian | |||
* @version 15/11/8 | |||
*/ | |||
@Data | |||
public class WxCardApiSignature implements Serializable { | |||
private static final long serialVersionUID = 158176707226975979L; | |||
private String appId; | |||
@@ -37,75 +38,4 @@ public class WxCardApiSignature implements Serializable { | |||
return ToStringUtils.toSimpleString(this); | |||
} | |||
public String getAppId() { | |||
return this.appId; | |||
} | |||
public void setAppId(String appId) { | |||
this.appId = appId; | |||
} | |||
public String getCardId() { | |||
return this.cardId; | |||
} | |||
public void setCardId(String cardId) { | |||
this.cardId = cardId; | |||
} | |||
public String getCardType() { | |||
return this.cardType; | |||
} | |||
public void setCardType(String cardType) { | |||
this.cardType = cardType; | |||
} | |||
public String getLocationId() { | |||
return this.locationId; | |||
} | |||
public void setLocationId(String locationId) { | |||
this.locationId = locationId; | |||
} | |||
public String getCode() { | |||
return this.code; | |||
} | |||
public void setCode(String code) { | |||
this.code = code; | |||
} | |||
public String getOpenId() { | |||
return this.openId; | |||
} | |||
public void setOpenId(String openId) { | |||
this.openId = openId; | |||
} | |||
public Long getTimestamp() { | |||
return this.timestamp; | |||
} | |||
public void setTimestamp(Long timestamp) { | |||
this.timestamp = timestamp; | |||
} | |||
public String getNonceStr() { | |||
return this.nonceStr; | |||
} | |||
public void setNonceStr(String nonceStr) { | |||
this.nonceStr = nonceStr; | |||
} | |||
public String getSignature() { | |||
return this.signature; | |||
} | |||
public void setSignature(String signature) { | |||
this.signature = signature; | |||
} | |||
} |
@@ -1,10 +1,13 @@ | |||
package me.chanjar.weixin.common.bean; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
* jspai signature | |||
* jspai signature. | |||
*/ | |||
@Data | |||
public class WxJsapiSignature implements Serializable { | |||
private static final long serialVersionUID = -1116808193154384804L; | |||
@@ -18,43 +21,4 @@ public class WxJsapiSignature implements Serializable { | |||
private String signature; | |||
public String getSignature() { | |||
return this.signature; | |||
} | |||
public void setSignature(String signature) { | |||
this.signature = signature; | |||
} | |||
public String getNonceStr() { | |||
return nonceStr; | |||
} | |||
public void setNonceStr(String nonceStr) { | |||
this.nonceStr = nonceStr; | |||
} | |||
public long getTimestamp() { | |||
return this.timestamp; | |||
} | |||
public void setTimestamp(long timestamp) { | |||
this.timestamp = timestamp; | |||
} | |||
public String getUrl() { | |||
return this.url; | |||
} | |||
public void setUrl(String url) { | |||
this.url = url; | |||
} | |||
public String getAppId() { | |||
return appId; | |||
} | |||
public void setAppId(String appId) { | |||
this.appId = appId; | |||
} | |||
} |
@@ -1,5 +1,6 @@ | |||
package me.chanjar.weixin.common.bean.menu; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||
@@ -11,12 +12,12 @@ import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* 菜单(公众号和企业号共用的) | |||
* 菜单(公众号和企业号共用的). | |||
* | |||
* @author Daniel Qian | |||
*/ | |||
@Data | |||
public class WxMenu implements Serializable { | |||
private static final long serialVersionUID = -7083914585539687746L; | |||
private List<WxMenuButton> buttons = new ArrayList<>(); | |||
@@ -36,23 +37,8 @@ public class WxMenu implements Serializable { | |||
* 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu | |||
*/ | |||
public static WxMenu fromJson(InputStream is) { | |||
return WxGsonBuilder.create().fromJson(new InputStreamReader(is, StandardCharsets.UTF_8), WxMenu.class); | |||
} | |||
public List<WxMenuButton> getButtons() { | |||
return this.buttons; | |||
} | |||
public void setButtons(List<WxMenuButton> buttons) { | |||
this.buttons = buttons; | |||
} | |||
public WxMenuRule getMatchRule() { | |||
return this.matchRule; | |||
} | |||
public void setMatchRule(WxMenuRule matchRule) { | |||
this.matchRule = matchRule; | |||
return WxGsonBuilder.create() | |||
.fromJson(new InputStreamReader(is, StandardCharsets.UTF_8), WxMenu.class); | |||
} | |||
public String toJson() { | |||
@@ -1,18 +1,20 @@ | |||
package me.chanjar.weixin.common.bean.menu; | |||
import com.google.gson.annotations.SerializedName; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import java.io.Serializable; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
@Data | |||
public class WxMenuButton implements Serializable { | |||
private static final long serialVersionUID = -1070939403109776555L; | |||
/** | |||
* <pre> | |||
* 菜单的响应动作类型: | |||
* 菜单的响应动作类型. | |||
* view表示网页类型, | |||
* click表示点击类型, | |||
* miniprogram表示小程序类型 | |||
@@ -21,13 +23,13 @@ public class WxMenuButton implements Serializable { | |||
private String type; | |||
/** | |||
* 菜单标题,不超过16个字节,子菜单不超过60个字节 | |||
* 菜单标题,不超过16个字节,子菜单不超过60个字节. | |||
*/ | |||
private String name; | |||
/** | |||
* <pre> | |||
* 菜单KEY值,用于消息接口推送,不超过128字节 | |||
* 菜单KEY值,用于消息接口推送,不超过128字节. | |||
* click等点击类型必须 | |||
* </pre> | |||
*/ | |||
@@ -35,7 +37,8 @@ public class WxMenuButton implements Serializable { | |||
/** | |||
* <pre> | |||
* 网页链接,用户点击菜单可打开链接,不超过1024字节。type为miniprogram时,不支持小程序的老版本客户端将打开本url。 | |||
* 网页链接. | |||
* 用户点击菜单可打开链接,不超过1024字节。type为miniprogram时,不支持小程序的老版本客户端将打开本url。 | |||
* view、miniprogram类型必须 | |||
* </pre> | |||
*/ | |||
@@ -43,7 +46,7 @@ public class WxMenuButton implements Serializable { | |||
/** | |||
* <pre> | |||
* 调用新增永久素材接口返回的合法media_id | |||
* 调用新增永久素材接口返回的合法media_id. | |||
* media_id类型和view_limited类型必须 | |||
* </pre> | |||
*/ | |||
@@ -52,7 +55,7 @@ public class WxMenuButton implements Serializable { | |||
/** | |||
* <pre> | |||
* 小程序的appid | |||
* 小程序的appid. | |||
* miniprogram类型必须 | |||
* </pre> | |||
*/ | |||
@@ -61,7 +64,7 @@ public class WxMenuButton implements Serializable { | |||
/** | |||
* <pre> | |||
* 小程序的页面路径 | |||
* 小程序的页面路径. | |||
* miniprogram类型必须 | |||
* </pre> | |||
*/ | |||
@@ -76,67 +79,4 @@ public class WxMenuButton implements Serializable { | |||
return ToStringUtils.toSimpleString(this); | |||
} | |||
public String getType() { | |||
return this.type; | |||
} | |||
public void setType(String type) { | |||
this.type = type; | |||
} | |||
public String getName() { | |||
return this.name; | |||
} | |||
public void setName(String name) { | |||
this.name = name; | |||
} | |||
public String getKey() { | |||
return this.key; | |||
} | |||
public void setKey(String key) { | |||
this.key = key; | |||
} | |||
public String getUrl() { | |||
return this.url; | |||
} | |||
public void setUrl(String url) { | |||
this.url = url; | |||
} | |||
public List<WxMenuButton> getSubButtons() { | |||
return this.subButtons; | |||
} | |||
public void setSubButtons(List<WxMenuButton> subButtons) { | |||
this.subButtons = subButtons; | |||
} | |||
public String getMediaId() { | |||
return this.mediaId; | |||
} | |||
public void setMediaId(String mediaId) { | |||
this.mediaId = mediaId; | |||
} | |||
public String getAppId() { | |||
return appId; | |||
} | |||
public void setAppId(String appId) { | |||
this.appId = appId; | |||
} | |||
public String getPagePath() { | |||
return pagePath; | |||
} | |||
public void setPagePath(String pagePath) { | |||
this.pagePath = pagePath; | |||
} | |||
} |
@@ -1,12 +1,19 @@ | |||
package me.chanjar.weixin.common.bean.menu; | |||
import com.google.gson.annotations.SerializedName; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import java.io.Serializable; | |||
@Data | |||
public class WxMenuRule implements Serializable { | |||
private static final long serialVersionUID = -4587181819499286670L; | |||
/** | |||
* 变态的微信接口,反序列化时这里反人类的使用和序列化时不一样的名字. | |||
*/ | |||
@SerializedName(value = "tag_id", alternate = "group_id") | |||
private String tagId; | |||
private String sex; | |||
private String country; | |||
@@ -15,62 +22,6 @@ public class WxMenuRule implements Serializable { | |||
private String clientPlatformType; | |||
private String language; | |||
public String getTagId() { | |||
return this.tagId; | |||
} | |||
public void setTagId(String tagId) { | |||
this.tagId = tagId; | |||
} | |||
public String getSex() { | |||
return this.sex; | |||
} | |||
public void setSex(String sex) { | |||
this.sex = sex; | |||
} | |||
public String getCountry() { | |||
return this.country; | |||
} | |||
public void setCountry(String country) { | |||
this.country = country; | |||
} | |||
public String getProvince() { | |||
return this.province; | |||
} | |||
public void setProvince(String province) { | |||
this.province = province; | |||
} | |||
public String getCity() { | |||
return this.city; | |||
} | |||
public void setCity(String city) { | |||
this.city = city; | |||
} | |||
public String getClientPlatformType() { | |||
return this.clientPlatformType; | |||
} | |||
public void setClientPlatformType(String clientPlatformType) { | |||
this.clientPlatformType = clientPlatformType; | |||
} | |||
public String getLanguage() { | |||
return this.language; | |||
} | |||
public void setLanguage(String language) { | |||
this.language = language; | |||
} | |||
@Override | |||
public String toString() { | |||
return ToStringUtils.toSimpleString(this); | |||
@@ -1,14 +1,18 @@ | |||
package me.chanjar.weixin.common.bean.result; | |||
import lombok.Builder; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||
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 | |||
*/ | |||
@Data | |||
@Builder | |||
public class WxError implements Serializable { | |||
private static final long serialVersionUID = 7869786563361406291L; | |||
@@ -23,34 +27,6 @@ public class WxError implements Serializable { | |||
return WxGsonBuilder.create().fromJson(json, WxError.class); | |||
} | |||
public static Builder newBuilder() { | |||
return new Builder(); | |||
} | |||
public int getErrorCode() { | |||
return this.errorCode; | |||
} | |||
public void setErrorCode(int errorCode) { | |||
this.errorCode = errorCode; | |||
} | |||
public String getErrorMsg() { | |||
return this.errorMsg; | |||
} | |||
public void setErrorMsg(String errorMsg) { | |||
this.errorMsg = errorMsg; | |||
} | |||
public String getJson() { | |||
return this.json; | |||
} | |||
public void setJson(String json) { | |||
this.json = json; | |||
} | |||
@Override | |||
public String toString() { | |||
if (this.json != null) { | |||
@@ -59,26 +35,4 @@ public class WxError implements Serializable { | |||
return "错误: Code=" + this.errorCode + ", Msg=" + this.errorMsg; | |||
} | |||
public static class Builder { | |||
private int errorCode; | |||
private String errorMsg; | |||
public Builder setErrorCode(int errorCode) { | |||
this.errorCode = errorCode; | |||
return this; | |||
} | |||
public Builder setErrorMsg(String errorMsg) { | |||
this.errorMsg = errorMsg; | |||
return this; | |||
} | |||
public WxError build() { | |||
WxError wxError = new WxError(); | |||
wxError.setErrorCode(this.errorCode); | |||
wxError.setErrorMsg(this.errorMsg); | |||
return wxError; | |||
} | |||
} | |||
} |
@@ -1,11 +1,12 @@ | |||
package me.chanjar.weixin.common.bean.result; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||
import org.apache.commons.lang3.builder.ToStringBuilder; | |||
import org.apache.commons.lang3.builder.ToStringStyle; | |||
import java.io.Serializable; | |||
@Data | |||
public class WxMediaUploadResult implements Serializable { | |||
private static final long serialVersionUID = 330834334738622341L; | |||
@@ -18,41 +19,9 @@ public class WxMediaUploadResult implements Serializable { | |||
return WxGsonBuilder.create().fromJson(json, WxMediaUploadResult.class); | |||
} | |||
public String getType() { | |||
return this.type; | |||
} | |||
public void setType(String type) { | |||
this.type = type; | |||
} | |||
public String getMediaId() { | |||
return this.mediaId; | |||
} | |||
public void setMediaId(String mediaId) { | |||
this.mediaId = mediaId; | |||
} | |||
public long getCreatedAt() { | |||
return this.createdAt; | |||
} | |||
public void setCreatedAt(long createdAt) { | |||
this.createdAt = createdAt; | |||
} | |||
public String getThumbMediaId() { | |||
return this.thumbMediaId; | |||
} | |||
public void setThumbMediaId(String thumbMediaId) { | |||
this.thumbMediaId = thumbMediaId; | |||
} | |||
@Override | |||
public String toString() { | |||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||
return ToStringUtils.toSimpleString(this); | |||
} | |||
} |
@@ -11,6 +11,7 @@ import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import java.lang.reflect.Field; | |||
import java.lang.reflect.Modifier; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
@@ -20,8 +21,9 @@ import java.util.Map; | |||
* <pre> | |||
* bean操作的一些工具类 | |||
* Created by Binary Wang on 2016-10-21. | |||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||
* </pre> | |||
* | |||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||
*/ | |||
public class BeanUtils { | |||
private static Logger log = LoggerFactory.getLogger(BeanUtils.class); | |||
@@ -42,22 +44,27 @@ public class BeanUtils { | |||
boolean isAccessible = field.isAccessible(); | |||
field.setAccessible(true); | |||
if (field.isAnnotationPresent(Required.class)) { | |||
if (field.get(bean) == null || (field.get(bean) instanceof String && StringUtils.isBlank(field.get(bean).toString()))) { | |||
//两种情况,一种是值为null,另外一种情况是类型为字符串,但是字符串内容为空的,都认为是没有提供值 | |||
// 两种情况,一种是值为null, | |||
// 另外一种情况是类型为字符串,但是字符串内容为空的,都认为是没有提供值 | |||
boolean isRequiredMissing = field.get(bean) == null | |||
|| (field.get(bean) instanceof String | |||
&& StringUtils.isBlank(field.get(bean).toString()) | |||
); | |||
if (isRequiredMissing) { | |||
requiredFields.add(field.getName()); | |||
} | |||
} | |||
field.setAccessible(isAccessible); | |||
} catch (SecurityException | IllegalArgumentException | |||
| IllegalAccessException e) { | |||
e.printStackTrace(); | |||
log.error(e.getMessage(), e); | |||
} | |||
} | |||
if (!requiredFields.isEmpty()) { | |||
String msg = "必填字段 " + requiredFields + " 必须提供值"; | |||
log.debug(msg); | |||
throw new WxErrorException(WxError.newBuilder().setErrorMsg(msg).build()); | |||
throw new WxErrorException(WxError.builder().errorMsg(msg).build()); | |||
} | |||
} | |||
@@ -82,11 +89,14 @@ public class BeanUtils { | |||
if (field.isAnnotationPresent(XStreamAlias.class)) { | |||
result.put(field.getAnnotation(XStreamAlias.class).value(), field.get(bean).toString()); | |||
} else if (!Modifier.isStatic(field.getModifiers())) { | |||
//忽略掉静态成员变量 | |||
result.put(field.getName(), field.get(bean).toString()); | |||
} | |||
field.setAccessible(isAccessible); | |||
} catch (SecurityException | IllegalArgumentException | IllegalAccessException e) { | |||
e.printStackTrace(); | |||
log.error(e.getMessage(), e); | |||
} | |||
} | |||
@@ -8,8 +8,9 @@ import org.apache.commons.lang3.builder.ToStringStyle; | |||
* <pre> | |||
* 自定义的ToString方法,用于产生去掉空值属性的字符串 | |||
* Created by Binary Wang on 2016-10-27. | |||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||
* </pre> | |||
* | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
public class ToStringUtils { | |||
public static final ToStringStyle THE_STYLE = new SimpleMultiLineToStringStyle(); | |||
@@ -1,26 +1,26 @@ | |||
package me.chanjar.weixin.common.util.crypto; | |||
import java.util.ArrayList; | |||
public class ByteGroup { | |||
ArrayList<Byte> byteContainer = new ArrayList<>(); | |||
public byte[] toBytes() { | |||
byte[] bytes = new byte[this.byteContainer.size()]; | |||
for (int i = 0; i < this.byteContainer.size(); i++) { | |||
bytes[i] = this.byteContainer.get(i); | |||
} | |||
return bytes; | |||
} | |||
public ByteGroup addBytes(byte[] bytes) { | |||
for (byte b : bytes) { | |||
this.byteContainer.add(b); | |||
} | |||
return this; | |||
} | |||
public int size() { | |||
return this.byteContainer.size(); | |||
} | |||
} | |||
package me.chanjar.weixin.common.util.crypto; | |||
import java.util.ArrayList; | |||
public class ByteGroup { | |||
ArrayList<Byte> byteContainer = new ArrayList<>(); | |||
public byte[] toBytes() { | |||
byte[] bytes = new byte[this.byteContainer.size()]; | |||
for (int i = 0; i < this.byteContainer.size(); i++) { | |||
bytes[i] = this.byteContainer.get(i); | |||
} | |||
return bytes; | |||
} | |||
public ByteGroup addBytes(byte[] bytes) { | |||
for (byte b : bytes) { | |||
this.byteContainer.add(b); | |||
} | |||
return this; | |||
} | |||
public int size() { | |||
return this.byteContainer.size(); | |||
} | |||
} |
@@ -1,68 +1,68 @@ | |||
/** | |||
* 对公众平台发送给公众账号的消息加解密示例代码. | |||
* | |||
* @copyright Copyright (c) 1998-2014 Tencent Inc. | |||
*/ | |||
// ------------------------------------------------------------------------ | |||
package me.chanjar.weixin.common.util.crypto; | |||
import java.nio.charset.Charset; | |||
import java.util.Arrays; | |||
/** | |||
* 提供基于PKCS7算法的加解 | |||
*/ | |||
public class PKCS7Encoder { | |||
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 decrypted 解密后的明文 | |||
* @return 删除补位字符后的明文 | |||
*/ | |||
public static byte[] decode(byte[] decrypted) { | |||
int pad = 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; | |||
} | |||
} | |||
/** | |||
* 对公众平台发送给公众账号的消息加解密示例代码. | |||
* | |||
* @copyright Copyright (c) 1998-2014 Tencent Inc. | |||
*/ | |||
// ------------------------------------------------------------------------ | |||
package me.chanjar.weixin.common.util.crypto; | |||
import java.nio.charset.Charset; | |||
import java.util.Arrays; | |||
/** | |||
* 提供基于PKCS7算法的加解 | |||
*/ | |||
public class PKCS7Encoder { | |||
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 decrypted 解密后的明文 | |||
* @return 删除补位字符后的明文 | |||
*/ | |||
public static byte[] decode(byte[] decrypted) { | |||
int pad = 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; | |||
} | |||
} |
@@ -1,52 +1,37 @@ | |||
package me.chanjar.weixin.common.util.fs; | |||
import java.io.File; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.nio.file.Files; | |||
public class FileUtils { | |||
/** | |||
* 创建临时文件 | |||
* | |||
* @param inputStream | |||
* @param inputStream 输入文件流 | |||
* @param name 文件名 | |||
* @param ext 扩展名 | |||
* @param tmpDirFile 临时文件夹目录 | |||
*/ | |||
public static File createTmpFile(InputStream inputStream, String name, String ext, File tmpDirFile) throws IOException { | |||
File tmpFile; | |||
if (tmpDirFile == null) { | |||
tmpFile = File.createTempFile(name, '.' + ext); | |||
} else { | |||
tmpFile = File.createTempFile(name, '.' + ext, tmpDirFile); | |||
} | |||
tmpFile.deleteOnExit(); | |||
try (FileOutputStream fos = new FileOutputStream(tmpFile)) { | |||
int read = 0; | |||
byte[] bytes = new byte[1024 * 100]; | |||
while ((read = inputStream.read(bytes)) != -1) { | |||
fos.write(bytes, 0, read); | |||
} | |||
File resultFile = File.createTempFile(name, '.' + ext, tmpDirFile); | |||
fos.flush(); | |||
return tmpFile; | |||
} | |||
resultFile.deleteOnExit(); | |||
org.apache.commons.io.FileUtils.copyInputStreamToFile(inputStream, resultFile); | |||
return resultFile; | |||
} | |||
/** | |||
* 创建临时文件 | |||
* | |||
* @param inputStream | |||
* @param inputStream 输入文件流 | |||
* @param name 文件名 | |||
* @param ext 扩展名 | |||
*/ | |||
public static File createTmpFile(InputStream inputStream, String name, String ext) throws IOException { | |||
return createTmpFile(inputStream, name, ext, null); | |||
return createTmpFile(inputStream, name, ext, Files.createTempDirectory("weixin-java-tools-temp").toFile()); | |||
} | |||
} |
@@ -12,11 +12,11 @@ import java.io.File; | |||
* | |||
* @author Daniel Qian | |||
*/ | |||
public abstract class MediaDownloadRequestExecutor<H, P> implements RequestExecutor<File, String> { | |||
public abstract class BaseMediaDownloadRequestExecutor<H, P> implements RequestExecutor<File, String> { | |||
protected RequestHttp<H, P> requestHttp; | |||
protected File tmpDirFile; | |||
public MediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { | |||
public BaseMediaDownloadRequestExecutor(RequestHttp<H, P> requestHttp, File tmpDirFile) { | |||
this.requestHttp = requestHttp; | |||
this.tmpDirFile = tmpDirFile; | |||
} |
@@ -19,6 +19,8 @@ import java.util.regex.Pattern; | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
public class HttpResponseProxy { | |||
private static final Pattern PATTERN = Pattern.compile(".*filename=\"(.*)\""); | |||
private CloseableHttpResponse apacheHttpResponse; | |||
private HttpResponse joddHttpResponse; | |||
private Response okHttpResponse; | |||
@@ -56,7 +58,7 @@ public class HttpResponseProxy { | |||
private String getFileName(CloseableHttpResponse response) throws WxErrorException { | |||
Header[] contentDispositionHeader = response.getHeaders("Content-disposition"); | |||
if (contentDispositionHeader == null || contentDispositionHeader.length == 0) { | |||
throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); | |||
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").build()); | |||
} | |||
return this.extractFileNameFromContentString(contentDispositionHeader[0].getValue()); | |||
@@ -74,15 +76,15 @@ public class HttpResponseProxy { | |||
private String extractFileNameFromContentString(String content) throws WxErrorException { | |||
if (content == null || content.length() == 0) { | |||
throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); | |||
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").build()); | |||
} | |||
Pattern p = Pattern.compile(".*filename=\"(.*)\""); | |||
Matcher m = p.matcher(content); | |||
Matcher m = PATTERN.matcher(content); | |||
if (m.matches()) { | |||
return m.group(1); | |||
} | |||
throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); | |||
throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").build()); | |||
} | |||
} |
@@ -4,51 +4,41 @@ import org.apache.http.conn.ssl.SSLConnectionSocketFactory; | |||
import org.apache.http.impl.client.CloseableHttpClient; | |||
/** | |||
* httpclient build interface | |||
* httpclient build interface. | |||
* | |||
* @author kakotor | |||
*/ | |||
public interface ApacheHttpClientBuilder { | |||
/** | |||
* 构建httpclient实例 | |||
* 构建httpclient实例. | |||
* | |||
* @return new instance of CloseableHttpClient | |||
*/ | |||
CloseableHttpClient build(); | |||
/** | |||
* 代理服务器地址 | |||
* | |||
* @param httpProxyHost | |||
* 代理服务器地址. | |||
*/ | |||
ApacheHttpClientBuilder httpProxyHost(String httpProxyHost); | |||
/** | |||
* 代理服务器端口 | |||
* | |||
* @param httpProxyPort | |||
* 代理服务器端口. | |||
*/ | |||
ApacheHttpClientBuilder httpProxyPort(int httpProxyPort); | |||
/** | |||
* 代理服务器用户名 | |||
* | |||
* @param httpProxyUsername | |||
* 代理服务器用户名. | |||
*/ | |||
ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername); | |||
/** | |||
* 代理服务器密码 | |||
* | |||
* @param httpProxyPassword | |||
* 代理服务器密码. | |||
*/ | |||
ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword); | |||
/** | |||
* ssl连接socket工厂 | |||
* | |||
* @param sslConnectionSocketFactory | |||
* ssl连接socket工厂. | |||
*/ | |||
ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory); | |||
} |
@@ -29,9 +29,8 @@ import java.util.concurrent.TimeUnit; | |||
import java.util.concurrent.atomic.AtomicBoolean; | |||
/** | |||
* httpclient 连接管理器 自带DNS解析 | |||
* <p> | |||
* 大部分代码拷贝自:DefaultApacheHttpClientBuilder | |||
* httpclient 连接管理器 自带DNS解析. | |||
* <p>大部分代码拷贝自:DefaultApacheHttpClientBuilder</p> | |||
* | |||
* @author Andy.Huo | |||
*/ | |||
@@ -64,7 +63,7 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||
private String httpProxyPassword; | |||
/** | |||
* 闲置连接监控线程 | |||
* 闲置连接监控线程. | |||
*/ | |||
private IdleConnectionMonitorThread idleConnectionMonitorThread; | |||
private HttpClientBuilder httpClientBuilder; | |||
@@ -162,7 +161,7 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||
} | |||
/** | |||
* 每路的最大链接数,默认10 | |||
* 每路的最大链接数,默认10. | |||
* | |||
* @param maxConnPerHost 每路的最大链接数,默认10 | |||
*/ | |||
@@ -171,7 +170,7 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||
} | |||
/** | |||
* 最大总连接数,默认50 | |||
* 最大总连接数,默认50. | |||
* | |||
* @param maxTotalConn 最大总连接数,默认50 | |||
*/ | |||
@@ -180,7 +179,7 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||
} | |||
/** | |||
* 自定义httpclient的User Agent | |||
* 自定义httpclient的User Agent. | |||
* | |||
* @param userAgent User Agent | |||
*/ | |||
@@ -196,9 +195,12 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||
if (prepared.get()) { | |||
return; | |||
} | |||
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() | |||
.register("http", this.plainConnectionSocketFactory).register("https", this.sslConnectionSocketFactory) | |||
.build(); | |||
Registry<ConnectionSocketFactory> registry = | |||
RegistryBuilder.<ConnectionSocketFactory>create() | |||
.register("http", this.plainConnectionSocketFactory) | |||
.register("https", this.sslConnectionSocketFactory) | |||
.build(); | |||
@SuppressWarnings("resource") | |||
PoolingHttpClientConnectionManager connectionManager; | |||
@@ -219,8 +221,8 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||
connectionManager | |||
.setDefaultSocketConfig(SocketConfig.copy(SocketConfig.DEFAULT).setSoTimeout(this.soTimeout).build()); | |||
this.idleConnectionMonitorThread = new IdleConnectionMonitorThread(connectionManager, this.idleConnTimeout, | |||
this.checkWaitTime); | |||
this.idleConnectionMonitorThread = new IdleConnectionMonitorThread( | |||
connectionManager, this.idleConnTimeout, this.checkWaitTime); | |||
this.idleConnectionMonitorThread.setDaemon(true); | |||
this.idleConnectionMonitorThread.start(); | |||
@@ -234,8 +236,8 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||
if (StringUtils.isNotBlank(this.httpProxyHost) && StringUtils.isNotBlank(this.httpProxyUsername)) { | |||
// 使用代理服务器 需要用户认证的代理服务器 | |||
CredentialsProvider provider = new BasicCredentialsProvider(); | |||
provider.setCredentials(new AuthScope(this.httpProxyHost, this.httpProxyPort), | |||
new UsernamePasswordCredentials(this.httpProxyUsername, this.httpProxyPassword)); | |||
provider.setCredentials(new AuthScope(this.httpProxyHost, this.httpProxyPort) | |||
, new UsernamePasswordCredentials(this.httpProxyUsername, this.httpProxyPassword)); | |||
this.httpClientBuilder.setDefaultCredentialsProvider(provider); | |||
} | |||
@@ -267,8 +269,10 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||
private final int checkWaitTime; | |||
private volatile boolean shutdown; | |||
public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr, int idleConnTimeout, | |||
int checkWaitTime) { | |||
/** | |||
* 构造方法. | |||
*/ | |||
public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr, int idleConnTimeout, int checkWaitTime) { | |||
super("IdleConnectionMonitorThread"); | |||
this.connMgr = connMgr; | |||
this.idleConnTimeout = idleConnTimeout; | |||
@@ -289,12 +293,18 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||
} | |||
} | |||
/** | |||
* 触发. | |||
*/ | |||
public void trigger() { | |||
synchronized (this) { | |||
notifyAll(); | |||
} | |||
} | |||
/** | |||
* 关闭. | |||
*/ | |||
public void shutdown() { | |||
this.shutdown = true; | |||
synchronized (this) { | |||
@@ -4,7 +4,7 @@ import me.chanjar.weixin.common.bean.result.WxError; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.common.util.fs.FileUtils; | |||
import me.chanjar.weixin.common.util.http.HttpResponseProxy; | |||
import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; | |||
import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor; | |||
import me.chanjar.weixin.common.util.http.RequestHttp; | |||
import org.apache.commons.io.FilenameUtils; | |||
import org.apache.commons.lang3.StringUtils; | |||
@@ -23,7 +23,7 @@ import java.io.InputStream; | |||
/** | |||
* Created by ecoolper on 2017/5/5. | |||
*/ | |||
public class ApacheMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor<CloseableHttpClient, HttpHost> { | |||
public class ApacheMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor<CloseableHttpClient, HttpHost> { | |||
public ApacheMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { | |||
super(requestHttp, tmpDirFile); | |||
@@ -39,9 +39,7 @@ public class ApacheSimplePostRequestExecutor extends SimplePostRequestExecutor<C | |||
try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { | |||
String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); | |||
if (responseContent.isEmpty()) { | |||
throw new WxErrorException( | |||
WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") | |||
.build()); | |||
throw new WxErrorException(WxError.builder().errorCode(9999).errorMsg("无响应内容").build()); | |||
} | |||
if (responseContent.startsWith("<xml>")) { | |||
@@ -9,7 +9,7 @@ import me.chanjar.weixin.common.bean.result.WxError; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.common.util.fs.FileUtils; | |||
import me.chanjar.weixin.common.util.http.HttpResponseProxy; | |||
import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; | |||
import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor; | |||
import me.chanjar.weixin.common.util.http.RequestHttp; | |||
import org.apache.commons.io.FilenameUtils; | |||
import org.apache.commons.lang3.StringUtils; | |||
@@ -22,7 +22,7 @@ import java.io.InputStream; | |||
/** | |||
* Created by ecoolper on 2017/5/5. | |||
*/ | |||
public class JoddHttpMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor<HttpConnectionProvider, ProxyInfo> { | |||
public class JoddHttpMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor<HttpConnectionProvider, ProxyInfo> { | |||
public JoddHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { | |||
super(requestHttp, tmpDirFile); | |||
@@ -5,7 +5,6 @@ import jodd.http.HttpRequest; | |||
import jodd.http.HttpResponse; | |||
import jodd.http.ProxyInfo; | |||
import jodd.util.StringPool; | |||
import me.chanjar.weixin.common.bean.result.WxError; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.common.util.http.RequestHttp; | |||
@@ -40,9 +39,8 @@ public class JoddHttpSimplePostRequestExecutor extends SimplePostRequestExecutor | |||
String responseContent = response.bodyText(); | |||
if (responseContent.isEmpty()) { | |||
throw new WxErrorException( | |||
WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") | |||
.build()); | |||
throw new WxErrorException(WxError.builder().errorCode(9999).errorMsg("无响应内容") | |||
.build()); | |||
} | |||
if (responseContent.startsWith("<xml>")) { | |||
@@ -2,8 +2,8 @@ package me.chanjar.weixin.common.util.http.okhttp; | |||
import me.chanjar.weixin.common.bean.result.WxError; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor; | |||
import me.chanjar.weixin.common.util.http.HttpResponseProxy; | |||
import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; | |||
import me.chanjar.weixin.common.util.http.RequestHttp; | |||
import okhttp3.OkHttpClient; | |||
import okhttp3.Request; | |||
@@ -21,7 +21,7 @@ import java.io.IOException; | |||
/** | |||
* Created by ecoolper on 2017/5/5. | |||
*/ | |||
public class OkHttpMediaDownloadRequestExecutor extends MediaDownloadRequestExecutor<OkHttpClient, OkHttpProxyInfo> { | |||
public class OkHttpMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor<OkHttpClient, OkHttpProxyInfo> { | |||
private final Logger logger = LoggerFactory.getLogger(this.getClass()); | |||
public OkHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { | |||
@@ -14,23 +14,26 @@ import me.chanjar.weixin.common.bean.result.WxError; | |||
import java.lang.reflect.Type; | |||
/** | |||
* @author Daniel Qian | |||
* @author Daniel Qian. | |||
*/ | |||
public class WxErrorAdapter implements JsonDeserializer<WxError> { | |||
@Override | |||
public WxError deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { | |||
WxError wxError = new WxError(); | |||
public WxError deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) | |||
throws JsonParseException { | |||
WxError.WxErrorBuilder errorBuilder = WxError.builder(); | |||
JsonObject wxErrorJsonObject = json.getAsJsonObject(); | |||
if (wxErrorJsonObject.get("errcode") != null && !wxErrorJsonObject.get("errcode").isJsonNull()) { | |||
wxError.setErrorCode(GsonHelper.getAsPrimitiveInt(wxErrorJsonObject.get("errcode"))); | |||
errorBuilder.errorCode(GsonHelper.getAsPrimitiveInt(wxErrorJsonObject.get("errcode"))); | |||
} | |||
if (wxErrorJsonObject.get("errmsg") != null && !wxErrorJsonObject.get("errmsg").isJsonNull()) { | |||
wxError.setErrorMsg(GsonHelper.getAsString(wxErrorJsonObject.get("errmsg"))); | |||
errorBuilder.errorMsg(GsonHelper.getAsString(wxErrorJsonObject.get("errmsg"))); | |||
} | |||
wxError.setJson(json.toString()); | |||
return wxError; | |||
errorBuilder.json(json.toString()); | |||
return errorBuilder.build(); | |||
} | |||
} |
@@ -70,6 +70,7 @@ public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializ | |||
return matchRule; | |||
} | |||
@Deprecated | |||
private WxMenuRule convertToRule(JsonObject json) { | |||
WxMenuRule menuRule = new WxMenuRule(); | |||
//变态的微信接口,这里居然反人类的使用和序列化时不一样的名字 | |||
@@ -8,7 +8,6 @@ import org.testng.annotations.*; | |||
public class WxErrorTest { | |||
public void testFromJson() { | |||
String json = "{ \"errcode\": 40003, \"errmsg\": \"invalid openid\" }"; | |||
WxError wxError = WxError.fromJson(json); | |||
Assert.assertTrue(wxError.getErrorCode() == 40003); | |||
@@ -10,7 +10,7 @@ import static org.testng.Assert.assertNotNull; | |||
* Created by BinaryWang on 2017/6/10. | |||
* </pre> | |||
* | |||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
public class SHA1Test { | |||
@Test | |||
@@ -7,7 +7,7 @@ | |||
<parent> | |||
<groupId>com.github.binarywang</groupId> | |||
<artifactId>weixin-java-parent</artifactId> | |||
<version>2.8.0</version> | |||
<version>2.9.0</version> | |||
</parent> | |||
<artifactId>weixin-java-cp</artifactId> | |||
@@ -3,7 +3,7 @@ package me.chanjar.weixin.cp.api.impl; | |||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.common.util.fs.FileUtils; | |||
import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; | |||
import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor; | |||
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; | |||
import me.chanjar.weixin.cp.api.WxCpMediaService; | |||
import me.chanjar.weixin.cp.api.WxCpService; | |||
@@ -43,7 +43,7 @@ public class WxCpMediaServiceImpl implements WxCpMediaService { | |||
public File download(String mediaId) throws WxErrorException { | |||
String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get"; | |||
return this.mainService.execute( | |||
MediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(), | |||
BaseMediaDownloadRequestExecutor.create(this.mainService.getRequestHttp(), | |||
this.mainService.getWxCpConfigStorage().getTmpDirFile()), | |||
url, "media_id=" + mediaId); | |||
} | |||
@@ -381,7 +381,7 @@ public abstract class WxCpServiceAbstractImpl<H, P> implements WxCpService, Requ | |||
throw new RuntimeException("微信服务端异常,超出重试次数"); | |||
} | |||
protected synchronized <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException { | |||
protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException { | |||
if (uri.contains("access_token=")) { | |||
throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); | |||
} | |||
@@ -4,8 +4,9 @@ package me.chanjar.weixin.cp.api.impl; | |||
* <pre> | |||
* 默认接口实现类,使用apache httpclient实现 | |||
* Created by Binary Wang on 2017-5-27. | |||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||
* </pre> | |||
* | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
public class WxCpServiceImpl extends WxCpServiceApacheHttpClientImpl { | |||
} |
@@ -7,14 +7,10 @@ import me.chanjar.weixin.common.util.http.HttpType; | |||
import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; | |||
import me.chanjar.weixin.cp.config.WxCpConfigStorage; | |||
import okhttp3.*; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import java.io.IOException; | |||
public class WxCpServiceOkHttpImpl extends WxCpServiceAbstractImpl<OkHttpClient, OkHttpProxyInfo> { | |||
private final Logger logger = LoggerFactory.getLogger(this.getClass()); | |||
protected OkHttpClient httpClient; | |||
protected OkHttpProxyInfo httpProxy; | |||
@@ -36,7 +32,7 @@ public class WxCpServiceOkHttpImpl extends WxCpServiceAbstractImpl<OkHttpClient, | |||
@Override | |||
public String getAccessToken(boolean forceRefresh) throws WxErrorException { | |||
logger.debug("WxCpServiceOkHttpImpl is running"); | |||
this.log.debug("WxCpServiceOkHttpImpl is running"); | |||
if (this.configStorage.isAccessTokenExpired() || forceRefresh) { | |||
synchronized (this.globalAccessTokenRefreshLock) { | |||
if (this.configStorage.isAccessTokenExpired()) { | |||
@@ -47,18 +43,14 @@ public class WxCpServiceOkHttpImpl extends WxCpServiceAbstractImpl<OkHttpClient, | |||
OkHttpClient client = getRequestHttpClient(); | |||
//请求的request | |||
Request request = new Request.Builder().url(url).get().build(); | |||
Response response = null; | |||
try { | |||
response = client.newCall(request).execute(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
String resultContent = null; | |||
try { | |||
Response response = client.newCall(request).execute(); | |||
resultContent = response.body().string(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
this.log.error(e.getMessage(), e); | |||
} | |||
WxError error = WxError.fromJson(resultContent); | |||
if (error.getErrorCode() != 0) { | |||
throw new WxErrorException(error); | |||
@@ -74,9 +66,16 @@ public class WxCpServiceOkHttpImpl extends WxCpServiceAbstractImpl<OkHttpClient, | |||
@Override | |||
public void initHttp() { | |||
logger.debug("WxCpServiceOkHttpImpl initHttp"); | |||
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); | |||
this.log.debug("WxCpServiceOkHttpImpl initHttp"); | |||
//设置代理 | |||
if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { | |||
httpProxy = OkHttpProxyInfo.httpProxy(configStorage.getHttpProxyHost(), | |||
configStorage.getHttpProxyPort(), | |||
configStorage.getHttpProxyUsername(), | |||
configStorage.getHttpProxyPassword()); | |||
} | |||
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); | |||
if (httpProxy != null) { | |||
clientBuilder.proxy(getRequestHttpProxy().getProxy()); | |||
@@ -1,69 +1,30 @@ | |||
package me.chanjar.weixin.cp.bean; | |||
import lombok.Data; | |||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | |||
import java.io.Serializable; | |||
/** | |||
* 微信部门 | |||
* 微信部门. | |||
* | |||
* @author Daniel Qian | |||
*/ | |||
@Data | |||
public class WxCpDepart implements Serializable { | |||
private static final long serialVersionUID = -5028321625140879571L; | |||
private Integer id; | |||
private String name; | |||
private Integer parentId; | |||
private Integer order; | |||
private Long order; | |||
public static WxCpDepart fromJson(String json) { | |||
return WxCpGsonBuilder.create().fromJson(json, WxCpDepart.class); | |||
} | |||
public Integer getId() { | |||
return this.id; | |||
} | |||
public void setId(Integer id) { | |||
this.id = id; | |||
} | |||
public String getName() { | |||
return this.name; | |||
} | |||
public void setName(String name) { | |||
this.name = name; | |||
} | |||
public Integer getParentId() { | |||
return this.parentId; | |||
} | |||
public void setParentId(Integer parentId) { | |||
this.parentId = parentId; | |||
} | |||
public Integer getOrder() { | |||
return this.order; | |||
} | |||
public void setOrder(Integer order) { | |||
this.order = order; | |||
} | |||
public String toJson() { | |||
return WxCpGsonBuilder.create().toJson(this); | |||
} | |||
@Override | |||
public String toString() { | |||
return "WxCpDepart{" + | |||
"id=" + this.id + | |||
", name='" + this.name + '\'' + | |||
", parentId=" + this.parentId + | |||
", order=" + this.order + | |||
'}'; | |||
} | |||
} |
@@ -1,5 +1,7 @@ | |||
package me.chanjar.weixin.cp.bean; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.api.WxConsts; | |||
import me.chanjar.weixin.cp.bean.article.MpnewsArticle; | |||
import me.chanjar.weixin.cp.bean.article.NewArticle; | |||
import me.chanjar.weixin.cp.bean.messagebuilder.*; | |||
@@ -10,13 +12,14 @@ import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* 消息 | |||
* 消息. | |||
* | |||
* @author Daniel Qian | |||
*/ | |||
@Data | |||
public class WxCpMessage implements Serializable { | |||
private static final long serialVersionUID = -2082278303476631708L; | |||
private String toUser; | |||
private String toParty; | |||
private String toTag; | |||
@@ -35,115 +38,72 @@ public class WxCpMessage implements Serializable { | |||
private List<MpnewsArticle> mpnewsArticles = new ArrayList<>(); | |||
/** | |||
* 获得文本消息builder | |||
* 获得文本消息builder. | |||
*/ | |||
public static TextBuilder TEXT() { | |||
return new TextBuilder(); | |||
} | |||
/** | |||
* 获得文本卡片消息builder | |||
* 获得文本卡片消息builder. | |||
*/ | |||
public static TextCardBuilder TEXTCARD() { | |||
return new TextCardBuilder(); | |||
} | |||
/** | |||
* 获得图片消息builder | |||
* 获得图片消息builder. | |||
*/ | |||
public static ImageBuilder IMAGE() { | |||
return new ImageBuilder(); | |||
} | |||
/** | |||
* 获得语音消息builder | |||
* 获得语音消息builder. | |||
*/ | |||
public static VoiceBuilder VOICE() { | |||
return new VoiceBuilder(); | |||
} | |||
/** | |||
* 获得视频消息builder | |||
* 获得视频消息builder. | |||
*/ | |||
public static VideoBuilder VIDEO() { | |||
return new VideoBuilder(); | |||
} | |||
/** | |||
* 获得图文消息builder | |||
* 获得图文消息builder. | |||
*/ | |||
public static NewsBuilder NEWS() { | |||
return new NewsBuilder(); | |||
} | |||
/** | |||
* 获得mpnews图文消息builder | |||
* 获得mpnews图文消息builder. | |||
*/ | |||
public static MpnewsBuilder MPNEWS() { | |||
return new MpnewsBuilder(); | |||
} | |||
/** | |||
* 获得文件消息builder | |||
* 获得文件消息builder. | |||
*/ | |||
public static FileBuilder FILE() { | |||
return new FileBuilder(); | |||
} | |||
public List<MpnewsArticle> getMpnewsArticles() { | |||
return mpnewsArticles; | |||
} | |||
public void setMpnewsArticles(List<MpnewsArticle> mpnewsArticles) { | |||
this.mpnewsArticles = mpnewsArticles; | |||
} | |||
public String getToUser() { | |||
return this.toUser; | |||
} | |||
public void setToUser(String toUser) { | |||
this.toUser = toUser; | |||
} | |||
public String getToParty() { | |||
return this.toParty; | |||
} | |||
public void setToParty(String toParty) { | |||
this.toParty = toParty; | |||
} | |||
public String getToTag() { | |||
return this.toTag; | |||
} | |||
public void setToTag(String toTag) { | |||
this.toTag = toTag; | |||
} | |||
public Integer getAgentId() { | |||
return this.agentId; | |||
} | |||
public void setAgentId(Integer agentId) { | |||
this.agentId = agentId; | |||
} | |||
public String getMsgType() { | |||
return this.msgType; | |||
} | |||
/** | |||
* <pre> | |||
* 请使用 | |||
* {@link me.chanjar.weixin.common.api.WxConsts#CUSTOM_MSG_TEXT} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#CUSTOM_MSG_IMAGE} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#CUSTOM_MSG_VOICE} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#CUSTOM_MSG_MUSIC} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#CUSTOM_MSG_VIDEO} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#CUSTOM_MSG_NEWS} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#CUSTOM_MSG_MPNEWS} | |||
* {@link WxConsts.KefuMsgType#TEXT} | |||
* {@link WxConsts.KefuMsgType#IMAGE} | |||
* {@link WxConsts.KefuMsgType#VOICE} | |||
* {@link WxConsts.KefuMsgType#MUSIC} | |||
* {@link WxConsts.KefuMsgType#VIDEO} | |||
* {@link WxConsts.KefuMsgType#NEWS} | |||
* {@link WxConsts.KefuMsgType#MPNEWS} | |||
* </pre> | |||
* | |||
* @param msgType 消息类型 | |||
@@ -152,87 +112,8 @@ public class WxCpMessage implements Serializable { | |||
this.msgType = msgType; | |||
} | |||
public String getSafe() { | |||
return this.safe; | |||
} | |||
public void setSafe(String safe) { | |||
this.safe = safe; | |||
} | |||
public String getContent() { | |||
return this.content; | |||
} | |||
public void setContent(String content) { | |||
this.content = content; | |||
} | |||
public String getMediaId() { | |||
return this.mediaId; | |||
} | |||
public void setMediaId(String mediaId) { | |||
this.mediaId = mediaId; | |||
} | |||
public String getThumbMediaId() { | |||
return this.thumbMediaId; | |||
} | |||
public void setThumbMediaId(String thumbMediaId) { | |||
this.thumbMediaId = thumbMediaId; | |||
} | |||
public String getTitle() { | |||
return this.title; | |||
} | |||
public void setTitle(String title) { | |||
this.title = title; | |||
} | |||
public String getDescription() { | |||
return this.description; | |||
} | |||
public void setDescription(String description) { | |||
this.description = description; | |||
} | |||
public String getMusicUrl() { | |||
return this.musicUrl; | |||
} | |||
public void setMusicUrl(String musicUrl) { | |||
this.musicUrl = musicUrl; | |||
} | |||
public String getHqMusicUrl() { | |||
return this.hqMusicUrl; | |||
} | |||
public void setHqMusicUrl(String hqMusicUrl) { | |||
this.hqMusicUrl = hqMusicUrl; | |||
} | |||
public List<NewArticle> getArticles() { | |||
return this.articles; | |||
} | |||
public void setArticles(List<NewArticle> articles) { | |||
this.articles = articles; | |||
} | |||
public String toJson() { | |||
return WxCpGsonBuilder.INSTANCE.create().toJson(this); | |||
} | |||
public String getUrl() { | |||
return this.url; | |||
} | |||
public void setUrl(String url) { | |||
this.url = url; | |||
} | |||
} |
@@ -2,21 +2,25 @@ package me.chanjar.weixin.cp.bean; | |||
import com.google.common.base.Splitter; | |||
import com.google.gson.annotations.SerializedName; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | |||
import org.apache.commons.lang3.StringUtils; | |||
import java.io.Serializable; | |||
import java.util.Collections; | |||
import java.util.List; | |||
/** | |||
* <pre> | |||
* 消息发送结果对象类 | |||
* 消息发送结果对象类. | |||
* Created by Binary Wang on 2017-6-22. | |||
* | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
* </pre> | |||
*/ | |||
public class WxCpMessageSendResult { | |||
@Data | |||
public class WxCpMessageSendResult implements Serializable { | |||
private static final long serialVersionUID = 916455987193190004L; | |||
@Override | |||
public String toString() { | |||
return ToStringUtils.toSimpleString(this); | |||
@@ -41,52 +45,13 @@ public class WxCpMessageSendResult { | |||
@SerializedName("invalidtag") | |||
private String invalidTag; | |||
public Integer getErrCode() { | |||
return this.errCode; | |||
} | |||
public void setErrCode(Integer errCode) { | |||
this.errCode = errCode; | |||
} | |||
public String getErrMsg() { | |||
return this.errMsg; | |||
} | |||
public void setErrMsg(String errMsg) { | |||
this.errMsg = errMsg; | |||
} | |||
public String getInvalidUser() { | |||
return this.invalidUser; | |||
} | |||
public void setInvalidUser(String invalidUser) { | |||
this.invalidUser = invalidUser; | |||
} | |||
public String getInvalidParty() { | |||
return this.invalidParty; | |||
} | |||
public void setInvalidParty(String invalidParty) { | |||
this.invalidParty = invalidParty; | |||
} | |||
public String getInvalidTag() { | |||
return this.invalidTag; | |||
} | |||
public void setInvalidTag(String invalidTag) { | |||
this.invalidTag = invalidTag; | |||
} | |||
public List<String> getInvalidUserList() { | |||
return this.content2List(this.invalidUser); | |||
} | |||
private List<String> content2List(String content) { | |||
if(StringUtils.isBlank(content)){ | |||
if (StringUtils.isBlank(content)) { | |||
return Collections.emptyList(); | |||
} | |||
@@ -1,50 +1,30 @@ | |||
package me.chanjar.weixin.cp.bean; | |||
import lombok.AllArgsConstructor; | |||
import lombok.Data; | |||
import lombok.NoArgsConstructor; | |||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | |||
import java.io.Serializable; | |||
/** | |||
* Created by Daniel Qian | |||
* Created by Daniel Qian. | |||
*/ | |||
@Data | |||
@AllArgsConstructor | |||
@NoArgsConstructor | |||
public class WxCpTag implements Serializable { | |||
private static final long serialVersionUID = -7243320279646928402L; | |||
private String id; | |||
private String name; | |||
public WxCpTag() { | |||
super(); | |||
} | |||
public WxCpTag(String id, String name) { | |||
super(); | |||
this.id = id; | |||
this.name = name; | |||
} | |||
public static WxCpTag fromJson(String json) { | |||
return WxCpGsonBuilder.create().fromJson(json, WxCpTag.class); | |||
} | |||
public String getName() { | |||
return this.name; | |||
} | |||
public void setName(String name) { | |||
this.name = name; | |||
} | |||
public String getId() { | |||
return this.id; | |||
} | |||
public void setId(String id) { | |||
this.id = id; | |||
} | |||
public String toJson() { | |||
return WxCpGsonBuilder.create().toJson(this); | |||
} | |||
@@ -2,21 +2,25 @@ package me.chanjar.weixin.cp.bean; | |||
import com.google.common.base.Splitter; | |||
import com.google.gson.annotations.SerializedName; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | |||
import org.apache.commons.lang3.StringUtils; | |||
import java.io.Serializable; | |||
import java.util.Collections; | |||
import java.util.List; | |||
/** | |||
* <pre> | |||
* 为标签添加或移除用户结果对象类 | |||
* 为标签添加或移除用户结果对象类. | |||
* Created by Binary Wang on 2017-6-22. | |||
* | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
* </pre> | |||
*/ | |||
public class WxCpTagAddOrRemoveUsersResult { | |||
@Data | |||
public class WxCpTagAddOrRemoveUsersResult implements Serializable { | |||
private static final long serialVersionUID = 1420065684270213578L; | |||
@Override | |||
public String toString() { | |||
return ToStringUtils.toSimpleString(this); | |||
@@ -38,44 +42,12 @@ public class WxCpTagAddOrRemoveUsersResult { | |||
@SerializedName("invalidparty") | |||
private String[] invalidParty; | |||
public Integer getErrCode() { | |||
return this.errCode; | |||
} | |||
public void setErrCode(Integer errCode) { | |||
this.errCode = errCode; | |||
} | |||
public String getErrMsg() { | |||
return this.errMsg; | |||
} | |||
public void setErrMsg(String errMsg) { | |||
this.errMsg = errMsg; | |||
} | |||
public String getInvalidUser() { | |||
return this.invalidUsers; | |||
} | |||
public void setInvalidUser(String invalidUser) { | |||
this.invalidUsers = invalidUser; | |||
} | |||
public String[] getInvalidParty() { | |||
return this.invalidParty; | |||
} | |||
public void setInvalidParty(String[] invalidParty) { | |||
this.invalidParty = invalidParty; | |||
} | |||
public List<String> getInvalidUserList() { | |||
return this.content2List(this.invalidUsers); | |||
} | |||
private List<String> content2List(String content) { | |||
if(StringUtils.isBlank(content)){ | |||
if (StringUtils.isBlank(content)) { | |||
return Collections.emptyList(); | |||
} | |||
@@ -1,5 +1,7 @@ | |||
package me.chanjar.weixin.cp.bean; | |||
import lombok.AllArgsConstructor; | |||
import lombok.Data; | |||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | |||
import java.io.Serializable; | |||
@@ -7,12 +9,12 @@ import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* 微信用户信息 | |||
* 微信用户信息. | |||
* | |||
* @author Daniel Qian | |||
*/ | |||
@Data | |||
public class WxCpUser implements Serializable { | |||
public enum Gender { | |||
MALE("男", "1"), | |||
FEMAIL("女", "2"); | |||
@@ -62,159 +64,23 @@ public class WxCpUser implements Serializable { | |||
private String englishName; | |||
private String telephone; | |||
public static WxCpUser fromJson(String json) { | |||
return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpUser.class); | |||
} | |||
public String getUserId() { | |||
return this.userId; | |||
} | |||
public void setUserId(String userId) { | |||
this.userId = userId; | |||
} | |||
public String getName() { | |||
return this.name; | |||
} | |||
public void setName(String name) { | |||
this.name = name; | |||
} | |||
public Integer[] getDepartIds() { | |||
return this.departIds; | |||
} | |||
public void setDepartIds(Integer[] departIds) { | |||
this.departIds = departIds; | |||
} | |||
public Gender getGender() { | |||
return this.gender; | |||
} | |||
public void setGender(Gender gender) { | |||
this.gender = gender; | |||
} | |||
public String getPosition() { | |||
return this.position; | |||
} | |||
public void setPosition(String position) { | |||
this.position = position; | |||
} | |||
public String getMobile() { | |||
return this.mobile; | |||
} | |||
public void setMobile(String mobile) { | |||
this.mobile = mobile; | |||
} | |||
public String getTelephone() { | |||
return this.telephone; | |||
} | |||
public void setTelephone(String telephone) { | |||
this.telephone = telephone; | |||
} | |||
public String getEmail() { | |||
return this.email; | |||
} | |||
public void setEmail(String email) { | |||
this.email = email; | |||
} | |||
public String getAvatar() { | |||
return this.avatar; | |||
} | |||
public void setAvatar(String avatar) { | |||
this.avatar = avatar; | |||
} | |||
public Integer getStatus() { | |||
return this.status; | |||
} | |||
public void setStatus(Integer status) { | |||
this.status = status; | |||
} | |||
public Integer getEnable() { | |||
return this.enable; | |||
} | |||
public void setEnable(Integer enable) { | |||
this.enable = enable; | |||
} | |||
public void addExtAttr(String name, String value) { | |||
this.extAttrs.add(new Attr(name, value)); | |||
} | |||
public List<Attr> getExtAttrs() { | |||
return this.extAttrs; | |||
} | |||
public Integer getIsLeader() { | |||
return isLeader; | |||
} | |||
public void setIsLeader(Integer isLeader) { | |||
this.isLeader = isLeader; | |||
} | |||
public Integer getHideMobile() { | |||
return hideMobile; | |||
} | |||
public void setHideMobile(Integer hideMobile) { | |||
this.hideMobile = hideMobile; | |||
} | |||
public String getEnglishName() { | |||
return englishName; | |||
} | |||
public void setEnglishName(String englishName) { | |||
this.englishName = englishName; | |||
public static WxCpUser fromJson(String json) { | |||
return WxCpGsonBuilder.INSTANCE.create().fromJson(json, WxCpUser.class); | |||
} | |||
public String toJson() { | |||
return WxCpGsonBuilder.INSTANCE.create().toJson(this); | |||
} | |||
@Data | |||
@AllArgsConstructor | |||
public static class Attr { | |||
private String name; | |||
private String value; | |||
public Attr(String name, String value) { | |||
this.name = name; | |||
this.value = value; | |||
} | |||
public String getName() { | |||
return this.name; | |||
} | |||
public void setName(String name) { | |||
this.name = name; | |||
} | |||
public String getValue() { | |||
return this.value; | |||
} | |||
public void setValue(String value) { | |||
this.value = value; | |||
} | |||
} | |||
} |
@@ -2,6 +2,9 @@ package me.chanjar.weixin.cp.bean; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.api.WxConsts; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||
import me.chanjar.weixin.cp.config.WxCpConfigStorage; | |||
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; | |||
@@ -26,6 +29,7 @@ import java.util.List; | |||
* @author Daniel Qian | |||
*/ | |||
@XStreamAlias("xml") | |||
@Data | |||
public class WxCpXmlMessage implements Serializable { | |||
private static final long serialVersionUID = -1042994982179476410L; | |||
@@ -128,28 +132,29 @@ public class WxCpXmlMessage implements Serializable { | |||
// 群发消息返回的结果 | |||
/////////////////////////////////////// | |||
/** | |||
* 群发的结果 | |||
* 群发的结果. | |||
*/ | |||
@XStreamAlias("Status") | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String status; | |||
/** | |||
* group_id下粉丝数;或者openid_list中的粉丝数 | |||
* group_id下粉丝数;或者openid_list中的粉丝数. | |||
*/ | |||
@XStreamAlias("TotalCount") | |||
private Integer totalCount; | |||
/** | |||
* 过滤(过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数,原则上,filterCount = sentCount + errorCount | |||
* 过滤. | |||
* (过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数,原则上,filterCount = sentCount + errorCount | |||
*/ | |||
@XStreamAlias("FilterCount") | |||
private Integer filterCount; | |||
/** | |||
* 发送成功的粉丝数 | |||
* 发送成功的粉丝数. | |||
*/ | |||
@XStreamAlias("SentCount") | |||
private Integer sentCount; | |||
/** | |||
* 发送失败的粉丝数 | |||
* 发送失败的粉丝数. | |||
*/ | |||
@XStreamAlias("ErrorCount") | |||
private Integer errorCount; | |||
@@ -174,13 +179,7 @@ public class WxCpXmlMessage implements Serializable { | |||
} | |||
/** | |||
* 从加密字符串转换 | |||
* | |||
* @param encryptedXml | |||
* @param wxCpConfigStorage | |||
* @param timestamp | |||
* @param nonce | |||
* @param msgSignature | |||
* 从加密字符串转换. | |||
*/ | |||
public static WxCpXmlMessage fromEncryptedXml( | |||
String encryptedXml, | |||
@@ -202,40 +201,16 @@ public class WxCpXmlMessage implements Serializable { | |||
} | |||
} | |||
public Integer getAgentId() { | |||
return this.agentId; | |||
} | |||
public void setAgentId(Integer agentId) { | |||
this.agentId = agentId; | |||
} | |||
public String getToUserName() { | |||
return this.toUserName; | |||
} | |||
public void setToUserName(String toUserName) { | |||
this.toUserName = toUserName; | |||
} | |||
public Long getCreateTime() { | |||
return this.createTime; | |||
} | |||
public void setCreateTime(Long createTime) { | |||
this.createTime = createTime; | |||
} | |||
/** | |||
* <pre> | |||
* 当接受用户消息时,可能会获得以下值: | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_TEXT} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_IMAGE} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_VOICE} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_VIDEO} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_LOCATION} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_LINK} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_EVENT} | |||
* {@link WxConsts.XmlMsgType#TEXT} | |||
* {@link WxConsts.XmlMsgType#IMAGE} | |||
* {@link WxConsts.XmlMsgType#VOICE} | |||
* {@link WxConsts.XmlMsgType#VIDEO} | |||
* {@link WxConsts.XmlMsgType#LOCATION} | |||
* {@link WxConsts.XmlMsgType#LINK} | |||
* {@link WxConsts.XmlMsgType#EVENT} | |||
* </pre> | |||
*/ | |||
public String getMsgType() { | |||
@@ -245,363 +220,60 @@ public class WxCpXmlMessage implements Serializable { | |||
/** | |||
* <pre> | |||
* 当发送消息的时候使用: | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_TEXT} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_IMAGE} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_VOICE} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_VIDEO} | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_NEWS} | |||
* {@link WxConsts.XmlMsgType#TEXT} | |||
* {@link WxConsts.XmlMsgType#IMAGE} | |||
* {@link WxConsts.XmlMsgType#VOICE} | |||
* {@link WxConsts.XmlMsgType#VIDEO} | |||
* {@link WxConsts.XmlMsgType#NEWS} | |||
* </pre> | |||
* | |||
* @param msgType | |||
*/ | |||
public void setMsgType(String msgType) { | |||
this.msgType = msgType; | |||
} | |||
public String getContent() { | |||
return this.content; | |||
} | |||
public void setContent(String content) { | |||
this.content = content; | |||
} | |||
public Long getMsgId() { | |||
return this.msgId; | |||
} | |||
public void setMsgId(Long msgId) { | |||
this.msgId = msgId; | |||
} | |||
public String getPicUrl() { | |||
return this.picUrl; | |||
} | |||
public void setPicUrl(String picUrl) { | |||
this.picUrl = picUrl; | |||
} | |||
public String getMediaId() { | |||
return this.mediaId; | |||
} | |||
public void setMediaId(String mediaId) { | |||
this.mediaId = mediaId; | |||
} | |||
public String getFormat() { | |||
return this.format; | |||
} | |||
public void setFormat(String format) { | |||
this.format = format; | |||
} | |||
public String getThumbMediaId() { | |||
return this.thumbMediaId; | |||
} | |||
public void setThumbMediaId(String thumbMediaId) { | |||
this.thumbMediaId = thumbMediaId; | |||
} | |||
public Double getLocationX() { | |||
return this.locationX; | |||
} | |||
public void setLocationX(Double locationX) { | |||
this.locationX = locationX; | |||
} | |||
public Double getLocationY() { | |||
return this.locationY; | |||
} | |||
public void setLocationY(Double locationY) { | |||
this.locationY = locationY; | |||
} | |||
public Double getScale() { | |||
return this.scale; | |||
} | |||
public void setScale(Double scale) { | |||
this.scale = scale; | |||
} | |||
public String getLabel() { | |||
return this.label; | |||
} | |||
public void setLabel(String label) { | |||
this.label = label; | |||
} | |||
public String getTitle() { | |||
return this.title; | |||
} | |||
public void setTitle(String title) { | |||
this.title = title; | |||
} | |||
public String getDescription() { | |||
return this.description; | |||
} | |||
public void setDescription(String description) { | |||
this.description = description; | |||
} | |||
public String getUrl() { | |||
return this.url; | |||
} | |||
public void setUrl(String url) { | |||
this.url = url; | |||
} | |||
public String getEvent() { | |||
return this.event; | |||
} | |||
public void setEvent(String event) { | |||
this.event = event; | |||
} | |||
public String getEventKey() { | |||
return this.eventKey; | |||
} | |||
public void setEventKey(String eventKey) { | |||
this.eventKey = eventKey; | |||
} | |||
public String getTicket() { | |||
return this.ticket; | |||
} | |||
public void setTicket(String ticket) { | |||
this.ticket = ticket; | |||
} | |||
public Double getLatitude() { | |||
return this.latitude; | |||
} | |||
public void setLatitude(Double latitude) { | |||
this.latitude = latitude; | |||
} | |||
public Double getLongitude() { | |||
return this.longitude; | |||
} | |||
public void setLongitude(Double longitude) { | |||
this.longitude = longitude; | |||
} | |||
public Double getPrecision() { | |||
return this.precision; | |||
} | |||
public void setPrecision(Double precision) { | |||
this.precision = precision; | |||
} | |||
public String getRecognition() { | |||
return this.recognition; | |||
} | |||
public void setRecognition(String recognition) { | |||
this.recognition = recognition; | |||
} | |||
public String getFromUserName() { | |||
return this.fromUserName; | |||
} | |||
public void setFromUserName(String fromUserName) { | |||
this.fromUserName = fromUserName; | |||
} | |||
public String getStatus() { | |||
return this.status; | |||
} | |||
public void setStatus(String status) { | |||
this.status = status; | |||
} | |||
public Integer getTotalCount() { | |||
return this.totalCount; | |||
} | |||
public void setTotalCount(Integer totalCount) { | |||
this.totalCount = totalCount; | |||
} | |||
public Integer getFilterCount() { | |||
return this.filterCount; | |||
} | |||
public void setFilterCount(Integer filterCount) { | |||
this.filterCount = filterCount; | |||
} | |||
public Integer getSentCount() { | |||
return this.sentCount; | |||
} | |||
public void setSentCount(Integer sentCount) { | |||
this.sentCount = sentCount; | |||
} | |||
public Integer getErrorCount() { | |||
return this.errorCount; | |||
} | |||
public void setErrorCount(Integer errorCount) { | |||
this.errorCount = errorCount; | |||
} | |||
public WxCpXmlMessage.ScanCodeInfo getScanCodeInfo() { | |||
return this.scanCodeInfo; | |||
} | |||
public void setScanCodeInfo(WxCpXmlMessage.ScanCodeInfo scanCodeInfo) { | |||
this.scanCodeInfo = scanCodeInfo; | |||
} | |||
public WxCpXmlMessage.SendPicsInfo getSendPicsInfo() { | |||
return this.sendPicsInfo; | |||
} | |||
public void setSendPicsInfo(WxCpXmlMessage.SendPicsInfo sendPicsInfo) { | |||
this.sendPicsInfo = sendPicsInfo; | |||
} | |||
public WxCpXmlMessage.SendLocationInfo getSendLocationInfo() { | |||
return this.sendLocationInfo; | |||
} | |||
public void setSendLocationInfo(WxCpXmlMessage.SendLocationInfo sendLocationInfo) { | |||
this.sendLocationInfo = sendLocationInfo; | |||
} | |||
@Override | |||
public String toString() { | |||
return "WxCpXmlMessage{" + | |||
"agentId=" + this.agentId + | |||
", toUserName='" + this.toUserName + '\'' + | |||
", fromUserName='" + this.fromUserName + '\'' + | |||
", createTime=" + this.createTime + | |||
", msgType='" + this.msgType + '\'' + | |||
", content='" + this.content + '\'' + | |||
", msgId=" + this.msgId + | |||
", picUrl='" + this.picUrl + '\'' + | |||
", mediaId='" + this.mediaId + '\'' + | |||
", format='" + this.format + '\'' + | |||
", thumbMediaId='" + this.thumbMediaId + '\'' + | |||
", locationX=" + this.locationX + | |||
", locationY=" + this.locationY + | |||
", scale=" + this.scale + | |||
", label='" + this.label + '\'' + | |||
", title='" + this.title + '\'' + | |||
", description='" + this.description + '\'' + | |||
", url='" + this.url + '\'' + | |||
", event='" + this.event + '\'' + | |||
", eventKey='" + this.eventKey + '\'' + | |||
", ticket='" + this.ticket + '\'' + | |||
", latitude=" + this.latitude + | |||
", longitude=" + this.longitude + | |||
", precision=" + this.precision + | |||
", recognition='" + this.recognition + '\'' + | |||
", status='" + this.status + '\'' + | |||
", totalCount=" + this.totalCount + | |||
", filterCount=" + this.filterCount + | |||
", sentCount=" + this.sentCount + | |||
", errorCount=" + this.errorCount + | |||
", scanCodeInfo=" + this.scanCodeInfo + | |||
", sendPicsInfo=" + this.sendPicsInfo + | |||
", sendLocationInfo=" + this.sendLocationInfo + | |||
'}'; | |||
return ToStringUtils.toSimpleString(this); | |||
} | |||
@Data | |||
@XStreamAlias("ScanCodeInfo") | |||
public static class ScanCodeInfo { | |||
/** | |||
* 扫描类型,一般是qrcode. | |||
*/ | |||
@XStreamAlias("ScanType") | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String scanType; | |||
/** | |||
* 扫描结果,即二维码对应的字符串信息. | |||
*/ | |||
@XStreamAlias("ScanResult") | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String scanResult; | |||
/** | |||
* 扫描类型,一般是qrcode | |||
*/ | |||
public String getScanType() { | |||
return this.scanType; | |||
} | |||
public void setScanType(String scanType) { | |||
this.scanType = scanType; | |||
} | |||
/** | |||
* 扫描结果,即二维码对应的字符串信息 | |||
*/ | |||
public String getScanResult() { | |||
return this.scanResult; | |||
} | |||
public void setScanResult(String scanResult) { | |||
this.scanResult = scanResult; | |||
} | |||
} | |||
@Data | |||
@XStreamAlias("SendPicsInfo") | |||
public static class SendPicsInfo { | |||
@XStreamAlias("PicList") | |||
protected final List<Item> picList = new ArrayList<>(); | |||
@XStreamAlias("Count") | |||
private Long count; | |||
public Long getCount() { | |||
return this.count; | |||
} | |||
public void setCount(Long count) { | |||
this.count = count; | |||
} | |||
public List<Item> getPicList() { | |||
return this.picList; | |||
} | |||
@XStreamAlias("item") | |||
@Data | |||
public static class Item { | |||
@XStreamAlias("PicMd5Sum") | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String PicMd5Sum; | |||
public String getPicMd5Sum() { | |||
return this.PicMd5Sum; | |||
} | |||
public void setPicMd5Sum(String picMd5Sum) { | |||
this.PicMd5Sum = picMd5Sum; | |||
} | |||
private String picMd5Sum; | |||
} | |||
} | |||
@Data | |||
@XStreamAlias("SendLocationInfo") | |||
public static class SendLocationInfo { | |||
@@ -623,47 +295,8 @@ public class WxCpXmlMessage implements Serializable { | |||
@XStreamAlias("Poiname") | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String poiname; | |||
public String getLocationX() { | |||
return this.locationX; | |||
} | |||
public void setLocationX(String locationX) { | |||
this.locationX = locationX; | |||
} | |||
public String getLocationY() { | |||
return this.locationY; | |||
} | |||
public void setLocationY(String locationY) { | |||
this.locationY = locationY; | |||
} | |||
private String poiName; | |||
public String getScale() { | |||
return this.scale; | |||
} | |||
public void setScale(String scale) { | |||
this.scale = scale; | |||
} | |||
public String getLabel() { | |||
return this.label; | |||
} | |||
public void setLabel(String label) { | |||
this.label = label; | |||
} | |||
public String getPoiname() { | |||
return this.poiname; | |||
} | |||
public void setPoiname(String poiname) { | |||
this.poiname = poiname; | |||
} | |||
} | |||
} |
@@ -2,10 +2,12 @@ package me.chanjar.weixin.cp.bean; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.api.WxConsts; | |||
import me.chanjar.weixin.common.util.xml.XStreamMediaIdConverter; | |||
@XStreamAlias("xml") | |||
@Data | |||
public class WxCpXmlOutImageMessage extends WxCpXmlOutMessage { | |||
private static final long serialVersionUID = -1099446240667237313L; | |||
@@ -14,15 +16,7 @@ public class WxCpXmlOutImageMessage extends WxCpXmlOutMessage { | |||
private String mediaId; | |||
public WxCpXmlOutImageMessage() { | |||
this.msgType = WxConsts.XML_MSG_IMAGE; | |||
} | |||
public String getMediaId() { | |||
return this.mediaId; | |||
} | |||
public void setMediaId(String mediaId) { | |||
this.mediaId = mediaId; | |||
this.msgType = WxConsts.XmlMsgType.IMAGE; | |||
} | |||
} |
@@ -2,6 +2,7 @@ package me.chanjar.weixin.cp.bean; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||
import me.chanjar.weixin.cp.config.WxCpConfigStorage; | |||
import me.chanjar.weixin.cp.bean.outxmlbuilder.*; | |||
@@ -11,8 +12,8 @@ import me.chanjar.weixin.cp.util.xml.XStreamTransformer; | |||
import java.io.Serializable; | |||
@XStreamAlias("xml") | |||
@Data | |||
public abstract class WxCpXmlOutMessage implements Serializable { | |||
private static final long serialVersionUID = 1418629839964153110L; | |||
@XStreamAlias("ToUserName") | |||
@@ -31,78 +32,46 @@ public abstract class WxCpXmlOutMessage implements Serializable { | |||
protected String msgType; | |||
/** | |||
* 获得文本消息builder | |||
* 获得文本消息builder. | |||
*/ | |||
public static TextBuilder TEXT() { | |||
return new TextBuilder(); | |||
} | |||
/** | |||
* 获得图片消息builder | |||
* 获得图片消息builder. | |||
*/ | |||
public static ImageBuilder IMAGE() { | |||
return new ImageBuilder(); | |||
} | |||
/** | |||
* 获得语音消息builder | |||
* 获得语音消息builder. | |||
*/ | |||
public static VoiceBuilder VOICE() { | |||
return new VoiceBuilder(); | |||
} | |||
/** | |||
* 获得视频消息builder | |||
* 获得视频消息builder. | |||
*/ | |||
public static VideoBuilder VIDEO() { | |||
return new VideoBuilder(); | |||
} | |||
/** | |||
* 获得图文消息builder | |||
* 获得图文消息builder. | |||
*/ | |||
public static NewsBuilder NEWS() { | |||
return new NewsBuilder(); | |||
} | |||
public String getToUserName() { | |||
return this.toUserName; | |||
} | |||
public void setToUserName(String toUserName) { | |||
this.toUserName = toUserName; | |||
} | |||
public String getFromUserName() { | |||
return this.fromUserName; | |||
} | |||
public void setFromUserName(String fromUserName) { | |||
this.fromUserName = fromUserName; | |||
} | |||
public Long getCreateTime() { | |||
return this.createTime; | |||
} | |||
public void setCreateTime(Long createTime) { | |||
this.createTime = createTime; | |||
} | |||
public String getMsgType() { | |||
return this.msgType; | |||
} | |||
public void setMsgType(String msgType) { | |||
this.msgType = msgType; | |||
} | |||
protected String toXml() { | |||
return XStreamTransformer.toXml((Class) this.getClass(), this); | |||
} | |||
/** | |||
* 转换成加密的xml格式 | |||
* 转换成加密的xml格式. | |||
*/ | |||
public String toEncryptedXml(WxCpConfigStorage wxCpConfigStorage) { | |||
String plainXml = toXml(); | |||
@@ -2,6 +2,7 @@ package me.chanjar.weixin.cp.bean; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.api.WxConsts; | |||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||
@@ -9,84 +10,46 @@ import java.util.ArrayList; | |||
import java.util.List; | |||
@XStreamAlias("xml") | |||
@Data | |||
public class WxCpXmlOutNewsMessage extends WxCpXmlOutMessage { | |||
private static final long serialVersionUID = -5796178637883178826L; | |||
@XStreamAlias("Articles") | |||
protected final List<Item> articles = new ArrayList<>(); | |||
@XStreamAlias("ArticleCount") | |||
protected int articleCount; | |||
public WxCpXmlOutNewsMessage() { | |||
this.msgType = WxConsts.XML_MSG_NEWS; | |||
this.msgType = WxConsts.XmlMsgType.NEWS; | |||
} | |||
public int getArticleCount() { | |||
return this.articleCount; | |||
} | |||
public void addArticle(Item item) { | |||
this.articles.add(item); | |||
this.articleCount = this.articles.size(); | |||
} | |||
public List<Item> getArticles() { | |||
return this.articles; | |||
} | |||
@XStreamAlias("item") | |||
@Data | |||
public static class Item { | |||
@XStreamAlias("Title") | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String Title; | |||
private String title; | |||
@XStreamAlias("Description") | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String Description; | |||
private String description; | |||
@XStreamAlias("PicUrl") | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String PicUrl; | |||
private String picUrl; | |||
@XStreamAlias("Url") | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String Url; | |||
public String getTitle() { | |||
return this.Title; | |||
} | |||
public void setTitle(String title) { | |||
this.Title = title; | |||
} | |||
public String getDescription() { | |||
return this.Description; | |||
} | |||
public void setDescription(String description) { | |||
this.Description = description; | |||
} | |||
public String getPicUrl() { | |||
return this.PicUrl; | |||
} | |||
public void setPicUrl(String picUrl) { | |||
this.PicUrl = picUrl; | |||
} | |||
public String getUrl() { | |||
return this.Url; | |||
} | |||
public void setUrl(String url) { | |||
this.Url = url; | |||
} | |||
private String url; | |||
} | |||
} |
@@ -2,10 +2,12 @@ package me.chanjar.weixin.cp.bean; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.api.WxConsts; | |||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||
@XStreamAlias("xml") | |||
@Data | |||
public class WxCpXmlOutTextMessage extends WxCpXmlOutMessage { | |||
private static final long serialVersionUID = 2569239617185930232L; | |||
@@ -14,16 +16,7 @@ public class WxCpXmlOutTextMessage extends WxCpXmlOutMessage { | |||
private String content; | |||
public WxCpXmlOutTextMessage() { | |||
this.msgType = WxConsts.XML_MSG_TEXT; | |||
this.msgType = WxConsts.XmlMsgType.TEXT; | |||
} | |||
public String getContent() { | |||
return this.content; | |||
} | |||
public void setContent(String content) { | |||
this.content = content; | |||
} | |||
} |
@@ -2,10 +2,12 @@ package me.chanjar.weixin.cp.bean; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.api.WxConsts; | |||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||
@XStreamAlias("xml") | |||
@Data | |||
public class WxCpXmlOutVideoMessage extends WxCpXmlOutMessage { | |||
private static final long serialVersionUID = -8672761162722733622L; | |||
@@ -13,7 +15,7 @@ public class WxCpXmlOutVideoMessage extends WxCpXmlOutMessage { | |||
protected final Video video = new Video(); | |||
public WxCpXmlOutVideoMessage() { | |||
this.msgType = WxConsts.XML_MSG_VIDEO; | |||
this.msgType = WxConsts.XmlMsgType.VIDEO; | |||
} | |||
public String getMediaId() { | |||
@@ -40,7 +42,7 @@ public class WxCpXmlOutVideoMessage extends WxCpXmlOutMessage { | |||
this.video.setDescription(description); | |||
} | |||
@Data | |||
@XStreamAlias("Video") | |||
public static class Video { | |||
@@ -56,30 +58,6 @@ public class WxCpXmlOutVideoMessage extends WxCpXmlOutMessage { | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String description; | |||
public String getMediaId() { | |||
return this.mediaId; | |||
} | |||
public void setMediaId(String mediaId) { | |||
this.mediaId = mediaId; | |||
} | |||
public String getTitle() { | |||
return this.title; | |||
} | |||
public void setTitle(String title) { | |||
this.title = title; | |||
} | |||
public String getDescription() { | |||
return this.description; | |||
} | |||
public void setDescription(String description) { | |||
this.description = description; | |||
} | |||
} | |||
} |
@@ -2,10 +2,12 @@ package me.chanjar.weixin.cp.bean; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.api.WxConsts; | |||
import me.chanjar.weixin.common.util.xml.XStreamMediaIdConverter; | |||
@XStreamAlias("xml") | |||
@Data | |||
public class WxCpXmlOutVoiceMessage extends WxCpXmlOutMessage { | |||
private static final long serialVersionUID = -7947384031546099340L; | |||
@@ -14,15 +16,7 @@ public class WxCpXmlOutVoiceMessage extends WxCpXmlOutMessage { | |||
private String mediaId; | |||
public WxCpXmlOutVoiceMessage() { | |||
this.msgType = WxConsts.XML_MSG_VOICE; | |||
} | |||
public String getMediaId() { | |||
return this.mediaId; | |||
} | |||
public void setMediaId(String mediaId) { | |||
this.mediaId = mediaId; | |||
this.msgType = WxConsts.XmlMsgType.VOICE; | |||
} | |||
} |
@@ -1,5 +1,8 @@ | |||
package me.chanjar.weixin.cp.bean.article; | |||
import lombok.Builder; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
@@ -9,6 +12,8 @@ import java.io.Serializable; | |||
* | |||
* @author Binary Wang | |||
*/ | |||
@Data | |||
@Builder(builderMethodName = "newBuilder") | |||
public class MpnewsArticle implements Serializable { | |||
private static final long serialVersionUID = 6985871812170756481L; | |||
@@ -20,125 +25,4 @@ public class MpnewsArticle implements Serializable { | |||
private String digest; | |||
private String showCoverPic; | |||
private MpnewsArticle(Builder builder) { | |||
setTitle(builder.title); | |||
setThumbMediaId(builder.thumbMediaId); | |||
setAuthor(builder.author); | |||
setContentSourceUrl(builder.contentSourceUrl); | |||
setContent(builder.content); | |||
setDigest(builder.digest); | |||
setShowCoverPic(builder.showCoverPic); | |||
} | |||
public static Builder newBuilder() { | |||
return new Builder(); | |||
} | |||
public String getTitle() { | |||
return title; | |||
} | |||
public void setTitle(String title) { | |||
this.title = title; | |||
} | |||
public String getThumbMediaId() { | |||
return thumbMediaId; | |||
} | |||
public void setThumbMediaId(String thumbMediaId) { | |||
this.thumbMediaId = thumbMediaId; | |||
} | |||
public String getAuthor() { | |||
return author; | |||
} | |||
public void setAuthor(String author) { | |||
this.author = author; | |||
} | |||
public String getContentSourceUrl() { | |||
return contentSourceUrl; | |||
} | |||
public void setContentSourceUrl(String contentSourceUrl) { | |||
this.contentSourceUrl = contentSourceUrl; | |||
} | |||
public String getContent() { | |||
return content; | |||
} | |||
public void setContent(String content) { | |||
this.content = content; | |||
} | |||
public String getDigest() { | |||
return digest; | |||
} | |||
public void setDigest(String digest) { | |||
this.digest = digest; | |||
} | |||
public String getShowCoverPic() { | |||
return showCoverPic; | |||
} | |||
public void setShowCoverPic(String showCoverPic) { | |||
this.showCoverPic = showCoverPic; | |||
} | |||
public static final class Builder { | |||
private String title; | |||
private String thumbMediaId; | |||
private String author; | |||
private String contentSourceUrl; | |||
private String content; | |||
private String digest; | |||
private String showCoverPic; | |||
private Builder() { | |||
} | |||
public Builder title(String title) { | |||
this.title = title; | |||
return this; | |||
} | |||
public Builder thumbMediaId(String thumbMediaId) { | |||
this.thumbMediaId = thumbMediaId; | |||
return this; | |||
} | |||
public Builder author(String author) { | |||
this.author = author; | |||
return this; | |||
} | |||
public Builder contentSourceUrl(String contentSourceUrl) { | |||
this.contentSourceUrl = contentSourceUrl; | |||
return this; | |||
} | |||
public Builder content(String content) { | |||
this.content = content; | |||
return this; | |||
} | |||
public Builder digest(String digest) { | |||
this.digest = digest; | |||
return this; | |||
} | |||
public Builder showCoverPic(String showCoverPic) { | |||
this.showCoverPic = showCoverPic; | |||
return this; | |||
} | |||
public MpnewsArticle build() { | |||
return new MpnewsArticle(this); | |||
} | |||
} | |||
} |
@@ -1,5 +1,7 @@ | |||
package me.chanjar.weixin.cp.bean.article; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
@@ -9,6 +11,7 @@ import java.io.Serializable; | |||
* | |||
* @author Binary Wang | |||
*/ | |||
@Data | |||
public class NewArticle implements Serializable { | |||
private static final long serialVersionUID = 4087852055781140659L; | |||
@@ -17,36 +20,4 @@ public class NewArticle implements Serializable { | |||
private String url; | |||
private String picUrl; | |||
public String getTitle() { | |||
return this.title; | |||
} | |||
public void setTitle(String title) { | |||
this.title = title; | |||
} | |||
public String getDescription() { | |||
return this.description; | |||
} | |||
public void setDescription(String description) { | |||
this.description = description; | |||
} | |||
public String getUrl() { | |||
return this.url; | |||
} | |||
public void setUrl(String url) { | |||
this.url = url; | |||
} | |||
public String getPicUrl() { | |||
return this.picUrl; | |||
} | |||
public void setPicUrl(String picUrl) { | |||
this.picUrl = picUrl; | |||
} | |||
} |
@@ -44,7 +44,7 @@ public class BaseBuilder<T> { | |||
m.setToUser(this.toUser); | |||
m.setToParty(this.toParty); | |||
m.setToTag(this.toTag); | |||
m.setSafe(StringUtils.defaultIfBlank(this.safe, WxConsts.CUSTOM_MSG_SAFE_NO)); | |||
m.setSafe(StringUtils.defaultIfBlank(this.safe, WxConsts.KefuMsgSafe.NO)); | |||
return m; | |||
} | |||
@@ -15,7 +15,7 @@ public final class FileBuilder extends BaseBuilder<FileBuilder> { | |||
private String mediaId; | |||
public FileBuilder() { | |||
this.msgType = WxConsts.CUSTOM_MSG_FILE; | |||
this.msgType = WxConsts.KefuMsgType.FILE; | |||
} | |||
public FileBuilder mediaId(String media_id) { | |||
@@ -15,7 +15,7 @@ public final class ImageBuilder extends BaseBuilder<ImageBuilder> { | |||
private String mediaId; | |||
public ImageBuilder() { | |||
this.msgType = WxConsts.CUSTOM_MSG_IMAGE; | |||
this.msgType = WxConsts.KefuMsgType.IMAGE; | |||
} | |||
public ImageBuilder mediaId(String media_id) { | |||
@@ -23,7 +23,7 @@ public final class MpnewsBuilder extends BaseBuilder<MpnewsBuilder> { | |||
private String mediaId; | |||
public MpnewsBuilder() { | |||
this.msgType = WxConsts.CUSTOM_MSG_MPNEWS; | |||
this.msgType = WxConsts.KefuMsgType.MPNEWS; | |||
} | |||
public MpnewsBuilder mediaId(String mediaId) { | |||
@@ -22,7 +22,7 @@ public final class NewsBuilder extends BaseBuilder<NewsBuilder> { | |||
private List<NewArticle> articles = new ArrayList<>(); | |||
public NewsBuilder() { | |||
this.msgType = WxConsts.CUSTOM_MSG_NEWS; | |||
this.msgType = WxConsts.KefuMsgType.NEWS; | |||
} | |||
public NewsBuilder addArticle(NewArticle... articles) { | |||
@@ -15,7 +15,7 @@ public final class TextBuilder extends BaseBuilder<TextBuilder> { | |||
private String content; | |||
public TextBuilder() { | |||
this.msgType = WxConsts.CUSTOM_MSG_TEXT; | |||
this.msgType = WxConsts.KefuMsgType.TEXT; | |||
} | |||
public TextBuilder content(String content) { | |||
@@ -18,7 +18,7 @@ public class TextCardBuilder extends BaseBuilder<TextCardBuilder> { | |||
private String url; | |||
public TextCardBuilder() { | |||
this.msgType = WxConsts.CUSTOM_MSG_TEXTCARD; | |||
this.msgType = WxConsts.KefuMsgType.TEXTCARD; | |||
} | |||
public TextCardBuilder title(String title) { | |||
@@ -24,7 +24,7 @@ public final class VideoBuilder extends BaseBuilder<VideoBuilder> { | |||
private String thumbMediaId; | |||
public VideoBuilder() { | |||
this.msgType = WxConsts.CUSTOM_MSG_VIDEO; | |||
this.msgType = WxConsts.KefuMsgType.VIDEO; | |||
} | |||
public VideoBuilder mediaId(String mediaId) { | |||
@@ -15,7 +15,7 @@ public final class VoiceBuilder extends BaseBuilder<VoiceBuilder> { | |||
private String mediaId; | |||
public VoiceBuilder() { | |||
this.msgType = WxConsts.CUSTOM_MSG_VOICE; | |||
this.msgType = WxConsts.KefuMsgType.VOICE; | |||
} | |||
public VoiceBuilder mediaId(String media_id) { | |||
@@ -9,7 +9,11 @@ import redis.clients.jedis.JedisPoolConfig; | |||
import java.io.File; | |||
/** | |||
* Jedis client implementor for wechat config storage | |||
* Jedis client implementor for wechat config storage. | |||
* <pre> | |||
* 使用说明:本实现仅供参考,并不完整, | |||
* 比如为减少项目依赖,未加入redis分布式锁的实现,如有需要请自行实现。 | |||
* </pre> | |||
* | |||
* @author gaigeshen | |||
*/ | |||
@@ -11,6 +11,7 @@ import me.chanjar.weixin.common.util.LogExceptionHandler; | |||
import me.chanjar.weixin.cp.api.WxCpService; | |||
import me.chanjar.weixin.cp.bean.WxCpXmlMessage; | |||
import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
@@ -215,17 +216,19 @@ public class WxCpMessageRouter { | |||
} | |||
protected boolean isDuplicateMessage(WxCpXmlMessage wxMessage) { | |||
String messageId = ""; | |||
String messageId; | |||
if (wxMessage.getMsgId() == null) { | |||
messageId = String.valueOf(wxMessage.getCreateTime()) | |||
+ "-" + String.valueOf(wxMessage.getAgentId() == null ? "" : wxMessage.getAgentId()) | |||
+ "-" + StringUtils.trimToEmpty(String.valueOf(wxMessage.getAgentId())) | |||
+ "-" + wxMessage.getFromUserName() | |||
+ "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey()) | |||
+ "-" + String.valueOf(wxMessage.getEvent() == null ? "" : wxMessage.getEvent()) | |||
+ "-" + StringUtils.trimToEmpty(wxMessage.getEventKey()) | |||
+ "-" + StringUtils.trimToEmpty(wxMessage.getEvent()) | |||
; | |||
} else { | |||
messageId = String.valueOf(wxMessage.getMsgId()); | |||
messageId = new StringBuilder().append(wxMessage.getMsgId()) | |||
.append("-").append(wxMessage.getCreateTime()) | |||
.append("-").append(wxMessage.getFromUserName()) | |||
.toString(); | |||
} | |||
return this.messageDuplicateChecker.isDuplicate(messageId); | |||
@@ -49,7 +49,7 @@ public class WxCpDepartGsonAdapter implements JsonSerializer<WxCpDepart>, JsonDe | |||
depart.setName(GsonHelper.getAsString(departJson.get("name"))); | |||
} | |||
if (departJson.get("order") != null && !departJson.get("order").isJsonNull()) { | |||
depart.setOrder(GsonHelper.getAsInteger(departJson.get("order"))); | |||
depart.setOrder(GsonHelper.getAsLong(departJson.get("order"))); | |||
} | |||
if (departJson.get("parentid") != null && !departJson.get("parentid").isJsonNull()) { | |||
depart.setParentId(GsonHelper.getAsInteger(departJson.get("parentid"))); | |||
@@ -37,13 +37,13 @@ public class WxCpMessageGsonAdapter implements JsonSerializer<WxCpMessage> { | |||
if (StringUtils.isNotBlank(message.getToTag())) { | |||
messageJson.addProperty("totag", message.getToTag()); | |||
} | |||
if (WxConsts.CUSTOM_MSG_TEXT.equals(message.getMsgType())) { | |||
if (WxConsts.KefuMsgType.TEXT.equals(message.getMsgType())) { | |||
JsonObject text = new JsonObject(); | |||
text.addProperty("content", message.getContent()); | |||
messageJson.add("text", text); | |||
} | |||
if (WxConsts.CUSTOM_MSG_TEXTCARD.equals(message.getMsgType())) { | |||
if (WxConsts.KefuMsgType.TEXTCARD.equals(message.getMsgType())) { | |||
JsonObject text = new JsonObject(); | |||
text.addProperty("title", message.getTitle()); | |||
text.addProperty("description", message.getDescription()); | |||
@@ -51,19 +51,19 @@ public class WxCpMessageGsonAdapter implements JsonSerializer<WxCpMessage> { | |||
messageJson.add("textcard", text); | |||
} | |||
if (WxConsts.CUSTOM_MSG_IMAGE.equals(message.getMsgType())) { | |||
if (WxConsts.KefuMsgType.IMAGE.equals(message.getMsgType())) { | |||
JsonObject image = new JsonObject(); | |||
image.addProperty("media_id", message.getMediaId()); | |||
messageJson.add("image", image); | |||
} | |||
if (WxConsts.CUSTOM_MSG_FILE.equals(message.getMsgType())) { | |||
if (WxConsts.KefuMsgType.FILE.equals(message.getMsgType())) { | |||
JsonObject image = new JsonObject(); | |||
image.addProperty("media_id", message.getMediaId()); | |||
messageJson.add("file", image); | |||
} | |||
if (WxConsts.CUSTOM_MSG_VOICE.equals(message.getMsgType())) { | |||
if (WxConsts.KefuMsgType.VOICE.equals(message.getMsgType())) { | |||
JsonObject voice = new JsonObject(); | |||
voice.addProperty("media_id", message.getMediaId()); | |||
messageJson.add("voice", voice); | |||
@@ -73,7 +73,7 @@ public class WxCpMessageGsonAdapter implements JsonSerializer<WxCpMessage> { | |||
messageJson.addProperty("safe", message.getSafe()); | |||
} | |||
if (WxConsts.CUSTOM_MSG_VIDEO.equals(message.getMsgType())) { | |||
if (WxConsts.KefuMsgType.VIDEO.equals(message.getMsgType())) { | |||
JsonObject video = new JsonObject(); | |||
video.addProperty("media_id", message.getMediaId()); | |||
video.addProperty("thumb_media_id", message.getThumbMediaId()); | |||
@@ -82,7 +82,7 @@ public class WxCpMessageGsonAdapter implements JsonSerializer<WxCpMessage> { | |||
messageJson.add("video", video); | |||
} | |||
if (WxConsts.CUSTOM_MSG_NEWS.equals(message.getMsgType())) { | |||
if (WxConsts.KefuMsgType.NEWS.equals(message.getMsgType())) { | |||
JsonObject newsJsonObject = new JsonObject(); | |||
JsonArray articleJsonArray = new JsonArray(); | |||
for (NewArticle article : message.getArticles()) { | |||
@@ -97,7 +97,7 @@ public class WxCpMessageGsonAdapter implements JsonSerializer<WxCpMessage> { | |||
messageJson.add("news", newsJsonObject); | |||
} | |||
if (WxConsts.CUSTOM_MSG_MPNEWS.equals(message.getMsgType())) { | |||
if (WxConsts.KefuMsgType.MPNEWS.equals(message.getMsgType())) { | |||
JsonObject newsJsonObject = new JsonObject(); | |||
if (message.getMediaId() != null) { | |||
newsJsonObject.addProperty("media_id", message.getMediaId()); | |||
@@ -28,7 +28,7 @@ public class XStreamTransformer { | |||
} | |||
/** | |||
* 注册扩展消息的解析器 | |||
* 注册扩展消息的解析器. | |||
* | |||
* @param clz 类型 | |||
* @param xStream xml解析器 | |||
@@ -46,17 +46,19 @@ public class XStreamTransformer { | |||
private static Map<Class, XStream> configXStreamInstance() { | |||
Map<Class, XStream> map = new HashMap<>(); | |||
map.put(WxCpXmlMessage.class, config_WxCpXmlMessage()); | |||
map.put(WxCpXmlOutNewsMessage.class, config_WxCpXmlOutNewsMessage()); | |||
map.put(WxCpXmlOutTextMessage.class, config_WxCpXmlOutTextMessage()); | |||
map.put(WxCpXmlOutImageMessage.class, config_WxCpXmlOutImageMessage()); | |||
map.put(WxCpXmlOutVideoMessage.class, config_WxCpXmlOutVideoMessage()); | |||
map.put(WxCpXmlOutVoiceMessage.class, config_WxCpXmlOutVoiceMessage()); | |||
map.put(WxCpXmlMessage.class, configWxCpXmlMessage()); | |||
map.put(WxCpXmlOutNewsMessage.class, configWxCpXmlOutNewsMessage()); | |||
map.put(WxCpXmlOutTextMessage.class, configWxCpXmlOutTextMessage()); | |||
map.put(WxCpXmlOutImageMessage.class, configWxCpXmlOutImageMessage()); | |||
map.put(WxCpXmlOutVideoMessage.class, configWxCpXmlOutVideoMessage()); | |||
map.put(WxCpXmlOutVoiceMessage.class, configWxCpXmlOutVoiceMessage()); | |||
return map; | |||
} | |||
private static XStream config_WxCpXmlMessage() { | |||
private static XStream configWxCpXmlMessage() { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.setClassLoader(Thread.currentThread().getContextClassLoader()); | |||
xstream.processAnnotations(WxCpXmlMessage.class); | |||
xstream.processAnnotations(WxCpXmlMessage.ScanCodeInfo.class); | |||
xstream.processAnnotations(WxCpXmlMessage.SendPicsInfo.class); | |||
@@ -65,38 +67,48 @@ public class XStreamTransformer { | |||
return xstream; | |||
} | |||
private static XStream config_WxCpXmlOutImageMessage() { | |||
private static XStream configWxCpXmlOutImageMessage() { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.setClassLoader(Thread.currentThread().getContextClassLoader()); | |||
xstream.processAnnotations(WxCpXmlOutMessage.class); | |||
xstream.processAnnotations(WxCpXmlOutImageMessage.class); | |||
return xstream; | |||
} | |||
private static XStream config_WxCpXmlOutNewsMessage() { | |||
private static XStream configWxCpXmlOutNewsMessage() { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.setClassLoader(Thread.currentThread().getContextClassLoader()); | |||
xstream.processAnnotations(WxCpXmlOutMessage.class); | |||
xstream.processAnnotations(WxCpXmlOutNewsMessage.class); | |||
xstream.processAnnotations(WxCpXmlOutNewsMessage.Item.class); | |||
return xstream; | |||
} | |||
private static XStream config_WxCpXmlOutTextMessage() { | |||
private static XStream configWxCpXmlOutTextMessage() { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.setClassLoader(Thread.currentThread().getContextClassLoader()); | |||
xstream.processAnnotations(WxCpXmlOutMessage.class); | |||
xstream.processAnnotations(WxCpXmlOutTextMessage.class); | |||
return xstream; | |||
} | |||
private static XStream config_WxCpXmlOutVideoMessage() { | |||
private static XStream configWxCpXmlOutVideoMessage() { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.setClassLoader(Thread.currentThread().getContextClassLoader()); | |||
xstream.processAnnotations(WxCpXmlOutMessage.class); | |||
xstream.processAnnotations(WxCpXmlOutVideoMessage.class); | |||
xstream.processAnnotations(WxCpXmlOutVideoMessage.Video.class); | |||
return xstream; | |||
} | |||
private static XStream config_WxCpXmlOutVoiceMessage() { | |||
private static XStream configWxCpXmlOutVoiceMessage() { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.setClassLoader(Thread.currentThread().getContextClassLoader()); | |||
xstream.processAnnotations(WxCpXmlOutMessage.class); | |||
xstream.processAnnotations(WxCpXmlOutVoiceMessage.class); | |||
return xstream; | |||
@@ -24,9 +24,7 @@ public class WxCpBusyRetryTest { | |||
RequestExecutor<T, E> executor, String uri, E data) | |||
throws WxErrorException { | |||
this.log.info("Executed"); | |||
WxError error = new WxError(); | |||
error.setErrorCode(-1); | |||
throw new WxErrorException(error); | |||
throw new WxErrorException(WxError.builder().errorCode(-1).build()); | |||
} | |||
}; | |||
@@ -3,7 +3,6 @@ package me.chanjar.weixin.cp.api; | |||
import com.google.inject.Inject; | |||
import me.chanjar.weixin.common.api.WxConsts; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl; | |||
import me.chanjar.weixin.cp.bean.WxCpMessage; | |||
import me.chanjar.weixin.cp.bean.WxCpMessageSendResult; | |||
import org.testng.annotations.*; | |||
@@ -32,7 +31,7 @@ public class WxCpMessageAPITest { | |||
public void testSendMessage() throws WxErrorException { | |||
WxCpMessage message = new WxCpMessage(); | |||
// message.setAgentId(configStorage.getAgentId()); | |||
message.setMsgType(WxConsts.CUSTOM_MSG_TEXT); | |||
message.setMsgType(WxConsts.KefuMsgType.TEXT); | |||
message.setToUser(configStorage.getUserId()); | |||
message.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>"); | |||
@@ -27,21 +27,21 @@ public class WxCpMessageRouterTest { | |||
router | |||
.rule() | |||
.async(async) | |||
.msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1").content("CONTENT_1") | |||
.msgType(WxConsts.XmlMsgType.TEXT).event(WxConsts.EventType.CLICK).eventKey("KEY_1").content("CONTENT_1") | |||
.handler(new WxEchoCpMessageHandler(sb, "COMBINE_4")) | |||
.end() | |||
.rule() | |||
.async(async) | |||
.msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1") | |||
.msgType(WxConsts.XmlMsgType.TEXT).event(WxConsts.EventType.CLICK).eventKey("KEY_1") | |||
.handler(new WxEchoCpMessageHandler(sb, "COMBINE_3")) | |||
.end() | |||
.rule() | |||
.async(async) | |||
.msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK) | |||
.msgType(WxConsts.XmlMsgType.TEXT).event(WxConsts.EventType.CLICK) | |||
.handler(new WxEchoCpMessageHandler(sb, "COMBINE_2")) | |||
.end() | |||
.rule().async(async).msgType(WxConsts.XML_MSG_TEXT).handler(new WxEchoCpMessageHandler(sb, WxConsts.XML_MSG_TEXT)).end() | |||
.rule().async(async).event(WxConsts.EVT_CLICK).handler(new WxEchoCpMessageHandler(sb, WxConsts.EVT_CLICK)).end() | |||
.rule().async(async).msgType(WxConsts.XmlMsgType.TEXT).handler(new WxEchoCpMessageHandler(sb, WxConsts.XmlMsgType.TEXT)).end() | |||
.rule().async(async).event(WxConsts.EventType.CLICK).handler(new WxEchoCpMessageHandler(sb, WxConsts.EventType.CLICK)).end() | |||
.rule().async(async).eventKey("KEY_1").handler(new WxEchoCpMessageHandler(sb, "KEY_1")).end() | |||
.rule().async(async).content("CONTENT_1").handler(new WxEchoCpMessageHandler(sb, "CONTENT_1")).end() | |||
.rule().async(async).rContent(".*bc.*").handler(new WxEchoCpMessageHandler(sb, "abcd")).end() | |||
@@ -104,10 +104,10 @@ public class WxCpMessageRouterTest { | |||
@DataProvider(name = "messages-1") | |||
public Object[][] messages2() { | |||
WxCpXmlMessage message1 = new WxCpXmlMessage(); | |||
message1.setMsgType(WxConsts.XML_MSG_TEXT); | |||
message1.setMsgType(WxConsts.XmlMsgType.TEXT); | |||
WxCpXmlMessage message2 = new WxCpXmlMessage(); | |||
message2.setEvent(WxConsts.EVT_CLICK); | |||
message2.setEvent(WxConsts.EventType.CLICK); | |||
WxCpXmlMessage message3 = new WxCpXmlMessage(); | |||
message3.setEventKey("KEY_1"); | |||
@@ -125,24 +125,24 @@ public class WxCpMessageRouterTest { | |||
message7.setFormat("strangeformat"); | |||
WxCpXmlMessage c2 = new WxCpXmlMessage(); | |||
c2.setMsgType(WxConsts.XML_MSG_TEXT); | |||
c2.setEvent(WxConsts.EVT_CLICK); | |||
c2.setMsgType(WxConsts.XmlMsgType.TEXT); | |||
c2.setEvent(WxConsts.EventType.CLICK); | |||
WxCpXmlMessage c3 = new WxCpXmlMessage(); | |||
c3.setMsgType(WxConsts.XML_MSG_TEXT); | |||
c3.setEvent(WxConsts.EVT_CLICK); | |||
c3.setMsgType(WxConsts.XmlMsgType.TEXT); | |||
c3.setEvent(WxConsts.EventType.CLICK); | |||
c3.setEventKey("KEY_1"); | |||
WxCpXmlMessage c4 = new WxCpXmlMessage(); | |||
c4.setMsgType(WxConsts.XML_MSG_TEXT); | |||
c4.setEvent(WxConsts.EVT_CLICK); | |||
c4.setMsgType(WxConsts.XmlMsgType.TEXT); | |||
c4.setEvent(WxConsts.EventType.CLICK); | |||
c4.setEventKey("KEY_1"); | |||
c4.setContent("CONTENT_1"); | |||
return new Object[][]{ | |||
new Object[]{message1, WxConsts.XML_MSG_TEXT + ","}, | |||
new Object[]{message2, WxConsts.EVT_CLICK + ","}, | |||
new Object[]{message1, WxConsts.XmlMsgType.TEXT + ","}, | |||
new Object[]{message2, WxConsts.EventType.CLICK + ","}, | |||
new Object[]{message3, "KEY_1,"}, | |||
new Object[]{message4, "CONTENT_1,"}, | |||
new Object[]{message5, "ALL,"}, | |||
@@ -1,12 +1,10 @@ | |||
package me.chanjar.weixin.cp.api.impl; | |||
import com.google.inject.Inject; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.cp.api.ApiTestModule; | |||
import me.chanjar.weixin.cp.api.WxCpService; | |||
import me.chanjar.weixin.cp.bean.WxCpDepart; | |||
import org.testng.annotations.Guice; | |||
import org.testng.annotations.Test; | |||
import org.testng.annotations.*; | |||
import java.util.List; | |||
@@ -31,7 +29,7 @@ public class WxCpDepartmentServiceImplTest { | |||
WxCpDepart cpDepart = new WxCpDepart(); | |||
cpDepart.setName("子部门" + System.currentTimeMillis()); | |||
cpDepart.setParentId(1); | |||
cpDepart.setOrder(1); | |||
cpDepart.setOrder(1L); | |||
Integer departId = this.wxCpService.getDepartmentService().create(cpDepart); | |||
System.out.println(departId); | |||
} | |||
@@ -34,11 +34,11 @@ public class WxCpMediaServiceImplTest { | |||
@DataProvider | |||
public Object[][] mediaData() { | |||
return new Object[][]{ | |||
new Object[]{WxConsts.MEDIA_IMAGE, TestConstants.FILE_JPG, "mm.jpeg"}, | |||
new Object[]{WxConsts.MEDIA_VOICE, TestConstants.FILE_MP3, "mm.mp3"}, | |||
new Object[]{WxConsts.MEDIA_VOICE, TestConstants.FILE_AMR, "mm.amr"},//{"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"} | |||
new Object[]{WxConsts.MEDIA_VIDEO, TestConstants.FILE_MP4, "mm.mp4"}, | |||
new Object[]{WxConsts.MEDIA_FILE, TestConstants.FILE_JPG, "mm.jpeg"} | |||
new Object[]{WxConsts.MediaFileType.IMAGE, TestConstants.FILE_JPG, "mm.jpeg"}, | |||
new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_MP3, "mm.mp3"}, | |||
new Object[]{WxConsts.MediaFileType.VOICE, TestConstants.FILE_AMR, "mm.amr"},//{"errcode":301017,"errmsg":"voice file only support amr like myvoice.amr"} | |||
new Object[]{WxConsts.MediaFileType.VIDEO, TestConstants.FILE_MP4, "mm.mp4"}, | |||
new Object[]{WxConsts.MediaFileType.FILE, TestConstants.FILE_JPG, "mm.jpeg"} | |||
}; | |||
} | |||
@@ -26,12 +26,12 @@ public class WxCpMenuServiceImplTest { | |||
public Object[][] menuData() { | |||
WxMenu menu = new WxMenu(); | |||
WxMenuButton button1 = new WxMenuButton(); | |||
button1.setType(WxConsts.BUTTON_CLICK); | |||
button1.setType(WxConsts.MenuButtonType.CLICK); | |||
button1.setName("今日歌曲"); | |||
button1.setKey("V1001_TODAY_MUSIC"); | |||
WxMenuButton button2 = new WxMenuButton(); | |||
button2.setType(WxConsts.BUTTON_CLICK); | |||
button2.setType(WxConsts.MenuButtonType.CLICK); | |||
button2.setName("歌手简介"); | |||
button2.setKey("V1001_TODAY_SINGER"); | |||
@@ -43,17 +43,17 @@ public class WxCpMenuServiceImplTest { | |||
menu.getButtons().add(button3); | |||
WxMenuButton button31 = new WxMenuButton(); | |||
button31.setType(WxConsts.BUTTON_VIEW); | |||
button31.setType(WxConsts.MenuButtonType.VIEW); | |||
button31.setName("搜索"); | |||
button31.setUrl("http://www.soso.com/"); | |||
WxMenuButton button32 = new WxMenuButton(); | |||
button32.setType(WxConsts.BUTTON_VIEW); | |||
button32.setType(WxConsts.MenuButtonType.VIEW); | |||
button32.setName("视频"); | |||
button32.setUrl("http://v.qq.com/"); | |||
WxMenuButton button33 = new WxMenuButton(); | |||
button33.setType(WxConsts.BUTTON_CLICK); | |||
button33.setType(WxConsts.MenuButtonType.CLICK); | |||
button33.setName("赞一下我们"); | |||
button33.setKey("V1001_GOOD"); | |||
@@ -58,7 +58,7 @@ public class WxCpXmlMessageTest { | |||
assertEquals(wxMessage.getToUserName(), "toUser"); | |||
assertEquals(wxMessage.getFromUserName(), "fromUser"); | |||
assertEquals(wxMessage.getCreateTime(), new Long(1348831860l)); | |||
assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); | |||
assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.TEXT); | |||
assertEquals(wxMessage.getContent(), "this is a test"); | |||
assertEquals(wxMessage.getMsgId(), new Long(1234567890123456l)); | |||
assertEquals(wxMessage.getPicUrl(), "this is a url"); | |||
@@ -86,7 +86,7 @@ public class WxCpXmlMessageTest { | |||
assertEquals(wxMessage.getSendLocationInfo().getLocationY(), "113"); | |||
assertEquals(wxMessage.getSendLocationInfo().getScale(), "15"); | |||
assertEquals(wxMessage.getSendLocationInfo().getLabel(), " 广州市海珠区客村艺苑路 106号"); | |||
assertEquals(wxMessage.getSendLocationInfo().getPoiname(), "wo de poi"); | |||
assertEquals(wxMessage.getSendLocationInfo().getPoiName(), "wo de poi"); | |||
} | |||
public void testSendPicsInfo() { | |||
@@ -108,7 +108,7 @@ public class WxCpXmlMessageTest { | |||
assertEquals(wxMessage.getToUserName(), "wx45a0972125658be9"); | |||
assertEquals(wxMessage.getFromUserName(), "xiaohe"); | |||
assertEquals(wxMessage.getCreateTime(), new Long(1502012364L)); | |||
assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_EVENT); | |||
assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.EVENT); | |||
assertEquals(wxMessage.getAgentId(), Integer.valueOf(1000004)); | |||
assertEquals(wxMessage.getEvent(), "pic_weixin"); | |||
assertEquals(wxMessage.getEventKey(), "faceSimilarity"); | |||
@@ -7,7 +7,7 @@ | |||
<parent> | |||
<groupId>com.github.binarywang</groupId> | |||
<artifactId>weixin-java-parent</artifactId> | |||
<version>2.8.0</version> | |||
<version>2.9.0</version> | |||
</parent> | |||
<artifactId>weixin-java-miniapp</artifactId> | |||
<name>WeiXin Java Tools - MiniApp</name> | |||
@@ -1,5 +1,6 @@ | |||
package cn.binarywang.wx.miniapp.api; | |||
import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import java.io.File; | |||
@@ -16,6 +17,9 @@ import java.io.File; | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
public interface WxMaQrcodeService { | |||
String CREATE_QRCODE_URL = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode"; | |||
String GET_WXACODE_URL = "https://api.weixin.qq.com/wxa/getwxacode"; | |||
String GET_WXACODE_UNLIMIT_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit"; | |||
/** | |||
* 接口C | |||
@@ -42,10 +46,8 @@ public interface WxMaQrcodeService { | |||
* @param width 默认430 二维码的宽度 | |||
* @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 | |||
* @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
File createWxCode(String path, int width, boolean autoColor, LineColor lineColor) throws WxErrorException; | |||
File createWxCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor) throws WxErrorException; | |||
File createWxCode(String path, int width) throws WxErrorException; | |||
@@ -65,49 +67,9 @@ public interface WxMaQrcodeService { | |||
* @param width 默认false 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 | |||
* @param autoColor 默认true 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 | |||
* @param lineColor auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
File createWxCodeLimit(String scene, String page, int width, boolean autoColor, LineColor lineColor) throws WxErrorException; | |||
File createWxCodeLimit(String scene, String page, int width, boolean autoColor, WxMaCodeLineColor lineColor) throws WxErrorException; | |||
File createWxCodeLimit(String scene, String page) throws WxErrorException; | |||
/** | |||
* lineColor 包装类 | |||
* 用于描述二维码(小程序码)颜色(RGB参数值),详情请查看文档 | |||
*/ | |||
public static class LineColor { | |||
private String r = "0", g = "0", b = "0"; | |||
public LineColor(String r, String g, String b) { | |||
this.r = r; | |||
this.g = g; | |||
this.b = b; | |||
} | |||
public String getR() { | |||
return r; | |||
} | |||
public void setR(String r) { | |||
this.r = r; | |||
} | |||
public String getG() { | |||
return g; | |||
} | |||
public void setG(String g) { | |||
this.g = g; | |||
} | |||
public String getB() { | |||
return b; | |||
} | |||
public void setB(String b) { | |||
this.b = b; | |||
} | |||
} | |||
} |
@@ -6,11 +6,9 @@ import me.chanjar.weixin.common.bean.result.WxError; | |||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.common.util.fs.FileUtils; | |||
import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; | |||
import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor; | |||
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; | |||
import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import java.io.File; | |||
import java.io.IOException; | |||
@@ -22,8 +20,6 @@ import java.util.UUID; | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
public class WxMaMediaServiceImpl implements WxMaMediaService { | |||
private final Logger log = LoggerFactory.getLogger(this.getClass()); | |||
private WxMaService wxMaService; | |||
public WxMaMediaServiceImpl(WxMaService wxMaService) { | |||
@@ -35,8 +31,7 @@ public class WxMaMediaServiceImpl implements WxMaMediaService { | |||
try { | |||
return this.uploadMedia(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
throw new WxErrorException(WxError.newBuilder().setErrorMsg(e.getMessage()).build()); | |||
throw new WxErrorException(WxError.builder().errorMsg(e.getMessage()).build(), e); | |||
} | |||
} | |||
@@ -49,12 +44,11 @@ public class WxMaMediaServiceImpl implements WxMaMediaService { | |||
@Override | |||
public File getMedia(String mediaId) throws WxErrorException { | |||
try { | |||
RequestExecutor<File, String> executor = MediaDownloadRequestExecutor | |||
RequestExecutor<File, String> executor = BaseMediaDownloadRequestExecutor | |||
.create(this.wxMaService.getRequestHttp(), Files.createTempDirectory("wxma").toFile()); | |||
return this.wxMaService.execute(executor, MEDIA_GET_URL, "media_id=" + mediaId); | |||
} catch (IOException e) { | |||
this.log.error(e.getMessage(), e); | |||
throw new WxErrorException(WxError.newBuilder().setErrorMsg(e.getMessage()).build()); | |||
throw new WxErrorException(WxError.builder().errorMsg(e.getMessage()).build(), e); | |||
} | |||
} | |||
@@ -4,6 +4,7 @@ import cn.binarywang.wx.miniapp.api.WxMaMsgService; | |||
import cn.binarywang.wx.miniapp.api.WxMaService; | |||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; | |||
import cn.binarywang.wx.miniapp.constant.WxMaConstants; | |||
import com.google.gson.JsonObject; | |||
import com.google.gson.JsonParser; | |||
import me.chanjar.weixin.common.bean.result.WxError; | |||
@@ -30,7 +31,7 @@ public class WxMaMsgServiceImpl implements WxMaMsgService { | |||
public void sendTemplateMsg(WxMaTemplateMessage templateMessage) throws WxErrorException { | |||
String responseContent = this.wxMaService.post(TEMPLATE_MSG_SEND_URL, templateMessage.toJson()); | |||
JsonObject jsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject(); | |||
if (jsonObject.get("errcode").getAsInt() != 0) { | |||
if (jsonObject.get(WxMaConstants.ERRCODE).getAsInt() != 0) { | |||
throw new WxErrorException(WxError.fromJson(responseContent)); | |||
} | |||
} | |||
@@ -2,6 +2,7 @@ package cn.binarywang.wx.miniapp.api.impl; | |||
import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; | |||
import cn.binarywang.wx.miniapp.api.WxMaService; | |||
import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor; | |||
import cn.binarywang.wx.miniapp.bean.WxMaQrcode; | |||
import cn.binarywang.wx.miniapp.bean.WxMaWxcode; | |||
import cn.binarywang.wx.miniapp.bean.WxMaWxcodeLimit; | |||
@@ -22,9 +23,8 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { | |||
@Override | |||
public File createQrcode(String path, int width) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode"; | |||
return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), | |||
url, new WxMaQrcode(path, width)); | |||
CREATE_QRCODE_URL, new WxMaQrcode(path, width)); | |||
} | |||
@Override | |||
@@ -33,15 +33,14 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { | |||
} | |||
@Override | |||
public File createWxCode(String path, int width, boolean autoColor, LineColor lineColor) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/wxa/getwxacode"; | |||
public File createWxCode(String path, int width, boolean autoColor, WxMaCodeLineColor lineColor) throws WxErrorException { | |||
WxMaWxcode wxMaWxcode = new WxMaWxcode(); | |||
wxMaWxcode.setPath(path); | |||
wxMaWxcode.setWidth(width); | |||
wxMaWxcode.setAutoColor(autoColor); | |||
wxMaWxcode.setLineColor(lineColor); | |||
return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), | |||
url, wxMaWxcode); | |||
GET_WXACODE_URL, wxMaWxcode); | |||
} | |||
@Override | |||
@@ -55,8 +54,7 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { | |||
} | |||
@Override | |||
public File createWxCodeLimit(String scene, String page, int width, boolean autoColor, LineColor lineColor) throws WxErrorException { | |||
String url = "http://api.weixin.qq.com/wxa/getwxacodeunlimit"; | |||
public File createWxCodeLimit(String scene, String page, int width, boolean autoColor, WxMaCodeLineColor lineColor) throws WxErrorException { | |||
WxMaWxcodeLimit wxMaWxcodeLimit = new WxMaWxcodeLimit(); | |||
wxMaWxcodeLimit.setScene(scene); | |||
wxMaWxcodeLimit.setPage(page); | |||
@@ -64,7 +62,7 @@ public class WxMaQrcodeServiceImpl implements WxMaQrcodeService { | |||
wxMaWxcodeLimit.setAutoColor(autoColor); | |||
wxMaWxcodeLimit.setLineColor(lineColor); | |||
return this.wxMaService.execute(new QrCodeRequestExecutor(this.wxMaService.getRequestHttp()), | |||
url, wxMaWxcodeLimit); | |||
GET_WXACODE_UNLIMIT_URL, wxMaWxcodeLimit); | |||
} | |||
@Override | |||
@@ -2,6 +2,7 @@ package cn.binarywang.wx.miniapp.api.impl; | |||
import cn.binarywang.wx.miniapp.api.*; | |||
import cn.binarywang.wx.miniapp.config.WxMaConfig; | |||
import cn.binarywang.wx.miniapp.constant.WxMaConstants; | |||
import com.google.gson.JsonParser; | |||
import me.chanjar.weixin.common.bean.WxAccessToken; | |||
import me.chanjar.weixin.common.bean.result.WxError; | |||
@@ -147,6 +148,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||
/** | |||
* 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 | |||
*/ | |||
@Override | |||
public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException { | |||
int retryTimes = 0; | |||
do { | |||
@@ -179,7 +181,7 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||
throw new RuntimeException("微信服务端异常,超出重试次数"); | |||
} | |||
public synchronized <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException { | |||
public <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException { | |||
if (uri.contains("access_token=")) { | |||
throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri); | |||
} | |||
@@ -195,11 +197,10 @@ public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpCl | |||
WxError error = e.getError(); | |||
/* | |||
* 发生以下情况时尝试刷新access_token | |||
* 40001 获取access_token时AppSecret错误,或者access_token无效 | |||
* 42001 access_token超时 | |||
* 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期) | |||
*/ | |||
if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001 || error.getErrorCode() == 40014) { | |||
if (error.getErrorCode() == WxMaConstants.ErrorCode.ERR_40001 | |||
|| error.getErrorCode() == WxMaConstants.ErrorCode.ERR_42001 | |||
|| error.getErrorCode() == WxMaConstants.ErrorCode.ERR_40014) { | |||
// 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token | |||
this.getWxMaConfig().expireAccessToken(); | |||
if (this.getWxMaConfig().autoRefreshToken()) { | |||
@@ -19,14 +19,14 @@ import java.util.Map; | |||
public class WxMaUserServiceImpl implements WxMaUserService { | |||
private WxMaService service; | |||
WxMaUserServiceImpl(WxMaService service) { | |||
public WxMaUserServiceImpl(WxMaService service) { | |||
this.service = service; | |||
} | |||
@Override | |||
public WxMaJscode2SessionResult getSessionInfo(String jsCode) throws WxErrorException { | |||
final WxMaConfig config = service.getWxMaConfig(); | |||
Map<String, String> params = new HashMap<>(); | |||
Map<String, String> params = new HashMap<>(8); | |||
params.put("appid", config.getAppid()); | |||
params.put("secret", config.getSecret()); | |||
params.put("js_code", jsCode); | |||
@@ -3,10 +3,11 @@ package cn.binarywang.wx.miniapp.bean; | |||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||
/** | |||
* 微信二维码(小程序码)包装器 | |||
* Created by Element on 2017/7/27. | |||
* 微信二维码(小程序码)包装器. | |||
* | |||
* @author Element | |||
*/ | |||
public abstract class WxMaQrcodeWrapper { | |||
public abstract class AbstractWxMaQrcodeWrapper { | |||
@Override | |||
public String toString() { |
@@ -0,0 +1,18 @@ | |||
package cn.binarywang.wx.miniapp.bean; | |||
import lombok.AllArgsConstructor; | |||
import lombok.Data; | |||
/** | |||
* <pre> | |||
* lineColor 包装类 | |||
* 用于描述二维码(小程序码)颜色(RGB参数值), | |||
* 详情请查看文档 https://mp.weixin.qq.com/debug/wxadoc/dev/api/qrcode.html | |||
* </pre> | |||
* @author Element | |||
*/ | |||
@Data | |||
@AllArgsConstructor | |||
public class WxMaCodeLineColor { | |||
private String r = "0", g = "0", b = "0"; | |||
} |
@@ -2,13 +2,21 @@ package cn.binarywang.wx.miniapp.bean; | |||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||
import com.google.gson.annotations.SerializedName; | |||
import lombok.Data; | |||
import lombok.EqualsAndHashCode; | |||
import java.io.Serializable; | |||
/** | |||
* {"session_key":"nzoqhc3OnwHzeTxJs+inbQ==","expires_in":2592000,"openid":"oVBkZ0aYgDMDIywRdgPW8-joxXc4"} | |||
* | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
public class WxMaJscode2SessionResult { | |||
@Data | |||
@EqualsAndHashCode(callSuper = false) | |||
public class WxMaJscode2SessionResult implements Serializable { | |||
private static final long serialVersionUID = -1060216618475607933L; | |||
@SerializedName("session_key") | |||
private String sessionKey; | |||
@@ -25,36 +33,4 @@ public class WxMaJscode2SessionResult { | |||
return WxMaGsonBuilder.create().fromJson(json, WxMaJscode2SessionResult.class); | |||
} | |||
public String getSessionKey() { | |||
return sessionKey; | |||
} | |||
public void setSessionKey(String sessionKey) { | |||
this.sessionKey = sessionKey; | |||
} | |||
public Integer getExpiresin() { | |||
return expiresin; | |||
} | |||
public void setExpiresin(Integer expiresin) { | |||
this.expiresin = expiresin; | |||
} | |||
public String getOpenid() { | |||
return openid; | |||
} | |||
public void setOpenid(String openid) { | |||
this.openid = openid; | |||
} | |||
public String getUnionid() { | |||
return unionid; | |||
} | |||
public void setUnionid(String unionid) { | |||
this.unionid = unionid; | |||
} | |||
} |
@@ -3,6 +3,7 @@ package cn.binarywang.wx.miniapp.bean; | |||
import cn.binarywang.wx.miniapp.builder.ImageBuilder; | |||
import cn.binarywang.wx.miniapp.builder.TextBuilder; | |||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
@@ -11,6 +12,7 @@ import java.io.Serializable; | |||
* | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
@Data | |||
public class WxMaKefuMessage implements Serializable { | |||
private static final long serialVersionUID = -9196732086954365246L; | |||
@@ -25,73 +27,17 @@ public class WxMaKefuMessage implements Serializable { | |||
/** | |||
* 获得文本消息builder | |||
*/ | |||
public static TextBuilder TEXT() { | |||
public static TextBuilder newTextBuilder() { | |||
return new TextBuilder(); | |||
} | |||
/** | |||
* 获得图片消息builder | |||
*/ | |||
public static ImageBuilder IMAGE() { | |||
public static ImageBuilder newImageBuilder() { | |||
return new ImageBuilder(); | |||
} | |||
public String getToUser() { | |||
return this.toUser; | |||
} | |||
public void setToUser(String toUser) { | |||
this.toUser = toUser; | |||
} | |||
public String getMsgType() { | |||
return this.msgType; | |||
} | |||
public void setMsgType(String msgType) { | |||
this.msgType = msgType; | |||
} | |||
public String getContent() { | |||
return this.content; | |||
} | |||
public void setContent(String content) { | |||
this.content = content; | |||
} | |||
public String getMediaId() { | |||
return this.mediaId; | |||
} | |||
public void setMediaId(String mediaId) { | |||
this.mediaId = mediaId; | |||
} | |||
public String getThumbMediaId() { | |||
return this.thumbMediaId; | |||
} | |||
public void setThumbMediaId(String thumbMediaId) { | |||
this.thumbMediaId = thumbMediaId; | |||
} | |||
public String getTitle() { | |||
return this.title; | |||
} | |||
public void setTitle(String title) { | |||
this.title = title; | |||
} | |||
public String getDescription() { | |||
return this.description; | |||
} | |||
public void setDescription(String description) { | |||
this.description = description; | |||
} | |||
public String toJson() { | |||
return WxMaGsonBuilder.create().toJson(this); | |||
} | |||
@@ -7,6 +7,7 @@ import cn.binarywang.wx.miniapp.util.xml.XStreamTransformer; | |||
import com.google.gson.annotations.SerializedName; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
import lombok.Data; | |||
import me.chanjar.weixin.common.util.ToStringUtils; | |||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||
import org.apache.commons.io.IOUtils; | |||
@@ -20,6 +21,7 @@ import java.nio.charset.StandardCharsets; | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
@XStreamAlias("xml") | |||
@Data | |||
public class WxMaMessage implements Serializable { | |||
private static final long serialVersionUID = -3586245291677274914L; | |||
@@ -146,91 +148,4 @@ public class WxMaMessage implements Serializable { | |||
return WxMaGsonBuilder.create().toJson(this); | |||
} | |||
public String getToUser() { | |||
return toUser; | |||
} | |||
public void setToUser(String toUser) { | |||
this.toUser = toUser; | |||
} | |||
public String getFromUser() { | |||
return fromUser; | |||
} | |||
public void setFromUser(String fromUser) { | |||
this.fromUser = fromUser; | |||
} | |||
public Integer getCreateTime() { | |||
return createTime; | |||
} | |||
public void setCreateTime(Integer createTime) { | |||
this.createTime = createTime; | |||
} | |||
public String getMsgType() { | |||
return msgType; | |||
} | |||
public void setMsgType(String msgType) { | |||
this.msgType = msgType; | |||
} | |||
public String getContent() { | |||
return content; | |||
} | |||
public void setContent(String content) { | |||
this.content = content; | |||
} | |||
public Long getMsgId() { | |||
return msgId; | |||
} | |||
public void setMsgId(Long msgId) { | |||
this.msgId = msgId; | |||
} | |||
public String getPicUrl() { | |||
return picUrl; | |||
} | |||
public void setPicUrl(String picUrl) { | |||
this.picUrl = picUrl; | |||
} | |||
public String getMediaId() { | |||
return mediaId; | |||
} | |||
public void setMediaId(String mediaId) { | |||
this.mediaId = mediaId; | |||
} | |||
public String getEvent() { | |||
return event; | |||
} | |||
public void setEvent(String event) { | |||
this.event = event; | |||
} | |||
public String getSessionFrom() { | |||
return sessionFrom; | |||
} | |||
public void setSessionFrom(String sessionFrom) { | |||
this.sessionFrom = sessionFrom; | |||
} | |||
public String getEncrypt() { | |||
return encrypt; | |||
} | |||
public void setEncrypt(String encrypt) { | |||
this.encrypt = encrypt; | |||
} | |||
} |
@@ -1,13 +1,17 @@ | |||
package cn.binarywang.wx.miniapp.bean; | |||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||
import lombok.Data; | |||
import lombok.EqualsAndHashCode; | |||
import java.io.Serializable; | |||
/** | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
public class WxMaQrcode extends WxMaQrcodeWrapper implements Serializable { | |||
@Data | |||
@EqualsAndHashCode(callSuper = false) | |||
public class WxMaQrcode extends AbstractWxMaQrcodeWrapper implements Serializable { | |||
private static final long serialVersionUID = 5777119669111011584L; | |||
private String path; | |||
private int width = 430; | |||
@@ -21,22 +25,6 @@ public class WxMaQrcode extends WxMaQrcodeWrapper implements Serializable { | |||
return WxMaGsonBuilder.create().fromJson(json, WxMaQrcode.class); | |||
} | |||
public String getPath() { | |||
return path; | |||
} | |||
public void setPath(String path) { | |||
this.path = path; | |||
} | |||
public int getWidth() { | |||
return width; | |||
} | |||
public void setWidth(int width) { | |||
this.width = width; | |||
} | |||
@Override | |||
public String toString() { | |||
return WxMaGsonBuilder.create().toJson(this); | |||
@@ -1,6 +1,8 @@ | |||
package cn.binarywang.wx.miniapp.bean; | |||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||
import lombok.Builder; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
import java.util.ArrayList; | |||
@@ -11,6 +13,8 @@ import java.util.List; | |||
* | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
@Data | |||
@Builder | |||
public class WxMaTemplateMessage implements Serializable { | |||
private static final long serialVersionUID = 5063374783759519418L; | |||
@@ -57,7 +61,8 @@ public class WxMaTemplateMessage implements Serializable { | |||
* 描述: 模板内容,不填则下发空模板 | |||
* </pre> | |||
*/ | |||
private List<Data> data = new ArrayList<>(); | |||
@Builder.Default | |||
private final List<Data> data = new ArrayList<>(); | |||
/** | |||
* <pre> | |||
@@ -77,80 +82,11 @@ public class WxMaTemplateMessage implements Serializable { | |||
*/ | |||
private String emphasisKeyword; | |||
private WxMaTemplateMessage(Builder builder) { | |||
setToUser(builder.toUser); | |||
setTemplateId(builder.templateId); | |||
setPage(builder.page); | |||
setFormId(builder.formId); | |||
setData(builder.data); | |||
setColor(builder.color); | |||
setEmphasisKeyword(builder.emphasisKeyword); | |||
} | |||
public static Builder newBuilder() { | |||
return new Builder(); | |||
} | |||
public String toJson() { | |||
return WxMaGsonBuilder.create().toJson(this); | |||
} | |||
public String getToUser() { | |||
return toUser; | |||
} | |||
public void setToUser(String toUser) { | |||
this.toUser = toUser; | |||
} | |||
public String getTemplateId() { | |||
return templateId; | |||
} | |||
public void setTemplateId(String templateId) { | |||
this.templateId = templateId; | |||
} | |||
public String getPage() { | |||
return page; | |||
} | |||
public void setPage(String page) { | |||
this.page = page; | |||
} | |||
public String getFormId() { | |||
return formId; | |||
} | |||
public void setFormId(String formId) { | |||
this.formId = formId; | |||
} | |||
public List<Data> getData() { | |||
return data; | |||
} | |||
public void setData(List<Data> data) { | |||
this.data = data; | |||
} | |||
public String getColor() { | |||
return color; | |||
} | |||
public void setColor(String color) { | |||
this.color = color; | |||
} | |||
public String getEmphasisKeyword() { | |||
return emphasisKeyword; | |||
} | |||
public void setEmphasisKeyword(String emphasisKeyword) { | |||
this.emphasisKeyword = emphasisKeyword; | |||
} | |||
@lombok.Data | |||
public static class Data { | |||
private String name; | |||
private String value; | |||
@@ -167,81 +103,6 @@ public class WxMaTemplateMessage implements Serializable { | |||
this.color = color; | |||
} | |||
public String getName() { | |||
return this.name; | |||
} | |||
public void setName(String name) { | |||
this.name = name; | |||
} | |||
public String getValue() { | |||
return this.value; | |||
} | |||
public void setValue(String value) { | |||
this.value = value; | |||
} | |||
public String getColor() { | |||
return this.color; | |||
} | |||
public void setColor(String color) { | |||
this.color = color; | |||
} | |||
} | |||
public static final class Builder { | |||
private String toUser; | |||
private String templateId; | |||
private String page; | |||
private String formId; | |||
private List<Data> data; | |||
private String color; | |||
private String emphasisKeyword; | |||
private Builder() { | |||
} | |||
public Builder toUser(String toUser) { | |||
this.toUser = toUser; | |||
return this; | |||
} | |||
public Builder templateId(String templateId) { | |||
this.templateId = templateId; | |||
return this; | |||
} | |||
public Builder page(String page) { | |||
this.page = page; | |||
return this; | |||
} | |||
public Builder formId(String formId) { | |||
this.formId = formId; | |||
return this; | |||
} | |||
public Builder data(List<Data> data) { | |||
this.data = data; | |||
return this; | |||
} | |||
public Builder color(String color) { | |||
this.color = color; | |||
return this; | |||
} | |||
public Builder emphasisKeyword(String emphasisKeyword) { | |||
this.emphasisKeyword = emphasisKeyword; | |||
return this; | |||
} | |||
public WxMaTemplateMessage build() { | |||
return new WxMaTemplateMessage(this); | |||
} | |||
} | |||
} |
@@ -1,13 +1,17 @@ | |||
package cn.binarywang.wx.miniapp.bean; | |||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||
import org.apache.commons.lang3.builder.ToStringBuilder; | |||
import org.apache.commons.lang3.builder.ToStringStyle; | |||
import lombok.Data; | |||
import java.io.Serializable; | |||
/** | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
public class WxMaUserInfo { | |||
@Data | |||
public class WxMaUserInfo implements Serializable { | |||
private static final long serialVersionUID = 6719822331555402137L; | |||
private String openId; | |||
private String nickName; | |||
private String gender; | |||
@@ -23,109 +27,9 @@ public class WxMaUserInfo { | |||
return WxMaGsonBuilder.create().fromJson(json, WxMaUserInfo.class); | |||
} | |||
@Override | |||
public String toString() { | |||
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); | |||
} | |||
public String getOpenId() { | |||
return openId; | |||
} | |||
public void setOpenId(String openId) { | |||
this.openId = openId; | |||
} | |||
public String getNickName() { | |||
return nickName; | |||
} | |||
public void setNickName(String nickName) { | |||
this.nickName = nickName; | |||
} | |||
public String getGender() { | |||
return gender; | |||
} | |||
public void setGender(String gender) { | |||
this.gender = gender; | |||
} | |||
public String getLanguage() { | |||
return language; | |||
} | |||
public void setLanguage(String language) { | |||
this.language = language; | |||
} | |||
public String getCity() { | |||
return city; | |||
} | |||
public void setCity(String city) { | |||
this.city = city; | |||
} | |||
public String getProvince() { | |||
return province; | |||
} | |||
public void setProvince(String province) { | |||
this.province = province; | |||
} | |||
public String getCountry() { | |||
return country; | |||
} | |||
public void setCountry(String country) { | |||
this.country = country; | |||
} | |||
public String getAvatarUrl() { | |||
return avatarUrl; | |||
} | |||
public void setAvatarUrl(String avatarUrl) { | |||
this.avatarUrl = avatarUrl; | |||
} | |||
public String getUnionId() { | |||
return unionId; | |||
} | |||
public void setUnionId(String unionId) { | |||
this.unionId = unionId; | |||
} | |||
public Watermark getWatermark() { | |||
return watermark; | |||
} | |||
public void setWatermark(Watermark watermark) { | |||
this.watermark = watermark; | |||
} | |||
@Data | |||
public static class Watermark { | |||
private String timestamp; | |||
private String appid; | |||
public String getTimestamp() { | |||
return timestamp; | |||
} | |||
public void setTimestamp(String timestamp) { | |||
this.timestamp = timestamp; | |||
} | |||
public String getAppid() { | |||
return appid; | |||
} | |||
public void setAppid(String appid) { | |||
this.appid = appid; | |||
} | |||
} | |||
} |
@@ -1,17 +1,22 @@ | |||
package cn.binarywang.wx.miniapp.bean; | |||
import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; | |||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||
import com.google.gson.annotations.SerializedName; | |||
import lombok.Data; | |||
import lombok.EqualsAndHashCode; | |||
import java.io.Serializable; | |||
/** | |||
* Created by Element on 2017/7/27. | |||
* | |||
* @author Element | |||
* @date 2017/7/27 | |||
*/ | |||
public class WxMaWxcode extends WxMaQrcodeWrapper implements Serializable { | |||
@Data | |||
@EqualsAndHashCode(callSuper = false) | |||
public class WxMaWxcode extends AbstractWxMaQrcodeWrapper implements Serializable { | |||
private static final long serialVersionUID = 1287399621649210322L; | |||
private String path; | |||
private int width = 430; | |||
@@ -19,46 +24,10 @@ public class WxMaWxcode extends WxMaQrcodeWrapper implements Serializable { | |||
private boolean autoColor = true; | |||
@SerializedName("line_color") | |||
private WxMaQrcodeService.LineColor lineColor = new WxMaQrcodeService.LineColor("0", "0", "0"); | |||
private WxMaCodeLineColor lineColor = new WxMaCodeLineColor("0", "0", "0"); | |||
public static WxMaWxcode fromJson(String json) { | |||
return WxMaGsonBuilder.create().fromJson(json, WxMaWxcode.class); | |||
} | |||
public static long getSerialVersionUID() { | |||
return serialVersionUID; | |||
} | |||
public String getPath() { | |||
return path; | |||
} | |||
public void setPath(String path) { | |||
this.path = path; | |||
} | |||
public int getWidth() { | |||
return width; | |||
} | |||
public void setWidth(int width) { | |||
this.width = width; | |||
} | |||
public boolean isAutoColor() { | |||
return autoColor; | |||
} | |||
public void setAutoColor(boolean autoColor) { | |||
this.autoColor = autoColor; | |||
} | |||
public WxMaQrcodeService.LineColor getLineColor() { | |||
return lineColor; | |||
} | |||
public void setLineColor(WxMaQrcodeService.LineColor lineColor) { | |||
this.lineColor = lineColor; | |||
} | |||
} |
@@ -1,15 +1,20 @@ | |||
package cn.binarywang.wx.miniapp.bean; | |||
import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; | |||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||
import com.google.gson.annotations.SerializedName; | |||
import lombok.Data; | |||
import lombok.EqualsAndHashCode; | |||
import java.io.Serializable; | |||
/** | |||
* Created by Element on 2017/7/27. | |||
* | |||
* @author Element | |||
* @date 2017/7/27 | |||
*/ | |||
public class WxMaWxcodeLimit extends WxMaQrcodeWrapper implements Serializable { | |||
@Data | |||
@EqualsAndHashCode(callSuper = false) | |||
public class WxMaWxcodeLimit extends AbstractWxMaQrcodeWrapper implements Serializable { | |||
private static final long serialVersionUID = 4782193774524960401L; | |||
private String scene; | |||
private String page; | |||
@@ -20,49 +25,10 @@ public class WxMaWxcodeLimit extends WxMaQrcodeWrapper implements Serializable { | |||
private boolean autoColor = true; | |||
@SerializedName("line_color") | |||
private WxMaQrcodeService.LineColor lineColor = new WxMaQrcodeService.LineColor("0", "0", "0"); | |||
private WxMaCodeLineColor lineColor = new WxMaCodeLineColor("0", "0", "0"); | |||
public static WxMaWxcodeLimit fromJson(String json) { | |||
return WxMaGsonBuilder.create().fromJson(json, WxMaWxcodeLimit.class); | |||
} | |||
public String getPage() { | |||
return page; | |||
} | |||
public void setPage(String page) { | |||
this.page = page; | |||
} | |||
public String getScene() { | |||
return scene; | |||
} | |||
public void setScene(String scene) { | |||
this.scene = scene; | |||
} | |||
public int getWidth() { | |||
return width; | |||
} | |||
public void setWidth(int width) { | |||
this.width = width; | |||
} | |||
public boolean isAutoColor() { | |||
return autoColor; | |||
} | |||
public void setAutoColor(boolean autoColor) { | |||
this.autoColor = autoColor; | |||
} | |||
public WxMaQrcodeService.LineColor getLineColor() { | |||
return lineColor; | |||
} | |||
public void setLineColor(WxMaQrcodeService.LineColor lineColor) { | |||
this.lineColor = lineColor; | |||
} | |||
} |
@@ -15,6 +15,9 @@ public class BaseBuilder<T> { | |||
return (T) this; | |||
} | |||
/** | |||
* 构造器方法. | |||
*/ | |||
public WxMaKefuMessage build() { | |||
WxMaKefuMessage m = new WxMaKefuMessage(); | |||
m.setMsgType(this.msgType); | |||
@@ -13,8 +13,8 @@ public final class ImageBuilder extends BaseBuilder<ImageBuilder> { | |||
this.msgType = WxMaConstants.KefuMsgType.IMAGE; | |||
} | |||
public ImageBuilder mediaId(String media_id) { | |||
this.mediaId = media_id; | |||
public ImageBuilder mediaId(String mediaId) { | |||
this.mediaId = mediaId; | |||
return this; | |||
} | |||
@@ -175,6 +175,7 @@ public class WxMaInMemoryConfig implements WxMaConfig { | |||
return true; | |||
} | |||
@Override | |||
public String getAppid() { | |||
return appid; | |||
} | |||
@@ -8,11 +8,19 @@ package cn.binarywang.wx.miniapp.constant; | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
public class WxMaConstants { | |||
/** | |||
* 微信接口返回的参数errcode | |||
*/ | |||
public static final String ERRCODE = "errcode"; | |||
/** | |||
* 素材类型 | |||
*/ | |||
public static class MediaType { | |||
public static final String IMAGE = "image";//图片 | |||
/** | |||
* 图片 | |||
*/ | |||
public static final String IMAGE = "image"; | |||
} | |||
/** | |||
@@ -27,7 +35,30 @@ public class WxMaConstants { | |||
* 客服消息的消息类型 | |||
*/ | |||
public static class KefuMsgType { | |||
public static final String TEXT = "text";//文本消息 | |||
public static final String IMAGE = "image";//图片消息 | |||
/** | |||
* 文本消息 | |||
*/ | |||
public static final String TEXT = "text"; | |||
/** | |||
* 图片消息 | |||
*/ | |||
public static final String IMAGE = "image"; | |||
} | |||
public static final class ErrorCode { | |||
/** | |||
* 40001 获取access_token时AppSecret错误,或者access_token无效 | |||
*/ | |||
public static final int ERR_40001 = 40001; | |||
/** | |||
* 42001 access_token超时 | |||
*/ | |||
public static final int ERR_42001 = 42001; | |||
/** | |||
* 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期) | |||
*/ | |||
public static final int ERR_40014 = 40014; | |||
} | |||
} |
@@ -2,6 +2,7 @@ package cn.binarywang.wx.miniapp.message; | |||
import cn.binarywang.wx.miniapp.api.WxMaService; | |||
import cn.binarywang.wx.miniapp.bean.WxMaMessage; | |||
import com.google.common.util.concurrent.ThreadFactoryBuilder; | |||
import me.chanjar.weixin.common.api.WxErrorExceptionHandler; | |||
import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; | |||
import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; | |||
@@ -17,10 +18,7 @@ import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.concurrent.ExecutionException; | |||
import java.util.concurrent.ExecutorService; | |||
import java.util.concurrent.Executors; | |||
import java.util.concurrent.Future; | |||
import java.util.concurrent.*; | |||
/** | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
@@ -42,7 +40,9 @@ public class WxMaMessageRouter { | |||
public WxMaMessageRouter(WxMaService wxMaService) { | |||
this.wxMaService = wxMaService; | |||
this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE); | |||
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("WxMaMessageRouter-pool-%d").build(); | |||
this.executorService = new ThreadPoolExecutor(DEFAULT_THREAD_POOL_SIZE, DEFAULT_THREAD_POOL_SIZE, | |||
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), namedThreadFactory); | |||
this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker(); | |||
this.sessionManager = new StandardSessionManager(); | |||
this.exceptionHandler = new LogExceptionHandler(); | |||
@@ -159,7 +159,7 @@ public class WxMaMessageRouter { | |||
} | |||
public void route(final WxMaMessage wxMessage) { | |||
this.route(wxMessage, new HashMap<String, Object>()); | |||
this.route(wxMessage, new HashMap<String, Object>(2)); | |||
} | |||
/** | |||
@@ -196,7 +196,7 @@ public class WxMaMessageRouterRule { | |||
WxSessionManager sessionManager, | |||
WxErrorExceptionHandler exceptionHandler) { | |||
if (context == null) { | |||
context = new HashMap<>(); | |||
context = new HashMap<>(16); | |||
} | |||
try { | |||
@@ -1,6 +1,6 @@ | |||
package cn.binarywang.wx.miniapp.util.http; | |||
import cn.binarywang.wx.miniapp.bean.WxMaQrcodeWrapper; | |||
import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper; | |||
import me.chanjar.weixin.common.bean.result.WxError; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.common.util.fs.FileUtils; | |||
@@ -25,7 +25,7 @@ import java.util.UUID; | |||
/** | |||
* @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
*/ | |||
public class QrCodeRequestExecutor implements RequestExecutor<File, WxMaQrcodeWrapper> { | |||
public class QrCodeRequestExecutor implements RequestExecutor<File, AbstractWxMaQrcodeWrapper> { | |||
protected RequestHttp<CloseableHttpClient, HttpHost> requestHttp; | |||
public QrCodeRequestExecutor(RequestHttp requestHttp) { | |||
@@ -33,14 +33,12 @@ public class QrCodeRequestExecutor implements RequestExecutor<File, WxMaQrcodeWr | |||
} | |||
@Override | |||
public File execute(String uri, WxMaQrcodeWrapper ticket) throws WxErrorException, IOException { | |||
public File execute(String uri, AbstractWxMaQrcodeWrapper ticket) throws WxErrorException, IOException { | |||
HttpPost httpPost = new HttpPost(uri); | |||
if (requestHttp.getRequestHttpProxy() != null) { | |||
httpPost | |||
.setConfig(RequestConfig.custom() | |||
.setProxy(requestHttp.getRequestHttpProxy()) | |||
.build() | |||
); | |||
httpPost.setConfig( | |||
RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build() | |||
); | |||
} | |||
httpPost.setEntity(new StringEntity(ticket.toString())); | |||
@@ -48,7 +46,8 @@ public class QrCodeRequestExecutor implements RequestExecutor<File, WxMaQrcodeWr | |||
InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { | |||
Header[] contentTypeHeader = response.getHeaders("Content-Type"); | |||
if (contentTypeHeader != null && contentTypeHeader.length > 0 | |||
&& ContentType.APPLICATION_JSON.getMimeType().equals(contentTypeHeader[0].getValue())) { | |||
&& ContentType.APPLICATION_JSON.getMimeType() | |||
.equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) { | |||
String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); | |||
throw new WxErrorException(WxError.fromJson(responseContent)); | |||
} | |||
@@ -18,7 +18,7 @@ public class XStreamTransformer { | |||
} | |||
/** | |||
* xml -> pojo | |||
* xml -> pojo. | |||
*/ | |||
@SuppressWarnings("unchecked") | |||
public static <T> T fromXml(Class<T> clazz, String xml) { | |||
@@ -33,14 +33,14 @@ public class XStreamTransformer { | |||
} | |||
/** | |||
* pojo -> xml | |||
* pojo -> xml. | |||
*/ | |||
public static <T> String toXml(Class<T> clazz, T object) { | |||
return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); | |||
} | |||
/** | |||
* 注册扩展消息的解析器 | |||
* 注册扩展消息的解析器. | |||
* | |||
* @param clz 类型 | |||
* @param xStream xml解析器 | |||
@@ -50,12 +50,14 @@ public class XStreamTransformer { | |||
} | |||
/** | |||
* 会自动注册该类及其子类 | |||
* 会自动注册该类及其子类. | |||
* | |||
* @param clz 要注册的类 | |||
*/ | |||
private static void registerClass(Class<?> clz) { | |||
XStream xstream = XStreamInitializer.getInstance(); | |||
xstream.setClassLoader(Thread.currentThread().getContextClassLoader()); | |||
xstream.processAnnotations(clz); | |||
xstream.processAnnotations(getInnerClasses(clz)); | |||
if (clz.equals(WxMaMessage.class)) { | |||
@@ -31,7 +31,7 @@ public class WxMaMsgServiceImplTest { | |||
TestConfig configStorage = (TestConfig) this.wxService | |||
.getWxMaConfig(); | |||
WxMaKefuMessage message = new WxMaKefuMessage(); | |||
message.setMsgType(WxConsts.CUSTOM_MSG_MPNEWS); | |||
message.setMsgType(WxConsts.KefuMsgType.MPNEWS); | |||
message.setToUser(configStorage.getOpenid()); | |||
this.wxService.getMsgService().sendKefuMsg(message); | |||
@@ -41,7 +41,7 @@ public class WxMaMsgServiceImplTest { | |||
TestConfig config = (TestConfig) this.wxService | |||
.getWxMaConfig(); | |||
WxMaKefuMessage message = new WxMaKefuMessage(); | |||
message.setMsgType(WxConsts.CUSTOM_MSG_TEXT); | |||
message.setMsgType(WxConsts.KefuMsgType.TEXT); | |||
message.setToUser(config.getOpenid()); | |||
message.setContent( | |||
"欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>"); | |||
@@ -54,7 +54,7 @@ public class WxMaMsgServiceImplTest { | |||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); | |||
TestConfig config = (TestConfig) this.wxService.getWxMaConfig(); | |||
WxMaTemplateMessage templateMessage = WxMaTemplateMessage.newBuilder() | |||
WxMaTemplateMessage templateMessage = WxMaTemplateMessage.builder() | |||
.toUser(config.getOpenid()) | |||
.formId("FORMID") | |||
.page("index") | |||