spring mvc

目录

一、web.xml文件

二、spring配置文件和spring mvc配置文件

三、controller

1. 获取请求参数的方式

(1)通过url访问地址获取请求参数。

(2)通过提交表单的方式获取参数。

2.响应返回页面的方式

(1)返回String的方式

(2)返回ModelAndView

(3)通过原始的Servlet响应(重定向和转发两种方式)

3.返会数据的方式。ModelAndView、Model、Map方式返回数据

四、视图解析器和页面

ViewResolver和View介绍


spring mvc (model+view+controller)

目录

一、web.xml文件

二、spring配置文件和spring mvc配置文件

三、controller

(1)通过url访问地址获取请求参数。

(2)通过提交表单的方式获取参数。

四、视图解析器和页面


Spring mvc 

其实就是做了一件是,从浏览器发送一个 请求,经过Spring mvc后,在将响应返回至浏览器。

流程:

1.浏览器发出请求

2.请求会先到DispatcherServlet,而DispatcherServer的作用就是将请求传递给Controller控制器。但是控制器可能有多个,不知道该传递给谁,所以HandlerMapping,就是用来告诉DispatcherServer该给那个Controller

3. 所以第三步就是DispatcherServer会查询 Handler Mapping 来确定是传给控制器。

4.确定控制器后,DispatcherServer会把请求传递给Controller.

5.这时候Controller就拿到请求数据,控制器开始处理信息。处理完成后,会有一些信息需要返回给浏览器,这个信息就是Model。所以控制器Controller就会把Model包装好,同时返回逻辑视图名称,一起给DispatcherServer.

6.DispatcherServer拿到Model和逻辑视图名,会通过视图解析器(view Resolver)将逻辑视图名称解析成真正的视图名称

7.然后根据真正的视图名称,匹配一个视图View的实现。jsp或html等

一、web.xml文件

理解两个上下文

  • 根上下文,加载的配置文件(数据库层Dao,服务层service等,除web层的组件)
  • web层上下文。继承根上下文,这个一般加载web层的文件(控制层Controller、HandlerMapping、ViewResolver视图解析器等),如果需要加载配置文件。也就是说如果加载bean是在web上下文中没有找到,可以在父上下文找,反之,则不可以。
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <!--这里有两个上下文,一个是ContextLoaderListener加载时创建的Spring上下文,也称根上下文。
  另一个是加载DispatcherServlet时创建的spring上下文-->

  <!--根上下文,加载的配置文件(数据库层Dao,服务层service等,除web层的组件)-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  

  <!--web层上下文。继承根上下文,这个一般加载web层的文件(控制层Controller、HandlerMapping、ViewResolver视图解析器等),如果
  需要加载配置文件-->
  <servlet>
    <servlet-name>webApp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springMvcConfig/spring-servlet.xml</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>webApp</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  
</web-app>


二、spring配置文件和spring mvc配置文件

  • context:annotation-config  自动装载显式配置的bean,比如在xml中 用<bean> 申明的或是用javaConfig配置的bean(@Configuration @Bean),仅能够在已经在已经注册过的bean上面起作用。对于没有在spring容器中注册的bean,它并不能执行任何操作。
  •  context:component-scan 这个拥有和context:annotation-config一样的作用,同时还能加载 @Service @Component 等注解隐式的类,仅能够在已经在已经注册过的bean上面起作用。对于没有在spring容器中注册的bean,它并不能执行任何操作。 

                如果同时使用这两个配置会不会出现重复注入的情况呢?

             答案:因为< context:annotation-config />和 < context:component-scan>同时存在的时候,前者会被忽略。如@autowire,                               @resource等注入注解只会被注入一次!

  • mvc:annotation-driven 标签的shecma就能看出来,mvc,主要就是为了Spring MVC来用的,提供Controller请求转发,json自动转换等功能。相比上面的两个shecma是context开头,那么主要是解决spring**容器**的一些注解。< mvc:annotation-driven /> 是一种简写形式,完全可以手动配置替代这种简写形式,简写形式可以让初学都快速应用默认配置方案。 会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,是spring MVC为@Controllers分发请求所必须的。 并提供了:数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson)。

spring mvc配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.tzw.springmvc"></context:component-scan>

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

</beans>

spring配置文件

三、controller

package com.tzw.springmvc;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.Map;

@Controller
public class MainController {

