Spring MVC注解

Author Avatar
stormjie 9月 22, 2018
  • 在其它设备中阅读本文章

一、一个小例子

上周Spring MVC入了个门,没有入门程序,今天补上,正好借这个入门小程序来讲讲今天的主题,有关Spring MVC的常用注解。

1.导入jar包

第一步当然是新建一个普通的web项目,在lib目录下添加运行Spring MVC程序需要的jar包,下图是所要添加的jar包:

2.配置DispatcherServlet

在项目的web.xml文件中做如下配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee                      
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_0.xsd"
         id="WebApp_ID" version="3.0">
    <!--配置DispatcherServlet-->
    <servlet>
        <!--servlet-name随意命名-->
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--配置初始化参数:作用是配置Spring MVC配置文件的位置和名称-->
        <!--可以不配置,默认Spring MVC配置文件名称为<servlet-name>-servlet.xml-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:dispatcherServlet-servlet.xml</param-value>
        </init-param>
        <!--表示容器在应用启动时就加载并初始化这个servlet-->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <!--截取所有请求-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>  
3.创建Spring MVC的配置文件

因为我们在web.xml文件中配置了Spring MVC配置文件的名称,所以我们要新建一个名为dispatcherServlet-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"
       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/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    <!--配置自动扫描注解的包-->
    <context:component-scan base-package="com.springmvc.controller"/>
    <!--对于适配器和解析器的配置,我们可以使用<mvc:annotation-driven/>代替-->
    <!--自动加载RequestMappingHandlerMapping和RequestMappingHandlerAdapter-->
    <mvc:annotation-driven/>
    <!--配置视图解析器:如何把handle方法返回值解析为实际的物理视图-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--prefix和suffix:查找视图页面的前缀和后缀(前缀[逻辑视图名]后缀)-->
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
4.创建Controller类

在com.springmvc.controller包下创建controller类

package com.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

//Controller注解,在《Spring的Bean与IoC实现》提过
@Controller
public class StartController {
    //DispatcherServlet根据配置的url地址决定调用哪个方法
    @RequestMapping("/helloworld")
    public String helloworld() {
        //返回jsp文件名
        return "helloworld";
    }
}
5.创建视图界面

在WEB-INF/views/目录下创建helloworld.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"  
    pageEncoding="utf-8"%> 
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Hello,World!</h1>
</body>
</html>
6.启动项目,测试应用

发布项目并启动Tomcat,在浏览器中输入地址http://localhost:8080/项目名/helloworld你便可以看到上面的helloworld.jsp界面。

二、常用注解

1.@RequestMapping

RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。在类的级别上的注解会将一个特定请求或者请求模式映射到一个控制器之上。之后你还可以另外添加方法级别的注解来进一步指定到处理方法的映射关系。

RequestMapping注解有六个属性:

value:指定请求的实际地址,指定的地址可以是RESTful风格;

有关RESTful风格可以看这篇帖子RESTful架构详解

  • method:指定请求的method类型, GET、POST、PUT、DELETE等;
  • consumes:指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
  • produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
  • params:指定request中必须包含某些参数值是,才让该方法处理;
  • headers:指定request中必须包含某些指定的header值,才能让该方法处理请求;

具体示例:SpringMVC--@RequestMapping的参数和用法

2.@Resource和@Autowired

@Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。

(1)共同点

两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。

(2)不同点

@Autowired

@Autowired为Spring提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入。

public class TestServiceImpl {
    // 下面两种@Autowired只要使用一种即可
    @Autowired
    private UserDao userDao; // 用于字段上

    @Autowired
    public void setUserDao(UserDao userDao) { // 用于属性的方法上
        this.userDao = userDao;
    }
}

@Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。如下:

public class TestServiceImpl {
    @Autowired
    @Qualifier("userDao")
    private UserDao userDao; 
}

@Resource

@Resource默认按照ByName自动注入,由J2EE提供,需要导入包javax.annotation.Resource。@Resource有两个重要的属性:name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略。

public class TestServiceImpl {
    // 下面两种@Resource只要使用一种即可
    @Resource(name="userDao")
    private UserDao userDao; // 用于字段上

    @Resource(name="userDao")
    public void setUserDao(UserDao userDao) { // 用于属性的setter方法上
        this.userDao = userDao;
    }
}

@Resource装配顺序:

  • 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。

  • 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。

  • 如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。

  • 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。

@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入。

3.@PathVariable

用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数。如:

