本文是《轻量级 Java Web 框架架构设计》的系列博文。
上一篇 提到了 MVC 的两种模式,目前 Smart Framework 仅提供了“反向 MVC 模式”,计划在 2.0 版本中实现“正向 MVC”。今天抽了一点时间,扩展了一下框架,详细开发过程如下:
第一步:定义一个 JavaBean 用于封装 View 与 Model,取名为 Page。
public class Page extends BaseBean {
private String path; // 页面路径
private Map<String, Object> data; // 相关数据
public Page(String path) {
this.path = path;
data = new HashMap<String, Object>();
}
public Page data(String key, Object value) {
data.put(key, value);
return this;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public Map<String, Object> getData() {
return data;
}
public void setData(Map<String, Object> data) {
this.data = data;
}
}
第二步:开发一个 Action,用于接收请求。
@Bean
public class FooAction extends BaseAction {
@Request("get:/foo")
public Page index() {
String aaa = "aaa";
String bbb = "bbb";
String ccc = "ccc";
return new Page("foo.jsp")
.data("aaa", aaa)
.data("bbb", bbb)
.data("ccc", ccc);
}
}
接收 /foo 请求,模拟在 Action 中处理业务逻辑,最后转发到 foo.jsp,并传递相应的数据(通过链式方法实现)。
第三步:编写一个 JSP,用户展现数据。
<%@ page pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Foo</title>
</head>
<body>
${aaa}, ${bbb}, ${ccc}
</body>
</html>
使用 JSTL 表达式获取相应的数据,即通过 key 获取 value。
第四步:扩展 DispatcherServlet,用户处理 Page 类型的 Action 返回值。
@WebServlet(urlPatterns = "/*", loadOnStartup = 0)
public class DispatcherServlet extends HttpServlet {
...
private void handleActionMethod(ActionBean actionBean, List<Object> paramList, HttpServletRequest request, HttpServletResponse response) {
...
// 调用 Action 方法
Object actionMethodResult = ...
// 判断返回值类型
if (actionMethodResult != null) {
if (actionMethodResult instanceof Result) {
...
} else if (actionMethodResult instanceof Page) {
// 若为 Page 类型,则 转发 或 重定向 到相应的页面中
Page page = (Page) actionMethodResult;
String path = page.getPath();
if (path.startsWith("/")) {
// 重定向请求
redirectRequest(page, response);
} else {
// 转发请求
forwordRequest(page, request, response);
}
}
}
}
...
private void redirectRequest(Page page, HttpServletResponse response) {
try {
// 获取路径
String path = page.getPath();
// 重定向请求
response.sendRedirect(path);
} catch (Exception e) {
logger.error("页面重定向出错!", e);
throw new RuntimeException(e);
}
}
private void forwordRequest(Page page, HttpServletRequest request, HttpServletResponse response) {
try {
// 获取路径
String path = "/jsp/" + page.getPath();
// 初始化 Request 属性
Map<String, Object> data = page.getData();
if (MapUtil.isNotEmpty(data)) {
for (Map.Entry<String, Object> entry : data.entrySet()) {
request.setAttribute(entry.getKey(), entry.getValue());
}
}
// 转发请求
request.getRequestDispatcher(path).forward(request, response);
} catch (Exception e) {
logger.error("页面转发出错!", e);
throw new RuntimeException(e);
}
}
}
以上考虑到了“转发(forword)”与“重定向(redirect)”两种模式,若返回的 path 中以“/”开头,则说明是重定向,否则即为转发。
此外,需要在 DispatchServlet 初始化的时候,将所有 JSP 请求注册到 JspServlet(由 Web 服务器提供)中:
...
// 用 JspServlet 映射所有 JSP 请求
ServletRegistration jspServletRegistration = context.getServletRegistration("jsp");
jspServletRegistration.addMapping("/jsp/*");
...
第五步:编译并启动服务器,发送请求进行测试。
发送 /foo 请求,返回如下页面:
通过简单扩展,实现了“正向 MVC”。此时,Smart Framework 可同时支持正向与反向 MVC,从此,我们的小伙伴们又多了一种选择,而且更加亲切!
期待您的点评!