MVC模式与Struts2框架的作用

来源:互联网 发布:试客联盟 淘宝查不查 编辑:程序博客网 时间:2024/03/29 05:49
郑重申明:包括本文在内的很多技术文章,大多出自山外高人,而非Fans。
                  Fans暂时没有能力写作优秀的技术文章,Fans只是转载、浓缩、加入部分自己的代码而已。

   MVC模式实际上是众多经典的Java开发模式中的一种。它的基本原理是通过元素分解,来处理基于“请求-响应”模式的程序中的各种问题。

    M (Model)—数据模型  V (View)—视图展现     C(Control)—控制器

 

   任何一个B/S应用,其本质实际上是一个“请求-响应”的处理过程的集合体。那么MVC模式是如何被提炼出来并成为一个模式的呢? 我们来模拟一个“请求-响应”的过程,如图2-7所示。

 图2-7 请求-响应模式

在整个请求-响应过程中,有哪些元素是必不可少的呢?

数据模型

在图中,就是顺着箭头方向进行传输的数据,它们是程序的核心载体,也是贯穿程序运行的核心内容。

对外交互

在图中,对外交互表现为一个“头”和一个“尾”。“头”指的是请求发起的地方,没有请求,一切之后的所有内容都无从谈起。“尾”指的是逻辑执行完成后,对外展现出来的执行结果。在传统意义上,我们利用HTML扩展的技术(如JSP等)来实现对外交互,在展现结果时,我们还需要完成一定的展现逻辑,比如错误展示、分支判断,等等。

程序的执行和控制

实际上它不仅是接受请求数据的场所,也是处理请求的场所。在请求处理完毕之后,它还要负责响应跳转。这个部分可能会存在着不同的表现形式。以前,我们用JSP和Servlet,后来用Struts1或者Struts2的Action。而这一变化,实际上包含了我们不断对程序进行重构的过程。

 

上面这3大元素,在不同的年代被赋予了不同的表现形式。例如,在很久以前,我们使用Servlet或者JSP来编写程序跳转的控制过程,有了Struts1.X后,我们使用框架所定义的Action类来处理。这些不同的表现形式有的受到时代的束缚,表现形式非常落后,有的甚至已经不再使用。但是我们忽略这些外在的表现形式就可以发现,这不就是我们已经熟悉的MVC吗?

数据模型—Model

对外交互—View

程序的执行和控制—Control

 

MVC的概念就这么简单,这些概念其实早已深入我们的内心,而我们所缺乏的是将其本质挖掘出来的能力。我们来看看如图2-8所示的这幅流行了很多年的讲述MVC模型的图。

 图2-8 MVC模型图

在这幅图中,MVC三个框框各司其职,结构清晰明朗。这也成为我们进行编程开发的最强有力的理论武器,我们需要做的,只是为这些框框赋予不同的表现形式。实际上,框架就是这么干的!而框架的高明之处,仅仅在于它不仅赋予这些元素正确而恰当的表现形式,同时解决了当元素运行起来时所碰到的各种问题。因此,我们始终应该做到:程序时时有,概念心中留。只要MVC的理念在你心中,无论程序怎么变,都能做到万变不离其宗。

 

Struts2框架的作用

        

       当表示层有了MVC模式,程序开发就会变得有章可循。至少,我们不会像无头苍蝇一样无从入手。MVC模式很直观地规定了表示层的各种元素,只要能够通过恰当的程序表现形式来实现这些元素,我们实际上已经在履行最佳实践了。

       至此,我们不妨返璞归真,忘记所谓的框架,用最简单的方式来实现一个简单的MVC雏形。在这个过程中,我们不妨回到框架的本质问题上,思考一下究竟一个框架为表示层解决了什么样的编程难题,难道框架只是实现MVC这三大元素那么简单而已?

 

        我们选择Registration(注册)作为业务场景。首先,我们需要一个JSP页面来呈现用户注册的各个字段、一个User类来表示用户实体以及一个RegistrationServlet类来处理注册请求。相关实现源码如代码清单2-6、代码清单2-7和代码清单2-8所示。

代码清单2-6 registration.jsp

  1. <form method="post" action="/struts2_example/registration"> 
  2.   user name: <input type="text" name="user.name" value="downpour" /> 
  3.   birthday: <input type="text" name="user.birthday" value="1982-04-15" /> 
  4.   <input type="submit" value="submit" /> 
  5. </form> 

