mirror of
				https://github.com/ZSCNetSupportDept/WechatTicketSystem.git
				synced 2025-10-31 10:26:19 +08:00 
			
		
		
		
	xml config support & multi-step command matcher
This commit is contained in:
		| @@ -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(); | ||||
| 	} | ||||
|   | ||||
| @@ -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; | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -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; } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -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; | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										51
									
								
								src/main/java/love/sola/netsupport/wechat/Command.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/main/java/love/sola/netsupport/wechat/Command.java
									
									
									
									
									
										Normal 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; | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -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); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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) { | ||||
|  | ||||
| 	} | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -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(); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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()); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Sola
					Sola