设计 REST 风格的 MVC 框架-3 集成模板引擎
- UID
- 1066743
|
设计 REST 风格的 MVC 框架-3 集成模板引擎
集成模板引擎作为示例,返回一个“<h1>Hello, world!</h1>”作为 HTML 页面非常容易。然而,实际应用的页面通常是极其复杂的,需要一个模板引擎来渲染出 HTML。可以把 JSP 看作是一种模板,只要不在 JSP 页面中编写复杂的 Java 代码。我们的设计目标是实现对 JSP 和 Velocity 这两种模板的支持。
和集成 IoC 框架类似,我们需要解耦 MVC 与模板系统,因此,TemplateFactory 用于初始化模板引擎,并返回 Template 模板对象。TemplateFactory 定义见清单 11。
清单 11. 定义 TemplateFactory1
2
3
4
5
6
7
8
| public abstract class TemplateFactory {
private static TemplateFactory instance;
public static TemplateFactory getTemplateFactory() {
return instance;
}
public abstract Template loadTemplate(String path) throws Exception;
}
|
Template 接口则实现真正的渲染任务。定义见清单 12。
清单 12. 定义 Template1
2
3
4
| public interface Template {
void render(HttpServletRequest request, HttpServletResponse response,
Map<String, Object> model) throws Exception;
}
|
以 JSP 为例,实现 JspTemplateFactory 非常容易。代码见清单 13。
清单 13. 定义 JspTemplateFactory1
2
3
4
5
6
7
8
9
10
11
12
13
| public class JspTemplateFactory extends TemplateFactory {
private Log log = LogFactory.getLog(getClass());
public Template loadTemplate(String path) throws Exception {
if (log.isDebugEnabled())
log.debug("Load JSP template '" + path + "'.");
return new JspTemplate(path);
}
public void init(Config config) {
log.info("JspTemplateFactory init ok.");
}
}
|
JspTemplate 用于渲染页面,只需要传入 JSP 的路径,将 Model 绑定到 HttpServletRequest,就可以调用 Servlet 规范的 forward 方法将请求转发给指定的 JSP 页面并渲染。代码见清单 14。
清单 14. 定义 JspTemplate1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public class JspTemplate implements Template {
private String path;
public JspTemplate(String path) {
this.path = path;
}
public void render(HttpServletRequest request, HttpServletResponse response,
Map<String, Object> model) throws Exception {
Set<String> keys = model.keySet();
for (String key : keys) {
request.setAttribute(key, model.get(key));
}
request.getRequestDispatcher(path).forward(request, response);
}
}
|
另一种比 JSP 更加简单且灵活的模板引擎是 Velocity,它使用更简洁的语法来渲染页面,对页面设计人员更加友好,并且完全阻止了开发人员试图在页面中编写 Java 代码的可能性。使用 Velocity 编写的页面示例如清单 15 所示。
清单 15. Velocity 模板页面1
2
3
4
| <html>
<head><title>${title}</title></head>
<body><h1>Hello, ${name}!</body>
</html>
|
通过 VelocityTemplateFactory 和 VelocityTemplate 就可以实现对 Velocity 的集成。不过,从 Web 开发人员看来,并不需要知道具体使用的模板,客户端仅需要提供模板路径和一个由 Map<String, Object> 组成的 Model,然后返回一个 TemplateRenderer 对象。代码如清单 16 所示。
清单 16. 定义 TemplateRenderer1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| public class TemplateRenderer extends Renderer {
private String path;
private Map<String, Object> model;
public TemplateRenderer(String path, Map<String, Object> model) {
this.path = path;
this.model = model;
}
@Override
public void render(ServletContext context, HttpServletRequest request,
HttpServletResponse response) throws Exception {
TemplateFactory.getTemplateFactory()
.loadTemplate(path)
.render(request, response, model);
}
}
|
TemplateRenderer 通过简单地调用 render 方法就实现了页面渲染。为了指定 Jsp 或 Velocity,需要在 web.xml 中配置 DispatcherServlet 的初始参数。配置示例请参考清单 17。
清单 17. 配置 Velocity 作为模板引擎1
2
3
4
5
6
7
8
| <servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.expressme.webwind.DispatcherServlet</servlet-class>
<init-param>
<param-name>template</param-name>
<param-value>Velocity</param-value>
</init-param>
</servlet>
|
如果没有该缺省参数,那就使用默认的 Jsp。
类似的,通过扩展 TemplateFactory 和 Template,就可以添加更多的模板支持,例如 FreeMarker。 |
|
|
|
|
|