* Licensed under the Apache License, Version 2.0 (the "License"); */ @@ -12,7 +12,6 @@ import com.jfinal.ext.interceptor.NotAction; import com.jfinal.kit.HttpKit; import com.jfinal.kit.StrKit; import com.jfinal.log.Log; -import com.jfinal.weixin.sdk.api.ApiConfig; import com.jfinal.weixin.sdk.api.ApiConfigKit; import com.jfinal.weixin.sdk.kit.MsgEncryptKit; import com.jfinal.weixin.sdk.msg.InMsgParser; @@ -26,13 +25,11 @@ import com.jfinal.weixin.sdk.msg.out.OutTextMsg; * 接收微信服务器消息,自动解析成 InMsg 并分发到相应的处理方法 */ public abstract class MsgController extends Controller { - - private static final Log log = Log.getLog(MsgController.class); - private String inMsgXml = null; // 本次请求 xml数据 - private InMsg inMsg = null; // 本次请求 xml 解析后的 InMsg 对象 - - public abstract ApiConfig getApiConfig(); - + + private static final Log log = Log.getLog(MsgController.class); + private String inMsgXml = null; // 本次请求 xml数据 + private InMsg inMsg = null; // 本次请求 xml 解析后的 InMsg 对象 + /** * weixin 公众号服务器调用唯一入口,即在开发者中心输入的 URL 必须要指向此 action */ @@ -43,7 +40,7 @@ public abstract class MsgController extends Controller { System.out.println("接收消息:"); System.out.println(getInMsgXml()); } - + // 解析消息并根据消息类型分发到相应的处理方法 InMsg msg = getInMsg(); if (msg instanceof InTextMsg) @@ -107,6 +104,7 @@ public abstract class MsgController extends Controller { /** * 在接收到微信服务器的 InMsg 消息后后响应 OutMsg 消息 + * * @param outMsg 输出对象 */ public void render(OutMsg outMsg) { @@ -117,26 +115,26 @@ public abstract class MsgController extends Controller { System.out.println(outMsgXml); System.out.println("--------------------------------------------------------------------------------\n"); } - + // 是否需要加密消息 if (ApiConfigKit.getApiConfig().isEncryptMessage()) { outMsgXml = MsgEncryptKit.encrypt(outMsgXml, getPara("timestamp"), getPara("nonce")); } - + renderText(outMsgXml, "text/xml"); } - + public void renderOutTextMsg(String content) { - OutTextMsg outMsg= new OutTextMsg(getInMsg()); + OutTextMsg outMsg = new OutTextMsg(getInMsg()); outMsg.setContent(content); render(outMsg); } - + @Before(NotAction.class) public String getInMsgXml() { if (inMsgXml == null) { inMsgXml = HttpKit.readData(getRequest()); - + // 是否需要解密消息 if (ApiConfigKit.getApiConfig().isEncryptMessage()) { inMsgXml = MsgEncryptKit.decrypt(inMsgXml, getPara("timestamp"), getPara("nonce"), getPara("msg_signature")); @@ -147,56 +145,56 @@ public abstract class MsgController extends Controller { } return inMsgXml; } - + @Before(NotAction.class) public InMsg getInMsg() { if (inMsg == null) - inMsg = InMsgParser.parse(getInMsgXml()); + inMsg = InMsgParser.parse(getInMsgXml()); return inMsg; } - + // 处理接收到的文本消息 protected abstract void processInTextMsg(InTextMsg inTextMsg); - + // 处理接收到的图片消息 protected abstract void processInImageMsg(InImageMsg inImageMsg); - + // 处理接收到的语音消息 protected abstract void processInVoiceMsg(InVoiceMsg inVoiceMsg); - + // 处理接收到的视频消息 protected abstract void processInVideoMsg(InVideoMsg inVideoMsg); // 处理接收到的视频消息 protected abstract void processInShortVideoMsg(InShortVideoMsg inShortVideoMsg); - + // 处理接收到的地址位置消息 protected abstract void processInLocationMsg(InLocationMsg inLocationMsg); // 处理接收到的链接消息 protected abstract void processInLinkMsg(InLinkMsg inLinkMsg); - // 处理接收到的多客服管理事件 - protected abstract void processInCustomEvent(InCustomEvent inCustomEvent); + // 处理接收到的多客服管理事件 + protected abstract void processInCustomEvent(InCustomEvent inCustomEvent); // 处理接收到的关注/取消关注事件 protected abstract void processInFollowEvent(InFollowEvent inFollowEvent); - + // 处理接收到的扫描带参数二维码事件 protected abstract void processInQrCodeEvent(InQrCodeEvent inQrCodeEvent); - + // 处理接收到的上报地理位置事件 protected abstract void processInLocationEvent(InLocationEvent inLocationEvent); - // 处理接收到的群发任务结束时通知事件 - protected abstract void processInMassEvent(InMassEvent inMassEvent); + // 处理接收到的群发任务结束时通知事件 + protected abstract void processInMassEvent(InMassEvent inMassEvent); // 处理接收到的自定义菜单事件 protected abstract void processInMenuEvent(InMenuEvent inMenuEvent); - + // 处理接收到的语音识别结果 protected abstract void processInSpeechRecognitionResults(InSpeechRecognitionResults inSpeechRecognitionResults); - + // 处理接收到的模板消息是否送达成功通知事件 protected abstract void processInTemplateMsgEvent(InTemplateMsgEvent inTemplateMsgEvent); @@ -208,7 +206,7 @@ public abstract class MsgController extends Controller { // 资质认证失败 || 名称认证失败 protected abstract void processInVerifyFailEvent(InVerifyFailEvent inVerifyFailEvent); - + // 门店在审核事件消息 protected abstract void processInPoiCheckNotifyEvent(InPoiCheckNotifyEvent inPoiCheckNotifyEvent); @@ -217,17 +215,22 @@ public abstract class MsgController extends Controller { // 微信会员卡二维码扫描领取接口 protected abstract void processInUserViewCardEvent(InUserViewCardEvent inUserViewCardEvent); + // 微信会员卡激活接口 protected abstract void processInSubmitMemberCardEvent(InSubmitMemberCardEvent inSubmitMemberCardEvent); + // 微信会员卡积分变更 protected abstract void processInUpdateMemberCardEvent(InUpdateMemberCardEvent inUpdateMemberCardEvent); + // 微信会员卡快速买单 protected abstract void processInUserPayFromCardEvent(InUserPayFromCardEvent inUserPayFromCardEvent); + // 微信小店订单支付成功接口消息 protected abstract void processInMerChantOrderEvent(InMerChantOrderEvent inMerChantOrderEvent); // 没有找到对应的事件消息 protected abstract void processIsNotDefinedEvent(InNotDefinedEvent inNotDefinedEvent); + // 没有找到对应的消息 protected abstract void processIsNotDefinedMsg(InNotDefinedMsg inNotDefinedMsg); } diff --git a/src/main/java/com/jfinal/weixin/sdk/jfinal/MsgControllerAdapter.java b/src/main/java/com/jfinal/weixin/sdk/jfinal/MsgControllerAdapter.java index 74fdf94b84812652ab8387e6804065ec88a54e2a..d9f75aca9dc2636ca80bf1c28176acbde29732e4 100644 --- a/src/main/java/com/jfinal/weixin/sdk/jfinal/MsgControllerAdapter.java +++ b/src/main/java/com/jfinal/weixin/sdk/jfinal/MsgControllerAdapter.java @@ -1,105 +1,105 @@ -/** - * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.com). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - */ - -package com.jfinal.weixin.sdk.jfinal; - -import com.jfinal.weixin.sdk.msg.in.*; -import com.jfinal.weixin.sdk.msg.in.event.*; -import com.jfinal.weixin.sdk.msg.in.speech_recognition.InSpeechRecognitionResults; - -/** - * MsgControllerAdapter 对 MsgController 部分方法提供了默认实现, - * 以便开发者不去关注 MsgController 中不需要处理的抽象方法,节省代码量 - */ -public abstract class MsgControllerAdapter extends MsgController { - // 关注/取消关注事件 - protected abstract void processInFollowEvent(InFollowEvent inFollowEvent); - - // 接收文本消息事件 - protected abstract void processInTextMsg(InTextMsg inTextMsg); - - // 自定义菜单事件 - protected abstract void processInMenuEvent(InMenuEvent inMenuEvent); - - // 接收图片消息事件 - protected void processInImageMsg(InImageMsg inImageMsg) {} - - // 接收语音消息事件 - protected void processInVoiceMsg(InVoiceMsg inVoiceMsg) {} - - // 接收视频消息事件 - protected void processInVideoMsg(InVideoMsg inVideoMsg) {} - - // 接收地理位置消息事件 - protected void processInLocationMsg(InLocationMsg inLocationMsg) {} - - // 接收链接消息事件 - protected void processInLinkMsg(InLinkMsg inLinkMsg) {} - - // 扫描带参数二维码事件 - protected void processInQrCodeEvent(InQrCodeEvent inQrCodeEvent) {} - - // 上报地理位置事件 - protected void processInLocationEvent(InLocationEvent inLocationEvent) {} - - // 接收语音识别结果,与 InVoiceMsg 唯一的不同是多了一个 Recognition 标记 - protected void processInSpeechRecognitionResults(InSpeechRecognitionResults inSpeechRecognitionResults) {} - - // 在模版消息发送任务完成后事件 - protected void processInTemplateMsgEvent(InTemplateMsgEvent inTemplateMsgEvent) {} - - // 群发完成事件 - protected void processInMassEvent(InMassEvent inMassEvent) {} - - // 接收小视频消息 - protected void processInShortVideoMsg(InShortVideoMsg inShortVideoMsg) {} - - // 接客服入会话事件 - protected void processInCustomEvent(InCustomEvent inCustomEvent) {} - - // 用户进入摇一摇界面,在“周边”页卡下摇一摇时事件 - protected void processInShakearoundUserShakeEvent(InShakearoundUserShakeEvent inShakearoundUserShakeEvent) {} - - // 资质认证事件 - protected void processInVerifySuccessEvent(InVerifySuccessEvent inVerifySuccessEvent) {} - - // 资质认证失败事件 - protected void processInVerifyFailEvent(InVerifyFailEvent inVerifyFailEvent){} - - // 门店在审核通过后下发消息事件 - protected void processInPoiCheckNotifyEvent(InPoiCheckNotifyEvent inPoiCheckNotifyEvent) {} - - // WIFI连网后下发消息 by unas at 2016-1-29 - protected void processInWifiEvent(InWifiEvent inWifiEvent) {} - - // 微信会员卡二维码扫描领取事件 - @Override - protected void processInUserViewCardEvent(InUserViewCardEvent msg) {} - - // 微信会员卡激活事件 - @Override - protected void processInSubmitMemberCardEvent(InSubmitMemberCardEvent msg) {} - - // 微信会员卡积分变更事件 - @Override - protected void processInUpdateMemberCardEvent(InUpdateMemberCardEvent msg) {} - - // 微信会员卡快速买单事件 - @Override - protected void processInUserPayFromCardEvent(InUserPayFromCardEvent msg) {} - - // 微信小店订单支付成功接口事件 - @Override - protected void processInMerChantOrderEvent(InMerChantOrderEvent inMerChantOrderEvent) {} - - // 没有找到对应的事件消息 - @Override - protected void processIsNotDefinedEvent(InNotDefinedEvent inNotDefinedEvent) {} - - // 没有找到对应的消息 - @Override - protected void processIsNotDefinedMsg(InNotDefinedMsg inNotDefinedMsg) {} -} +/** + * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + */ + +package com.jfinal.weixin.sdk.jfinal; + +import com.jfinal.weixin.sdk.msg.in.*; +import com.jfinal.weixin.sdk.msg.in.event.*; +import com.jfinal.weixin.sdk.msg.in.speech_recognition.InSpeechRecognitionResults; + +/** + * MsgControllerAdapter 对 MsgController 部分方法提供了默认实现, + * 以便开发者不去关注 MsgController 中不需要处理的抽象方法,节省代码量 + */ +public abstract class MsgControllerAdapter extends MsgController { + // 关注/取消关注事件 + protected abstract void processInFollowEvent(InFollowEvent inFollowEvent); + + // 接收文本消息事件 + protected abstract void processInTextMsg(InTextMsg inTextMsg); + + // 自定义菜单事件 + protected abstract void processInMenuEvent(InMenuEvent inMenuEvent); + + // 接收图片消息事件 + protected void processInImageMsg(InImageMsg inImageMsg) {} + + // 接收语音消息事件 + protected void processInVoiceMsg(InVoiceMsg inVoiceMsg) {} + + // 接收视频消息事件 + protected void processInVideoMsg(InVideoMsg inVideoMsg) {} + + // 接收地理位置消息事件 + protected void processInLocationMsg(InLocationMsg inLocationMsg) {} + + // 接收链接消息事件 + protected void processInLinkMsg(InLinkMsg inLinkMsg) {} + + // 扫描带参数二维码事件 + protected void processInQrCodeEvent(InQrCodeEvent inQrCodeEvent) {} + + // 上报地理位置事件 + protected void processInLocationEvent(InLocationEvent inLocationEvent) {} + + // 接收语音识别结果,与 InVoiceMsg 唯一的不同是多了一个 Recognition 标记 + protected void processInSpeechRecognitionResults(InSpeechRecognitionResults inSpeechRecognitionResults) {} + + // 在模版消息发送任务完成后事件 + protected void processInTemplateMsgEvent(InTemplateMsgEvent inTemplateMsgEvent) {} + + // 群发完成事件 + protected void processInMassEvent(InMassEvent inMassEvent) {} + + // 接收小视频消息 + protected void processInShortVideoMsg(InShortVideoMsg inShortVideoMsg) {} + + // 接客服入会话事件 + protected void processInCustomEvent(InCustomEvent inCustomEvent) {} + + // 用户进入摇一摇界面,在“周边”页卡下摇一摇时事件 + protected void processInShakearoundUserShakeEvent(InShakearoundUserShakeEvent inShakearoundUserShakeEvent) {} + + // 资质认证事件 + protected void processInVerifySuccessEvent(InVerifySuccessEvent inVerifySuccessEvent) {} + + // 资质认证失败事件 + protected void processInVerifyFailEvent(InVerifyFailEvent inVerifyFailEvent){} + + // 门店在审核通过后下发消息事件 + protected void processInPoiCheckNotifyEvent(InPoiCheckNotifyEvent inPoiCheckNotifyEvent) {} + + // WIFI连网后下发消息 by unas at 2016-1-29 + protected void processInWifiEvent(InWifiEvent inWifiEvent) {} + + // 微信会员卡二维码扫描领取事件 + @Override + protected void processInUserViewCardEvent(InUserViewCardEvent msg) {} + + // 微信会员卡激活事件 + @Override + protected void processInSubmitMemberCardEvent(InSubmitMemberCardEvent msg) {} + + // 微信会员卡积分变更事件 + @Override + protected void processInUpdateMemberCardEvent(InUpdateMemberCardEvent msg) {} + + // 微信会员卡快速买单事件 + @Override + protected void processInUserPayFromCardEvent(InUserPayFromCardEvent msg) {} + + // 微信小店订单支付成功接口事件 + @Override + protected void processInMerChantOrderEvent(InMerChantOrderEvent inMerChantOrderEvent) {} + + // 没有找到对应的事件消息 + @Override + protected void processIsNotDefinedEvent(InNotDefinedEvent inNotDefinedEvent) {} + + // 没有找到对应的消息 + @Override + protected void processIsNotDefinedMsg(InNotDefinedMsg inNotDefinedMsg) {} +} diff --git a/src/main/java/com/jfinal/weixin/sdk/jfinal/MsgInterceptor.java b/src/main/java/com/jfinal/weixin/sdk/jfinal/MsgInterceptor.java index e972fa402ad907d0bb6145f9b04a8c4e35fd9a55..e6731aa835ecbcedfe5ecfc9c45ab0881fd3727e 100644 --- a/src/main/java/com/jfinal/weixin/sdk/jfinal/MsgInterceptor.java +++ b/src/main/java/com/jfinal/weixin/sdk/jfinal/MsgInterceptor.java @@ -1,6 +1,6 @@ /** * Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.com). - * + *
* Licensed under the Apache License, Version 2.0 (the "License"); */ @@ -20,27 +20,33 @@ import com.jfinal.weixin.sdk.kit.SignatureCheckKit; * 2:响应开发者中心服务器配置 URL 与 Token 请求 * 3:签名检测 * 注意: MsgController 的继承类如果覆盖了 index 方法,则需要对该 index 方法声明该拦截器 - * 因为子类覆盖父类方法会使父类方法配置的拦截器失效,从而失去本拦截器的功能 + * 因为子类覆盖父类方法会使父类方法配置的拦截器失效,从而失去本拦截器的功能 */ public class MsgInterceptor implements Interceptor { - - private static final Log log = Log.getLog(MsgInterceptor.class); - + private static final Log log = Log.getLog(MsgInterceptor.class); + + private static AppIdParser _parser = new AppIdParser.DefaultParameterAppIdParser(); + + public static void setAppIdParser(AppIdParser parser) { + _parser = parser; + } + public void intercept(Invocation inv) { Controller controller = inv.getController(); - if (controller instanceof MsgController == false) + if (!(controller instanceof MsgController)) throw new RuntimeException("控制器需要继承 MsgController"); - + try { - // 将 ApiConfig 对象与当前线程绑定,以便在后续操作中方便获取该对象: ApiConfigKit.getApiConfig(); - ApiConfigKit.setThreadLocalApiConfig(((MsgController)controller).getApiConfig()); - + String appId = _parser.getAppId(controller); + // 将 appId 与当前线程绑定,以便在后续操作中方便获取ApiConfig对象: ApiConfigKit.getApiConfig(); + ApiConfigKit.setThreadLocalAppId(appId); + // 如果是服务器配置请求,则配置服务器并返回 if (isConfigServerRequest(controller)) { configServer(controller); - return ; + return; } - + // 对开发测试更加友好 if (ApiConfigKit.isDevMode()) { inv.invoke(); @@ -48,18 +54,16 @@ public class MsgInterceptor implements Interceptor { // 签名检测 if (checkSignature(controller)) { inv.invoke(); - } - else { + } else { controller.renderText("签名验证失败,请确定是微信服务器在发送消息过来"); } } - - } - finally { - ApiConfigKit.removeThreadLocalApiConfig(); + + } finally { + ApiConfigKit.removeThreadLocalAppId(); } } - + /** * 检测签名 */ @@ -71,29 +75,29 @@ public class MsgInterceptor implements Interceptor { controller.renderText("check signature failure"); return false; } - + if (SignatureCheckKit.me.checkSignature(signature, timestamp, nonce)) { return true; - } - else { + } else { log.error("check signature failure: " + " signature = " + controller.getPara("signature") + " timestamp = " + controller.getPara("timestamp") + " nonce = " + controller.getPara("nonce")); - + return false; } } - + /** * 是否为开发者中心保存服务器配置的请求 */ private boolean isConfigServerRequest(Controller controller) { return StrKit.notBlank(controller.getPara("echostr")); } - + /** * 配置开发者中心微信服务器所需的 url 与 token + * * @param c 控制器 */ public void configServer(Controller c) { diff --git a/src/test/java/com/jfinal/weixin/sdk/api/AccessTokenApiTest.java b/src/test/java/com/jfinal/weixin/sdk/api/AccessTokenApiTest.java index 5c620e6f439dd308512c236d8cbfea025280cc28..179d45796b8196cc820bd047ab68d37a78a56c2d 100644 --- a/src/test/java/com/jfinal/weixin/sdk/api/AccessTokenApiTest.java +++ b/src/test/java/com/jfinal/weixin/sdk/api/AccessTokenApiTest.java @@ -12,12 +12,13 @@ public class AccessTokenApiTest { public static String AppID = "wx9803d1188fa5fbda"; public static String AppSecret = "db859c968763c582794e7c3d003c3d87"; - + public static void init(){ ApiConfig ac = new ApiConfig(); ac.setAppId(AppID); ac.setAppSecret(AppSecret); - ApiConfigKit.setThreadLocalApiConfig(ac); + ApiConfigKit.putApiConfig(ac); + ApiConfigKit.setThreadLocalAppId(ac.getAppId()); } public static void main(String[] args) throws IOException { @@ -37,13 +38,13 @@ public class AccessTokenApiTest { System.out.println("access_token : " + at.getAccessToken()); else System.out.println(at.getErrorCode() + " : " + at.getErrorMsg()); - + at = AccessTokenApi.getAccessToken(); if (at.isAvailable()) System.out.println("access_token : " + at.getAccessToken()); else System.out.println(at.getErrorCode() + " : " + at.getErrorMsg()); - + at = AccessTokenApi.getAccessToken(); if (at.isAvailable()) System.out.println("access_token : " + at.getAccessToken());