支持“正向 MVC 模式”

原创
2013/10/18 17:34
阅读数 5K

本文是《轻量级 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,从此,我们的小伙伴们又多了一种选择,而且更加亲切!

期待您的点评!

展开阅读全文
加载中
点击加入讨论🔥(7) 发布并加入讨论🔥
打赏
7 评论
30 收藏
2
分享
返回顶部
顶部