Spring Web MVC(二)

  1. 云栖社区>
  2. 博客>
  3. 正文

Spring Web MVC(二)

龙神之怒 2017-08-24 21:18:00 浏览1014
展开阅读全文

五大核心组件

Controller (处理器、控制器)

  控制器的概念是MVC设计模式的一部分(确切地说,是MVC中的C)。应用程序的行为通常被定义为服务接口, 而控制器使得用户可以访问应用所提供的服务。控制器解析用户输入,并将其转换成合理的模型数据,从而可以进一步由视图展示给用户。

  Spring控制器架构的基础是org.springframework.mvc.Controller接口,Controller接口仅仅声明了一个方法,它负责处理请求并返回合适的模型和视图。Controller接口仅仅定义了每个控制器都必须提供的基本功能: 处理请求并返回一个模型和一个视图。

MVC(补充)

模式一:
这里写图片描述

模式二:
这里写图片描述

  MVC模式是经典的设计模式,是代码的分层思想:
   1.M:Moder,即业务层,用来处理业务。
   2.V:View,即视图层,用来显示数据。
   3.C:Controller,即控制层,用来管理和调度程序,它是M和V的桥梁。
其目的是降低代码之间的耦合度,便于团队开发和维护。

Spring MVC实现的基础
  就是这三个概念:Mdel、View(ModelAndView)以及 Controller。虽然 Controller接口是完全抽象的,但Spring也提供了许多你可能会用到的控制器。Controller接口仅仅定义了每个控制器都必须提供的基本功能: 处理请求并返回一个模型和一个视图。

AbstractController 和 WebContentGenerator

所有的Spring控制器都继承了 AbstractController ,AbstractController 提供了诸如缓存支持和mimetype设置这样的功能。

功能 描述
supportedMethods 指定这个控制器应该接受什么样的请求方法。通常它被设置成同时支持GET和POST,但是可以选择你想支持的方法。如果控制器不支持请求发送的方法, 客户端会得到通知(通常是抛出一个ServletException)。
requiresSession 表明这个控制器是否需要HTTP session才能正常工作。如果控制器在没有session的情况下接收到请求,客户端会因为抛出ServletException 而得到通知。
synchronizeOnSession 指定controller是否同步用户的HTTP session。
cacheSeconds 指定controller通知客户端对数据内容缓存的秒数,一般为大于零的整数。默认值为-1,即不缓存。
useExpiresHeader 指定Controller在响应请求时是否兼容HTTP 1.0 Expires header。缺省值为true。
useCacheHeader 指定Controller在相应请求时是否兼容HTTP 1.1 Cache-Control header。默认值为true。

当从AbstractController**继承时只需要实现handleRequestInternal**(HttpServletRequest, HttpServletResponse)抽象方法,该方法将用来实现自定义的逻辑,并返回一个ModelAndView对象。

当从AbstractController继承时,只需要实现handleRequestInternal(HttpServletRequest, HttpServletResponse)抽象方法,该方法将用来实现自定义的逻辑,并返回一个ModelAndView对象。
例子演示 了如何从AbstractController继承以及如何在applicationContext.xml中进行配置。

package samples;

public class SampleController extends AbstractController {

    public ModelAndView handleRequestInternal(
        HttpServletRequest request,
        HttpServletResponse response) throws Exception {

        ModelAndView mav = new ModelAndView("hello");
        mav.addObject("message", "Hello World!");
        return mav;        
    }
}
<bean id="sampleController" class="samples.SampleController">
    <property name="cacheSeconds" value="120"/>
</bean>

其它的简单控制器

尽管可以继承AbstractController来实现自己的控制器,不过Spring提供的众多控制器减轻了我们开发简单MVC应用时的负担。 ParameterizableViewController基本上和上面例子中的一样,不同的是,可以在application context中指定返回的视图名称(从而 避免了在Java代码中的硬编码)。

UrlFilenameViewController会检查URL,获取文件请求的文件名,并把它作为视图名加以使用。。
例如
http://www.springframework.org/index.html
对应的视图文件名是index