    @RequestMapping(value = "/aa",method= RequestMethod.GET)
    public String login(Model model,Map<String,Object> map){
        model.addAttribute("clientName","tzw");
        model.addAttribute("clientNameEn,tzwEn");
        map.put("idNo","123333");
        map.put("idType","01");
        return "login";
    }

}

1. 获取请求参数的方式

(1)通过url访问地址获取请求参数。

在Controller中用这样的方式获取值。当然如果参数名称和请求中的参数名称一致,则@RequestParam可以不用写。

  //访问地址携带参数。
    @RequestMapping(value = "/user",method= RequestMethod.GET)
    public String login1(Model model, @RequestParam("username") String username){

        System.out.println("进入"+username+"界面");
        System.out.println("进入"+username+"界面");
        model.addAttribute("username",username);
        return "user";
    }

同时也可以用实例对象的方式获取值,这里用User对象获取参数。

package com.tzw.springmvc.entity;

public class User {

    public String username;
    public String password;
    public int age;
    public String name;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
//访问地址携带参数。
    @RequestMapping(value = "/user",method= RequestMethod.GET)
    public String login1(Model model, User user){

        System.out.println("进入"+user.getUsername()+"界面");
        System.out.println("进入"+user.getName()+"界面");
        model.addAttribute("username",user.username);
        return "user";
    }

//通过路径变量
    @RequestMapping(value = "/user/{username}",method= RequestMethod.GET)
    public String login1(Model model, @PathVariable String username){

        System.out.println("进入"+username+"界面");
        System.out.println("进入"+username+"界面");
        model.addAttribute("username",username);
        return "user";
    }

在controller中用{}占位符的方式获取参数。 {参数名称} 和方法中的参数名称一致,可以省去@PathVariable。但这里不能用实体对对象的方式获取。

(2)通过提交表单的方式获取参数。

可以直接用实体对象的方式获取。实体对象User上面已经展示。

@RequestMapping(value = "/register",method =POST)
    public String longUser(User user,Map<String,Object> map){

        System.out.println(user.toString());
        map.put("user",user);

        return "userInfo";
    }

 这里是jsp页面的内容。如果form 中没有定义action,则点击提交是还会访问原来的路径。

<%@ page contentType="text/html;charset=UTF-8" import="java.util.*" language="java"  isELIgnored="false"%>
<html>
<head>
    <title>${username}用户界面</title>
    <h2>我是${username}用户中心</h2>


    <form action="/guanzhuang_tzw_web_war/register" method="post">
        <h3>登陆用户</h3>
        用户名:<input type="text" name="username"/><br/>
        密码:<input type="text" name="password"/><br/>
        姓名:<input type="text" name="name"/><br/>
        年龄:<input type="text" name="age"/><br/>
        <input type="submit" value="注册">
    </form>

</head>
<body>

</body>
</html>

2.响应返回页面的方式

(1)返回String的方式


    //直接返回String视图名
    @RequestMapping(value = "/view1")
    public String  viewTest1(){

//        return "forward:user";
        return "redirect:user";
    }

小知识:返回转发和重定向两种方式。forward 和 redirect,返回的写法如上图所示。

这两种的区别是:

转发:

  1. 地址栏不发生变化,显示的是上一个页面的地址
  2. 请求次数:只有1次请求
  3. 请求域中数据不会丢失

重定向

在这里插入图片描述

