From c2b2f89805111b1cd4310bfe61af70d3285884f9 Mon Sep 17 00:00:00 2001 From: Sola Date: Thu, 26 Nov 2015 03:54:13 +0800 Subject: [PATCH] xml config support & multi-step command matcher --- .../love/sola/netsupport/api/GetUser.java | 13 +++-- .../love/sola/netsupport/api/Response.java | 44 +++++++++++++++- .../love/sola/netsupport/config/Settings.java | 11 ++-- .../config/WxMpXmlInMemoryConfigStorage.java | 23 +++++++++ .../sola/netsupport/enums/ResponseCode.java | 47 ----------------- .../love/sola/netsupport/wechat/Command.java | 51 +++++++++++++++++++ .../sola/netsupport/wechat/WxMpServlet.java | 30 +++++++---- .../wechat/handler/HandlerList.java | 28 ---------- .../wechat/handler/RegisterHandler.java | 26 +++++++--- .../intercepter/CheckSpamInterceptor.java | 17 ++++--- .../wechat/matcher/CommandMatcher.java | 36 +++++++++++++ src/main/resources/wechat-config.xml | 6 +++ 12 files changed, 221 insertions(+), 111 deletions(-) create mode 100644 src/main/java/love/sola/netsupport/config/WxMpXmlInMemoryConfigStorage.java delete mode 100644 src/main/java/love/sola/netsupport/enums/ResponseCode.java create mode 100644 src/main/java/love/sola/netsupport/wechat/Command.java delete mode 100644 src/main/java/love/sola/netsupport/wechat/handler/HandlerList.java create mode 100644 src/main/java/love/sola/netsupport/wechat/matcher/CommandMatcher.java create mode 100644 src/main/resources/wechat-config.xml diff --git a/src/main/java/love/sola/netsupport/api/GetUser.java b/src/main/java/love/sola/netsupport/api/GetUser.java index b79ef06..decab07 100644 --- a/src/main/java/love/sola/netsupport/api/GetUser.java +++ b/src/main/java/love/sola/netsupport/api/GetUser.java @@ -1,7 +1,6 @@ package love.sola.netsupport.api; import com.google.gson.Gson; -import love.sola.netsupport.enums.ResponseCode; import love.sola.netsupport.pojo.User; import love.sola.netsupport.sql.TableUser; @@ -43,23 +42,23 @@ public class GetUser extends HttpServlet { String id = request.getParameter("id"); String name = request.getParameter("name"); if ((id == null || id.isEmpty()) && (name == null || name.isEmpty())) { - out.println(gson.toJson(new Response(ResponseCode.PARAMETER_REQUIRED))); + out.println(gson.toJson(new Response(Response.ResponseCode.PARAMETER_REQUIRED))); } else if (id != null) { try { User u = TableUser.getUserById(Integer.parseInt(id)); if (u == null) - out.println(gson.toJson(new Response(ResponseCode.USER_NOT_FOUND))); + out.println(gson.toJson(new Response(Response.ResponseCode.USER_NOT_FOUND))); else - out.println(gson.toJson(new Response(ResponseCode.OK, u))); + out.println(gson.toJson(new Response(Response.ResponseCode.OK, u))); } catch (NumberFormatException e) { - out.println(gson.toJson(new Response(ResponseCode.ILLEGAL_PARAMETER))); + out.println(gson.toJson(new Response(Response.ResponseCode.ILLEGAL_PARAMETER))); } } else { User u = TableUser.getUserByName(name); if (u == null) - out.println(gson.toJson(new Response(ResponseCode.USER_NOT_FOUND))); + out.println(gson.toJson(new Response(Response.ResponseCode.USER_NOT_FOUND))); else - out.println(gson.toJson(new Response(ResponseCode.OK, u))); + out.println(gson.toJson(new Response(Response.ResponseCode.OK, u))); } out.close(); } diff --git a/src/main/java/love/sola/netsupport/api/Response.java b/src/main/java/love/sola/netsupport/api/Response.java index 958fde1..49eaad0 100644 --- a/src/main/java/love/sola/netsupport/api/Response.java +++ b/src/main/java/love/sola/netsupport/api/Response.java @@ -1,7 +1,9 @@ package love.sola.netsupport.api; import lombok.AllArgsConstructor; -import love.sola.netsupport.enums.ResponseCode; + +import java.util.HashMap; +import java.util.Map; /** * *********************************************** @@ -26,4 +28,42 @@ public class Response { this.result = result; } -} + + public enum ResponseCode { + + OK(0, "OK"), + PARAMETER_REQUIRED(-1, "Parameter Required"), + ILLEGAL_PARAMETER(-2, "Illegal parameter"), + USER_NOT_FOUND(-11, "User not found"), + ; + + private static final Map ID_MAP = new HashMap<>(); + + static { + for (ResponseCode type : values()) { + if (type.id > 0) { + ID_MAP.put(type.id, type); + } + } + } + + public final String info; + public final int id; + + ResponseCode(int id, String info) { + this.info = info; + this.id = id; + } + + public static ResponseCode fromId(int id) { + return ID_MAP.get(id); + } + + @Override + public String toString() { + return info; + } + + } + +} \ No newline at end of file diff --git a/src/main/java/love/sola/netsupport/config/Settings.java b/src/main/java/love/sola/netsupport/config/Settings.java index 068d678..22c5179 100644 --- a/src/main/java/love/sola/netsupport/config/Settings.java +++ b/src/main/java/love/sola/netsupport/config/Settings.java @@ -1,6 +1,7 @@ package love.sola.netsupport.config; import lombok.ToString; +import love.sola.netsupport.sql.TableConfig; /** * *********************************************** @@ -13,6 +14,10 @@ public class Settings { public static Settings I; + static { + I = TableConfig.getSettings(); + } + // -------------------------------------------- // // CONFIGURATIONS // -------------------------------------------- // @@ -21,10 +26,10 @@ public class Settings { public String Wechat_Token; public String Wechat_AesKey; + public int Check_Spam_Cache_Expire_Time; + public int Check_Spam_Interval; //No arg constructor for Yaml.loadAs - public Settings() { - I = this; - } + public Settings() { I = this; } } diff --git a/src/main/java/love/sola/netsupport/config/WxMpXmlInMemoryConfigStorage.java b/src/main/java/love/sola/netsupport/config/WxMpXmlInMemoryConfigStorage.java new file mode 100644 index 0000000..4594c86 --- /dev/null +++ b/src/main/java/love/sola/netsupport/config/WxMpXmlInMemoryConfigStorage.java @@ -0,0 +1,23 @@ +package love.sola.netsupport.config; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import lombok.ToString; +import me.chanjar.weixin.common.util.xml.XStreamInitializer; +import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; + +import java.io.InputStream; + +@XStreamAlias("wechat-config") +@ToString +public class WxMpXmlInMemoryConfigStorage extends WxMpInMemoryConfigStorage { + + @SuppressWarnings("unchecked") + public static T fromXml(Class clazz, InputStream is) { + XStream xstream = XStreamInitializer.getInstance(); + xstream.alias("wechat-config", clazz); + xstream.processAnnotations(clazz); + return (T) xstream.fromXML(is); + } + +} diff --git a/src/main/java/love/sola/netsupport/enums/ResponseCode.java b/src/main/java/love/sola/netsupport/enums/ResponseCode.java deleted file mode 100644 index fa69530..0000000 --- a/src/main/java/love/sola/netsupport/enums/ResponseCode.java +++ /dev/null @@ -1,47 +0,0 @@ -package love.sola.netsupport.enums; - -import java.util.HashMap; -import java.util.Map; - -/** - * *********************************************** - * Created by Sola on 2015/11/6. - * Don't modify this source without my agreement - * *********************************************** - */ -public enum ResponseCode { - - OK(0, "OK"), - PARAMETER_REQUIRED(-1, "Parameter Required"), - ILLEGAL_PARAMETER(-2, "Illegal parameter"), - USER_NOT_FOUND(-11, "User not found"), - ; - - private static final Map ID_MAP = new HashMap<>(); - - static { - for (ResponseCode type : values()) { - if (type.id > 0) { - ID_MAP.put(type.id, type); - } - } - } - - public final String info; - public final int id; - - ResponseCode(int id, String info) { - this.info = info; - this.id = id; - } - - public static ResponseCode fromId(int id) { - return ID_MAP.get(id); - } - - @Override - public String toString() { - return info; - } - -} diff --git a/src/main/java/love/sola/netsupport/wechat/Command.java b/src/main/java/love/sola/netsupport/wechat/Command.java new file mode 100644 index 0000000..548776b --- /dev/null +++ b/src/main/java/love/sola/netsupport/wechat/Command.java @@ -0,0 +1,51 @@ +package love.sola.netsupport.wechat; + +import lombok.Getter; + +import java.util.HashMap; +import java.util.Map; + +/** + * *********************************************** + * Created by Sola on 2015/11/26. + * Don't modify this source without my agreement + * *********************************************** + */ +public enum Command { + + REGISTER(0, "Register", "(?i)^Register$"), + ; + + private static final Map ID_MAP = new HashMap<>(); + + static { + for (Command type : values()) { + if (type.id > 0) { + ID_MAP.put(type.id, type); + } + } + } + + @Getter + private final String name; + @Getter + private final String regex; + @Getter + private final int id; + + Command(int id, String name, String regex) { + this.name = name; + this.id = id; + this.regex = regex; + } + + public static Command fromId(int id) { + return ID_MAP.get(id); + } + + @Override + public String toString() { + return name; + } + +} diff --git a/src/main/java/love/sola/netsupport/wechat/WxMpServlet.java b/src/main/java/love/sola/netsupport/wechat/WxMpServlet.java index e3b08e4..7bb4aa9 100644 --- a/src/main/java/love/sola/netsupport/wechat/WxMpServlet.java +++ b/src/main/java/love/sola/netsupport/wechat/WxMpServlet.java @@ -1,11 +1,11 @@ package love.sola.netsupport.wechat; import love.sola.netsupport.config.Settings; +import love.sola.netsupport.wechat.handler.RegisterHandler; +import love.sola.netsupport.wechat.intercepter.CheckSpamInterceptor; +import love.sola.netsupport.wechat.matcher.CommandMatcher; import me.chanjar.weixin.common.util.StringUtils; -import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; -import me.chanjar.weixin.mp.api.WxMpMessageRouter; -import me.chanjar.weixin.mp.api.WxMpService; -import me.chanjar.weixin.mp.api.WxMpServiceImpl; +import me.chanjar.weixin.mp.api.*; import me.chanjar.weixin.mp.bean.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; @@ -29,6 +29,7 @@ public class WxMpServlet extends HttpServlet { protected WxMpInMemoryConfigStorage config; protected WxMpService wxMpService; protected WxMpMessageRouter wxMpMessageRouter; + protected CheckSpamInterceptor checkSpamInterceptor; public WxMpServlet() { instance = this; @@ -46,7 +47,15 @@ public class WxMpServlet extends HttpServlet { wxMpService = new WxMpServiceImpl(); wxMpService.setWxMpConfigStorage(config); + + checkSpamInterceptor = new CheckSpamInterceptor(); wxMpMessageRouter = new WxMpMessageRouter(wxMpService); + wxMpMessageRouter.rule() + .async(false) + .matcher(new CommandMatcher(Command.REGISTER)) + .handler(new RegisterHandler()) + .interceptor(checkSpamInterceptor) + .end(); } @Override @@ -75,12 +84,12 @@ public class WxMpServlet extends HttpServlet { String encryptType = StringUtils.isBlank(request.getParameter("encrypt_type")) ? "raw" : request.getParameter("encrypt_type"); - if ("raw".equals(encryptType)) { - WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(request.getInputStream()); - WxMpXmlOutMessage outMessage = wxMpMessageRouter.route(inMessage); - response.getWriter().write(outMessage.toXml()); - return; - } +// if ("raw".equals(encryptType)) { +// WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(request.getInputStream()); +// WxMpXmlOutMessage outMessage = wxMpMessageRouter.route(inMessage); +// response.getWriter().write(outMessage.toXml()); +// return; +// } if ("aes".equals(encryptType)) { String msgSignature = request.getParameter("msg_signature"); @@ -98,4 +107,5 @@ public class WxMpServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } + } diff --git a/src/main/java/love/sola/netsupport/wechat/handler/HandlerList.java b/src/main/java/love/sola/netsupport/wechat/handler/HandlerList.java deleted file mode 100644 index feae960..0000000 --- a/src/main/java/love/sola/netsupport/wechat/handler/HandlerList.java +++ /dev/null @@ -1,28 +0,0 @@ -package love.sola.netsupport.wechat.handler; - -import me.chanjar.weixin.mp.api.WxMpMessageHandler; -import me.chanjar.weixin.mp.api.WxMpMessageRouter; - -import java.util.HashMap; -import java.util.Map; - -/** - * *********************************************** - * Created by Sola on 2015/11/5. - * Don't modify this source without my agreement - * *********************************************** - */ -public class HandlerList { - - public static Map> handlers = new HashMap<>(); - - static { - handlers.put("Register", RegisterHandler.class); - } - - public void init(WxMpMessageRouter router) { - - } - - -} diff --git a/src/main/java/love/sola/netsupport/wechat/handler/RegisterHandler.java b/src/main/java/love/sola/netsupport/wechat/handler/RegisterHandler.java index 41155a6..8b36aea 100644 --- a/src/main/java/love/sola/netsupport/wechat/handler/RegisterHandler.java +++ b/src/main/java/love/sola/netsupport/wechat/handler/RegisterHandler.java @@ -1,13 +1,17 @@ package love.sola.netsupport.wechat.handler; +import love.sola.netsupport.pojo.User; +import love.sola.netsupport.wechat.Command; +import love.sola.netsupport.wechat.matcher.CommandMatcher; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.mp.api.WxMpMessageHandler; -import me.chanjar.weixin.mp.api.WxMpMessageRouter; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.outxmlbuilder.TextBuilder; +import java.util.HashMap; import java.util.Map; /** @@ -18,16 +22,24 @@ import java.util.Map; */ public class RegisterHandler implements WxMpMessageHandler { - - public RegisterHandler(WxMpMessageRouter router) { - router.rule().async(false).rContent("^").handler(this).end(); - } + Map pre_confirm = new HashMap<>(); @Override public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService, WxSessionManager sessionManager) throws WxErrorException { - - return null; + TextBuilder out = WxMpXmlOutMessage.TEXT().fromUser(wxMessage.getToUserName()).toUser(wxMessage.getFromUserName()); + String in = wxMessage.getContent(); + String userName = wxMessage.getFromUserName(); + if (in.matches(Command.REGISTER.getRegex())) { + out.content("Welcome, please type your student identification number."); + } else if (pre_confirm.containsKey(userName)) { + //TODO + + } else { + out.content("Illegal Operation."); + CommandMatcher.inCmdUsers.remove(userName); + } + return out.build(); } } diff --git a/src/main/java/love/sola/netsupport/wechat/intercepter/CheckSpamInterceptor.java b/src/main/java/love/sola/netsupport/wechat/intercepter/CheckSpamInterceptor.java index 83a457e..d53b50b 100644 --- a/src/main/java/love/sola/netsupport/wechat/intercepter/CheckSpamInterceptor.java +++ b/src/main/java/love/sola/netsupport/wechat/intercepter/CheckSpamInterceptor.java @@ -3,6 +3,7 @@ package love.sola.netsupport.wechat.intercepter; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import love.sola.netsupport.config.Settings; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.mp.api.WxMpMessageInterceptor; @@ -20,26 +21,28 @@ import java.util.concurrent.TimeUnit; */ public class CheckSpamInterceptor implements WxMpMessageInterceptor { - private static class ValueLoader extends CacheLoader { + private class ValueLoader extends CacheLoader { @Override public Long load(String key) throws Exception { - return System.currentTimeMillis(); //TODO: CONFIGURATION + return System.currentTimeMillis() + Settings.I.Check_Spam_Interval; } } - private static LoadingCache cache = CacheBuilder.newBuilder() + private LoadingCache cache = CacheBuilder.newBuilder() .concurrencyLevel(4) .weakKeys() .maximumSize(4096) - .expireAfterWrite(5, TimeUnit.SECONDS) + .expireAfterWrite(Settings.I.Check_Spam_Cache_Expire_Time, TimeUnit.SECONDS) .build(new ValueLoader()); @Override public boolean intercept(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService, WxSessionManager sessionManager) throws WxErrorException { - if (cache.getIfPresent(wxMessage.getFromUserName()) != null) { - + Long l = cache.getIfPresent(wxMessage.getFromUserName()); + if (l != null && l > System.currentTimeMillis()) { + return false; } - return false; + cache.refresh(wxMessage.getFromUserName()); + return true; } } diff --git a/src/main/java/love/sola/netsupport/wechat/matcher/CommandMatcher.java b/src/main/java/love/sola/netsupport/wechat/matcher/CommandMatcher.java new file mode 100644 index 0000000..2b3b78f --- /dev/null +++ b/src/main/java/love/sola/netsupport/wechat/matcher/CommandMatcher.java @@ -0,0 +1,36 @@ +package love.sola.netsupport.wechat.matcher; + +import love.sola.netsupport.wechat.Command; +import me.chanjar.weixin.mp.api.WxMpMessageMatcher; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * *********************************************** + * Created by Sola on 2015/11/26. + * Don't modify this source without my agreement + * *********************************************** + */ +public class CommandMatcher implements WxMpMessageMatcher { + + public static Map inCmdUsers = new ConcurrentHashMap<>(); + + Command command; + + public CommandMatcher(Command command) { + this.command = command; + } + + @Override + public boolean match(WxMpXmlMessage message) { + String fromUser = message.getFromUserName(); + if (inCmdUsers.containsKey(fromUser)) { + return command == inCmdUsers.get(fromUser); + } else { + return message.getContent().matches(command.getRegex()); + } + } + +} diff --git a/src/main/resources/wechat-config.xml b/src/main/resources/wechat-config.xml new file mode 100644 index 0000000..78b8f7c --- /dev/null +++ b/src/main/resources/wechat-config.xml @@ -0,0 +1,6 @@ + + **** + **** + **** + **** + \ No newline at end of file