MultiActionController

  MultiActionController来将多个请求处理方法合并在一个控制器里,这样可以把相关功能组合在一起。位于org.springframework.web.mvc.multiaction包中,它可以定义页面

请求到控制器方法名的映射, 然后在处理相应请求时调用该方法。
  当你有很多比较小的且相关的功能时使用MultiActionController很方便,这样就不必为每个小功能创建 一个单独的Controller了。

  MultiActionController有两种使用方式

  •   一是创建MultiActionController的子类,并指定将被 MethodNameResolver解析的方法(这种情况下不需要这个delegate参数);

  •   二是定义一个委托对象, MethodNameResolver解析出目标方法后将调用该对象的相应方法。这种情况下需要定义MultiActionController 的实例并将委托对象作为协作者注入(可通过构造参数或者setDelegate方法)。

       MultiActionController需要一种策略,使其可以通过解析请求信息来获得要调用的方法。这个解析策略由* MethodNameResolver接口*定义。MultiActionController提供了’methodNameResolver’ 属性使得你可以注入需要的MethodNameResolver。在自己的MultiActionController(或者前面说的委托对象) 上定义的请求处理方法必须符合如下签名:

说明:’anyMeaningfulName’指任意方法名
public [ModelAndView | Map | void] anyMeaningfulName(HttpServletRequest, HttpServletResponse [,HttpSession] [,AnyObject])

注意:接受一个AnyObject参数,这个参数包含从请求中抽取出来的信息,并且要求请求中已经存在一个 合法的session对象。注意参数的顺序很重要:session必须是第三个参数,而绑定参数必须是final的,并位于session之后。

命令控制器(command controllers)重点

  命令控制器提供了一种和数据对象交互的方式,并动态地将来自HttpServletRequest的参数绑定到指定的数据对象上。 它的功能和Struts中的ActionForm有点像,不过在Spring中,不需要实现任何接口来实现数据绑定。

AbstractCommandController ####

  可以使用该抽象命令控制器来创建自己的命令控制器,它能够将请求参数绑定到指定的命令对象

  这个类并不提供任何表单功能,但是它提供验证功能,并且让你在控制器中去实现如何处理由请求参数值产生的命令对象。

AbstractFormController

  一个支持表单提交的抽象控制器类。 使用这个控制器,可以定义表单,并使用从控制器获取的数据对象构建表单

  当用户输入表单内容,AbstractFormController将用户输入的内容绑定到命令对象,验证表单内容, 并将该对象交给控制器,完成相应的操作。它支持的功能有防止重复提交、表单验证以及一般的表单处理流程
  子类需要实现自己的方法来指定采用哪个视图来显示输入表单,哪个视图显示表单正确提交后的结果。 如果需要表单,但不想在应用上下文中指定显示给用户的视图,可使用该控制器。

SimpleFormController

  这是一个form controller,当需要根据命令对象来创建相应的form的时候,该类可以提供更多的支持。 可以为其指定一个命令对象,显示表单的视图名,当表单提交成功后显示给用户的视图名等等。

AbstractWizardFormController

  这是一个抽象类,继承这个类需要实现validatePage()、processFinish() 和processCancel() 方法。

  你有可能也需要写一个contractor,它至少需要调用setPages()和setCommandName()方法。setPages()的参数是一个String数组,这个数组包含了组成向导的视图名。 setCommandName()的参数是一个String,该参数将用来在视图中调用你的命令对象。

  和AbstractFormController的实例一样, 需要使用命令对象(其实就是一个JavaBean, 这个bean中包含了表单的信息)。 这里有两个选择:在构造函数中调用setCommandClass()方法(参数是命令对象的类名),或者实现formBackingObject()方法。

  AbstractWizardFormController 有多个可以覆写(override)的方法。 最有用的一个是referenceData(..)。 这个方法允许把模型数据以Map的格式传递给视图;getTargetPage() 允许动态地更改向导的页面顺序, 或者直接跳过某些页面;onBindAndValidate() 允许覆写内置的绑定和验证流程。