@Controller  
public class TestController {  
     @RequestMapping(value="/user/{userId}/roles/{roleId}",method = RequestMethod.GET)  
     public String getLogin(@PathVariable("userId") String userId,  
         @PathVariable("roleId") String roleId){  
         System.out.println("User Id : " + userId);  
         System.out.println("Role Id : " + roleId);  
         return "hello";  
     }  
     @RequestMapping(value="/product/{productId}",method = RequestMethod.GET)  
     public String getProduct(@PathVariable("productId") String productId){  
           System.out.println("Product Id : " + productId);  
           return "hello";  
     } 
}
4.@RequestParam

主要用于在Spring MVC后台控制层获取参数,类似一种是request.getParameter(“name”),它有三个常用参数:defaultValue = “0”, required = false, value = “isApp”;defaultValue表示设置默认值,required通过boolean设置是否是必须要传入的参数,value值表示接受的传入的参数类型。

@PathVariable和@RequestParam的区别:

请求路径上有个变量值,可以通过@PathVariable来获取;

@RequestParam用来获得静态的URL请求参数。

5. @RequestHeader和@CookieValue

@RequestHeader 注解,可以把Request请求header部分的值绑定到方法的参数上。

@CookieValue 可以把Request header中关于cookie的值绑定到方法的参数上。

Request请求header部分如下:

Host                    localhost:8080  
Accept                  text/html,application/xhtml+xml,application/xml;q=0.9  
Accept-Language         fr,en-gb;q=0.7,en;q=0.3  
Accept-Encoding         gzip,deflate  
Accept-Charset          ISO-8859-1,utf-8;q=0.7,*;q=0.7  
Keep-Alive              300  

示例代码:

@Controller  
public class TestController {  
    //例如有cookie值 JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84
    @RequestMapping("/displayHeaderInfo")  
    public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding,  
                                  @RequestHeader("Keep-Alive") long keepAlive,
                                  @CookieValue("JSESSIONID") String cookie) {
        System.out.println("Accept-Encoding : " + encoding);  
        System.out.println("Keep-Alive : " + keepAlive);
        System.out.println("JSESSIONID : " + cookie);
    } 
}
6.@RequestBody

该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上,再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上 。

7.@ResponseBody

该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。

使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用。

8.@ModelAttribute和@SessionAttributes

@ModelAttribute主要有两种使用方式,一种是标注在方法上,一种是标注在 Controller 方法参数上。当@ModelAttribute标记在方法上的时候,该方法将在处理器方法执行之前执行,然后把返回的对象存放在模型属性中,属性名称可以使用@ModelAttribute(“attributeName”) 在标记方法的时候指定,若未指定,则使用返回类型的类名称(首字母小写)作为属性名称。

@Controller
@RequestMapping("/myTest")
public class MyController {

    @ModelAttribute("hello")
    public String getModel() {
        return "world";
    }

    @ModelAttribute("intValue")
    public int getInteger() {
        return 10;
    }

    @ModelAttribute("user2")
    public User getUser() {
        //省略User类代码,只有一个字段为userName
        return new User("user2");
    }

    @RequestMapping("/sayHello")
    public void sayHello(@ModelAttribute("hello") String hello, @ModelAttribute("intValue") int num, @ModelAttribute("user2") User user, Writer writer) throws IOException {
       writer.write("Hello " + hello + " , Hello " + user.getUsername() + num);
       writer.write("\r");
    } 
}

当我们请求 /myTest/sayHello的时候使用@ModelAttribute 标记的方法会先执行,然后把它们返回的对象存放到模型中。最终访问到 sayHello方法的时候,使用 @ModelAttribute 标记的方法参数都能被正确的注入值。执行结果如下所示:

Hello world,Hello user210

@ModelAttribute注解作用在方法上或者方法的参数上,表示将被注解的方法的返回值或者是被注解的参数作为Model的属性加入到Model中,然后Spring框架自会将这个Model传递给ViewResolver。Model的生命周期只有一个http请求的处理过程,请求处理完后,Model就销毁了。如果想让参数在多个请求间共享,那么可以用到要说到的@SessionAttribute注解。

@SessionAttributes即将值放到session作用域中,只能作用在类上 。

具体使用可以参考这篇帖子spring学习之@SessionAttributes实例解析

三、POST中文乱码解决方案

在web.xml里配置:

<!-- spring Web MVC框架提供了org.springframework.web.filter.CharacterEncodingFilter
用于解决POST方式造成的中文乱码问题 -->
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>