代码清单2-7 User.java

  1. public class User {  
  2.  
  3.     private String name;  
  4.  
  5.     private Date birthday;  
  6.  
  7.     public User() {  
  8.  
  9.     }  
  10.  
  11.     // 此处省略setter与getter方法  

代码清单2-8 RegistrationServlet.java

  1. public class RegistrationServlet extends HttpServlet {  
  2.  
  3.     @Override  
  4.     protected void doPost(HttpServletRequest req, HttpServletResponse  
  5. resp) throws ServletException, IOException {  
  6.  
  7.         // 从request获取参数  
  8.  
  9.         String name = req.getParameter("name");  
  10.         String birthdayString = req.getParameter("birthday");  
  11.  
  12.         // 做必要的类型转化  
  13.  
  14.         Date birthday = null;  
  15.         try {  
  16.              birthday = new SmpleDateFormat("yyyy-MM-dd").  
  17. parse(birthdayString);  
  18.         } catch (ParseException e) {  
  19.         e.printStackTrace();  
  20.         }  
  21.  
  22.         // 初始化User类,并设置字段到user对象中去  
  23.  
  24.         User user = new User();  
  25.         user.setName(name);  
  26.         user.setBirthday(birthday);  
  27.  
  28.         // 调用业务逻辑代码完成注册  
  29.  
  30.         UserService userService = new UserService();  
  31.         userService.register(user);  
  32.  
  33.         req.getRequestDispatcher("/success.jsp").forward(req, resp);  
  34.     }  

除了上述这3段源代码外,我们还需要建立起JSP页面中的form请求与Servlet类的响应之间的关系。这一关系,是在web.xml中维护的,如代码清单2-9所示。

代码清单2-9 web.xml

  1. <servlet> 
  2.  <servlet-name>Register</servlet-name> 
  3.  <servlet-class>example.RegistrationServlet</servlet-class> 
  4. </servlet> 
  5. <servlet-mapping> 
  6.  <servlet-name>Register</servlet-name> 
  7.  <url-pattern>/struts2_example/registration</url-pattern> 
  8. </servlet-mapping> 
 

我们来看看上面的这4段代码是如何构成MVC的雏形的。

Model(数据模型)—User.java

View(对外交互)—registration.jsp

Control(程序执行和控制)—RegistrationServlet.java

URL Mapping(请求转化)—web.xml

 

我们可以看到MVC的实现似乎并不复杂。在不借助额外的框架帮助的前提下,只要基本知晓JSP和Servlet标准(它们是使用Java进行Web开发的规范和标准),任何程序员都可以像模像样地实现MVC模式,因为从原理上讲,MVC只是一个概念,我们只需要把这个概念中的各个元素赋予相应的程序实现即可。

不过程序终究是一个动态的执行过程。一旦程序开始运行,上面的这些程序实现就会开始遭遇种种困境。这些困境主要来源于两个方面:其一,出于程序自身的可读性和可维护性考虑,需要通过重构来解决程序的复杂性困境。其二,出于业务扩展的需求,需要通过框架级别的功能增强来解决可扩展性困境。

 

具体来说,上面的这些程序实现有如下不太好的地方:

 

1.RegistrationServlet 和很多其它的Servlet有着非常相似的执行步骤:接受参数--进行类型转换--调度业务逻辑接口执行逻辑--返回处理结果。

 

2.在上面的例子中,我们可以看到负责视图层跳转的RegistrationServlet 是通过硬编码的方式完成程序执行跳转的。这种方式不但不能无法支持多种新的视图技术,比如Flash、Stream数据流,同时也无法使我们从复杂的视图跳转的硬编码中释放出来。


3.类型转换 多种多样,如何做到 复用、可扩展。

 4.Web容器是一个典型的多线程环境,针对每个Http请求,Web容器的线程池会分配一个特定的线程进行处理。那么如何保证在多线程环境下,处理请求的Java类是线程安全的对象?如何保证数据的流转和访问都是线程安全的?
   在上面的例子中,我们使用的是基于Servlet标准的方式进行编程,扩展Servlet用于处理Http请求。然而恰恰就是这种编程模型,是一种非线程安全的编程模型,因为Servlet对象是一个非线程安全的对象。也就是说,如果我们在doPost方法中访问RegistrationServlet中所定义的局部变量,就会产生线程安全问题。
   不好的地方还有很多,就不再举例子了。
    Struts2框架的作用:接收参数、参数校验、流程控制、页面展现等很多功能,减轻了我们的开发负担,提高了开发效率。