xml config support & multi-step command matcher

This commit is contained in:
Sola
2015-11-26 03:54:13 +08:00
parent ad0c75c12a
commit c2b2f89805
12 changed files with 221 additions and 111 deletions

View File

@@ -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();
}

View File

@@ -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<Integer, ResponseCode> 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;
}
}
}

View File

@@ -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; }
}

View File

@@ -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> T fromXml(Class<T> clazz, InputStream is) {
XStream xstream = XStreamInitializer.getInstance();
xstream.alias("wechat-config", clazz);
xstream.processAnnotations(clazz);
return (T) xstream.fromXML(is);
}
}

View File

@@ -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<Integer, ResponseCode> 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;
}
}

View File

@@ -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<Integer, Command> 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;
}
}

View File

@@ -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);
}
}

View File

@@ -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<String, Class<? extends WxMpMessageHandler>> handlers = new HashMap<>();
static {
handlers.put("Register", RegisterHandler.class);
}
public void init(WxMpMessageRouter router) {
}
}

View File

@@ -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<String, User> pre_confirm = new HashMap<>();
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> 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();
}
}

View File

@@ -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<String, Long> {
private class ValueLoader extends CacheLoader<String, Long> {
@Override
public Long load(String key) throws Exception {
return System.currentTimeMillis(); //TODO: CONFIGURATION
return System.currentTimeMillis() + Settings.I.Check_Spam_Interval;
}
}
private static LoadingCache<String, Long> cache = CacheBuilder.newBuilder()
private LoadingCache<String, Long> 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<String, Object> 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;
}
}

View File

@@ -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<String, Command> 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());
}
}
}

View File

@@ -0,0 +1,6 @@
<wechat-config>
<appId>****</appId>
<secret>****</secret>
<token>****</token>
<aesKey>****</aesKey>
</wechat-config>