ViewResolver和View (视图与视图解析器)

  ViewResolver和View是Spring的视图处理方式中特别重要的两个接口。 ViewResolver提供了从视图名称到实际视图的映射。 View处理请求的准备工作,并将该请求提交给某种具体的视图技术。

视图解析器(ViewResolver)

SpringWeb框架的所有控制器都返回一个ModelAndView实例。 Sprnig中的视图以名字为标识,视图解析器通过名字来解析视图。

ViewResolver 描述
AbstractCachingViewResolver 抽象视图解析器实现了对视图的缓存。在视图被使用之前,通常需要进行一些准备工作。 从它继承的视图解析器将对要解析的视图进行缓存。
XmlViewResolver XmlViewResolver实现ViewResolver,支持XML格式的配置文件。 该配置文件必须采用与Spring XML Bean Factory相同的DTD。默认的配置文件是 /WEB-INF/views.xml。
ResourceBundleViewResolver ResourceBundleViewResolver实现ViewResolver, 在一个ResourceBundle中寻找所需bean的定义。 这个bundle通常定义在一个位于classpath中的属性文件中。默认的属性文件是views.properties。
UrlBasedViewResolver UrlBasedViewResolver实现ViewResolver, 将视图名直接解析成对应的URL,不需要显式的映射定义。 如果你的视图名和视图资源的名字是一致的,就可使用该解析器,而无需进行映射。
InternalResourceViewResolver 作为UrlBasedViewResolver的子类, 它支持InternalResourceView(对Servlet和JSP的包装), 以及其子类JstlView和TilesView。 通过setViewClass方法,可以指定用于该解析器生成视图使用的视图类。 更多信息请参考UrlBasedViewResolver的Javadoc。
VelocityViewResolver / FreeMarkerViewResolver 作为UrlBasedViewResolver的子类, 它能支持VelocityView(对Velocity模版的包装)和FreeMarkerView以及它们的子类。

  当使用JSP作为视图层技术时,就可以使用UrlBasedViewResolver。 这个视图解析器会将视图名解析成URL,并将请求传递给RequestDispatcher来显示视图。

<bean id="viewResolver"
      class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>

  当返回的视图名为test时, 这个视图解析器将请求传递给RequestDispatcher,RequestDispatcher再将请求传递给/WEB-INF/jsp/test.jsp。

  当在一个web应用中混合使用不同的视图技术时,可以使用ResourceBundleViewResolver:

<bean id="viewResolver"
      class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
    <property name="basename" value="views"/>
    <property name="defaultParentView" value="parentView"/>
</bean

  ResourceBundleViewResolver通过basename所指定的ResourceBundle解析视图名。 对每个待解析的视图,ResourceBundle里的[视图名].class所对应的值就是实现该视图的类。 同样,[视图名].url所对应的值是该视图所对应的URL。

  从上面的例子里能够发现,可以指定一个parent view,其它的视图都可以从parent view扩展。用这种方法,可以声明一个默认的视图。

视图解析链

  Spring支持多个视图解析器一起使用。可以把它们当作一个解析链
  这样有很多好处,比如在特定情况下重新定义某些视图。 定义视图解析链很容易,只要在应用上下文中定义多个解析器就可以了。 必要时,也可以通过order属性来声明每个解析器的序列。 要记住的是,某个解析器的order越高, 它在解析链中的位置越靠后

  例子:展示了一个包含两个解析器的解析链。 一个是InternalResourceViewResolver,这个解析器总是被自动的放到链的末端。 另一个是XmlViewResolver,它支持解析Excel视图(而InternalResourceViewResolver不可以)。

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
  <property name="prefix" value="/WEB-INF/jsp/"/>
  <property name="suffix" value=".jsp"/>
</bean>

<bean id="excelViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
  <property name="order" value="1"/>
  <property name="location" value="/WEB-INF/views.xml"/>
</bean>

<!-- in views.xml -->

<beans>
  <bean name="report" class="org.springframework.example.ReportExcelView"/>
</beans>

  如果某个解析器没有找到合适的视图,Spring会在上下文中寻找是否配置了其它的解析器。 如果有,它会继续进行解析,否则,Srping会抛出一个Exception。
  当一个视图解析器找不到合适的视图时,它可能 返回null值。

