“意大利面条式”代码
在 ASP 端,“意大利面条式”代码方法使用单个 .aspx 文件来同时包含应用逻辑和 HTML 表单。(不建议对现实中的例子采用这种方法,因为这样所有表示逻辑和应用逻辑都将是单个文件,从而您就不能重用用于验证用户凭证的代码。)该代码的轮廓看起来类似清单 23 中所示的代码。(为简单起见,我们省略了所有错误处理代码。)
清单 23. ASP 中的“意大利面条式”代码
2 '--Code to validate users credentials goes here
3 ...
4 END FUNCTION %>
5 <html>
6 <head>
7 <title>Login example</title>
8 </head>
9 <body>
10 <% IF (REQUEST.SERVERVARIABLES("REQUEST_METHOD") = "GET") THEN %>
11 <form action="login.asp" method="post">
12
13 <!-- login form fields go here -->
14
15 </form>
16 <% ELSE userName = REQUEST.FORM("username") password = REQUEST.FORM("password")
17 IF (ValidateUser(userName, password)) THEN
18 RESPONSE.REDIRECT("mainpage.asp") ELSE ... END IF END IF %>
19 <font color="red"><b><%=LoginMessage%></b></font>
20 </body>
21 </html>
22
正如清单 24 所示,您可以在 J2EE 中采用相同的方法,使用单个 JSP 页面来同时包含表单和应用逻辑。
清单 24.J2EE 中的“意大利面条式”代码
2 <head>
3 <title>Login example</title>
4 <%!
5 private boolean validateUser(String userName, String password) {
6 ...
7 }
8 %>
9 ...
10 </head>
11 <body>
12 <%
13 if (request.getMethod().equals("GET") ) { %>
14 <form method="POST" target="login.jsp">
15 <!-- login form fields go here -->
16 </form> <% }
17 else {
18 String userName = request.getParameter("username");
19 String password = request.getParameter("password");
20 if (validateUser(userName, password)) {
21 response.sendRedirect("mainpage.jsp");
22 }
23 ...
24 } %>
25 </body>
26 </html>
27
与 ASP 模型类似,JSP 模型不是事件驱动的,因此您需要检查表单是否被发送回去了,方法是检查该请求,并且如果不是 POST 请求时则添加表单的 HTML。如果它是 POST 请求,您将使用在 JSP 中声明的一个方法来验证登录。注意,使用 )对方法无效。还要注意如何使用 if/then/else 编程结构来方便地添加或去除较大的 HTML 块。与在 ASP 例子中一样,不推荐将此方法用于 J2EE 开发。表示代码(HTML)和应用逻辑的混合仅允许很少的重用,并且使得代码难于维护。
改进的“意大利面条式”代码
在 ASP 端,可以以前一个例子为基础建立一种更好的方法,不过除了 login.asp 文件外,还使用只包含验证逻辑的一个 include ASP 文件。这样您就可以重用其他 ASP 文件中的代码。
J2EE 端的一种更好方法是将应用逻辑转移到一个 Java Servlet,从而使 JSP 页面仅限于使用 HTML 组件。现在验证逻辑独立于显示表单的页面,这是一种改进,而 JSP 页面仅限于使用 HTML 组件也是一种改进。清单 25 显示了如何将应用逻辑放到 servlet 中从而简化 JSP 页面。
清单 25. J2EE:JSP 页面中改进的“意大利面条式”代码
2 <head>
3 <title>Login example</title>
4 ...
5 </head>
6 <body>
7 <form method="POST" target="LoginServlet">
8 <!-- login form fields go here -->
9 </form>
10 </body>
11 </html>
12
清单 26 显示了 servlet 中的验证代码和导航逻辑。
清单 26. J2EE:Java Servlet 中改进的“意大利面条式”代码
2 /**
3 * Handles all HTTP POST requests
4 *
5 * @param request Object that encapsulates the request to the servlet
6 * @param response Object that encapsulates the response from the servlet
7 */
8 public void doPost(
9 javax.servlet.http.HttpServletRequest request,
10 javax.servlet.http.HttpServletResponse response)
11 throws ServletException, IOException {
12 try {
13 String userName = request.getParameter("username");
14 String password = request.getParameter("password");
15 if (validateUser(userName, password)) {
16 response.sendRedirect("mainpage.jsp");
17 }
18 ...
19 } catch (Throwable t) {
20 ...
21 }
22 }
23 private boolean validateUser(String userName, String password) {
24 ...
25 }
26 }
27
清单 26 中的 servlet 是表单提交的目标,并且充当一个控制器――处理用户输入并基于该输入调出适当的页面。注意 HttpServlet 父类允许您通过提供可重载的方法( doGet() 和 doPost() )来同时处理 GET 和 POST 请求。
这种方法的主要缺点在于,凭证验证代码(它很可能要访问数据库)是 J2EE 例子中 servlet 的一部分。如果不同的页面需要使用这个逻辑,您就必须重复它。重复的代码更难于维护和更易于出错,因为您必须跟踪多个副本。
模型-视图-控制器(MVC)方法
下面我们将展示如何对这个例子使用更纯的 MVC 方法。在 ASP 端,这体现为将凭证验证逻辑转移到一个单独 COM 组件,然后您在 ASP 文件中进行访问。在 J2EE 端,凭证验证代码将转移到一个单独的类中,然后从 servlet 访问该类。清单 27 中的代码片断显示了该 servlet 的外观。
清单 27. J2EE: Java Servlet 中的 MVC
2 public class LoginServlet extends HttpServlet {
3 /**
4 * Handles all HTTP POST requests
5 *
6 * @param request Object that encapsulates the request to the servlet
7 * @param response Object that encapsulates the response from the servlet
8 */
9 public void doPost(
10 javax.servlet.http.HttpServletRequest request,
11 javax.servlet.http.HttpServletResponse response)
12 throws ServletException, IOException {
13 try {
14 String userName = request.getParameter("username");
15 String password = request.getParameter("password");
16 UserValidation user = new UserValidation();
17 if (user.validate(userName, password)) {
18 response.sendRedirect("mainpage.jsp");
19 }
20 ...
21 } catch (Throwable t) {
22 ...
23 }
24 }
25 }
26
清单 28 显示了位于一个单独的类中的凭证验证代码。
清单 28. J2EE:用户验证类中的 MVC
2 public class UserValidation {
3 public boolean validate(String username, String password) {
4 ...
5 }
6 }
7
凭证验证在 servlet 使用的类中进行。现在该 servlet 不必直接了解验证如何进行。只要您保持相同的公共接口不变,就可以随意更改 UserValidation 而不需改变 servlet 代码。您还可以在非 Web 应用程序中重用该代码。
其他 J2EE 组件
前面的例子展示了如何将业务逻辑分离到一个或一组单独的类中。这样允许您以各种不同的方式实现业务逻辑,而不会影响 servlet 和 JSP 页面。与使用一个需要访问数据库(使用 JDBC)的业务对象不同,您可以通过各种不同的方式实现这个逻辑。例如:
使用 JCA 来访问诸如大型机等遗留系统:JCA 是一个 J2EE API,它允许 J2EE 应用程序使用标准接口与遗留系统(比如 CICS 或者 IMS)交互。
使用 Web 服务客户端 API 来访问 Web 服务:这种方法涉及使用 Apache Axis 或其他某种 Java Web 服务客户端 API 来访问 Web 服务。
使用 JMS 将消息作为验证请求来发送:这种方法涉及使用标准 API 来访问 JMS 相容的消息中间件(比如 WebSphere MQ)。
使用 EJB 技术来实现验证逻辑:这种方法涉及使用 EJB 组件(而不是简单的 Java 类)来实现业务逻辑。EJB 组件能够使用应用服务器中的服务来管理(数据库或其他)事务,管理方法级的安全,以及提供群集和高速缓存。将此类任务委托给应用服务器,您可以把精力集中在业务逻辑上,而不必担心系统级的问题。