  1. 地址栏:显示新的地址
  2. 请求次数:2次
  3. 请求域中的数据会丢失,因为是2次请求

(2)返回ModelAndView

注意如果使用ModelAndView时,要看清楚,不要导错包。(反正我导错过)

import org.springframework.web.servlet.ModelAndView;
  @RequestMapping(value = "/v2")
    public ModelAndView viewTest2(){

        System.out.println("进入modelAndView");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("user");

        return modelAndView;
    

(3)通过原始的Servlet响应(重定向和转发两种方式)

@RequestMapping(value="/view3")
    public void viewTest3(HttpServletRequest request, HttpServletResponse response){

        try {
            request.getRequestDispatcher("user").forward(request,response);
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @RequestMapping(value="/view4")
    public void viewTest4(HttpServletRequest request, HttpServletResponse response){

        try {

            response.sendRedirect("user");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

3.返会数据的方式。ModelAndView、Model、Map方式返回数据

@RequestMapping(value = "/v3")
    public ModelAndView viewV3(ModelAndView modelAndView){

        modelAndView.addObject("username","李四");
        modelAndView.setViewName("user");
        return modelAndView;
    }




@RequestMapping(value = "/login",method= RequestMethod.GET)
    public String login(Model model,Map<String,Object> map){

        model.addAttribute("clientName","tzw");
        model.addAttribute("clientNameEn","tzwEn");
        model.addAttribute("clientScope","sdkfdkfkdkfd");
        map.put("idNo","123333");
        map.put("idType","01");
        return "login";
    }

四、视图解析器和页面

视图解析器见spring mvc配置文件

页面获取值:注意EL表达式默认是true关闭的。如果想用EL表达式需要      isELIgnored="false"

<%@ page contentType="text/html;charset=UTF-8" import="java.util.*" language="java"  isELIgnored="false"%>
<html>
<head>
    <title>登陆</title>
    <h2>LOGIN!</h2>
    ${clientName}
    ${clientNameEn}
    ${idNo}
    ${idType}

</head>
<body>

</body>
</html>

视图解析器

ViewResolver和View介绍

SpringMVC用于处理视图最重要的两个接口是ViewResolver和View。ViewResolver的主要作用是把一个逻辑上的视图名称解析为一个真正的视图,SpringMVC中用于把View对象呈现给客户端的是View对象本身,而ViewResolver只是把逻辑视图名称解析为对象的View对象。View接口的主要作用是用于处理视图,然后返回给客户端。

Spring为我们提供了非常多的视图解析器,下面将列举一些视图解析器。

AbstractCachingViewResolver:这是一个抽象类,这种视图解析器会把它曾经解析过的视图保存起来,然后每次要解析视图的时候先从缓存里面找,如果找到了对应的视图就直接返回,如果没有就创建一个新的视图对象,然后把它放到一个用于缓存的map中,接着再把新建的视图返回。使用这种视图缓存的方式可以把解析视图的性能问题降到最低。

UrlBasedViewResolver:它是对ViewResolver的一种简单实现,而且继承了AbstractCachingViewResolver,主要就是提供的一种拼接URL的方式来解析视图,它可以让我们通过prefix属性指定一个指定的前缀,通过suffix属性指定一个指定的后缀,然后把返回的逻辑视图名称加上指定的前缀和后缀就是指定的视图URL了。如prefix=/WEB-INF/jsps/,suffix=.jsp,返回的视图名称viewName=test/indx,则UrlBasedViewResolver解析出来的视图URL就是/WEB-INF/jsps/test/index.jsp。默认的prefix和suffix都是空串。URLBasedViewResolver支持返回的视图名称中包含redirect:前缀,这样就可以支持URL在客户端的跳转,如当返回的视图名称是”redirect:test.do”的时候,URLBasedViewResolver发现返回的视图名称包含”redirect:”前缀,于是把返回的视图名称前缀”redirect:”去掉,取后面的test.do组成一个RedirectView,RedirectView中将把请求返回的模型属性组合成查询参数的形式组合到redirect的URL后面,然后调用HttpServletResponse对象的sendRedirect方法进行重定向。同样URLBasedViewResolver还支持forword:前缀,对于视图名称中包含forword:前缀的视图名称将会被封装成一个InternalResourceView对象,然后在服务器端利用RequestDispatcher的forword方式跳转到指定的地址。使用UrlBasedViewResolver的时候必须指定属性viewClass,表示解析成哪种视图,一般使用较多的就是InternalResourceView,利用它来展现jsp,但是当我们使用JSTL的时候我们必须使用JstlView。下面是一段UrlBasedViewResolver的定义,根据该定义,当返回的逻辑视图名称是test的时候,UrlBasedViewResolver将把逻辑视图名称加上定义好的前缀和后缀,即“/WEB-INF/test.jsp”,然后新建一个viewClass属性指定的视图类型予以返回,即返回一个url为“/WEB-INF/test.jsp”的InternalResourceView对象。

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

InternalResourceViewResolver:它是URLBasedViewResolver的子类,所以URLBasedViewResolver支持的特性它都支持。在实际应用中InternalResourceViewResolver也是使用的最广泛的一个视图解析器。那么InternalResourceViewResolver有什么自己独有的特性呢?单从字面意思来看,我们可以把InternalResourceViewResolver解释为内部资源视图解析器,这就是InternalResourceViewResolver的一个特性。InternalResourceViewResolver会把返回的视图名称都解析为InternalResourceView对象,InternalResourceView会把Controller处理器方法返回的模型属性都存放到对应的request属性中,然后通过RequestDispatcher在服务器端把请求forword重定向到目标URL。比如在InternalResourceViewResolver中定义了prefix=/WEB-INF/,suffix=.jsp,然后请求的Controller处理器方法返回的视图名称为test,那么这个时候InternalResourceViewResolver就会把test解析为一个InternalResourceView对象,先把返回的模型属性都存放到对应的HttpServletRequest属性中,然后利用RequestDispatcher在服务器端把请求forword到/WEB-INF/test.jsp。这就是InternalResourceViewResolver一个非常重要的特性,我们都知道存放在/WEB-INF/下面的内容是不能直接通过request请求的方式请求到的,为了安全性考虑,我们通常会把jsp文件放在WEB-INF目录下,而InternalResourceView在服务器端跳转的方式可以很好的解决这个问题。下面是一个InternalResourceViewResolver的定义,根据该定义当返回的逻辑视图名称是test的时候,InternalResourceViewResolver会给它加上定义好的前缀和后缀,组成“/WEB-INF/test.jsp”的形式,然后把它当做一个InternalResourceView的url新建一个InternalResourceView对象返回。

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

XmlViewResolver:它继承自AbstractCachingViewResolver抽象类,所以它也是支持视图缓存的。XmlViewResolver需要给定一个xml配置文件,该文件将使用和Spring的bean工厂配置文件一样的DTD定义,所以其实该文件就是用来定义视图的bean对象的。在该文件中定义的每一个视图的bean对象都给定一个名字,然后XmlViewResolver将根据Controller处理器方法返回的逻辑视图名称到XmlViewResolver指定的配置文件中寻找对应名称的视图bean用于处理视图。该配置文件默认是/WEB-INF/views.xml文件,如果不使用默认值的时候可以在XmlViewResolver的location属性中指定它的位置。XmlViewResolver还实现了Ordered接口,因此我们可以通过其order属性来指定在ViewResolver链中它所处的位置,order的值越小优先级越高。以下是使用XmlViewResolver的一个示例:

(1)在SpringMVC的配置文件中加入XmlViewResolver的bean定义。使用location属性指定其配置文件所在的位置,order属性指定当有多个ViewResolver的时候其处理视图的优先级。关于ViewResolver链的问题将在后续内容中讲到。

Xml代码 复制代码 收藏代码

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

(2)在XmlViewResolver对应的配置文件中配置好所需要的视图定义。在下面的代码中我们就配置了一个名为internalResource的InternalResourceView,其url属性为“/index.jsp”。

Xml代码 复制代码 收藏代码

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  5.      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
  6.     <bean id="internalResource" class="org.springframework.web.servlet.view.InternalResourceView">  
  7.        <property name="url" value="/index.jsp"/>  
  8.     </bean>  
  9. </beans>  
<?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-3.0.xsd">    <bean id="internalResource" class="org.springframework.web.servlet.view.InternalResourceView">       <property name="url" value="/index.jsp"/>    </bean></beans>

(3)定义一个返回的逻辑视图名称为在XmlViewResolver配置文件中定义的视图名称——internalResource。

Java代码 复制代码 收藏代码

  1. @RequestMapping("/xmlViewResolver")   
  2. public String testXmlViewResolver() {   
  3.    return "internalResource";   
  4. }  
    @RequestMapping("/xmlViewResolver")    public String testXmlViewResolver() {       return "internalResource";    }

(4)这样当我们访问到上面定义好的testXmlViewResolver处理器方法的时候返回的逻辑视图名称为“internalResource”,这时候Spring就会到定义好的views.xml中寻找id或name为“internalResource”的bean对象予以返回,这里Spring找到的是一个url为“/index.jsp”的InternalResourceView对象。

BeanNameViewResolver:这个视图解析器跟XmlViewResolver有点类似,也是通过把返回的逻辑视图名称去匹配定义好的视图bean对象。不同点有二,一是BeanNameViewResolver要求视图bean对象都定义在Spring的application context中,而XmlViewResolver是在指定的配置文件中寻找视图bean对象,二是BeanNameViewResolver不会进行视图缓存。看一个例子,在SpringMVC的配置文件中定义了一个BeanNameViewResolver视图解析器和一个id为test的InternalResourceview bean对象。

Xml代码 复制代码 收藏代码

  1. <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">  
  2.    <property name="order" value="1"/>  
  3. </bean>  
  4.   
  5. <bean id="test" class="org.springframework.web.servlet.view.InternalResourceView">  
  6.    <property name="url" value="/index.jsp"/>  
  7. </bean>  
    <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">       <property name="order" value="1"/>    </bean>    <bean id="test" class="org.springframework.web.servlet.view.InternalResourceView">       <property name="url" value="/index.jsp"/>    </bean>

这样当返回的逻辑视图名称是 test的时候,就会解析为上面定义好id为test的InternalResourceView。

ResourceBundleViewResolver:它和XmlViewResolver一样,也是继承自AbstractCachingViewResolver,但是它缓存的不是视图,这个会在后面有说到。和XmlViewResolver一样它也需要有一个配置文件来定义逻辑视图名称和真正的View对象的对应关系,不同的是ResourceBundleViewResolver的配置文件是一个属性文件,而且必须是放在classpath路径下面的,默认情况下这个配置文件是在classpath根目录下的views.properties文件,如果不使用默认值的话,则可以通过属性baseName或baseNames来指定。baseName只是指定一个基名称,Spring会在指定的classpath根目录下寻找以指定的baseName开始的属性文件进行View解析,如指定的baseName是base,那么base.properties、baseabc.properties等等以base开始的属性文件都会被Spring当做ResourceBundleViewResolver解析视图的资源文件。ResourceBundleViewResolver使用的属性配置文件的内容类似于这样:

Properties代码 复制代码 收藏代码

  1. resourceBundle.(class)=org.springframework.web.servlet.view.InternalResourceView   
  2. resourceBundle.url=/index.jsp   
  3. test.(class)=org.springframework.web.servlet.view.InternalResourceView   
  4. test.url=/test.jsp  
resourceBundle.(class)=org.springframework.web.servlet.view.InternalResourceViewresourceBundle.url=/index.jsptest.(class)=org.springframework.web.servlet.view.InternalResourceViewtest.url=/test.jsp

在这个配置文件中我们定义了两个InternalResourceView对象,一个的名称是resourceBundle,对应URL是/index.jsp,另一个名称是test,对应的URL是/test.jsp。从这个定义来看我们可以知道resourceBundle是对应的视图名称,使用resourceBundle.(class)来指定它对应的视图类型,resourceBundle.url指定这个视图的url属性。会思考的读者看到这里可能会有这样一个问题:为什么resourceBundle的class属性要用小括号包起来,而它的url属性就不需要呢?这就需要从ResourceBundleViewResolver进行视图解析的方法来说了。ResourceBundleViewResolver还是通过bean工厂来获得对应视图名称的视图bean对象来解析视图的。那么这些bean从哪里来呢?就是从我们定义的properties属性文件中来。在ResourceBundleViewResolver第一次进行视图解析的时候会先new一个BeanFactory对象,然后把properties文件中定义好的属性按照它自身的规则生成一个个的bean对象注册到该BeanFactory中,之后会把该BeanFactory对象保存起来,所以ResourceBundleViewResolver缓存的是BeanFactory,而不是直接的缓存从BeanFactory中取出的视图bean。然后会从bean工厂中取出名称为逻辑视图名称的视图bean进行返回。接下来就讲讲Spring通过properties文件生成bean的规则。它会把properties文件中定义的属性名称按最后一个点“.”进行分割,把点前面的内容当做是bean名称,点后面的内容当做是bean的属性。这其中有几个特别的属性,Spring把它们用小括号包起来了,这些特殊的属性一般是对应的attribute,但不是bean对象所有的attribute都可以这样用。其中(class)是一个,除了(class)之外,还有(scope)、(parent)、(abstract)、(lazy-init)。而除了这些特殊的属性之外的其他属性,Spring会把它们当做bean对象的一般属性进行处理,就是bean对象对应的property。所以根据上面的属性配置文件将生成如下两个bean对象:

Xml代码 复制代码 收藏代码

  1. <bean id="resourceBundle" class="org.springframework.web.servlet.view.InternalResourceView">  
  2.    <property name="url" value="/index.jsp"/>  
  3. </bean>  
  4.   
  5. <bean id="test" class="org.springframework.web.servlet.view.InternalResourceView">  
  6.    <property name="url" value="/test.jsp"/>  
  7. </bean>  
    <bean id="resourceBundle" class="org.springframework.web.servlet.view.InternalResourceView">       <property name="url" value="/index.jsp"/>    </bean>    <bean id="test" class="org.springframework.web.servlet.view.InternalResourceView">       <property name="url" value="/test.jsp"/>    </bean>

从ResourceBundleViewResolver使用的配置文件我们可以看出,它和XmlViewResolver一样可以解析多种不同类型的View,因为它们的View是通过配置的方式指定的,这也就意味着我们可以指定A视图是InternalResourceView,B视图是JstlView。

来看下面这个一个例子,我在SpringMVC的配置文件中定义了一个ResourceBundleViewResolver对象,指定其baseName为views,然后order为1。

Xml代码 复制代码 收藏代码

  1. <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">  
  2.    <property name="basename" value="views"/>  
  3.    <property name="order" value="1"/>  
  4. </bean>  
    <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">       <property name="basename" value="views"/>       <property name="order" value="1"/>    </bean>

我在classpath的根目录下有两个属性文件,一个是views.properties,一个是views_abc.properties,它们的内容分别如下:

views.properties:

Properties代码 复制代码 收藏代码

  1. resourceBundle.(class)=org.springframework.web.servlet.view.InternalResourceView   
  2. resourceBundle.url=/index.jsp   
  3. test.(class)=org.springframework.web.servlet.view.InternalResourceView   
  4. test.url=/test.jsp  
resourceBundle.(class)=org.springframework.web.servlet.view.InternalResourceViewresourceBundle.url=/index.jsptest.(class)=org.springframework.web.servlet.view.InternalResourceViewtest.url=/test.jsp

views_abc.properties:

Properties代码 复制代码 收藏代码

  1. abc.(class)=org.springframework.web.servlet.view.InternalResourceView   
  2. abc.url=/abc.jsp  
abc.(class)=org.springframework.web.servlet.view.InternalResourceViewabc.url=/abc.jsp

定义了如下这样一个Controller,它有三个处理器方法。

Java代码 复制代码 收藏代码

  1. @Controller  
  2. @RequestMapping("/mytest")   
  3. public class MyController {   
  4.     @RequestMapping("resourceBundle")   
  5.     public String resourceBundle() {   
  6.        return "resourceBundle";   
  7.     }   
  8.   
  9.     @RequestMapping("testResourceBundle")   
  10.     public String testResourceBundle() {   
  11.        return "test";   

    }   

  1.   
  2.     @RequestMapping("abc")   
  3.     public String abc() {   
  4.        return "abc";   
  5.     }   
  6.   
  7. }  
@Controller@RequestMapping("/mytest")public class MyController {    @RequestMapping("resourceBundle")    public String resourceBundle() {       return "resourceBundle";    }    @RequestMapping("testResourceBundle")    public String testResourceBundle() {       return "test";    }    @RequestMapping("abc")    public String abc() {       return "abc";    }}

那么当我们请求/mytest/resourceBundle.do的时候,ResourceBundleViewResolver会首先尝试着来解析该视图,这里Controller处理器方法返回的逻辑视图名称是resourceBundle,ResourceBundleViewResolver按照上面提到的解析方法进行解析,这个时候它发现它是可以解析的,然后就返回了一个url为/index.jsp的InternalResourceView对象。同样,请求/mytest/testResourceBundle.do返回的逻辑视图test和/mytest/abc.do返回的逻辑视图abc它都可以解析。当我们把basename指定为包的形式,如“com.tiantian.views”,的时候Spring会按照点“.”划分为目录的形式,到classpath相应目录下去寻找basename开始的配置文件,如上面我们指定basename为“com.tiantian.views”,那么spring就会到classpath下的com/tiantian目录下寻找文件名以views开始的properties文件作为解析视图的配置文件。

FreeMarkerViewResolver、VolocityViewResolver:这两个视图解析器都是UrlBasedViewResolver的子类。FreeMarkerViewResolver会把Controller处理方法返回的逻辑视图解析为FreeMarkerView,而VolocityViewResolver会把返回的逻辑视图解析为VolocityView。因为这两个视图解析器类似,所以这里我就只挑FreeMarkerViewResolver来做一个简单的讲解。FreeMarkerViewResolver和VilocityViewResolver都继承了UrlBasedViewResolver。

对于FreeMarkerViewResolver而言,它会按照UrlBasedViewResolver拼接URL的方式进行视图路径的解析。但是使用FreeMarkerViewResolver的时候不需要我们指定其viewClass,因为FreeMarkerViewResolver中已经把viewClass定死为FreeMarkerView了。

我们先在SpringMVC的配置文件里面定义一个FreeMarkerViewResolver视图解析器,并定义其解析视图的order顺序为1。

Xml代码 复制代码 收藏代码

  1. <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">  
  2.    <property name="prefix" value="fm_"/>  
  3.    <property name="suffix" value=".ftl"/>  
  4.    <property name="order" value="1"/>  
  5. </bean>  
    <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">       <property name="prefix" value="fm_"/>       <property name="suffix" value=".ftl"/>       <property name="order" value="1"/>    </bean>

那么当我们请求的处理器方法返回一个逻辑视图名称viewName的时候,就会被该视图处理器加上前后缀解析为一个url为“fm_viewName.ftl”的FreeMarkerView对象。对于FreeMarkerView我们需要给定一个FreeMarkerConfig的bean对象来定义FreeMarker的配置信息。FreeMarkerConfig是一个接口,Spring已经为我们提供了一个实现,它就是FreeMarkerConfigurer。我们可以通过在SpringMVC的配置文件里面定义该bean对象来定义FreeMarker的配置信息,该配置信息将会在FreeMarkerView进行渲染的时候使用到。对于FreeMarkerConfigurer而言,我们最简单的配置就是配置一个templateLoaderPath,告诉Spring应该到哪里寻找FreeMarker的模板文件。这个templateLoaderPath也支持使用“classpath:”和“file:”前缀。当FreeMarker的模板文件放在多个不同的路径下面的时候,我们可以使用templateLoaderPaths属性来指定多个路径。在这里我们指定模板文件是放在“/WEB-INF/freemarker/template”下面的。

Xml代码 复制代码 收藏代码

  1. <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">  
  2.    <property name="templateLoaderPath" value="/WEB-INF/freemarker/template"/>  
  3. </bean>  
    <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">       <property name="templateLoaderPath" value="/WEB-INF/freemarker/template"/>    </bean>

接下来我们定义如下一个Controller:

Java代码 复制代码 收藏代码

  1. @Controller  
  2. @RequestMapping("/mytest")   
  3. public class MyController {   
  4.   
  5.     @RequestMapping("freemarker")   
  6.     public ModelAndView freemarker() {   
  7.        ModelAndView mav = new ModelAndView();   
  8.        mav.addObject("hello", "andy");   
  9.        mav.setViewName("freemarker");   
  10.        return mav;   
  11.     }   
  12.   
  13. }  
可以看到这个Controller的处理器方法freemarker返回的逻辑视图名称是“freemarker”。那么如果我们需要把该freemarker视图交给FreeMarkerViewResolver来解析的话,我们就需要根据上面的定义,在模板路径下定义视图对应的模板,即在“/WEB-INF/freemarker/template”目录下建立fm_freemarker.ftl模板文件。这里我们定义其内容如下:

Ftl代码 复制代码 收藏代码

  1. <html>   
  2.     <head>   
  3.        <title>FreeMarker</title>   
  4.     </head>   
  5.     <body>   
  6.        <b>Hello World</b>   
  7.        <font color="red">Hello World!</font>   
  8.        ${hello}   
  9.     </body>   
  10. </html>  

经过上面的定义当我们访问/mytest/freemarker.do的时候就会返回一个逻辑视图名称为“freemarker”的ModelAndView对象,根据定义好的视图解析的顺序,首先进行视图解析的是FreeMarkerViewResolver,这个时候FreeMarkerViewResolver会试着解析该视图,根据它自身的定义,它会先解析到该视图的URL为fm_freemarker.ftl,然后它会看是否能够实例化该视图对象,即在定义好的模板路径下是否有该模板存在,如果有则返回该模板对应的FreeMarkerView。在这里的话/WEB-INF/freemarker/template目录下是存在模板文件fm_freemarker.ftl的,所以会返回一个url为fm_freemarker.ftl的FreeMarkerView对象。接着FreeMarkerView就可以利用该模板文件进行视图的渲染了。所以访问结果应该如下所示:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值