├── README.md
├── pom.xml
├── robot-demo
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── org
│ │ └── mvnsearch
│ │ └── wx
│ │ └── web
│ │ └── controllers
│ │ └── PortalController.java
│ ├── resources
│ ├── appContext-robot.xml
│ ├── struts.properties
│ ├── struts.xml
│ └── struts2packages
│ │ └── portal-package.xml
│ └── webapp
│ ├── WEB-INF
│ ├── pages
│ │ ├── weixin.jspx
│ │ └── welcome.jsp
│ ├── web.xml
│ └── weixin-router.xml
│ └── index.action
└── robot-sdk
├── pom.xml
└── src
├── main
└── java
│ └── org
│ └── mvnsearch
│ └── wx
│ ├── WeixinMessage.java
│ ├── WeixinUtils.java
│ ├── rewrite
│ ├── Conf.java
│ ├── NormalRewrittenUrl.java
│ ├── NormalRule.java
│ ├── RewrittenUrl.java
│ ├── Rule.java
│ ├── RuleChain.java
│ └── UrlRewriter.java
│ └── servlet
│ ├── WeixinMessageContext.java
│ └── WexinRobotServlet.java
└── test
├── java
└── org
│ └── mvnsearch
│ └── wx
│ ├── ConfTest.java
│ └── WeixinMessageTest.java
└── resources
├── weixin-robot-flow.puml
└── weixin-router.xml
/README.md:
--------------------------------------------------------------------------------
1 | Weixin robot Java
2 | ========================================
3 | 微信公共平台自动回复机器人的Java SDK,你可以使用SDK简单快速构建微信机器人。
4 | 微信Robot Java借鉴了url rewrite的思想,url rewrite是根据url进行路由,而微信Robot则是根据消息类型和内容进行路由。
5 | 整理的流程如下:
6 |
7 | * WexinRobotServlet负责认证和微信消息接收
8 | * 接收后进行XML解析,构建出 WeixinMessage对象,并注入到request的attribute中,名字为wxMsg
9 | * 根据配置的路由参数,对微信消息进行匹配
10 | * 根据匹配的结果进行URL路由转发
11 | * 最后由处理的组件完成xml格式反馈的输出
12 |
13 |
14 | ### 如何使用
15 | 首先我们要在pom.xml中添加:
16 |
17 |
18 | org.mvnsearch.wx
19 | wx-robot-sdk
20 | 1.0.0
21 |
22 |
23 | 接下来就是修改web.xml添加Servlet负责接收微信公共平台发过来的消息:
24 |
25 |
26 | WexinRobotServlet
27 | org.mvnsearch.wx.servlet.WexinRobotServlet
28 |
29 | token
30 | yourTokenHere
31 |
32 |
33 | confFile
34 | /WEB-INF/weixin-router.xml
35 |
36 |
37 |
38 |
39 |
40 | WexinRobotServlet
41 | /servlet/weixinrobot
42 |
43 |
44 | 其中token是指你在微信公共平台上的token,这里和其一致。接下来我们还需要设置servlet mapping,添加url-pattern,
45 | 然后将最终的url,如上述配置的 http://www.foobar.com/servlet/weixinrobot 作为微信公共平台接口配置中的URL。
46 | 接下来是在WEB-INF目录下创建一个weixin-router.xml的文件,完成信息的路由。
47 |
48 | 接收到的消息如何路由到指定的组件处理,如Struts的Controller等,这里我们需要创建一个router文件,这里还是根据
49 | 消息的类型和内容进行转发,内容如下:
50 |
51 |
52 |
53 |
54 |
55 |
56 | text
57 | [\d]{11}
58 | /weixin2.wx
59 |
60 |
61 |
62 | text
63 | /weixin.wx
64 |
65 |
66 |
67 |
68 | 上述的例子就是如果内容是手机号,交与/weixin2.wx这个URL处理。当然我们设置了一个默认的选项,如果text类型的消息没有任何
69 | 匹配,则由/weixin.wx处理。
70 |
71 | 收到微信消息后,要给出消息反馈。微信公共平台的消息反馈是一个xml格式的数据,在Java的系统中,我们使用jspx输出接口,样例如下:
72 |
73 |
74 |
75 | ${wxMsg.sender}
76 | ${wxMsg.receiver}
77 | ${wxMsg.createdTime}
78 | text
79 | ${content}
80 | 0
81 |
82 |
83 | ### 编码
84 |
85 | * 在代码中获取解析好的微信消息 WeixinMessage wxMsg = (WeixinMessage)request.getAttribute("wxMsg");
86 |
87 | ### FAQ
88 |
89 | * 如何调试: 由于微信服务器只能通知互联网IP和80端口,开发时你可以在你家中的ADSL拨号路由器上设置一下80转发,
90 | 然后微信服务器的消息通知就可以路由到你的笔记本上,方便你测试和开发。查看你的互联网Ip请访问 http://ip.mvnsearch.org
91 | * 参考样例清访问robot-demo Maven module
92 |
93 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | org.mvnsearch.wx
6 | weixin-robot
7 | pom
8 | 1.0.0-SNAPSHOT
9 |
10 | robot-sdk
11 | robot-demo
12 |
13 | Weixin Robot Java Project
14 |
15 | 微信公共平台自动回复机器人Java SDK
16 |
17 | 2013
18 |
19 | MvnSearch
20 | http://www.mvnsearch.org
21 |
22 |
23 | UTF-8
24 |
25 |
26 |
27 | linux_china
28 | Jacky Chan
29 | libing.chen@gmail.com
30 | http://weibo.com/linux2china
31 |
32 | 开发人员
33 |
34 |
35 |
36 |
37 | scm:git@github.com:linux-china/weixin-robot-java.git
38 | scm:git@github.com:linux-china/weixin-robot-java.git
39 | https://github.com/linux-china/weixin-robot-java
40 |
41 |
42 |
43 |
44 | junit
45 | junit
46 | 3.8.2
47 | test
48 |
49 |
50 |
--------------------------------------------------------------------------------
/robot-demo/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | weixin-robot
7 | org.mvnsearch.wx
8 | 1.0.0-SNAPSHOT
9 |
10 | robot-demo
11 | 1.0.0-SNAPSHOT
12 | war
13 | robot demo Maven Webapp
14 |
15 | 2.3.15.1
16 | 3.2.2.RELEASE
17 |
18 |
19 |
20 | org.mvnsearch.wx
21 | wx-robot-sdk
22 | 1.0.0-SNAPSHOT
23 |
24 |
25 |
26 | javax.servlet
27 | servlet-api
28 | 3.0-alpha-1
29 | provided
30 |
31 |
32 | javax.servlet.jsp
33 | jsp-api
34 | 2.2
35 | provided
36 |
37 |
38 |
39 | org.springframework
40 | spring-beans
41 | ${spring.version}
42 |
43 |
44 | org.springframework
45 | spring-core
46 | ${spring.version}
47 |
48 |
49 | org.springframework
50 | spring-context
51 | ${spring.version}
52 |
53 |
54 | org.springframework
55 | spring-context-support
56 | ${spring.version}
57 |
58 |
59 | org.springframework
60 | spring-aspects
61 | ${spring.version}
62 |
63 |
64 | org.springframework
65 | spring-web
66 | ${spring.version}
67 |
68 |
69 | org.springframework
70 | spring-aop
71 | ${spring.version}
72 |
73 |
74 |
75 | org.apache.struts
76 | struts2-core
77 | ${struts2.version}
78 |
79 |
80 | org.apache.struts
81 | struts2-spring-plugin
82 | ${struts2.version}
83 |
84 |
85 | org.springframework
86 | spring-beans
87 |
88 |
89 | org.springframework
90 | spring-context
91 |
92 |
93 | org.springframework
94 | spring-core
95 |
96 |
97 | org.springframework
98 | spring-web
99 |
100 |
101 |
102 |
103 | junit
104 | junit
105 | 3.8.1
106 | test
107 |
108 |
109 |
110 | robot-demo
111 |
112 |
113 |
--------------------------------------------------------------------------------
/robot-demo/src/main/java/org/mvnsearch/wx/web/controllers/PortalController.java:
--------------------------------------------------------------------------------
1 | package org.mvnsearch.wx.web.controllers;
2 |
3 | import com.opensymphony.xwork2.ActionSupport;
4 | import org.apache.struts2.interceptor.ServletRequestAware;
5 | import org.mvnsearch.wx.WeixinMessage;
6 |
7 | import javax.servlet.http.HttpServletRequest;
8 | import java.util.Date;
9 |
10 | /**
11 | * portal controller
12 | *
13 | * @author linux_china
14 | */
15 | public class PortalController extends ActionSupport implements ServletRequestAware {
16 | /**
17 | * http servlet request
18 | */
19 | HttpServletRequest request;
20 |
21 | /**
22 | * inject http servlet request
23 | *
24 | * @param httpServletRequest http servlet request
25 | */
26 | public void setServletRequest(HttpServletRequest httpServletRequest) {
27 | this.request = httpServletRequest;
28 | }
29 |
30 | /**
31 | * project front page
32 | *
33 | * @return welcome page
34 | */
35 | public String index() {
36 | return "index";
37 | }
38 |
39 | /**
40 | * 显示微信消息
41 | *
42 | * @return weixing response
43 | */
44 | public String weixin() {
45 | WeixinMessage wxMsg = (WeixinMessage) request.getAttribute("wxMsg");
46 | if (wxMsg == null) {
47 | wxMsg = new WeixinMessage();
48 | wxMsg.setSender("jacky");
49 | wxMsg.setReceiver("leijuan");
50 | wxMsg.setContent("txt");
51 | wxMsg.setCreatedTime(new Date());
52 | request.setAttribute("wxMsg", wxMsg);
53 | }
54 | request.setAttribute("content", "echo:" + wxMsg.getContent());
55 | return "weixin";
56 | }
57 |
58 | /**
59 | * 显示微信消息2
60 | *
61 | * @return weixing response
62 | */
63 | public String weixin2() {
64 | request.setAttribute("content", "weixin2");
65 | return "weixin";
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/robot-demo/src/main/resources/appContext-robot.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
--------------------------------------------------------------------------------
/robot-demo/src/main/resources/struts.properties:
--------------------------------------------------------------------------------
1 | struts.i18n.reload = true
2 | struts.devMode = true
3 | struts.configuration.xml.reload = true
4 | struts.url.http.port = 80
5 | struts.serve.static = true
6 | struts.serve.static.browserCache = false
7 | struts.objectFactory = spring
8 | struts.objectFactory.spring.autoWire = name
9 | struts.objectFactory.spring.useClassCache = true
10 | struts.locale = zh_CN
11 | struts.i18n.encoding = UTF-8
12 | struts.ui.theme = xhtml
13 | struts.enable.DynamicMethodInvocation = true
14 | struts.custom.i18n.resources = global
15 | struts.action.extension = action,do,jsn,wx
16 | struts.multipart.maxSize = 5242880
--------------------------------------------------------------------------------
/robot-demo/src/main/resources/struts.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/robot-demo/src/main/resources/struts2packages/portal-package.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | /WEB-INF/pages/welcome.jsp
11 | /WEB-INF/pages/weixin.jspx
12 |
13 |
14 |
--------------------------------------------------------------------------------
/robot-demo/src/main/webapp/WEB-INF/pages/weixin.jspx:
--------------------------------------------------------------------------------
1 |
2 |
3 | ${wxMsg.sender}
4 | ${wxMsg.receiver}
5 | ${wxMsg.createdTime}
6 | text
7 | ${content}
8 | 0
9 |
10 |
--------------------------------------------------------------------------------
/robot-demo/src/main/webapp/WEB-INF/pages/welcome.jsp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Weixin Robot
6 |
7 |
8 | Weixin Robot Demo
9 |
10 |
11 |
--------------------------------------------------------------------------------
/robot-demo/src/main/webapp/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 | Weixin Robot Demo
9 |
10 |
11 | contextConfigLocation
12 |
13 | classpath:/appContext-robot.xml
14 |
15 |
16 |
17 |
18 |
19 | org.springframework.web.context.ContextLoaderListener
20 |
21 |
22 |
23 | WexinRobotServlet
24 | org.mvnsearch.wx.servlet.WexinRobotServlet
25 |
26 | token
27 | nananjingdu
28 |
29 |
30 | confFile
31 | /WEB-INF/weixin-router.xml
32 |
33 |
34 |
35 |
36 |
37 | WexinRobotServlet
38 | /servlet/weixinrobot
39 |
40 |
41 |
42 | struts
43 | org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
44 |
45 |
46 |
47 | struts
48 | *.action
49 | REQUEST
50 | FORWARD
51 |
52 |
53 | struts
54 | *.wx
55 | REQUEST
56 | FORWARD
57 |
58 |
59 | index.action
60 |
61 |
62 |
63 |
64 | *.jsp
65 | UTF-8
66 | true
67 |
68 |
69 | *.jspx
70 | UTF-8
71 | true
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/robot-demo/src/main/webapp/WEB-INF/weixin-router.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | text
7 | [\d]{11}
8 | /weixin2.wx
9 |
10 |
11 |
12 | text
13 | /weixin.wx
14 |
15 |
16 |
--------------------------------------------------------------------------------
/robot-demo/src/main/webapp/index.action:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/linux-china/weixin-robot-java/985b1f68c3b21fb2ae3607aac2554dd6380848d0/robot-demo/src/main/webapp/index.action
--------------------------------------------------------------------------------
/robot-sdk/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.mvnsearch.wx
7 | wx-robot-sdk
8 | 1.0.0-SNAPSHOT
9 |
10 | Weixin Robot Java SDK
11 |
12 |
13 | UTF-8
14 |
15 |
16 |
17 | linux_china
18 | Jacky Chan
19 | libing.chen@gmail.com
20 | http://weibo.com/linux2china
21 |
22 | 开发人员
23 |
24 |
25 |
26 |
27 | scm:git@github.com:linux-china/weixin-robot-java.git
28 | scm:git@github.com:linux-china/weixin-robot-java.git
29 | https://github.com/linux-china/weixin-robot-java
30 |
31 |
32 |
33 |
34 | javax.servlet
35 | servlet-api
36 | 2.5
37 | provided
38 |
39 |
40 | org.jdom
41 | jdom
42 | 1.1.3
43 |
44 |
45 | commons-codec
46 | commons-codec
47 | 1.7
48 |
49 |
50 | com.intellij
51 | annotations
52 | 12.0
53 |
54 |
55 | junit
56 | junit
57 | 3.8.1
58 | test
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/robot-sdk/src/main/java/org/mvnsearch/wx/WeixinMessage.java:
--------------------------------------------------------------------------------
1 | package org.mvnsearch.wx;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 |
5 | import java.util.Date;
6 |
7 | /**
8 | * weixin message
9 | *
10 | * @author linux_china
11 | */
12 | public class WeixinMessage {
13 | /**
14 | * text message
15 | */
16 | public static final String type_text = "text";
17 | /**
18 | * image message
19 | */
20 | public static final String type_image = "image";
21 | /**
22 | * location message
23 | */
24 | public static final String type_location = "location";
25 | /**
26 | * link message
27 | */
28 | public static final String type_link = "link";
29 | /**
30 | * news message
31 | */
32 | public static final String type_news = "news";
33 | /**
34 | * music message
35 | */
36 | public static final String type_music = "music";
37 |
38 | /**
39 | * subscribe message
40 | */
41 | public static final String type_subscribe = "subscribe";
42 | /**
43 | * unsubscribe message
44 | */
45 | public static final String type_unsubscribe = "unsubscribe";
46 | /**
47 | * click message
48 | */
49 | public static final String type_click = "click";
50 | /**
51 | * message id
52 | */
53 | private String id;
54 | /**
55 | * sender,微信号
56 | */
57 | private String sender;
58 | /**
59 | * receiver,微信号
60 | */
61 | private String receiver;
62 | /**
63 | * created timestamp
64 | */
65 | private Date createdTime;
66 | /**
67 | * type: text, image, location, link
68 | */
69 | private String type;
70 | /**
71 | * content, such as text, image url, link etc
72 | */
73 | private String content;
74 |
75 | public String getId() {
76 | return id;
77 | }
78 |
79 | public void setId(String id) {
80 | this.id = id;
81 | }
82 |
83 | public String getSender() {
84 | return sender;
85 | }
86 |
87 | public void setSender(String sender) {
88 | this.sender = sender;
89 | }
90 |
91 | public String getReceiver() {
92 | return receiver;
93 | }
94 |
95 | public void setReceiver(String receiver) {
96 | this.receiver = receiver;
97 | }
98 |
99 | public Date getCreatedTime() {
100 | return createdTime;
101 | }
102 |
103 | public void setCreatedTime(Date createdTime) {
104 | this.createdTime = createdTime;
105 | }
106 |
107 | public Long getCreatedSeconds() {
108 | return this.createdTime.getTime() / 1000;
109 | }
110 |
111 | public String getType() {
112 | return type;
113 | }
114 |
115 | public void setType(String type) {
116 | this.type = type;
117 | }
118 |
119 | public String getContent() {
120 | return content;
121 | }
122 |
123 | public void setContent(String content) {
124 | this.content = content;
125 | }
126 |
127 | /**
128 | * fill message
129 | *
130 | * @param type type
131 | * @param content content
132 | */
133 | public void fill(String type, String content) {
134 | this.type = type;
135 | this.content = content;
136 | }
137 |
138 | /**
139 | * get reply message
140 | *
141 | * @return reply message
142 | */
143 | @NotNull
144 | public WeixinMessage getReply() {
145 | WeixinMessage reply = new WeixinMessage();
146 | reply.setReceiver(this.sender);
147 | reply.setSender(this.receiver);
148 | reply.setCreatedTime(new Date());
149 | return reply;
150 | }
151 |
152 | /**
153 | * get response xml
154 | *
155 | * @param type type
156 | * @param content content
157 | * @return response xml
158 | */
159 | public String getResponseXml(String type, String content) {
160 | String template = "\n" +
161 | " \n" +
162 | " \n" +
163 | " %s\n" +
164 | " \n" +
165 | " \n" +
166 | " 0\n" +
167 | "";
168 | return String.format(template, sender, receiver, String.valueOf(System.currentTimeMillis() / 1000), type, content);
169 | }
170 |
171 | }
172 |
--------------------------------------------------------------------------------
/robot-sdk/src/main/java/org/mvnsearch/wx/WeixinUtils.java:
--------------------------------------------------------------------------------
1 | package org.mvnsearch.wx;
2 |
3 | import org.jdom.Document;
4 | import org.jdom.Element;
5 | import org.jdom.input.SAXBuilder;
6 |
7 | import java.io.InputStream;
8 | import java.io.StringReader;
9 | import java.util.Date;
10 |
11 | /**
12 | * weixin utils
13 | *
14 | * @author linux_china
15 | */
16 | public class WeixinUtils {
17 |
18 | /**
19 | * parse xml to get weixin message
20 | *
21 | * @param xmlText xml text
22 | * @return weixin message
23 | * @throws Exception exception
24 | */
25 | public static WeixinMessage parseXML(String xmlText) throws Exception {
26 | SAXBuilder saxBuilder = new SAXBuilder();
27 | Document document = saxBuilder.build(new StringReader(xmlText));
28 | return constructMsg(document);
29 | }
30 |
31 | /**
32 | * parse xml to get weixin message
33 | *
34 | * @param inputStream xml text
35 | * @return weixin message
36 | * @throws Exception exception
37 | */
38 | public static WeixinMessage parseXML(InputStream inputStream) throws Exception {
39 | SAXBuilder saxBuilder = new SAXBuilder();
40 | Document document = saxBuilder.build(inputStream);
41 | return constructMsg(document);
42 | }
43 |
44 | /**
45 | * construct weixin message from xml document
46 | *
47 | * @param document xml document
48 | * @return weixin message
49 | */
50 | private static WeixinMessage constructMsg(Document document) {
51 | Element rootElement = document.getRootElement();
52 | WeixinMessage msg = new WeixinMessage();
53 | msg.setId(rootElement.getChildTextTrim("MsgId"));
54 | msg.setReceiver(rootElement.getChildTextTrim("ToUserName"));
55 | msg.setSender(rootElement.getChildTextTrim("FromUserName"));
56 | msg.setType(rootElement.getChildTextTrim("MsgType"));
57 | msg.setContent(rootElement.getChildTextTrim("Content"));
58 | String createTime = rootElement.getChildTextTrim("CreateTime");
59 | if (createTime != null) {
60 | msg.setCreatedTime(new Date(Long.valueOf(createTime) * 1000));
61 | }
62 | //event message
63 | if ("event".equals(msg.getType())) {
64 | String event = rootElement.getChildText("EventKey");
65 | String eventKey = rootElement.getChildText("EventKey");
66 | msg.setType(event);
67 | msg.setContent(eventKey);
68 | }
69 | return msg;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/robot-sdk/src/main/java/org/mvnsearch/wx/rewrite/Conf.java:
--------------------------------------------------------------------------------
1 | package org.mvnsearch.wx.rewrite;
2 |
3 | import org.jdom.Document;
4 | import org.jdom.Element;
5 | import org.jdom.input.SAXBuilder;
6 |
7 | import javax.servlet.ServletContext;
8 | import java.io.InputStream;
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | /**
13 | * weixin robot configuration
14 | *
15 | * @author linux_china
16 | */
17 | public class Conf {
18 | /**
19 | * rules
20 | */
21 | private List rules = new ArrayList();
22 |
23 | /**
24 | * construct method
25 | *
26 | * @param path path
27 | * @throws Exception exception
28 | */
29 | @SuppressWarnings("unchecked")
30 | public Conf(ServletContext servletContext, String path) throws Exception {
31 | InputStream inputStream;
32 | if (path.startsWith("classpath:")) {
33 | inputStream = this.getClass().getResourceAsStream(path.replace("classpath:", "/"));
34 | } else {
35 | inputStream = servletContext.getResourceAsStream(path);
36 | }
37 | SAXBuilder saxBuilder = new SAXBuilder();
38 | Document document = saxBuilder.build(inputStream);
39 | List ruleElements = document.getRootElement().getChildren("rule");
40 | for (Element ruleElement : ruleElements) {
41 | rules.add(new NormalRule(ruleElement.getChildTextTrim("type"), ruleElement.getChildTextTrim("content"), (ruleElement.getChildTextTrim("forward"))));
42 | }
43 | }
44 |
45 | /**
46 | * get forward rules
47 | *
48 | * @return rules
49 | */
50 | public List getRules() {
51 | return rules;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/robot-sdk/src/main/java/org/mvnsearch/wx/rewrite/NormalRewrittenUrl.java:
--------------------------------------------------------------------------------
1 | package org.mvnsearch.wx.rewrite;
2 |
3 | import javax.servlet.ServletException;
4 | import javax.servlet.http.HttpServletRequest;
5 | import javax.servlet.http.HttpServletResponse;
6 | import java.io.IOException;
7 |
8 | /**
9 | * normal rewrite url
10 | *
11 | * @author linux_china
12 | */
13 | public class NormalRewrittenUrl implements RewrittenUrl {
14 | /**
15 | * target forward url
16 | */
17 | private String target;
18 |
19 | /**
20 | * construct method
21 | *
22 | * @param target target url
23 | */
24 | public NormalRewrittenUrl(String target) {
25 | this.target = target;
26 | }
27 |
28 | /**
29 | * get target url
30 | *
31 | * @return target url
32 | */
33 | public String getTarget() {
34 | return this.target;
35 | }
36 |
37 | /**
38 | * execute rewrite
39 | *
40 | * @param request http servlet request
41 | * @param response http servlet response
42 | * @return rewrite mark
43 | * @throws ServletException servlet exception
44 | * @throws IOException IO exception
45 | */
46 | public boolean doRewrite(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
47 | request.getRequestDispatcher(getTarget()).forward(request, response);
48 | return true;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/robot-sdk/src/main/java/org/mvnsearch/wx/rewrite/NormalRule.java:
--------------------------------------------------------------------------------
1 | package org.mvnsearch.wx.rewrite;
2 |
3 | import org.jetbrains.annotations.Nullable;
4 | import org.mvnsearch.wx.WeixinMessage;
5 |
6 | import javax.servlet.ServletException;
7 | import javax.servlet.http.HttpServletRequest;
8 | import javax.servlet.http.HttpServletResponse;
9 | import java.io.IOException;
10 | import java.util.regex.Pattern;
11 |
12 | /**
13 | * normal rule
14 | *
15 | * @author linux_china
16 | */
17 | public class NormalRule implements Rule {
18 | /**
19 | * type
20 | */
21 | private String type;
22 | /**
23 | * content
24 | */
25 | private String content;
26 | /**
27 | * regex pattern
28 | */
29 | private Pattern regexPattern;
30 | /**
31 | * forward
32 | */
33 | private String forward;
34 |
35 | /**
36 | * construct method
37 | *
38 | * @param type type
39 | * @param content content
40 | * @param forward forward
41 | */
42 | public NormalRule(String type, String content, String forward) {
43 | this.type = type;
44 | this.content = content;
45 | if (content != null && !content.isEmpty()) {
46 | this.regexPattern = Pattern.compile(content);
47 | }
48 | this.forward = forward;
49 | }
50 |
51 | /**
52 | * match weixin message?
53 | *
54 | * @param wxMsg weixin message
55 | * @param request http servlet request
56 | * @param response http servlet response
57 | * @return rewritten url
58 | * @throws IOException io exception
59 | * @throws ServletException servlet exception
60 | */
61 | @Nullable
62 | public RewrittenUrl matches(WeixinMessage wxMsg, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
63 | boolean matched = false;
64 | if (type.equals(wxMsg.getType())) {
65 | matched = regexPattern == null || regexPattern.matcher(wxMsg.getContent()).find();
66 | }
67 | return matched ? new NormalRewrittenUrl(forward) : null;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/robot-sdk/src/main/java/org/mvnsearch/wx/rewrite/RewrittenUrl.java:
--------------------------------------------------------------------------------
1 | package org.mvnsearch.wx.rewrite;
2 |
3 | import javax.servlet.ServletException;
4 | import javax.servlet.http.HttpServletRequest;
5 | import javax.servlet.http.HttpServletResponse;
6 | import java.io.IOException;
7 |
8 | /**
9 | * rewritten url
10 | *
11 | * @author linux_china
12 | */
13 | public interface RewrittenUrl {
14 | /**
15 | * get target url
16 | *
17 | * @return target url
18 | */
19 | public String getTarget();
20 |
21 | /**
22 | * execute rewrite
23 | *
24 | * @param request http servlet request
25 | * @param response http servlet response
26 | * @return rewrite mark
27 | * @throws ServletException servlet exception
28 | * @throws IOException IO exception
29 | */
30 | public boolean doRewrite(HttpServletRequest request,
31 | HttpServletResponse response)
32 | throws ServletException, IOException;
33 | }
34 |
--------------------------------------------------------------------------------
/robot-sdk/src/main/java/org/mvnsearch/wx/rewrite/Rule.java:
--------------------------------------------------------------------------------
1 | package org.mvnsearch.wx.rewrite;
2 |
3 | import org.jetbrains.annotations.Nullable;
4 | import org.mvnsearch.wx.WeixinMessage;
5 |
6 | import javax.servlet.ServletException;
7 | import javax.servlet.http.HttpServletRequest;
8 | import javax.servlet.http.HttpServletResponse;
9 | import java.io.IOException;
10 | import java.lang.reflect.InvocationTargetException;
11 |
12 | /**
13 | * rewrite rule
14 | *
15 | * @author linux_china
16 | */
17 | public interface Rule {
18 | /**
19 | * match weixin message?
20 | *
21 | * @param wxMsg weixin message
22 | * @param request http servlet request
23 | * @param response http servlet response
24 | * @return rewritten url
25 | * @throws IOException io exception
26 | * @throws ServletException servlet exception
27 | */
28 | @Nullable
29 | public RewrittenUrl matches(WeixinMessage wxMsg,
30 | final HttpServletRequest request,
31 | final HttpServletResponse response)
32 | throws IOException, ServletException;
33 | }
34 |
--------------------------------------------------------------------------------
/robot-sdk/src/main/java/org/mvnsearch/wx/rewrite/RuleChain.java:
--------------------------------------------------------------------------------
1 | package org.mvnsearch.wx.rewrite;
2 |
3 | import org.mvnsearch.wx.WeixinMessage;
4 |
5 | import javax.servlet.ServletException;
6 | import javax.servlet.http.HttpServletRequest;
7 | import javax.servlet.http.HttpServletResponse;
8 | import java.io.IOException;
9 | import java.lang.reflect.InvocationTargetException;
10 | import java.util.List;
11 |
12 | /**
13 | * rule chain
14 | *
15 | * @author linux_china
16 | */
17 | public class RuleChain {
18 | /**
19 | * rules
20 | */
21 | private List rules;
22 | /**
23 | * target
24 | */
25 | private RewrittenUrl rewrittenUrl;
26 |
27 | /**
28 | * rule chain construct
29 | *
30 | * @param rules rules
31 | */
32 | public RuleChain(List rules) {
33 | this.rules = rules;
34 | }
35 |
36 | /**
37 | * process weixin message
38 | *
39 | * @param wxMsg weixin message
40 | * @param request http servlet request
41 | * @param response response
42 | * @throws IOException IO Exception
43 | * @throws ServletException servlet exception
44 | * @throws InvocationTargetException invocation target exception
45 | */
46 | public void process(WeixinMessage wxMsg, HttpServletRequest request, HttpServletResponse response)
47 | throws IOException, ServletException, InvocationTargetException {
48 | doRules(wxMsg, request, response);
49 | }
50 |
51 | /**
52 | * iterated match in rules
53 | *
54 | * @param wxMsg weixin message
55 | * @param request http servlet request
56 | * @param response http servlet response
57 | * @throws IOException IO Exception
58 | * @throws ServletException servlet exception
59 | */
60 | public void doRules(WeixinMessage wxMsg, HttpServletRequest request, HttpServletResponse response)
61 | throws IOException, ServletException {
62 | for (Rule rule : rules) {
63 | RewrittenUrl rewrittenUrl = rule.matches(wxMsg, request, response);
64 | if (rewrittenUrl != null) {
65 | this.rewrittenUrl = rewrittenUrl;
66 | return;
67 | }
68 | }
69 | }
70 |
71 | /**
72 | * get final rewritten request
73 | *
74 | * @return rewritten url
75 | */
76 | public RewrittenUrl getFinalRewrittenRequest() {
77 | return this.rewrittenUrl;
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/robot-sdk/src/main/java/org/mvnsearch/wx/rewrite/UrlRewriter.java:
--------------------------------------------------------------------------------
1 | package org.mvnsearch.wx.rewrite;
2 |
3 | import org.mvnsearch.wx.WeixinMessage;
4 |
5 | import javax.servlet.ServletException;
6 | import javax.servlet.http.HttpServletRequest;
7 | import javax.servlet.http.HttpServletResponse;
8 | import java.io.IOException;
9 | import java.lang.reflect.InvocationTargetException;
10 |
11 | /**
12 | * url rewriter
13 | *
14 | * @author linux_china
15 | */
16 | public class UrlRewriter {
17 | /**
18 | * rewriter configuration
19 | */
20 | private Conf conf;
21 |
22 | /**
23 | * construct method
24 | *
25 | * @param conf rewriter configuration
26 | */
27 | public UrlRewriter(Conf conf) {
28 | this.conf = conf;
29 | }
30 |
31 |
32 | /**
33 | * Helpful for testing but otherwise, don't use.
34 | */
35 | public RewrittenUrl processRequest(WeixinMessage wxMsg,
36 | final HttpServletRequest request,
37 | final HttpServletResponse response)
38 | throws IOException, ServletException, InvocationTargetException {
39 | RuleChain chain = getNewChain(request);
40 | chain.process(wxMsg, request, response);
41 | return chain.getFinalRewrittenRequest();
42 | }
43 |
44 | /**
45 | * get new rule chain
46 | *
47 | * @param request http servlet request
48 | * @return rule chain
49 | */
50 | private RuleChain getNewChain(final HttpServletRequest request) {
51 | return new RuleChain(conf.getRules());
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/robot-sdk/src/main/java/org/mvnsearch/wx/servlet/WeixinMessageContext.java:
--------------------------------------------------------------------------------
1 | package org.mvnsearch.wx.servlet;
2 |
3 | import org.mvnsearch.wx.WeixinMessage;
4 |
5 | import java.util.Collections;
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | /**
10 | * weixin message context
11 | *
12 | * @author linux_china
13 | */
14 | @SuppressWarnings("unchecked")
15 | public class WeixinMessageContext {
16 | /**
17 | * empty map
18 | */
19 | private static Map emptyMap = Collections.emptyMap();
20 | /**
21 | * thread local variable
22 | */
23 | private final static ThreadLocal