重定向(Rediret)

RedirectView
在控制器中强制重定向的方法之一是让控制器创建并返回一个Spring的RedirectView的实例。 在这种情况下,DispatcherServlet不会使用通常的视图解析机制, 既然它已经拿到了一个(重定向)视图,它就让这个视图去完成余下的工作。
RedirectView会调用HttpServletResponse.sendRedirect()方法, 其结果是给用户的浏览器发回一个HTTP redirect。所有的模型属性都被转换成以HTTP请求的访问参数。

redirect:前缀

  redirect:/my/response/controller.html这个逻辑视图名中的URL是当前servlet context中的相对路径。
  redirect:http ://myhost.com/some/arbitrary/path.html中的URL是绝对路径。
   如果返回的视图名包含redirect:前缀,UrlBasedViewResolver (以及它的子类) 会知道系统要生成一个HTTP redirect。 视图名其余的部分会被当作重定向URL。

forward:前缀

  使用包含有forward:前缀的视图名,这些视图名会被UrlBasedViewResolver和它的子类正确解析。 解析的内部实现是生成一个InternalResourceView, 这个视图最终会调用RequestDispatcher.forward()方法,将forward视图名的其余部分作为URL。 所以,当使用InternalResourceViewResolver/InternalResourceView, 并且你所用的视图技术是JSP时,你没有必要使用这个前缀。 但是,当你主要使用其它的视图技术,但仍需要对Servlet/JSP engine处理的页面强制forward时

 如果含有redirect和forward前缀的视图名和其他视图名一样被注入控制器, 控制器根本不需要知道在处理响应的过程中是否发生任何特殊情况

视图

对模型的支持:ModelMap(ModelAndView)

  ModelMap类首先是一个绚丽的Map实现, 它可以使新增的将要显示在View中(或上)的对象也遵循同一命名规范。 考虑下面的Controller实现,注意对象被加入ModelAndView, 而并没有指定任何名称。

public class DisplayShoppingCartController implements Controller {

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {

        List cartItems = // get a List of CartItem objects
        User user = // get the User doing the shopping

        ModelAndView mav = new ModelAndView("displayShoppingCart"); <-- the logical view name

        mav.addObject(cartItems); <-- look ma, no name, just the object
        mav.addObject(user); <-- and again ma!

        return mav;
    }
}

  ModelAndView类使用的ModelMap类是一个自定义的Map的实现。 当有一个新对象加入的时候,它就被用于为这个对象自动生成一个键。 决定某个加入的对象的名字的策略是,当它是一个标量对象(scalar object),比如User时, 就使用这个对象所属类的简短类名。

对视图的支持:RequestToViewNameTranslator

RequestToViewNameTranslator接口的功能是当没有显式的提供这样一个逻辑视图名称的时候, 确定一个逻辑的View名称。 这个接口只有一个实现,精明的命名为DefaultRequestToViewNameTranslator。

public class RegistrationController implements Controller {

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
        // process the request...
        ModelAndView mav = new ModelAndView();
        // add data as necessary to the model...
        return mav;
        // notice that no View or logical view name has been set
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
        "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>

    <!-- this bean with the well known name generates view names for us -->
    <bean id="viewNameTranslator" class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator"/>

    <bean class="x.y.RegistrationController">
        <!-- inject dependencies as necessary -->
    </bean>

    <!-- maps request URLs to Controller names -->
    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

  在这个handleRequest(..)方法的实现中, 没有在返回的ModelAndView上设置任何的View或者逻辑视图名称。 而是把从请求的URL生成一个逻辑视图名称的任务交给了DefaultRequestToViewNameTranslator。 在上面这个RegistrationController与ControllerClassNameHandlerMapping联合使用的例子中, 一个“http://localhost/registration.html”请求URL将会由DefaultRequestToViewNameTranslator生成一个“registration”逻辑视图名称。 这个逻辑视图名称接下来就会被InternalResourceViewResolver bean解析为“/WEB-INF/jsp/registration.jsp”视图。

网友评论

登录后评论
0/500
评论