`

SpringMVC中的HandlerMapping、ModelAndView、Adapter

 
阅读更多

一、原始代码(不用注解的情况)

(1)web.xml配置

 

<servlet>

    <servlet-name>spring</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <init-param>

      <param-name>contextConfigLocation</param-name>

      <param-value>/WEB-INF/framework/spring-config/SpringMVC-config.xml</param-value>

    </init-param>

    <load-on-startup>1</load-on-startup>

  </servlet>

  <servlet-mapping>

    <servlet-name>spring</servlet-name>

    <url-pattern>*.htm</url-pattern>  --如果这里写成/,会拦截所有请求,包括css和img文件

  </servlet-mapping>

 

(2)SpringMVC配置

 

    <!-- 自动扫描的包名。 通过component-scan 让Spring扫描org.swinglife.controller下的所有的类,

                      让Spring的代码注解生效 -->  

    <context:component-scan base-package="com.common.bssp"></context:component-scan>  

 

<!-- 注释类型Adapter -->

<beans:bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> 

    

    <!-- 配置Adapter -->

    <beans:bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />

     

    <!-- 配置SpringMVC的视图渲染器, 让其前缀为:/ 后缀为.jsp  将视图渲染到/page/<method返回值>.jsp中 -->  

    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  

    <beans:property name="prefix" value="/WEB-INF/app/" />  

  <beans:property name="suffix" value=".jsp" />  

</beans:bean> 

 

<!-- bean的配置,可以和上面的可以写在同一个文件xml文件,也可以分开写 -->

<bean id="handlerMapping" 

    class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

        <property name="mappings">

            <props>

                <prop key="/toHomePage.htm">loginAction</prop>

            </props>

        </property>

    </bean> 

    

 

     <bean id="loginAction"  

        class="com.common.bssp.home.struts.action.LoginController" >

        <property name="success">

            <value>home/jsp/homePage</value>

        </property>   

        <property name="welcome">

            <value>home/jsp/homePage</value>

        </property>  

     </bean>   

     

    因为controller中返回的是 return new ModelAndView(success) ,所以要在上面配置路径(见下面);

如果返回的是return new ModelAndView(“success”) 或者 return new ModelAndView("home/jsp/homePage");  则直接拼接上.jsp返回。

所以带双引号和不带双引号是有区别的。

 

(3)controller代码

public class LoginController extends AbstractController{  

 

//跳转地址可配置,在home-spring-config.xml文件中

private String success;

private String welcome;

   

@RequestMapping("toHomePage.htm")

public ModelAndView loginSuccess()

{

       return new ModelAndView("home/jsp/homePage"); 

}

 

 

 

 

 

//旧方法

@Override  

    protected ModelAndView handleRequestInternal(HttpServletRequest request,  

            HttpServletResponse response) throws Exception 

    { 

        return new ModelAndView(success);   //返回的路径,通过xml配置文件找,相当于把路径从xml文件注入。

                                                                                          //如果这里是双引号,则直接匹配jsp文件,上面的bean id="loginAction" 

                                                                                         //去掉 property属性

    } 

 

public String getSuccess() {

return success;

}

public void setSuccess(String success) {

this.success = success;

}

public String getWelcome() {

return welcome;

}

public void setWelcome(String welcome) {

this.welcome = welcome;

}

 

==============================以下是深入学习==========================

一、SpringMVC中的HandlerMapping

DispatcherServlet要将一个请求交给哪个特定的Controller,它需要咨询一个Bean——这个Bean的名字为“HandlerMapping”。

HandlerMapping是把一个URL指定到一个Controller上,(就像应用系统的web.xml文件使用<servlet-mapping>URL映射到servlet)。

Spring带有三种HandlerMapping,(SpringMVC中的所有HandlerMapping都实现了接口org.springframework.web.servlet. HandlerMapping)。

1BeanNameUrlHandlerMapping

这是Dispatcher Servlet的默认的HandlerMapping,所以在应用上下文配置文件中简单地用“Url样式”来定义一个控制器Bean的名字,就可以告诉Dispatcher Servlet什么样式的请求应该由哪个控制器去处理,而不用显式地定义一个HandlerMapping(私下说一句,这样做虽然简单,但这样用URL样式定义出来的ControllerBean,其名字显得古怪,因为这个名字同时也是Controller Bean的实例名)

例:若控制器ListCoursesControllerURL样式是“listCourses.go”,则

       <bean name="/listCourses.go"

class="com.w3cs.vlar.ListCoursesController">

        <property name="couseService">

             <ref bean="courceService"/>

        </property>

    </bean>

当然,也可以在定义这个控制器Bean之前,显式地声明你所用的HandlerMapping,显式定义如下:

<bean id="beanNameUrlMapping"

class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">

 

2SimpleUrlHandlerMapping

这种方式不同于BeanNameUrlHandlerMappingSimpleUrlHandlerMapping不需定义Controller Bean的名字,而是直接把URL映射到控制器。

由于SimpleUrlHandlerMapping不是Dispatcher Servlet默认的HandlerMapping,所以这个HandlerMapping必须得显式定义。

下面定义了一个ID为“SimpleUrl”的HandlerMapping Bean

<bean id="simpleUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

<property name="mappings">

<props>

    <prop key="/listCourses.go">listCoursesController</prop>

    <prop key="/login.go">loginController</prop>

</props>

</property>

</bean>

解释:

1)、SimpleUrlHandlerMapping中,用<prop>装配了一个名为mappings的java.util.Properties。

2)、<prop>元素的key属性是URL样式,而<prop>的值是处理这个URL的控制器Bean的名字。(而在BeanNameUrlMapping中的那个古怪的名字是控制器Bean的实例名)。

 

3CommonsPathMapHandlerMapping

这个处理器使用控制器代码中的元数据将控制器映射到URL。但具体俺不会用。谁知道了可以告诉俺!!!

 

 

SimpleUrlHandlerMapping(有三种配法)

使用背景:
第一步>>>
在包com.spring.web.controller下创建一个Controller: LoginConstroller
public class LoginController  extends AbstractController{
    
    public ModelAndView handleRequestInternal(HttpServletRequest request,
           HttpServletResponse response)throws Exception{
        
        String userName=request.getParameter("username");
        String pwd=request.getParameter("pwd");
        
        String msg="";
        ModelAndView mav=new ModelAndView("loginResult");        //注意要在/WEB-INF/jsp下面创建loginResult.jsp页面
        if(!userName.equals("liuxi")){
            msg="用户名不存在!";
        }else if(!pwd.equals("8888")){
            msg="密码不正确!";    
            
        }else{
            msg="恭喜您登录成功!";
        }
        
        
        mav.addObject("msg",msg);
        return mav;
    }

}

第二步>>>>
配置web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    
    
    <servlet>
       <servlet-name>sample</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       
    </servlet>
    
    <servlet-mapping>
       <servlet-name>sample</servlet-name>
       <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

第三步>>>>
配置sample-servlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
    
   <bean id="loginController" class="com.spring.web.controller.LoginController"/>
   
 
   <bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
   <!-- 配置方法一
     <property name="urlMap">
         <map>
            <entry key="/user/login.do" value-ref="loginController"/>
         </map>
     </property>
  -->
  <!-- 配置方法二
    <property name="mappings">
       <bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
           <property name="location">
              <value>urlMap.properties</value>  <!-- 此时urlMap.properties文件应放在WebRoot目录下! -->
           </property>
       </bean>
    </property>
   -->
   <!-- 配置方法三 -->
     <property name="mappings">
        <props>
           <prop key="/user/login.do">loginController</prop>
        </props>
     </property>
  </bean>
  
   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
     <property name="prefix"><value>/WEB-INF/jsp/</value></property>
     <property name="suffix"><value>.jsp</value></property>
     <property name="viewClass">
       <value>
        org.springframework.web.servlet.view.JstlView
       </value>
     </property>
   </bean>  
   

</beans>

 

 

二、在Spring配置文件中配置HandlerMapping、HandlerAdapter子类的区别

java代码:
Java代码  收藏代码
  1. <!-- HandlerMapping -->  
  2. <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>  
  3.    
  4. <!-- HandlerAdapter -->  
  5. <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>  

 

BeanNameUrlHandlerMapping:表示将请求的URL和Bean名字映射,如URL为 “上下文/hello”,则Spring配置文件必须有一个名字为“/hello”的Bean,上下文默认忽略。

SimpleControllerHandlerAdapter:表示所有实现了org.springframework.web.servlet.mvc.Controller接口的Bean可以作为Spring Web MVC中的处理器。如果需要其他类型的处理器可以通过实现HadlerAdapter来解决。

 

三、ModelAndView详解

当控制器处理完请求时,通常会将包含视图名称或视图对象以及一些模型属性的ModelAndView对象返回到DispatcherServlet。

因此,经常需要在控制器中构造ModelAndView对象。ModelAndView类提供了几个重载的构造器和一些方便的方法,

让你可以根据自己的喜好来构造ModelAndView对象。这些构造器和方法以类似的方式支持视图名称和视图对象。

当你只有一个模型属性要返回时,可以在构造器中指定该属性来构造ModelAndView对象

 

在上篇的基础上,只修改Login类

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
 
  1. package com.itmyhome;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7.   
  8. import org.springframework.stereotype.Controller;  
  9. import org.springframework.web.bind.annotation.RequestMapping;  
  10. import org.springframework.web.servlet.ModelAndView;  
  11.   
  12. @Controller  
  13. public class Login {  
  14.   
  15.     @RequestMapping(value="login")  
  16.     public ModelAndView login(){  
  17.         ModelAndView mav = new ModelAndView();  
  18.         mav.setViewName("welcome"); //返回的文件名  
  19.           
  20.         mav.addObject("message","hello kitty");  
  21.           
  22.         //List  
  23.         List<String> list = new ArrayList<String>();  
  24.         list.add("java");  
  25.         list.add("c++");  
  26.         list.add("oracle");  
  27.         mav.addObject("bookList", list);  
  28.           
  29.         //Map  
  30.         Map<String,String> map = new HashMap<String,String>();  
  31.         map.put("zhangsan""北京");  
  32.         map.put("lisi""上海");  
  33.         map.put("wangwu""深圳");  
  34.         mav.addObject("map",map);  
  35.           
  36.         return mav;  
  37.     }  
  38. }  

亦或如下方法来构建你的ModelAndView对象

 

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
 
  1. @RequestMapping(value="logout")  
  2. public ModelAndView logout(){  
  3.     String message = "欢迎下次光临!";  
  4.     return new ModelAndView("logout","message",message);  
  5. }  

 

然后修改welcome.jsp输出数据

遍历集合可使用jstl表达式,需在jsp中引入头文件

 

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
 
  1. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>  
lib下导入jstl.jar和standard.jar

 

首先这两个jar在哪里可以找到,当然可以在网上下载。

另外在tomcat下面就有,在\webapps\examples\WEB-INF\lib

前提是你还没有把webapps下面的一些无用项目删掉。

 

welcome.jsp

 

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
 
  1. <body>  
  2.    <!-- 输出普通字符 -->  
  3.    ${message } <br/>  
  4.    <!-- 输出List -->  
  5.    <p>书籍列表</p>  
  6.    <c:forEach items="${bookList}" var="node">  
  7.         <c:out value="${node}"></c:out>  
  8.    </c:forEach>  
  9.    <br/>  
  10.    <br/>  
  11.      
  12.    <!-- 输出Map -->  
  13.    <c:forEach items="${map}" var="node">  
  14.         姓名:<c:out value="${node.key}"></c:out>  
  15.         住址:<c:out value="${node.value}"></c:out>  
  16.         <br/>  
  17.    </c:forEach>  
  18. </body>  

 

结果如图:

 

ModelAndView详解

    ModelAndView的构造方法有7个。但是它们都是相通的。这里使用无参构造函数来举例说明如何构造ModelAndView实例。   
    ModelAndView类别就如其名称所示,是代表了MVC Web程序中Model与View的对象,不过它只是方便您一次返回这两个对象的holder,Model与View两者仍是分离的概念。 
  最简单的ModelAndView是持有View的名称返回,之后View名称被view resolver,也就是实作org.springframework.web.servlet.View接口的实例解析,例如 InternalResourceView或JstlView等等:

ModelAndView(String viewName)


 如果您要返回Model对象,则可以使用Map来收集这些Model对象,然后设定给ModelAndView,使用下面这个版本的ModelAndView:

ModelAndView(String viewName, Map model)


 Map对象中设定好key与value值,之后可以在视图中取出,如果您只是要返回一个Model对象,则可以使用下面这个ModelAndView版本:

ModelAndView(String viewName, String modelName, Object modelObject)


 藉由modelName,您可以在视图中取出Model并显示。 
 ModelAndView类别提供实作View接口的对象来作View的参数:

ModelAndView(View view)

ModelAndView(View view, Map model)

ModelAndView(View view, String modelName, Object modelObject)


  一个例子是org.springframework.web.servlet.view.RedirectView,ModelAndView预设是使 用forward来转发请求结果至视图,使用RedirectView的话,则会使用redirect将请求重导至视图,例如:

public ModelAndView handleRequest(....) … {

    ....

   

    return new ModelAndView(new RedirectView(this.getViewPage()));

}

....


  在这边,viewPage的地址是从服务器网页根目录开始指定,而不是Web应用程序的根目录,所以您的getViewPage()传回的地址必须像是 /springapp/pages/index.htm这样的地址,其中springapp是您的Web应用程序目录。 
 使用forward的话,网址列上并不会出现被转发的目标地址,而且forward是在Web应用程序之内进行,可以访问Web应用程序的隐藏目录,像是WEB-INF,然而forward只能在Web应用程序中进行,不能指定至其它的Web应用程序地址。 
  使用redirect的话,是要求客户端浏览器重新发出一个指定的请求地址,因此网址列上会出现被重导的目录地址,重导的请求是由浏览器发出,所以不能 访问Web应用程序中的隐藏目录,像是WEB-INF,然而重导是重新要求一个网页,所以可以指定至其它的Web应用程序地址。 
  DispatcherServlet会根据传回的ModelAndView来解析View名称,并处理给予的Model。View名称的解析是委托给实 作org.springframework.web.servlet.ViewResolver接口的实例,ViewResolver接口定义如下:

public interface ViewResolver {

    public view resolveViewName(String, Locale locale) throws ServletException;

}


  ViewResolver的一个实例是InternalResourceViewResolver,名称解析完之后,实际的View绘制与Model转 换处理是交给实作org.springframework.web.servlet.View的实例,View接口如下:

public interface View {

    public void render(Map model, HttpServletResquest resquest, HttpServletResponse response) throws ServletException, IOException;

}


 View的实作之前用过org.springframework.web.servlet.view.InternalResourceView,另外也还有JstlView、TilesView、VelocityView等等的实作,分别进行不同的表现展处理 。




ModelAndView()

    这个构造方法构造出来的ModelAndView 

不能直接使用,应为它没有指定view,也没有绑定对应的model对象。当然,model对象不是必须的,但是view确实必须的。

    用这个构造方法构造的实例主要用来在以后往其中加view设置和model对象。 

    给ModelAndView

实例设置view的方法有两

个:setViewName(String viewName) 和 setView(View view)。前者是使用view

name,后者是使用预先构造好的View对象。其中前者比较常用。事实上View是一个接口,而不是一个可以构造的具体类,我们只能通过其他途径来获取

View的实例。对于view

name,它既可以是jsp的名字,也可以是tiles定义的名字,取决于使用的ViewNameResolver如何理解这个view name。

    如何获取View的实例以后再研究。

而对应如何给ModelAndView

实例设置model则比较复杂。有三个方法可以使用:

addObject(Object modelObject)

addObject(String modelName, Object modelObject)

addAllObjects(Map modelMap)

ModelAndView

可以接收Object类型的对象,ModelAndView

将它视为其众多model中的一个。当使用Object类型的对象的时候,必须指定一个名字。ModelAndView

也可以接收没有明显名字的对象,原因在于ModelAndView

将调用spring自己定义的Conventions 类的.getVariableName()方法来为这个model生成一个名字。显然,对model而言,名字是必须的。

Conventions.getVariableName()生成名字的规则是使用对象的类名的小写模式来作model名字。当这个model是集合或数组的时候,使用集合的第一个元素的类名加s来作model的名字。

ModelAndView

也可以接收Map类型的对象,ModelAndView

将这个Map中的元素视为model,而不是把这个Map本身视为model。但是其他的集合类可以用本身作为model对象。

实际上,ModelAndView

对model的支持来自于类ModelMap,这个类继承自HashMap。

完整的例子

Java代码  收藏代码
  1. <span style="font-size: small;">public ModelAndView handleRequestInternal(  
  2.         HttpServletRequest request,  
  3.         HttpServletResponse response) throws Exception {  
  4.           
  5.   
  6. ModelAndView mav = new ModelAndView("hello");//实例化一个VIew的ModelAndView实例  
  7.   
  8. mav.addObject("message""Hello World!");//添加一个带名的model对象  
  9.   
  10.   
  11.         return mav;          
  12.       
  13.   
  14. }  
  15. </span>  

 

 

 

 

 

     

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics