如何理解MVC中的Model?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何理解MVC中的Model?相关的知识,希望对你有一定的参考价值。

MVC包括三类对象。Model是应用对象,View是它在屏幕上的表示,Controller定义用户界面对用户输入的响应方式。

MVC:

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。

参考技术A MVC(Model/View/Controller)模式是国外用得比较多的一种设计模式,好象最早是在Smaltalk中出现。MVC包括三类对象。Model是应用对象,View是它在屏幕上的表示,Controller定义用户界面对用户输入的响应方式。
模型-视图-控制器(MVC)是80年代Smalltalk-80出现的一种软件设计模式,现在已经被广泛的使用。
1、模型(Model)

模型是应用程序的主体部分。模型表示业务数据,或者业务逻辑.

2、视图(View)

视图是应用程序中用户界面相关的部分,是用户看到并与之交互的界面。

3、控制器(controller)

控制器工作就是根据用户的输入,控制用户界面数据显示和更新model对象状态。

MVC 式的出现不仅实现了功能模块和显示模块的分离,同时它还提高了应用系统的可维护性、可扩展性、可移植性和组件的可复用性

早期的程序中,如果不注意对数功能和显示的解耦合,常常会导致程序的复杂及难以维护。很多VB,Delphi等RAD程序都有这种问题。甚至现在的C#,Java有时候也会出现把业务逻辑写在显示模块中的现象

管MVC设计模式很早就提出,但在Web项目的开发中引入MVC却是步履维艰。主要原因:一是在早期的Web项目的开发中,程序语言和html的分离一直难以实现。CGI程序以字符串输出的形式动态地生成HTML内容。后来随着脚本语言的出现,前面的方式又被倒了过来,改成将脚本语言书写的程序嵌入在HTML内容中。这两种方式有一个相同的不足之处即它们总是无法将程序语言和HTML分离。二是脚本语言的功能相对较弱,缺乏支持MVC设计模式的一些必要的技术基础。直到基于J2EE的JSP Model 2问世时才得以改观。它用JSP技术实现视图的功能,用Servlet技术实现控制器的功能,用JavaBean技术实现模型的功能

JSP Model 1 与 JSP Model 2

SUN在JSP出现早期制定了两种规范,称为Model1和Model2。虽然Model2在一定程度上实现了MVC,但是它的应用用并不尽如人意

JSP Model 1

JSP Model 2

model2 容易使系统出现多个Controller,并且对页面导航的处理比较复杂

有些人觉得model2仍不够好,于是Craig R. McClanahan 2000年5月提交了一个WEB framework给Java Community.这就是后来的Struts.

2001年7月,Struts1.0,正式发布。该项目也成为了Apache Jakarta的子项目之一

Struts 质上就是在Model2的基础上实现的一个MVC架构。它只有一个中心控制器,他采用XML定制转向的URL。采用Action来处理逻辑

へ伤苡趫载ご 回答时间 2008-02-20 20:49

其他答案MVC就是模型,视图,控制器.
模型不用说了吧,视图只负责显示,不要带任何逻辑.控制器就是负责控制.
遵循这个思想就可以了。
现在有很多MVC的框架.比如JAVA EE 的STRUTS之类的.

理解Spring MVC Model Attribute和Session Attribute

作为一名 Java Web 应用开发者,你已经快速学习了 request(HttpServletRequest)和 session(HttpSession)作用域。在设计和构建 Java Web 应用时,理解这些作用域,如何将数据与对象和这些作用域交互是十分重要的。【在 StackOverflow 上有一篇文章可以帮助你快速了解 request 和 session 作用域】

SPRING MVC 作用域

当我开始用 Spring MVC 编写 Web 应用时,我发现 Spring model 和 session attribute 有一点神秘,尤其当它们与我熟知的 HTTP request 和 session 作用域交互时。一个 Spring model 元素可以从我的 session 或者 request 中找到吗?如果是这样的话,我该如何控制?在这篇文章中,我希望讲解清楚 Spring MVC 的 model 与 session 是如何工作的。

SPRING 的 @MODELATTRIBUTE

有几种方法将数据或对象添加到 Spring 的 model 中。一般来说,数据或对象是通过 controller 层的一个注解添加进 Spring 的 model 中。在下面的例子中,使用 @ModelAttribute 添加一个名为 MyCommandBean 的实例给 key 值为『myRequestObject』的 model。

@CONTROLLER
PUBLIC CLASS MYCONTROLLER {

    @MODELATTRIBUTE("MYREQUESTOBJECT")
    PUBLIC MYCOMMANDBEAN ADDSTUFFTOREQUESTSCOPE() {
        SYSTEM.OUT.PRINTLN("INSIDE OF ADDSTUFFTOREQUESTSCOPE");
        MYCOMMANDBEAN BEAN = NEW MYCOMMANDBEAN("HELLO WORLD",42);
        RETURN BEAN;
    }

    @REQUESTMAPPING("/DOSOMETHING")
    PUBLIC STRING REQUESTHANDLINGMETHOD(MODEL MODEL, HTTPSERVLETREQUEST REQUEST) {
        SYSTEM.OUT.PRINTLN("INSIDE OF DOSOMETHING HANDLER METHOD");

        SYSTEM.OUT.PRINTLN("--- MODEL DATA ---");
        MAP MODELMAP = MODEL.ASMAP();
        FOR (OBJECT MODELKEY : MODELMAP.KEYSET()) {
            OBJECT MODELVALUE = MODELMAP.GET(MODELKEY);
            SYSTEM.OUT.PRINTLN(MODELKEY + " -- " + MODELVALUE);
        }

        SYSTEM.OUT.PRINTLN("=== REQUEST DATA ===");
        JAVA.UTIL.ENUMERATION REQENUM = REQUEST.GETATTRIBUTENAMES();
        WHILE (REQENUM.HASMOREELEMENTS()) {
            STRING S = REQENUM.NEXTELEMENT();
            SYSTEM.OUT.PRINTLN(S);
            SYSTEM.OUT.PRINTLN("==" + REQUEST.GETATTRIBUTE(S));
        }

        RETURN "NEXTPAGE";
    }

         //  ... THE REST OF THE CONTROLLER
}

在一个到达的 request 中,任何被 @ModelAttribute 注解的方法都会在 controller handler method 之前调用(就像上面例子中的 requestHandlingMethod 一样)。这些方法会赶在 handler method 执行之前将数据添加进一个 java.util.Map,然后加入 Spring model 中。可以用一个示例操作展示出来。我创建了两个 JSP 页面:index.jsp 和 nextpage.jsp。index.jsp 上的一个链接用于向 MyController 中的 requestHandlingMethod() 应用触发器发送一个 request。上面的代码中,requestHandlingMethod() 将『nextpage』作为下个视图的逻辑名返回,其在这个例子中会处理为 nextpage.jsp。

技术分享

当这个小小的网址被修改为这种形式后,controller 的 System.out.println 展现了 @ModelAttribute 方法是如何在 handler method 之前执行的。同时也展现了 MyCommandBean 创建和加入 Spring model,并在 handler method 中可用的过程。

INSIDE OF ADDSTUFFTOREQUESTSCOPE
INSIDE OF DOSOMETHING HANDLER METHOD
--- MODEL DATA ---
MYREQUESTOBJECT -- MYCOMMANDBEAN [SOMESTRING=HELLO WORLD, SOMENUMBER=42]
=== REQUEST DATA ===
ORG.SPRINGFRAMEWORK.WEB.SERVLET.DISPATCHERSERVLET.THEME_SOURCE
==WEBAPPLICATIONCONTEXT FOR NAMESPACE ‘DISPATCHER-SERVLET‘: STARTUP DATE [SUN OCT 13 21:40:56 CDT 2013]; ROOT OF CONTEXT HIERARCHY
ORG.SPRINGFRAMEWORK.WEB.SERVLET.DISPATCHERSERVLET.THEME_RESOLVER
[email protected]48C
ORG.SPRINGFRAMEWORK.WEB.SERVLET.DISPATCHERSERVLET.CONTEXT
==WEBAPPLICATIONCONTEXT FOR NAMESPACE ‘DISPATCHER-SERVLET‘: STARTUP DATE [SUN OCT 13 21:40:56 CDT 2013]; ROOT OF CONTEXT HIERARCHY
ORG.SPRINGFRAMEWORK.WEB.SERVLET.HANDLERMAPPING.PATHWITHINHANDLERMAPPING
==DOSOMETHING.REQUEST
ORG.SPRINGFRAMEWORK.WEB.SERVLET.HANDLERMAPPING.BESTMATCHINGPATTERN
==/DOSOMETHING.*
ORG.SPRINGFRAMEWORK.WEB.SERVLET.DISPATCHERSERVLET.LOCALE_RESOLVER
==[email protected]18FD23E4

现在问题变为了『Spring model 的数据存储在哪里?』是存储在标准 Java request 作用域中么?答案是 —— 对的。。。就最终而言的话。就像你从上面的输出中读到的,MyCommandBean 在 model 中,但当 handler method 执行时还不在 request 对象中。的确,handler method 执行之后,下个视图(本例中为 nextpage.jsp)显示之前为止,Spring 都没有将 model 数据作为 attribute 加入 request 中。

技术分享

也可以通过输出存储在 index.jsp 与 nextpage.jsp 的 HttpServletRequest 中的 attribute 展现出来。我在两个页面中都布置了一个 JSP 代码块(如下面所示),用以展现 HttpServletRequest 的 attribute。

<HR />
<H3>REQUEST SCOPE (KEY==VALUES)</H3>
<%
    JAVA.UTIL.ENUMERATION<STRING> REQENUM = REQUEST.GETATTRIBUTENAMES();
    WHILE (REQENUM.HASMOREELEMENTS()) {
        STRING S = REQENUM.NEXTELEMENT();
        OUT.PRINT(S);
        OUT.PRINTLN("==" + REQUEST.GETATTRIBUTE(S));
%><BR />
<%
    }
%>

当应用启动,index.jsp 加载完毕,你可以看到在 request 作用域中没有 attribute。

技术分享

在本例中,当『do something』被点击时执行 MyController 的 handler method,然后会跳转并展示 nextpage.jsp。而 nextpage.jsp 中已经编写了相同的 JSP 代码块,同样提供了 request 作用域中的 attribute。瞧,当 nextpage.jsp 渲染后,显示出在 controller 中创建的 MyCommandBean model 被加进 HttpServletRequest 作用域中了!Spring model attribute 的键值『myRequestObject』被复制后用作 request attribute 的键值。

技术分享

所以下一个视图呈现之前,Spring model 数据已经在 handler method 执行之前(或者之间)被拷贝给了 HttpServletRequest。

使用 SPRING MODEL 与 REQUEST 的原因

你或许想知道为什么 Spring 使用 model attribute。为何不直接把数据加到 request 对象里?我在 Rod Johnson 等人的书籍《Professional Java Development with the Spring Framework》中找到了答案。这本书关于 Spring API 的部分有一点过时(基于 Spring 2.0 编写),但是我发现该书提供了一些对于 Spring 引擎运行的扩展解释。下面是书中 model 元素部分的引用:

直接将元素加入 HttpServletRequest(像 request attributes 一样)看起来就像在服务同样的目标。这样做的理由是当看到我们为 MVC 框架设置的 requirements 时,能够更明确。它应尽可能与视图无关,这意味着我们可以合并视图技术,并不受 HttpServletRequest 的束缚。

SPRING 的 @SESSIONATTRIBUTES

所以现在你知道了 Spring 如何管理 model 数据,与如何连接标准的 Http request attribute 数据。那么关于 Spring 的 session 数据呢?

Spring 的 @SessionAttribute 在 controller 中用来指定哪一个 model attributes 需要存储到 session。事实上,Spring 文档声明了 @SessionAttributes 注解『列举需要显式地存储 session 或一些交互用的存储空间内的 model attributes 名称。』另外说一下,『一些交互存储空间』表明了 Spring MVC 试图保持与技术无关联的设计思想。

事实上,@SessionAttributes 允许你做的就是告诉 Spring 哪一个 model attributes 将在视图展现之前一同拷贝给 HttpSession。关于这一点同样可以用一个简短的代码来展示。

在 index.jsp 和 nextpage.jsp 中,我添加了额外的 JSP 代码块,使其显示 HttpSession attributes。

<H3>SESSION SCOPE (KEY==VALUES)</H3>
<%
  JAVA.UTIL.ENUMERATION<STRING> SESSENUM = REQUEST.GETSESSION()
    .GETATTRIBUTENAMES();
  WHILE (SESSENUM.HASMOREELEMENTS()) {
    STRING S = SESSENUM.NEXTELEMENT();
    OUT.PRINT(S);
    OUT.PRINTLN("==" + REQUEST.GETSESSION().GETATTRIBUTE(S));
%><BR />
<%
  }
%>

我使用 @SessionAttributes 注解 MyController,使其将同一个 model attributes(myRequestObject)放入 Spring session 中。

