在Servlet程序中夹杂HTML的画面输出绝对不是什么好主意,即冗余又麻烦又难看,尽管JSP代码相比Servlet优化了许多,但在JSP网页中的HTML间夹杂Java程序代码,仍然看起来很凌乱,后期的修改维护也很麻烦。
谈及Web应用程序架构上的设计时,总会谈到MVC和model 2这两个名词。MVC是Model、View、Controller的缩写,大家再熟悉不过。这里译为模型、视图、控制器,分别代表应用程序中三种职责各不相同的对象。最原始的MVC模式其实是指桌面应用程序的一种设计方式,为了让同一份数据能有不同的画面呈现方式,并且当数据被变更时,画面可获得通知并根据资料更新画面呈现。
可以看出,MVC模型是个职责分明的设计方式:
- 模型不会有画面相关的程序代码
- 视图负责画面相关逻辑
- 控制器知道某个操作必须调用那些模型
后来有人认为,MVC这样的职责分配,可以套用在WEB应用程序的设计上:
- 视图部分可由网页来实现
- 服务器上的数据访问或业务逻辑(Business logic)由模型负责
- 控制器接送浏览器的请求,决定调用哪些模型来处理
然而,桌面应用程序上的MVC设计方式,有个与Web应用程序决定性的不同。Web应用程序是基于HTTP,必须基于请求/响应模型,没有请求就不会有响应,也就是HTTP服务器不可能主动对浏览器发出响应。因此,对MVC的行为作了变化,因而形成所谓的Model 2架构。
在Model 2的架构上,仍将程序职责分为模型(Model)、视图(View)、控制器(Controller),因此该架构也称为MVC,或并称为MVC/model 2。
在Model 2的架构上,控制器、模型、视图各负的职责:
- 控制器:取得请求参数、验证请求参数、转发请求给模型、转发请求给画面,这些都使程序代码来实现。
- 模型:接受控制器的请求调用,负责处理业务逻辑、负责数据存取逻辑等,这部分还可依应用程序功能,产生各多种不同职责的模型对象,模型使用程序代码来实现。
- 视图:接受控制器的请求调用,会从模型提取运算后的结果,根据需求呈现所需的画面,在职责分配良好的情况下,基本上可做到不出现程序代码,因此不会发生程序代码与HTML混杂在一起的情况。
既然了解了MVC/model 2模型的基本原理,下面简单实现以下:
HelloController.java (控制器,负责参数的请求与转发)
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author Barudisshu
*/
@WebServlet(name = "HelloController", urlPatterns = {"/hello.do"})
public class HelloController extends HttpServlet {
private HelloModel model = new HelloModel();
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//收集请求参数
String name = request.getParameter("user");
//委托HelloModel对象处理
String message = model.doHello(name);
//将结果信息设置到请求对象成为属性
request.setAttribute("message", message);
//转发hello.view进行相应
request.getRequestDispatcher("equivalent.jsp").forward(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}
HelloModel.java (模型,负责处理业务逻辑、数据存取逻辑等)
import java.util.HashMap;
import java.util.Map;
/**
*
* @author Barudisshu
*/
class HelloModel {
private Map<String, String> messages = new HashMap<>();
public HelloModel() {
messages.put("caterpillar", "Hello");
messages.put("Justin", "Welcome");
messages.put("momor", "Hi");
}
public String doHello(String user) {
String message = messages.get(user);
return message + "," + user + "!";
}
}
HelloView.java (视图,用于呈现结果,基本上做到不出现程序代码)
/**
*
* @author Barudisshu
*/
@WebServlet(name = "HelloView", urlPatterns = {"/hello.view"})
public class HelloView extends HttpServlet {
private String htmlTemplate =
"<!doctype html>"
+ "<html>"
+ "<head>"
+ "<meta charset='utf-8'>"
+ "<title>%s</title>"
+ "</head>"
+ "<body>"
+ "<h1>%s</h1>"
+ "</body>"
+ "</html>";
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//取得请求参数
String user = request.getParameter("user");
//取得请求属性
String message = (String) request.getAttribute("message");
//产生html结果
String html = String.format(htmlTemplate, user, message);
response.getWriter().print(html);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}
equivalent.jsp (视图,等效于HelloView,使用EL表达语言,没有出现任何Java代码)
<%--
Document : equivalent
Created on : 2013-8-26, 19:58:04
Author : Barudisshu
--%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>${param.user}</title>
</head>
<body>
<h1>${message}</h1>
</body>
</html>
可以看到,在Model 2架构的实现下,控制器、视图、模型各司其职,该呈现画面的元件不会有Java代码出现(HelloView),在负责业务逻辑的元件不会有HTML输出(HelloModel),该处理请求参数的元件不会牵涉业务逻辑的代码(HelloController)。