1.2 自定义MVC框架
Java EE领域的MVC框架有很多,本书首先会设计一个简单的自定义MVC框架,以此帮助读者体会MVC框架的含义和实现过程,以及在MVC设计模式中控制器(Controller)的作用。通过此框架的实现还可以帮助读者理解Struts2的原理。
使用自定义MVC框架开发加法器程序的结构图如图1-6所示。
图1-6 加法器的MVC结构图
此加法器程序首先需要用户在add.jsp页面中输入两个数,单击“加”按钮进行计算,计算的结果在add_result.jsp页面中显示,如图1-7所示。
图1-7 加法器运行效果
下述内容用于实现任务描述1.D.1,使用自定义的MVC框架完成加法计算器。
1.2.1 实现控制器
自定义的MVC框架的核心是控制器的实现:定义Action接口,实现Controller类。
首先在com.haiersoft.ch01.framework包中创建Action接口,代码如下。
【描述1.D.1】Action.java
public interface Action { //定义该接口的实现类必须实现的execute方法 String execute(HttpServletRequest request,HttpServletResponse response); }
上述Action接口中定义了一个execute()方法,该方法有请求对象request和响应对象response两个参数;该方法返回一个字符串类型的值,表示执行完操作后转发到的页面。Action接口对各种动作的执行方法进行统一,便于在控制器中进行调用和访问。
然后在com.haiersoft.ch01.framework包中创建一个名为Controller的Servlet,代码如下。
【描述1.D.1】Controller.java
/** * 自定义MVC框架:基于Servlet实现的控制器 */ public class Controller extends HttpServlet { //声明由控制器Controller维护的Action映射,其中保存所有的Action实例 private HashMap actionMap; /** * Servlet初始化方法 */ @SuppressWarnings("unchecked") public void init() throws ServletException { // 初始化actionMap actionMap = new HashMap(); // 将AddAction对象放入到actionMap 中 actionMap.put("add", new AddAction()); } /** * 根据path判断由哪个action执行操作 */ private Action determinActionByPath(String path) { //如:从http://localhost:8080/ch01/add.action中得到add String actionName = path.substring(path.lastIndexOf('/') + 1, path.length() - 7); // 获得该请求对应的action对象 Action ret = (Action)actionMap.get(actionName); return ret; } /** * 处理页面以get方式提交的请求 */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 得到path,诸如:http://localhost:8080/ch01/ShowBaby.action String path = request.getServletPath(); // 找出Action Action action = (Action)this.determinActionByPath(path); // 执行操作 String resultView = action.execute(request,response); // 控制页面转向 if (null!=resultView){ request.getRequestDispatcher(resultView).forward(request, response); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 执行doGet方法 this.doGet(request, response); } }
上述的Controller类是基于Servlet技术实现的一个控制器,在处理每次请求时,首先根据请求路径找到将要被执行的Action对象,然后调用Action对象中的execute()方法,最后根据execute()方法返回的路径转发到相应的页面。
Controller类是一个Servlet,因此在web.xml中需要对其进行如下配置。
【描述1.D.1】web.xml
<servlet> <!-- 使用自定义的控制器 --> <servlet-name>Controller</servlet-name> <servlet-class>com.haiersoft.ch01.framework.Controller</servlet-class> </servlet> <servlet-mapping> <servlet-name>Controller</servlet-name> <!-- 请求匹配类型 --> <url-pattern>*.action</url-pattern> </servlet-mapping>
在上述Servlet配置中,所有以“.action”结尾的请求全部派发到Controller类进行处理。因此Action接口和Controller类组成了自定义MVC框架中核心的控制器部分。
注意 在许多框架结构中(例如Struts2)已经提供类似Action接口和Controller类的控制器,无须自己定义。
1.2.2 实现加法器功能
框架提供了控制器,也规定了模型和视图的集成方式,这样在此自定义框架上开发加法器可以按照如下4个步骤进行。
01 创建add.jsp页面,用于接收用户输入数据;
02 创建业务逻辑类Calculator,实现数据的算术运算;
03 创建AddAction类,该类实现Action接口。在execute()方法中获取add.jsp页面中的表单数据,并调用Calculator进行计算;
04 创建add_result.jsp页面,用于显示计算结果。
下述内容对实现加法器功能的4个步骤进行详细介绍。
1. 实现add.jsp页面
在WebContent目录中创建add.jsp页面,用于接收两个数值,页面代码如下。
【描述1.D.1】add.jsp
<%@ page contentType="text/html; charset=GBK"%> <html> <head> <title>计算器</title> </head> <body bgcolor="#ffffc0"> <h1>算术计算器</h1> <form id="calcForm" method="post" action="add.action"> <table> <tbody> <tr> <td>第一个数</td> <td><input type="text" name="num1" /></td> </tr> <tr> <td>第二个数</td> <td><input type="text" name="num2" /></td> </tr> <tr> <td><input type="submit" value="加" /></td> </tr> </tbody> </table> </form> </body> </html>
在add.jsp页面中,表单的action属性值为“add.action”,即表单提交给“add.action”处理。同时因为在web.xml中已经配置了将所有以“.action”结尾的请求全部派发到Controller进行处理,所以此表单会提交给Controller类处理。
2. 实现Calculator类
在com.haiersoft.ch01.biz包中创建Calculator类,进行加减乘除运算,代码如下。
【描述1.D.1】Calculator.java
public class Calculator { /** * 实现算术加法 */ public double add(double a, double b) { return a + b; } /** * 实现算术减法 */ public double subtract(double a, double b) { return a - b; } /** * 实现算术乘法 */ public double multiply(double a, double b) { return a * b; } /** * 实现算术除法 */ public double divide(double a, double b) { // 注意:此处未判断除数不能为零,即b!=0,页面输入的第二个数不可为0,否则报错 return a / b; } }
3. 实现AddAction类
在com.haiersoft.ch01.action包中创建AddAction类,该类实现Action接口,代码如下。
【描述1.D.1】AddAction.java
public class AddAction implements Action { // 业务逻辑对象 private Calculator biz = new Calculator(); public String execute(HttpServletRequest request, HttpServletResponse response) { // 获得页面输入 double num1 = Double.parseDouble(request.getParameter("num1")); double num2 = Double.parseDouble(request.getParameter("num2")); // 调用业务逻辑方法,获得返回值 double result = biz.add(num1, num2); // 将结果保存在request中,以便在页面中得到 request.setAttribute("result", result); // 返回将要转发到的页面路径 return "add_result.jsp"; } }
在上述AddAction类的execute()方法中,首先从request中获取表单数据并转换成double类型,然后调用Calculator类的对象“biz”中的add()方法进行计算,再将结果保存到request对象的属性中,最后返回将要转发的页面add_result.jsp。
4. 实现add_result.jsp页面
在WebContent目录中创建add_result.jsp页面,显示计算结果值,代码如下。
【描述1.D.1】add_result.jsp
<%@ page contentType="text/html; charset=GBK" pageEncoding="GBK"%> <html> <head> <title>计算器</title> </head> <body bgcolor="#ffffc0"> <h1>算术计算器</h1> <table> <tbody> <tr> <td>第一个数</td> <td>${param.num1}</td> </tr> <tr> <td>第二个数</td> <td>${param.num2}</td> </tr> <tr> <td>结果</td> <!-- 使用EL表达式显示结果 --> <td>${requestScope.result}</td> </tr> </tbody> </table> <button onclick="history.go(-1);">返回</button> </body> </html>
上述add_result.jsp页面中使用EL表达式显示结果。程序的运行结果如图1-7所示。
通过在此自定义MVC框架然后用其开发加法器的过程,读者可以体会到在开发过程中使用框架所带来的便利和限制,初步了解框架的功能及作用,为学习Struts2做好充分的准备。