@CONTROLLER
@SESSIONATTRIBUTES("MYREQUESTOBJECT")
PUBLIC CLASS MYCONTROLLER {
  ...
}

另外在 controller 的 handler method 中添加代码显示 HttpSession 中的 attributes(就像显示 HttpServletRequest 中的 attributes 一样)。

@SUPPRESSWARNINGS("RAWTYPES")
@REQUESTMAPPING("/DOSOMETHING")
PUBLIC STRING REQUESTHANDLINGMETHOD(MODEL MODEL, HTTPSERVLETREQUEST REQUEST, HTTPSESSION SESSION) {
  SYSTEM.OUT.PRINTLN("INSIDE OF DOSOMETHING HANDLER METHOD");

  SYSTEM.OUT.PRINTLN("--- MODEL DATA ---");
  MAP MODELMAP = MODEL.ASMAP();
  FOR (OBJECT MODELKEY : MODELMAP.KEYSET()) {
    OBJECT MODELVALUE = MODELMAP.GET(MODELKEY);
    SYSTEM.OUT.PRINTLN(MODELKEY + " -- " + MODELVALUE);
  }

  SYSTEM.OUT.PRINTLN("=== REQUEST DATA ===");
  JAVA.UTIL.ENUMERATION<STRING> REQENUM = REQUEST.GETATTRIBUTENAMES();
  WHILE (REQENUM.HASMOREELEMENTS()) {
    STRING S = REQENUM.NEXTELEMENT();
    SYSTEM.OUT.PRINTLN(S);
    SYSTEM.OUT.PRINTLN("==" + REQUEST.GETATTRIBUTE(S));
  }

  SYSTEM.OUT.PRINTLN("*** SESSION DATA ***");
  ENUMERATION<STRING> E = SESSION.GETATTRIBUTENAMES();
  WHILE (E.HASMOREELEMENTS()){
    STRING S = E.NEXTELEMENT();
    SYSTEM.OUT.PRINTLN(S);
    SYSTEM.OUT.PRINTLN("**" + SESSION.GETATTRIBUTE(S));
  }

  RETURN "NEXTPAGE";
}

现在,我们可以看见加上 @SessionAttributes 注解后,Spring MVC 处理一个 HTTP 请求之前、之间和之后的 session 对象情况。下面显示了结果。首先,当 index.jsp 显示时(请求被 Spring MVC 发送和处理之前),我们可以看见 HttpServletRequest 和 HttpSession 都没有 attribute 数据。

技术分享

handler method 执行时(requestHandlingMethod),你可以看见 MyCommandBean 被添加进 Spring model attributes,但是还没有加入 HttpServletRequest 或 HttpSession 作用域。

技术分享

但是 handler method 执行后和 nextpage.jsp 显示时,你可以看见 model attribute 数据(MyCommandBean)已经作为一个 attribute 被复制给了 HttpServletRequest 和 HttpSession(拥有相同的 attribute key)。

技术分享

控制 SESSION ATTRIBUTES

现在你已经理解了 Spring model 和 session attribute 数据如何添加进 HttpServletRequest 与 HttpSession。或许又开始关心怎么管理 Spring session 中的数据。Spring 提供了一个方法移除 Spring session attributes,同时也会从 HttpSession 中移除(不需要删除整个 HttpSession)。简单地将一个 Spring SessionStatus 对象作为参数加入一个 controller handler method 中。在此方法中,使用 SessionStatus 对象结束这个 Spring session。

@REQUESTMAPPING("/ENDSESSION")
PUBLIC STRING NEXTHANDLINGMETHOD2(SESSIONSTATUS STATUS){
  STATUS.SETCOMPLETE();
  RETURN "LASTPAGE";
}

总结

希望这篇文章能够帮助你理解 Spring model 和 session attributes。这并不神奇,仅仅是一个理解 HttpSession 和 HttpServletRequest 如何存储 Spring model 和 session attributes 的问题。我已经将展示用的代码放在了 Intertech Web site 上。如果你对继续探索与理解 Spring model 和 session 感兴趣,尽管从这里下载吧。

 

以上是关于如何理解MVC中的Model?的主要内容,如果未能解决你的问题,请参考以下文章

Android 中的MVC MVP MVVM

iOS开发之理解iOS中的MVC设计模式

php的tp框架和mvc有什么区别?

干货理解理解javascript中实现MVC的原理

MV*模式的个人理解

MVC 5 视图中的@model 和 Model 是啥