动手写web框架(7): 请求转发器

类似于Spring MVC中的DispatcherServlet,所以我们也需要编写一个Servlet,让它处理所有的请求。

  1. HttpServletRequest对象中获取请求方法和请求路径;
  2. 通过ControllerHelper获取Request对应的Handler,Handler包括Controller的类以及处理方法Method;
  3. HttpServletRequest对象中获取所有参数,封装到一个Param对象中;
  4. 通过反射调用Controller实例中对应的Method方法,并获取返回值;
  5. 如果返回值是View类型,则返回一个Jsp页面;如果是Data类型,则返回一个JSON数据。
DispatcherServlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package org.smart4j.framework;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.smart4j.framework.bean.Data;
import org.smart4j.framework.bean.Handler;
import org.smart4j.framework.bean.Param;
import org.smart4j.framework.bean.View;
import org.smart4j.framework.helper.BeanHelper;
import org.smart4j.framework.helper.ConfigHelper;
import org.smart4j.framework.helper.ControllerHelper;
import org.smart4j.framework.util.CodecUtil;
import org.smart4j.framework.util.JsonUtil;
import org.smart4j.framework.util.ReflectionUtil;
import org.smart4j.framework.util.StreamUtil;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Roger on 2016/11/23.
*/
@WebServlet(urlPatterns = "/*", loadOnStartup = 0)
public class DispatcherServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
// 初始化Helper类
HelperLoader.init();
ServletContext servletContext = config.getServletContext();
// 注册处理jsp的servlet
// 传入一个"jsp"参数, 意味着从容器中获取JspServlet(这个Servlet由容器实现, The JSP page compiler and execution servlet)
ServletRegistration jspServlet = servletContext.getServletRegistration("jsp");
jspServlet.addMapping(ConfigHelper.getAppJspPath() + "*");
// 注册处理静态资源的默认servlet
// 传入一个"default"参数, 意味着从容器中获取DefaultServlet(这个Servlet由容器实现, 它负责处理普通的静态资源响应)
ServletRegistration defaultServlet = servletContext.getServletRegistration("default");
defaultServlet.addMapping(ConfigHelper.getAppAssetPath() + "*");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求方法与请求路径
String requestMethod = req.getMethod().toLowerCase();
String requestPath = req.getPathInfo();
// 获取Action处理器
Handler handler = ControllerHelper.getHandler(requestMethod, requestPath);
if (handler != null) {
// 获取Controller类及其实例
Class<?> controllerCls = handler.getControllerClass();
Object controllerBean = BeanHelper.getBean(controllerCls);
// 创建请求参数对象
Map<String, Object> paramMap = new HashMap<>();
Enumeration<String> paramNames = req.getParameterNames();
while (paramNames.hasMoreElements()){
String paramName = paramNames.nextElement();
String paramValue = req.getParameter(paramName);
paramMap.put(paramName, paramValue);
}
String body = CodecUtil.decodeURL(StreamUtil.getString(req.getInputStream()));
if (StringUtils.isNotEmpty(body)){
String[] params = StringUtils.split(body, "&");
if (ArrayUtils.isNotEmpty(params)){
for (String param: params){
String[] array = StringUtils.split(param, "=");
if (ArrayUtils.isNotEmpty(array)){
String paramName = array[0];
String paramValue = array[1];
paramMap.put(paramName, paramValue);
}
}
}
}
Param param = new Param(paramMap);
// 调用Action方法
Method actionMethod = handler.getActionMethod();
Object result = ReflectionUtil.invokeMethod(controllerBean, actionMethod, param);
// 处理Action方法返回值
if (result instanceof View){
View view = (View) result;
String path = view.getPath();
if (StringUtils.isNotEmpty(path)){
if (path.startsWith("/")){
resp.sendRedirect(req.getContextPath() + path);
}else {
Map<String, Object> model = view.getModel();
for (Map.Entry<String, Object> entry: model.entrySet()){
req.setAttribute(entry.getKey(), entry.getValue());
}
req.getRequestDispatcher(ConfigHelper.getAppJspPath() + path).forward(req, resp);
}
}
}else if (result instanceof Data){
// 返回json数据
Data data = (Data) result;
Object model = data.getModel();
if (model != null){
resp.setContentType("application/json");
resp.setCharacterEncoding("UTF-8");
PrintWriter writer = resp.getWriter();
writer.write(JsonUtil.toJson(model));
writer.flush();
writer.close();
}
}
}
}
}
Param
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package org.smart4j.framework.bean;
import org.smart4j.framework.util.CastUtil;
import java.util.Map;
/**
* 请求参数对象
* Created by Roger on 2016/11/23.
*/
public class Param {
private Map<String, Object> paramMap;
public Param(Map<String, Object> paramMap) {
this.paramMap = paramMap;
}
public long getLong(String name){
return CastUtil.castLong(paramMap.get(name));
}
public int getInt(String name){
return CastUtil.castInt(paramMap.get(name));
}
public double getDouble(String name){
return CastUtil.castDouble(paramMap.get(name));
}
public boolean getBoolean(String name){
return CastUtil.castBoolean(paramMap.get(name));
}
public Map<String, Object> getParamMap() {
return paramMap;
}
}
View
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package org.smart4j.framework.bean;
import java.util.HashMap;
import java.util.Map;
/**
* 视图对象
* Created by Roger on 2016/11/23.
*/
public class View {
/**
* 视图路径
*/
private String path;
/**
* 模型数据
*/
private Map<String, Object> model;
public View(String path) {
this.path = path;
model = new HashMap<>();
}
public View addAttr(String key, Object value){
model.put(key, value);
return this;
}
public String getPath() {
return path;
}
public Map<String, Object> getModel() {
return model;
}
}
Data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package org.smart4j.framework.bean;
/**
* 数据对象
* Created by Roger on 2016/11/23.
*/
public class Data {
/**
* 模型数据
*/
private Object model;
public Data(Object model) {
this.model = model;
}
public Object getModel() {
return model;
}
}
StreamUtil
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package org.smart4j.framework.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* 流操作工具集
* Created by Roger on 2016/11/23.
*/
public final class StreamUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(StreamUtil.class);
public static String getString(InputStream is){
StringBuilder sb = new StringBuilder();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = br.readLine()) != null){
sb.append(line);
}
} catch (IOException e) {
LOGGER.error("get string failure", e);
throw new RuntimeException(e);
}
return sb.toString();
}
}
CodecUtil
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package org.smart4j.framework.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
/**
* 编码与解码工具集
* Created by Roger on 2016/11/23.
*/
public final class CodecUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(CodecUtil.class);
/**
* 将URL编码
* @param source
* @return
*/
public static String encodeURL(String source){
String target;
try {
target = URLEncoder.encode(source, "UTF-8");
} catch (UnsupportedEncodingException e) {
LOGGER.error("encode url failure", e);
throw new RuntimeException(e);
}
return target;
}
/**
* 将URL解码
* @param source
* @return
*/
public static String decodeURL(String source){
String target;
try {
target = URLDecoder.decode(source, "UTF-8");
} catch (UnsupportedEncodingException e) {
LOGGER.error("decode url failure", e);
throw new RuntimeException(e);
}
return target;
}
}
JsonUtil
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package org.smart4j.framework.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* Created by Roger on 2016/11/23.
*/
public final class JsonUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(JsonUtil.class);
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public static <T> String toJson(T obj){
String json;
try {
json = OBJECT_MAPPER.writeValueAsString(obj);
} catch (JsonProcessingException e) {
LOGGER.error("convert POJO to JSON failure", e);
throw new RuntimeException(e);
}
return json;
}
public static <T> T fromJson(String json, Class<T> type){
T pojo;
try {
pojo = OBJECT_MAPPER.readValue(json, type);
} catch (IOException e) {
LOGGER.error("convert JSON to POJO failure", e);
throw new RuntimeException(e);
}
return pojo;
}
}