@@ -40,7 +40,7 @@ | |||||
<property name="allowNonPrintableEscapes" value="true"/> | <property name="allowNonPrintableEscapes" value="true"/> | ||||
</module> | </module> | ||||
<module name="LineLength"> | <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://"/> | <property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/> | ||||
</module> | </module> | ||||
<module name="AvoidStarImport"/> | <module name="AvoidStarImport"/> | ||||
@@ -52,7 +52,7 @@ | |||||
</module> | </module> | ||||
<module name="NeedBraces"/> | <module name="NeedBraces"/> | ||||
<module name="LeftCurly"> | <module name="LeftCurly"> | ||||
<property name="maxLineLength" value="100"/> | |||||
<property name="maxLineLength" value="120"/> | |||||
</module> | </module> | ||||
<module name="RightCurly"> | <module name="RightCurly"> | ||||
<property name="id" value="RightCurlySame"/> | <property name="id" value="RightCurlySame"/> | ||||
@@ -4,13 +4,13 @@ import java.util.HashMap; | |||||
import java.util.Map; | import java.util.Map; | ||||
/** | /** | ||||
* 微信开发所使用到的常量类 | |||||
* 微信开发所使用到的常量类. | |||||
* | * | ||||
* @author chanjarster & binarywang | * @author chanjarster & binarywang | ||||
*/ | */ | ||||
public class WxConsts { | public class WxConsts { | ||||
/** | /** | ||||
* 微信推送过来的消息的类型,和发送给微信xml格式消息的消息类型 | |||||
* 微信推送过来的消息的类型,和发送给微信xml格式消息的消息类型. | |||||
*/ | */ | ||||
public static class XmlMsgType { | public static class XmlMsgType { | ||||
public static final String TEXT = "text"; | public static final String TEXT = "text"; | ||||
@@ -31,24 +31,57 @@ public class WxConsts { | |||||
} | } | ||||
/** | /** | ||||
* 主动发送消息(即客服消息)的消息类型 | |||||
* 主动发送消息(即客服消息)的消息类型. | |||||
*/ | */ | ||||
public static class KefuMsgType { | 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";//图文消息(点击跳转到图文消息页面) | |||||
public static final String FILE = "file";//发送文件(CP专用) | |||||
public static final String TEXTCARD = "textcard";//文本卡片消息(CP专用) | |||||
public static final String WXCARD = "wxcard";//卡券消息 | |||||
/** | |||||
* 文本消息. | |||||
*/ | |||||
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"; | public static final String TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; | ||||
} | } | ||||
/** | /** | ||||
* 表示是否是保密消息,0表示否,1表示是,默认0 | |||||
* 表示是否是保密消息,0表示否,1表示是,默认0. | |||||
*/ | */ | ||||
public static class KefuMsgSafe { | public static class KefuMsgSafe { | ||||
public static final String NO = "0"; | public static final String NO = "0"; | ||||
@@ -56,7 +89,7 @@ public class WxConsts { | |||||
} | } | ||||
/** | /** | ||||
* 群发消息的消息类型 | |||||
* 群发消息的消息类型. | |||||
*/ | */ | ||||
public static class MassMsgType { | public static class MassMsgType { | ||||
public static final String MPNEWS = "mpnews"; | public static final String MPNEWS = "mpnews"; | ||||
@@ -67,7 +100,7 @@ public class WxConsts { | |||||
} | } | ||||
/** | /** | ||||
* 群发消息后微信端推送给服务器的反馈消息 | |||||
* 群发消息后微信端推送给服务器的反馈消息. | |||||
*/ | */ | ||||
public static class MassMsgStatus { | public static class MassMsgStatus { | ||||
public static final String SEND_SUCCESS = "send success"; | public static final String SEND_SUCCESS = "send success"; | ||||
@@ -83,7 +116,7 @@ public class WxConsts { | |||||
public static final String ERR_21000 = "err(21000)"; | public static final String ERR_21000 = "err(21000)"; | ||||
/** | /** | ||||
* 群发反馈消息代码所对应的文字描述 | |||||
* 群发反馈消息代码所对应的文字描述. | |||||
*/ | */ | ||||
public static final Map<String, String> STATUS_DESC = new HashMap<>(); | public static final Map<String, String> STATUS_DESC = new HashMap<>(); | ||||
@@ -103,7 +136,7 @@ public class WxConsts { | |||||
} | } | ||||
/** | /** | ||||
* 微信端推送过来的事件类型 | |||||
* 微信端推送过来的事件类型. | |||||
*/ | */ | ||||
public static class EventType { | public static class EventType { | ||||
public static final String SUBSCRIBE = "subscribe"; | public static final String SUBSCRIBE = "subscribe"; | ||||
@@ -124,7 +157,7 @@ public class WxConsts { | |||||
} | } | ||||
/** | /** | ||||
* 上传多媒体(临时素材)文件的类型 | |||||
* 上传多媒体(临时素材)文件的类型. | |||||
*/ | */ | ||||
public static class MediaFileType { | public static class MediaFileType { | ||||
public static final String IMAGE = "image"; | public static final String IMAGE = "image"; | ||||
@@ -135,78 +168,78 @@ public class WxConsts { | |||||
} | } | ||||
/** | /** | ||||
* 自定义菜单的按钮类型 | |||||
* 自定义菜单的按钮类型. | |||||
*/ | */ | ||||
public static class MenuButtonType { | public static class MenuButtonType { | ||||
/** | /** | ||||
* 点击推事件 | |||||
* 点击推事件. | |||||
*/ | */ | ||||
public static final String CLICK = "click"; | public static final String CLICK = "click"; | ||||
/** | /** | ||||
* 跳转URL | |||||
* 跳转URL. | |||||
*/ | */ | ||||
public static final String VIEW = "view"; | public static final String VIEW = "view"; | ||||
/** | /** | ||||
* 跳转到小程序 | |||||
* 跳转到小程序. | |||||
*/ | */ | ||||
public static final String MINIPROGRAM = "miniprogram"; | public static final String MINIPROGRAM = "miniprogram"; | ||||
/** | /** | ||||
* 扫码推事件 | |||||
* 扫码推事件. | |||||
*/ | */ | ||||
public static final String SCANCODE_PUSH = "scancode_push"; | public static final String SCANCODE_PUSH = "scancode_push"; | ||||
/** | /** | ||||
* 扫码推事件且弹出“消息接收中”提示框 | |||||
* 扫码推事件且弹出“消息接收中”提示框. | |||||
*/ | */ | ||||
public static final String SCANCODE_WAITMSG = "scancode_waitmsg"; | public static final String SCANCODE_WAITMSG = "scancode_waitmsg"; | ||||
/** | /** | ||||
* 弹出系统拍照发图 | |||||
* 弹出系统拍照发图. | |||||
*/ | */ | ||||
public static final String PIC_SYSPHOTO = "pic_sysphoto"; | 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_PHOTO_OR_ALBUM = "pic_photo_or_album"; | ||||
/** | /** | ||||
* 弹出微信相册发图器 | |||||
* 弹出微信相册发图器. | |||||
*/ | */ | ||||
public static final String PIC_WEIXIN = "pic_weixin"; | public static final String PIC_WEIXIN = "pic_weixin"; | ||||
/** | /** | ||||
* 弹出地理位置选择器 | |||||
* 弹出地理位置选择器. | |||||
*/ | */ | ||||
public static final String LOCATION_SELECT = "location_select"; | public static final String LOCATION_SELECT = "location_select"; | ||||
/** | /** | ||||
* 下发消息(除文本消息) | |||||
* 下发消息(除文本消息). | |||||
*/ | */ | ||||
public static final String MEDIA_ID = "media_id"; | public static final String MEDIA_ID = "media_id"; | ||||
/** | /** | ||||
* 跳转图文消息URL | |||||
* 跳转图文消息URL. | |||||
*/ | */ | ||||
public static final String VIEW_LIMITED = "view_limited"; | public static final String VIEW_LIMITED = "view_limited"; | ||||
} | } | ||||
/** | /** | ||||
* oauth2网页授权的scope | |||||
* oauth2网页授权的scope. | |||||
*/ | */ | ||||
public static class OAuth2Scope { | public static class OAuth2Scope { | ||||
/** | /** | ||||
* 不弹出授权页面,直接跳转,只能获取用户openid | |||||
* 不弹出授权页面,直接跳转,只能获取用户openid. | |||||
*/ | */ | ||||
public static final String SNSAPI_BASE = "snsapi_base"; | public static final String SNSAPI_BASE = "snsapi_base"; | ||||
/** | /** | ||||
* 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息 | |||||
* 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息. | |||||
*/ | */ | ||||
public static final String SNSAPI_USERINFO = "snsapi_userinfo"; | public static final String SNSAPI_USERINFO = "snsapi_userinfo"; | ||||
} | } | ||||
/** | /** | ||||
* 网页应用登录授权作用域 | |||||
* 网页应用登录授权作用域. | |||||
*/ | */ | ||||
public static class QrConnectScope { | public static class QrConnectScope { | ||||
public static final String SNSAPI_LOGIN = "snsapi_login"; | public static final String SNSAPI_LOGIN = "snsapi_login"; | ||||
} | } | ||||
/** | /** | ||||
* 永久素材类型 | |||||
* 永久素材类型. | |||||
*/ | */ | ||||
public static class MaterialType { | public static class MaterialType { | ||||
public static final String NEWS = "news"; | public static final String NEWS = "news"; | ||||
@@ -3,7 +3,7 @@ package me.chanjar.weixin.common.api; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
/** | /** | ||||
* WxErrorException处理器 | |||||
* WxErrorException处理器. | |||||
*/ | */ | ||||
public interface WxErrorExceptionHandler { | public interface WxErrorExceptionHandler { | ||||
@@ -2,22 +2,21 @@ package me.chanjar.weixin.common.api; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 消息重复检查器 | |||||
* 消息重复检查器. | |||||
* 微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次 | * 微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次 | ||||
* </pre> | * </pre> | ||||
*/ | */ | ||||
public interface WxMessageDuplicateChecker { | public interface WxMessageDuplicateChecker { | ||||
/** | /** | ||||
* 判断消息是否重复. | |||||
* <h2>公众号的排重方式</h2> | * <h2>公众号的排重方式</h2> | ||||
* <p> | |||||
* | |||||
* <p>普通消息:关于重试的消息排重,推荐使用msgid排重。<a href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html">文档参考</a>。</p> | * <p>普通消息:关于重试的消息排重,推荐使用msgid排重。<a href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html">文档参考</a>。</p> | ||||
* <p>事件消息:关于重试的消息排重,推荐使用FromUserName + CreateTime 排重。<a href="http://mp.weixin.qq.com/wiki/2/5baf56ce4947d35003b86a9805634b1e.html">文档参考</a></p> | * <p>事件消息:关于重试的消息排重,推荐使用FromUserName + CreateTime 排重。<a href="http://mp.weixin.qq.com/wiki/2/5baf56ce4947d35003b86a9805634b1e.html">文档参考</a></p> | ||||
* <p> | |||||
* | |||||
* <h2>企业号的排重方式</h2> | * <h2>企业号的排重方式</h2> | ||||
* <p> | |||||
* 官方文档完全没有写,参照公众号的方式排重。 | |||||
* <p> | |||||
* <p>官方文档完全没有写,参照公众号的方式排重。</p> | |||||
* <p>或者可以采取更简单的方式,如果有MsgId就用MsgId排重,如果没有就用FromUserName+CreateTime排重</p> | * <p>或者可以采取更简单的方式,如果有MsgId就用MsgId排重,如果没有就用FromUserName+CreateTime排重</p> | ||||
* | * | ||||
* @param messageId messageId需要根据上面讲的方式构造 | * @param messageId messageId需要根据上面讲的方式构造 | ||||
@@ -6,46 +6,46 @@ import java.util.concurrent.atomic.AtomicBoolean; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 默认消息重复检查器 | |||||
* 默认消息重复检查器. | |||||
* 将每个消息id保存在内存里,每隔5秒清理已经过期的消息id,每个消息id的过期时间是15秒 | * 将每个消息id保存在内存里,每隔5秒清理已经过期的消息id,每个消息id的过期时间是15秒 | ||||
* </pre> | * </pre> | ||||
*/ | */ | ||||
public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChecker { | public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChecker { | ||||
/** | /** | ||||
* 一个消息ID在内存的过期时间:15秒 | |||||
* 一个消息ID在内存的过期时间:15秒. | |||||
*/ | */ | ||||
private final Long timeToLive; | private final Long timeToLive; | ||||
/** | /** | ||||
* 每隔多少周期检查消息ID是否过期:5秒 | |||||
* 每隔多少周期检查消息ID是否过期:5秒. | |||||
*/ | */ | ||||
private final Long clearPeriod; | private final Long clearPeriod; | ||||
/** | /** | ||||
* 消息id->消息时间戳的map | |||||
* 消息id->消息时间戳的map. | |||||
*/ | */ | ||||
private final ConcurrentHashMap<String, Long> msgId2Timestamp = new ConcurrentHashMap<>(); | private final ConcurrentHashMap<String, Long> msgId2Timestamp = new ConcurrentHashMap<>(); | ||||
/** | /** | ||||
* 后台清理线程是否已经开启 | |||||
* 后台清理线程是否已经开启. | |||||
*/ | */ | ||||
private final AtomicBoolean backgroundProcessStarted = new AtomicBoolean(false); | private final AtomicBoolean backgroundProcessStarted = new AtomicBoolean(false); | ||||
/** | /** | ||||
* WxMsgIdInMemoryDuplicateChecker构造函数 | |||||
* 无参构造方法. | |||||
* <pre> | * <pre> | ||||
* 一个消息ID在内存的过期时间:15秒 | * 一个消息ID在内存的过期时间:15秒 | ||||
* 每隔多少周期检查消息ID是否过期:5秒 | * 每隔多少周期检查消息ID是否过期:5秒 | ||||
* </pre> | * </pre> | ||||
*/ | */ | ||||
public WxMessageInMemoryDuplicateChecker() { | public WxMessageInMemoryDuplicateChecker() { | ||||
this.timeToLive = 15 * 1000l; | |||||
this.clearPeriod = 5 * 1000l; | |||||
this.timeToLive = 15 * 1000L; | |||||
this.clearPeriod = 5 * 1000L; | |||||
} | } | ||||
/** | /** | ||||
* WxMsgIdInMemoryDuplicateChecker构造函数 | |||||
* 构造方法. | |||||
* | * | ||||
* @param timeToLive 一个消息ID在内存的过期时间:毫秒 | * @param timeToLive 一个消息ID在内存的过期时间:毫秒 | ||||
* @param clearPeriod 每隔多少周期检查消息ID是否过期:毫秒 | * @param clearPeriod 每隔多少周期检查消息ID是否过期:毫秒 | ||||
@@ -66,7 +66,8 @@ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChec | |||||
while (true) { | while (true) { | ||||
Thread.sleep(WxMessageInMemoryDuplicateChecker.this.clearPeriod); | Thread.sleep(WxMessageInMemoryDuplicateChecker.this.clearPeriod); | ||||
Long now = System.currentTimeMillis(); | 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) { | if (now - entry.getValue() > WxMessageInMemoryDuplicateChecker.this.timeToLive) { | ||||
WxMessageInMemoryDuplicateChecker.this.msgId2Timestamp.entrySet().remove(entry); | WxMessageInMemoryDuplicateChecker.this.msgId2Timestamp.entrySet().remove(entry); | ||||
} | } | ||||
@@ -11,7 +11,7 @@ import java.util.ArrayList; | |||||
import java.util.List; | import java.util.List; | ||||
/** | /** | ||||
* 菜单(公众号和企业号共用的) | |||||
* 菜单(公众号和企业号共用的). | |||||
* | * | ||||
* @author Daniel Qian | * @author Daniel Qian | ||||
*/ | */ | ||||
@@ -36,7 +36,8 @@ public class WxMenu implements Serializable { | |||||
* 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu | * 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu | ||||
*/ | */ | ||||
public static WxMenu fromJson(InputStream is) { | public static WxMenu fromJson(InputStream is) { | ||||
return WxGsonBuilder.create().fromJson(new InputStreamReader(is, StandardCharsets.UTF_8), WxMenu.class); | |||||
return WxGsonBuilder.create() | |||||
.fromJson(new InputStreamReader(is, StandardCharsets.UTF_8), WxMenu.class); | |||||
} | } | ||||
public List<WxMenuButton> getButtons() { | public List<WxMenuButton> getButtons() { | ||||
@@ -12,7 +12,7 @@ public class WxMenuButton implements Serializable { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 菜单的响应动作类型: | |||||
* 菜单的响应动作类型. | |||||
* view表示网页类型, | * view表示网页类型, | ||||
* click表示点击类型, | * click表示点击类型, | ||||
* miniprogram表示小程序类型 | * miniprogram表示小程序类型 | ||||
@@ -21,13 +21,13 @@ public class WxMenuButton implements Serializable { | |||||
private String type; | private String type; | ||||
/** | /** | ||||
* 菜单标题,不超过16个字节,子菜单不超过60个字节 | |||||
* 菜单标题,不超过16个字节,子菜单不超过60个字节. | |||||
*/ | */ | ||||
private String name; | private String name; | ||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 菜单KEY值,用于消息接口推送,不超过128字节 | |||||
* 菜单KEY值,用于消息接口推送,不超过128字节. | |||||
* click等点击类型必须 | * click等点击类型必须 | ||||
* </pre> | * </pre> | ||||
*/ | */ | ||||
@@ -35,7 +35,8 @@ public class WxMenuButton implements Serializable { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 网页链接,用户点击菜单可打开链接,不超过1024字节。type为miniprogram时,不支持小程序的老版本客户端将打开本url。 | |||||
* 网页链接. | |||||
* 用户点击菜单可打开链接,不超过1024字节。type为miniprogram时,不支持小程序的老版本客户端将打开本url。 | |||||
* view、miniprogram类型必须 | * view、miniprogram类型必须 | ||||
* </pre> | * </pre> | ||||
*/ | */ | ||||
@@ -43,7 +44,7 @@ public class WxMenuButton implements Serializable { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 调用新增永久素材接口返回的合法media_id | |||||
* 调用新增永久素材接口返回的合法media_id. | |||||
* media_id类型和view_limited类型必须 | * media_id类型和view_limited类型必须 | ||||
* </pre> | * </pre> | ||||
*/ | */ | ||||
@@ -52,7 +53,7 @@ public class WxMenuButton implements Serializable { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 小程序的appid | |||||
* 小程序的appid. | |||||
* miniprogram类型必须 | * miniprogram类型必须 | ||||
* </pre> | * </pre> | ||||
*/ | */ | ||||
@@ -61,7 +62,7 @@ public class WxMenuButton implements Serializable { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 小程序的页面路径 | |||||
* 小程序的页面路径. | |||||
* miniprogram类型必须 | * miniprogram类型必须 | ||||
* </pre> | * </pre> | ||||
*/ | */ | ||||
@@ -9,7 +9,7 @@ public class WxMenuRule implements Serializable { | |||||
private static final long serialVersionUID = -4587181819499286670L; | private static final long serialVersionUID = -4587181819499286670L; | ||||
/** | /** | ||||
* 变态的微信接口,反序列化时这里反人类的使用和序列化时不一样的名字 | |||||
* 变态的微信接口,反序列化时这里反人类的使用和序列化时不一样的名字. | |||||
*/ | */ | ||||
@SerializedName(value = "tag_id", alternate = "group_id") | @SerializedName(value = "tag_id", alternate = "group_id") | ||||
private String tagId; | private String tagId; | ||||
@@ -5,7 +5,7 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
import java.io.Serializable; | import java.io.Serializable; | ||||
/** | /** | ||||
* 微信错误码说明,请阅读: <a href="http://mp.weixin.qq.com/wiki/10/6380dc743053a91c544ffd2b7c959166.html">全局返回码说明</a> | |||||
* 微信错误码说明,请阅读: <a href="http://mp.weixin.qq.com/wiki/10/6380dc743053a91c544ffd2b7c959166.html">全局返回码说明</a>. | |||||
* | * | ||||
* @author Daniel Qian | * @author Daniel Qian | ||||
*/ | */ | ||||
@@ -73,6 +73,9 @@ public class WxError implements Serializable { | |||||
return this; | return this; | ||||
} | } | ||||
/** | |||||
* 构造器方法. | |||||
*/ | |||||
public WxError build() { | public WxError build() { | ||||
WxError wxError = new WxError(); | WxError wxError = new WxError(); | ||||
wxError.setErrorCode(this.errorCode); | wxError.setErrorCode(this.errorCode); | ||||
@@ -4,51 +4,41 @@ import org.apache.http.conn.ssl.SSLConnectionSocketFactory; | |||||
import org.apache.http.impl.client.CloseableHttpClient; | import org.apache.http.impl.client.CloseableHttpClient; | ||||
/** | /** | ||||
* httpclient build interface | |||||
* httpclient build interface. | |||||
* | * | ||||
* @author kakotor | * @author kakotor | ||||
*/ | */ | ||||
public interface ApacheHttpClientBuilder { | public interface ApacheHttpClientBuilder { | ||||
/** | /** | ||||
* 构建httpclient实例 | |||||
* 构建httpclient实例. | |||||
* | * | ||||
* @return new instance of CloseableHttpClient | * @return new instance of CloseableHttpClient | ||||
*/ | */ | ||||
CloseableHttpClient build(); | CloseableHttpClient build(); | ||||
/** | /** | ||||
* 代理服务器地址 | |||||
* | |||||
* @param httpProxyHost | |||||
* 代理服务器地址. | |||||
*/ | */ | ||||
ApacheHttpClientBuilder httpProxyHost(String httpProxyHost); | ApacheHttpClientBuilder httpProxyHost(String httpProxyHost); | ||||
/** | /** | ||||
* 代理服务器端口 | |||||
* | |||||
* @param httpProxyPort | |||||
* 代理服务器端口. | |||||
*/ | */ | ||||
ApacheHttpClientBuilder httpProxyPort(int httpProxyPort); | ApacheHttpClientBuilder httpProxyPort(int httpProxyPort); | ||||
/** | /** | ||||
* 代理服务器用户名 | |||||
* | |||||
* @param httpProxyUsername | |||||
* 代理服务器用户名. | |||||
*/ | */ | ||||
ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername); | ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername); | ||||
/** | /** | ||||
* 代理服务器密码 | |||||
* | |||||
* @param httpProxyPassword | |||||
* 代理服务器密码. | |||||
*/ | */ | ||||
ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword); | ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword); | ||||
/** | /** | ||||
* ssl连接socket工厂 | |||||
* | |||||
* @param sslConnectionSocketFactory | |||||
* ssl连接socket工厂. | |||||
*/ | */ | ||||
ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory); | ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory); | ||||
} | } |
@@ -29,9 +29,8 @@ import java.util.concurrent.TimeUnit; | |||||
import java.util.concurrent.atomic.AtomicBoolean; | import java.util.concurrent.atomic.AtomicBoolean; | ||||
/** | /** | ||||
* httpclient 连接管理器 自带DNS解析 | |||||
* <p> | |||||
* 大部分代码拷贝自:DefaultApacheHttpClientBuilder | |||||
* httpclient 连接管理器 自带DNS解析. | |||||
* <p>大部分代码拷贝自:DefaultApacheHttpClientBuilder</p> | |||||
* | * | ||||
* @author Andy.Huo | * @author Andy.Huo | ||||
*/ | */ | ||||
@@ -64,7 +63,7 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||||
private String httpProxyPassword; | private String httpProxyPassword; | ||||
/** | /** | ||||
* 闲置连接监控线程 | |||||
* 闲置连接监控线程. | |||||
*/ | */ | ||||
private IdleConnectionMonitorThread idleConnectionMonitorThread; | private IdleConnectionMonitorThread idleConnectionMonitorThread; | ||||
private HttpClientBuilder httpClientBuilder; | private HttpClientBuilder httpClientBuilder; | ||||
@@ -162,7 +161,7 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||||
} | } | ||||
/** | /** | ||||
* 每路的最大链接数,默认10 | |||||
* 每路的最大链接数,默认10. | |||||
* | * | ||||
* @param maxConnPerHost 每路的最大链接数,默认10 | * @param maxConnPerHost 每路的最大链接数,默认10 | ||||
*/ | */ | ||||
@@ -171,7 +170,7 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||||
} | } | ||||
/** | /** | ||||
* 最大总连接数,默认50 | |||||
* 最大总连接数,默认50. | |||||
* | * | ||||
* @param maxTotalConn 最大总连接数,默认50 | * @param maxTotalConn 最大总连接数,默认50 | ||||
*/ | */ | ||||
@@ -180,7 +179,7 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||||
} | } | ||||
/** | /** | ||||
* 自定义httpclient的User Agent | |||||
* 自定义httpclient的User Agent. | |||||
* | * | ||||
* @param userAgent User Agent | * @param userAgent User Agent | ||||
*/ | */ | ||||
@@ -196,9 +195,12 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||||
if (prepared.get()) { | if (prepared.get()) { | ||||
return; | 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") | @SuppressWarnings("resource") | ||||
PoolingHttpClientConnectionManager connectionManager; | PoolingHttpClientConnectionManager connectionManager; | ||||
@@ -219,8 +221,8 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||||
connectionManager | connectionManager | ||||
.setDefaultSocketConfig(SocketConfig.copy(SocketConfig.DEFAULT).setSoTimeout(this.soTimeout).build()); | .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.setDaemon(true); | ||||
this.idleConnectionMonitorThread.start(); | this.idleConnectionMonitorThread.start(); | ||||
@@ -234,8 +236,8 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||||
if (StringUtils.isNotBlank(this.httpProxyHost) && StringUtils.isNotBlank(this.httpProxyUsername)) { | if (StringUtils.isNotBlank(this.httpProxyHost) && StringUtils.isNotBlank(this.httpProxyUsername)) { | ||||
// 使用代理服务器 需要用户认证的代理服务器 | // 使用代理服务器 需要用户认证的代理服务器 | ||||
CredentialsProvider provider = new BasicCredentialsProvider(); | 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); | this.httpClientBuilder.setDefaultCredentialsProvider(provider); | ||||
} | } | ||||
@@ -267,8 +269,10 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||||
private final int checkWaitTime; | private final int checkWaitTime; | ||||
private volatile boolean shutdown; | private volatile boolean shutdown; | ||||
public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr, int idleConnTimeout, | |||||
int checkWaitTime) { | |||||
/** | |||||
* 构造方法. | |||||
*/ | |||||
public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr, int idleConnTimeout, int checkWaitTime) { | |||||
super("IdleConnectionMonitorThread"); | super("IdleConnectionMonitorThread"); | ||||
this.connMgr = connMgr; | this.connMgr = connMgr; | ||||
this.idleConnTimeout = idleConnTimeout; | this.idleConnTimeout = idleConnTimeout; | ||||
@@ -289,12 +293,18 @@ public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||||
} | } | ||||
} | } | ||||
/** | |||||
* 触发. | |||||
*/ | |||||
public void trigger() { | public void trigger() { | ||||
synchronized (this) { | synchronized (this) { | ||||
notifyAll(); | notifyAll(); | ||||
} | } | ||||
} | } | ||||
/** | |||||
* 关闭. | |||||
*/ | |||||
public void shutdown() { | public void shutdown() { | ||||
this.shutdown = true; | this.shutdown = true; | ||||
synchronized (this) { | synchronized (this) { | ||||
@@ -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.bean.result.WxError; | ||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
import me.chanjar.weixin.common.util.http.HttpResponseProxy; | |||||
import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor; | import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor; | ||||
import me.chanjar.weixin.common.util.http.HttpResponseProxy; | |||||
import me.chanjar.weixin.common.util.http.RequestHttp; | import me.chanjar.weixin.common.util.http.RequestHttp; | ||||
import okhttp3.OkHttpClient; | import okhttp3.OkHttpClient; | ||||
import okhttp3.Request; | import okhttp3.Request; | ||||
@@ -28,7 +28,7 @@ public class XStreamTransformer { | |||||
} | } | ||||
/** | /** | ||||
* 注册扩展消息的解析器 | |||||
* 注册扩展消息的解析器. | |||||
* | * | ||||
* @param clz 类型 | * @param clz 类型 | ||||
* @param xStream xml解析器 | * @param xStream xml解析器 | ||||
@@ -3,7 +3,7 @@ package cn.binarywang.wx.miniapp.bean; | |||||
import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | ||||
/** | /** | ||||
* 微信二维码(小程序码)包装器 | |||||
* 微信二维码(小程序码)包装器. | |||||
* | * | ||||
* @author Element | * @author Element | ||||
*/ | */ | ||||
@@ -15,6 +15,9 @@ public class BaseBuilder<T> { | |||||
return (T) this; | return (T) this; | ||||
} | } | ||||
/** | |||||
* 构造器方法. | |||||
*/ | |||||
public WxMaKefuMessage build() { | public WxMaKefuMessage build() { | ||||
WxMaKefuMessage m = new WxMaKefuMessage(); | WxMaKefuMessage m = new WxMaKefuMessage(); | ||||
m.setMsgType(this.msgType); | m.setMsgType(this.msgType); | ||||
@@ -36,11 +36,9 @@ public class QrCodeRequestExecutor implements RequestExecutor<File, AbstractWxMa | |||||
public File execute(String uri, AbstractWxMaQrcodeWrapper ticket) throws WxErrorException, IOException { | public File execute(String uri, AbstractWxMaQrcodeWrapper ticket) throws WxErrorException, IOException { | ||||
HttpPost httpPost = new HttpPost(uri); | HttpPost httpPost = new HttpPost(uri); | ||||
if (requestHttp.getRequestHttpProxy() != null) { | 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())); | httpPost.setEntity(new StringEntity(ticket.toString())); | ||||
@@ -48,8 +46,8 @@ public class QrCodeRequestExecutor implements RequestExecutor<File, AbstractWxMa | |||||
InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { | InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) { | ||||
Header[] contentTypeHeader = response.getHeaders("Content-Type"); | Header[] contentTypeHeader = response.getHeaders("Content-Type"); | ||||
if (contentTypeHeader != null && contentTypeHeader.length > 0 | if (contentTypeHeader != null && contentTypeHeader.length > 0 | ||||
&& ContentType.APPLICATION_JSON.getMimeType() | |||||
.equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) { | |||||
&& ContentType.APPLICATION_JSON.getMimeType() | |||||
.equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) { | |||||
String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); | String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); | ||||
throw new WxErrorException(WxError.fromJson(responseContent)); | throw new WxErrorException(WxError.fromJson(responseContent)); | ||||
} | } | ||||
@@ -18,7 +18,7 @@ public class XStreamTransformer { | |||||
} | } | ||||
/** | /** | ||||
* xml -> pojo | |||||
* xml -> pojo. | |||||
*/ | */ | ||||
@SuppressWarnings("unchecked") | @SuppressWarnings("unchecked") | ||||
public static <T> T fromXml(Class<T> clazz, String xml) { | 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) { | public static <T> String toXml(Class<T> clazz, T object) { | ||||
return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); | return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); | ||||
} | } | ||||
/** | /** | ||||
* 注册扩展消息的解析器 | |||||
* 注册扩展消息的解析器. | |||||
* | * | ||||
* @param clz 类型 | * @param clz 类型 | ||||
* @param xStream xml解析器 | * @param xStream xml解析器 | ||||
@@ -50,7 +50,7 @@ public class XStreamTransformer { | |||||
} | } | ||||
/** | /** | ||||
* 会自动注册该类及其子类 | |||||
* 会自动注册该类及其子类. | |||||
* | * | ||||
* @param clz 要注册的类 | * @param clz 要注册的类 | ||||
*/ | */ | ||||
@@ -5,6 +5,8 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
import java.io.Serializable; | import java.io.Serializable; | ||||
/** | /** | ||||
* 设备抽象类. | |||||
* | |||||
* @author keungtung | * @author keungtung | ||||
* @date 14/12/2016 | * @date 14/12/2016 | ||||
*/ | */ | ||||
@@ -22,9 +22,13 @@ import java.util.HashMap; | |||||
import java.util.Map; | import java.util.Map; | ||||
/** | /** | ||||
* Created by ecoolper on 2017/5/5. | |||||
* httpclient 实现的素材请求执行器. | |||||
* | |||||
* @author ecoolper | |||||
* @date 2017/5/5 | |||||
*/ | */ | ||||
public class ApacheMaterialNewsInfoRequestExecutor extends MaterialNewsInfoRequestExecutor<CloseableHttpClient, HttpHost> { | |||||
public class ApacheMaterialNewsInfoRequestExecutor | |||||
extends MaterialNewsInfoRequestExecutor<CloseableHttpClient, HttpHost> { | |||||
private final Logger logger = LoggerFactory.getLogger(this.getClass()); | private final Logger logger = LoggerFactory.getLogger(this.getClass()); | ||||
public ApacheMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { | public ApacheMaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { | ||||
@@ -19,16 +19,17 @@ import java.util.TreeMap; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 签名相关工具类 | |||||
* 签名相关工具类. | |||||
* Created by Binary Wang on 2017-3-23. | * Created by Binary Wang on 2017-3-23. | ||||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||||
* </pre> | * </pre> | ||||
* | |||||
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a> | |||||
*/ | */ | ||||
public class SignUtils { | public class SignUtils { | ||||
private static final Logger log = LoggerFactory.getLogger(SignUtils.class); | private static final Logger log = LoggerFactory.getLogger(SignUtils.class); | ||||
/** | /** | ||||
* 请参考并使用 {@link #createSign(Object, String, String, boolean)} | |||||
* 请参考并使用 {@link #createSign(Object, String, String, boolean)}. | |||||
*/ | */ | ||||
@Deprecated | @Deprecated | ||||
public static String createSign(Object xmlBean, String signKey) { | public static String createSign(Object xmlBean, String signKey) { | ||||
@@ -36,7 +37,7 @@ public class SignUtils { | |||||
} | } | ||||
/** | /** | ||||
* 请参考并使用 {@link #createSign(Map, String, String, boolean)} | |||||
* 请参考并使用 {@link #createSign(Map, String, String, boolean)}. | |||||
*/ | */ | ||||
@Deprecated | @Deprecated | ||||
public static String createSign(Map<String, String> params, String signKey) { | public static String createSign(Map<String, String> params, String signKey) { | ||||
@@ -44,7 +45,7 @@ public class SignUtils { | |||||
} | } | ||||
/** | /** | ||||
* 微信支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3) | |||||
* 微信支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3). | |||||
* | * | ||||
* @param xmlBean Bean里的属性如果存在XML注解,则使用其作为key,否则使用变量名 | * @param xmlBean Bean里的属性如果存在XML注解,则使用其作为key,否则使用变量名 | ||||
* @param signType 签名类型,如果为空,则默认为MD5 | * @param signType 签名类型,如果为空,则默认为MD5 | ||||
@@ -57,27 +58,25 @@ public class SignUtils { | |||||
} | } | ||||
/** | /** | ||||
* 微信支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3) | |||||
* 微信支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3). | |||||
* | * | ||||
* @param params 参数信息 | |||||
* @param signType 签名类型,如果为空,则默认为MD5 | |||||
* @param signKey 签名Key | |||||
* @param isIgnoreSignType 签名时,是否忽略signType | |||||
* @param params 参数信息 | |||||
* @param signType 签名类型,如果为空,则默认为MD5 | |||||
* @param signKey 签名Key | |||||
* @param ignoreSignType 签名时,是否忽略signType | |||||
* @return 签名字符串 | * @return 签名字符串 | ||||
*/ | */ | ||||
public static String createSign(Map<String, String> params, String signType, String signKey, boolean isIgnoreSignType) { | |||||
public static String createSign(Map<String, String> params, String signType, String signKey, boolean ignoreSignType) { | |||||
SortedMap<String, String> sortedMap = new TreeMap<>(params); | SortedMap<String, String> sortedMap = new TreeMap<>(params); | ||||
StringBuilder toSign = new StringBuilder(); | StringBuilder toSign = new StringBuilder(); | ||||
for (String key : sortedMap.keySet()) { | for (String key : sortedMap.keySet()) { | ||||
String value = params.get(key); | String value = params.get(key); | ||||
boolean shouldSign = false; | boolean shouldSign = false; | ||||
if (isIgnoreSignType && "sign_type".equals(key)) { | |||||
if (ignoreSignType && "sign_type".equals(key)) { | |||||
shouldSign = false; | shouldSign = false; | ||||
} else if (StringUtils.isNotEmpty(value) | } else if (StringUtils.isNotEmpty(value) | ||||
&& !Lists.newArrayList( | |||||
"sign", "key", "xmlString", "xmlDoc", "couponList").contains(key) | |||||
) { | |||||
&& !Lists.newArrayList("sign", "key", "xmlString", "xmlDoc", "couponList").contains(key)) { | |||||
shouldSign = true; | shouldSign = true; | ||||
} | } | ||||
@@ -88,18 +87,18 @@ public class SignUtils { | |||||
toSign.append("key=").append(signKey); | toSign.append("key=").append(signKey); | ||||
if (SignType.HMAC_SHA256.equals(signType)) { | if (SignType.HMAC_SHA256.equals(signType)) { | ||||
return createHMACSha256Sign(toSign.toString(), signKey); | |||||
return createHmacSha256Sign(toSign.toString(), signKey); | |||||
} else { | } else { | ||||
return DigestUtils.md5Hex(toSign.toString()).toUpperCase(); | return DigestUtils.md5Hex(toSign.toString()).toUpperCase(); | ||||
} | } | ||||
} | } | ||||
private static String createHMACSha256Sign(String message, String key) { | |||||
private static String createHmacSha256Sign(String message, String key) { | |||||
try { | try { | ||||
Mac hmacSHA256 = Mac.getInstance("HmacSHA256"); | |||||
Mac sha256 = Mac.getInstance("HmacSHA256"); | |||||
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "HmacSHA256"); | SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "HmacSHA256"); | ||||
hmacSHA256.init(secretKeySpec); | |||||
byte[] bytes = hmacSHA256.doFinal(message.getBytes()); | |||||
sha256.init(secretKeySpec); | |||||
byte[] bytes = sha256.doFinal(message.getBytes()); | |||||
return Hex.encodeHexString(bytes).toUpperCase(); | return Hex.encodeHexString(bytes).toUpperCase(); | ||||
} catch (NoSuchAlgorithmException | InvalidKeyException e) { | } catch (NoSuchAlgorithmException | InvalidKeyException e) { | ||||
log.error(e.getMessage(), e); | log.error(e.getMessage(), e); | ||||
@@ -109,7 +108,7 @@ public class SignUtils { | |||||
} | } | ||||
/** | /** | ||||
* 校验签名是否正确 | |||||
* 校验签名是否正确. | |||||
* | * | ||||
* @param xmlBean Bean需要标记有XML注解 | * @param xmlBean Bean需要标记有XML注解 | ||||
* @param signType 签名类型,如果为空,则默认为MD5 | * @param signType 签名类型,如果为空,则默认为MD5 | ||||
@@ -121,7 +120,7 @@ public class SignUtils { | |||||
} | } | ||||
/** | /** | ||||
* 校验签名是否正确 | |||||
* 校验签名是否正确. | |||||
* | * | ||||
* @param params 需要校验的参数Map | * @param params 需要校验的参数Map | ||||
* @param signType 签名类型,如果为空,则默认为MD5 | * @param signType 签名类型,如果为空,则默认为MD5 | ||||
@@ -2,6 +2,7 @@ package com.github.binarywang.wxpay.service.impl; | |||||
import com.github.binarywang.utils.qrcode.QrcodeUtils; | import com.github.binarywang.utils.qrcode.QrcodeUtils; | ||||
import com.github.binarywang.wxpay.bean.coupon.*; | import com.github.binarywang.wxpay.bean.coupon.*; | ||||
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; | |||||
import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult; | import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult; | ||||
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; | import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; | ||||
import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult; | import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult; | ||||
@@ -398,9 +399,43 @@ public class WxPayServiceAbstractImplTest { | |||||
this.logger.info(result); | this.logger.info(result); | ||||
} | } | ||||
/** | |||||
* @see {@link com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResultTest} | |||||
* @throws Exception | |||||
*/ | |||||
@Test | @Test | ||||
public void testParseOrderNotifyResult() throws Exception { | public void testParseOrderNotifyResult() throws Exception { | ||||
// 请参考com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResultTest里的单元测试 | |||||
// 请参考com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResultTest 里的单元测试 | |||||
String xmlString = "<xml>\n" + | |||||
" <appid><![CDATA[wx2421b1c4370ec43b]]></appid>\n" + | |||||
" <attach><![CDATA[支付测试]]></attach>\n" + | |||||
" <bank_type><![CDATA[CFT]]></bank_type>\n" + | |||||
" <fee_type><![CDATA[CNY]]></fee_type>\n" + | |||||
" <is_subscribe><![CDATA[Y]]></is_subscribe>\n" + | |||||
" <mch_id><![CDATA[10000100]]></mch_id>\n" + | |||||
" <nonce_str><![CDATA[5d2b6c2a8db53831f7eda20af46e531c]]></nonce_str>\n" + | |||||
" <openid><![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]]></openid>\n" + | |||||
" <out_trade_no><![CDATA[1409811653]]></out_trade_no>\n" + | |||||
" <result_code><![CDATA[SUCCESS]]></result_code>\n" + | |||||
" <return_code><![CDATA[SUCCESS]]></return_code>\n" + | |||||
" <sign><![CDATA[B552ED6B279343CB493C5DD0D78AB241]]></sign>\n" + | |||||
" <sub_mch_id><![CDATA[10000100]]></sub_mch_id>\n" + | |||||
" <time_end><![CDATA[20140903131540]]></time_end>\n" + | |||||
" <total_fee>1</total_fee>\n" + | |||||
" <trade_type><![CDATA[JSAPI]]></trade_type>\n" + | |||||
" <transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id>\n" + | |||||
" <coupon_count>2</coupon_count>\n" + | |||||
" <coupon_type_0><![CDATA[CASH]]></coupon_type_0>\n" + | |||||
" <coupon_id_0>10000</coupon_id_0>\n" + | |||||
" <coupon_fee_0>100</coupon_fee_0>\n" + | |||||
" <coupon_type_1><![CDATA[NO_CASH]]></coupon_type_1>\n" + | |||||
" <coupon_id_1>10001</coupon_id_1>\n" + | |||||
" <coupon_fee_1>200</coupon_fee_1>\n" + | |||||
"</xml>"; | |||||
WxPayOrderNotifyResult result = this.payService.parseOrderNotifyResult(xmlString); | |||||
System.out.println(result); | |||||
} | } | ||||
@Test | @Test | ||||