第三章 Spring MVC的常用注解

《Spring+MyBatis企业应用实战》笔记

P26 @Controller注解

@Controller用于标记一个类,使用它标记的类就是一个Spring MVC Controller对象,即一个控制器类。Spring使用扫描机制查找应用程序中所有基于注解的控制器类。分发处理器会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping注解,而使用@RequestMapping注解的方法才是真正处理请求的处理器。为了保证Spring能找到控制器,需要完成两件事情:

  • 在Spring MVC的配置文件的头文件中引入spring-conext。
  • 使用<context:component-scan/>元素,该元素的功能为:启动包扫描功能,以便注册带有@Controller、@Service、@reposity、@Component等注解的类成为Spring的Bean。base-package属性指定了需要扫描的类包,类包及其递归子包中所有的类都会被处理。

配置文件如下所示:

<context:component-scan base-package="org.fkit.controller" />

示例:

springmvc-config.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: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-4.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.2.xsd">
    <!-- spring可以自动去扫描base-pack下面的包或者子包下面的java文件,
    	如果扫描到有Spring的相关注解的类,则把这些类注册为Spring的bean -->
    <context:component-scan base-package="org.fkit.controller"/>
    <!-- 视图解析器 class一定要写对“InternalResourceViewResolver”-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix">
            <value>/</value>
        </property>
        <!--后缀-->
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
</beans>

视图解析器中配置的prefix属性表示视图的前缀,suffix表示视图的前缀,返回的视图字符串是“helloWorld”,经过视图解析器之后,则视图的完整路径为“/helloWorld.jsp”(idea IDE环境下)。需要注意的是,此处没有配置之处理映射器和处理器适配器,当用户没有配置这两项时,Spring会使用默认的处理映射器和处理器适配器处理请求。

HelloWorldController.java

package org.fkit.controller;

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

@Controller
public class HelloWorldController {
    @RequestMapping("/helloWorld")
    public String helloWorld(Model model){
        model.addAttribute("message","Hello World!");
        return "helloWorld";
    }
}

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_4_0.xsd"
         version="4.0">

    <!--<context-param>-->
    <!--<param-name>contextConfigLocation</param-name>-->
    <!--<param-value>/WEB-INF/applicationContext.xml</param-value>-->
    <!--</context-param>-->
    <!--<listener>-->
    <!--<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>-->
    <!--</listener>-->

    <!-- 定义Spring MVC的前端控制器 -->
    <servlet>
        <!--Servlet的名称-->
        <servlet-name>springmvc</servlet-name>
        <!--Servlet对应的Java类-->
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--当前Servlet的参数信息-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/springmvc-config.xml</param-value>
        </init-param>
        <!--再Web应用启动时立即加载Servlet-->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- 让Spring MVC的前端控制器拦截所有请求 -->
    <!--Servlet的映射声明-->
    <servlet-mapping>
        <!--请求对应的Servlet的名称-->
        <servlet-name>springmvc</servlet-name>
        <!--监听当前域的所有请求-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>welcome.jsp</welcome-file>
    </welcome-file-list>
</web-app>

helloWorld.jsp

<%--
  Created by IntelliJ IDEA.
  User: Jeanne d'Arc
  Date: 2018/7/29
  Time: 18:14
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>测试@Controller注解</title>
  </head>
  <body>
  <!-- 页面可以访问Controller传递传递出来的message -->
  ${requestScope.message}
  </body>
</html>

Spring MVC中用于参数绑定的注解有很多,都在org.springframework.web.bind.annotation包中,根据他们处理的request的不同内容部分可以分为四类(主要讲解常用内容):

  • 处理request body部分的注解:@RequestParam、@RequestBody
  • 处理request uri部分的注解:@PathVariable
  • 处理request header部分的注解:@RequestHeader、@CookiePath
  • 处理attribute部分的注解:@SessionAttributes、@ModelAttribute。

P28 @RequestMapping注解

org.springframework.web.bind.annotation.RequestMapping注解类型指示Spring用那一个类或方法来处理请求动作,该注解可用于类或方法。

@RequestMapping可以用于注释一个控制器类,在这种情况下,所有方法都将映射为相对于类级别的请求,表示该控制器处理的所有请求都被映射到value属性所指示的路径下,示例代码如下:

@Controller
@RequestMapping(value="/user")
public class UserController{
    @RequestMapping(value="/register")
    public String register(){
        return "register";
    }
    @RequestMapping(value="/login")
    public String login(){
        return "login";
    }
}

由于UserController类中加入了value="/user"的@RequestMapping注解,因此所有相关路径都要加上"/user",此时方法被映射到如下请求URL:

http://localhost:8080/user/register
http://localhost:8080/user/login
@RequestMapping注解支持的属性
属性 类型 是否必要 说明
value String[] 用于将指定请求的实际地址映射到方法上
name String 给映射地址制定一个别名
method RequestMethod[] 映射指定请求的方法类型,包括GET、POST、HEAD、OPTIONS、PUT、PATCH、DELETE、TRACE
consumes String[] 指定处理请求的提交内容类型(Content-Type),例如application/json、text/html等
produces String[] 指定返回的内容类型,返回的内容类型必须是request请求头(Accept)中所包含的类型
params String[] 指定request中必须包含某些参数时,才让该方法处理
headers String[] 指定request中必须包含某些指定的header值,才能让该方法处理请求
Path String[] 在Servlet环境中只有:uri路径映射(例如"/myPath.do")。也支持如ant的基于路径模式(例如"/myPath/*,")。在方法层面上,支持相对路径(例如"edit.do")

@RequestMapping注解支持的常用属性示例

  1. value属性,value属性是@RequestMapping注释的默认属性,因此,如果只有唯一的属性,则可以省略属性名。如果有超过一个属性,就必须写上value属性名。value属性的值也可以是一个空字符串。 
    @RequestMapping(value="/hello")
    public ModelAndView hello(){
        return ...;
    }
    //将hello映射到hello方法上,使用如下URL访问应用时将由hello方法进行处理:
    http://localhost:8080/context/hello
    //当value是空字符串时:
    http://localhost:8080/context
  2. method属性
    @RequestMapping(value="/hello",method=RequestMethod.POST)
    //只支持POST请求
    @RequestMapping(value="/hello",method={RequestMethod.POST,RequestMethod.GET})
    //支持多个HTTP请求方式
    //如果没有指定,则请求处理方法可以处理任意的HTTP请求方式
  3. consumes属性

    @RequestMapping(value="/hello",method=RequestMethod.POST,consumes="application/json")
    //仅处理request Content-Type为“application/json”类型的请求
  4. produces属性

    ​@RequestMapping(value="/hello",method=RequestMethod.POST,produces="application/json")
    //仅处理request请求头Accept投中包含“application/json”的请求,同时指明了返回的内容类型为“application/json”
  5. params属性

    ​@RequestMapping(value="/hello",method=RequestMethod.POST,params="myParams=myValue")
    //仅处理其中名为“myParams”、值为“myValue”的请求

P30 请求处理方法可出现的参数类型

HttpServletRequest、HttpServletResponse、HttpSesson、WebRequest或NativeWebRequest、Locale、Reader、Writer、Principal、HttpEntity<?>、Map、Model、ModelMap、RedirectAttributes、Errors、BindingResult、SessionStatus、UriComponentsBuilder、@PathVariable、@MatrixVariable、@RequestParam、@RequestHeader、@RequestBody、@RequestPart

其中最重要的是Model类型。这不是一个Servlet API类型,而是一个Spring MVC类型。其中包含了Map对象用来存储数据。如果方法中添加了Model参数,则每次调用请求处理方法时,Spring MVC都会创建Model对象,并将其作为参数传递给方法。

P31 请求处理方法可返回的类型

ModelAndView、Model、Map<k,v>,View、String、HttpEntity或ReponseEntity、Callable、DeferredResult、void

P31 Model和ModelAndView

对于MVC框架,控制器(Controller)执行业务逻辑,用于产生模型数据(Model),而视图(View)则用于渲染模型数据。

如何将模型数据传递给视图是Spring MVC框架的一项重要工作,Spring MVC提供了多种途径输出模型数据,如:

  • Model和ModelMap
  • ModelAndView
  • @ModelAttribute
  • @SessionAttributes

P31 Model和ModelMap

Spring MVC在内部使用了一个org.springframework.ui.Model接口存储模型数据,它的功能类似骄傲va.util.Map接口,但是比Map易于使用。org.springframework.ui.ModelMap接口实现了Map接口。

Spring MVC在调用处理方法之前会创建一个隐含的模型对象,作为模型数据的存储容器。如果处理方法的参数为Model或ModelMap类型,则Spring MVC会将隐含模型的引用传递给这些参数。在处理方法内部,开发者就可以通过这个参数对象访问模型中的所有数据,也可以像模型中添加新的属性数据。

在处理方法中,Model和ModelMap对象都可以使用如下方法添加模型数据:

addObject(Stringh attributeName,Object attributeValue)

2018.7.31

P33 参数绑定注解

@RequestParam注解

org.springframework.web.bind.annotation.RequestParam注解类型用于将指定的请求参数赋值给方法中的形参。

@RequestParam注解支持的属性
属性 类型 是否必要 说明
name String 指定请求头绑定的名称
value String name属性的别名
required String 指示参数是否必须绑定
defaultValue String 如果没有传递参数而使用的默认值

请求处理方法参数的可选类型为Java基本数据类型和String。示例代码如下:

@RequestMapping(value="/login")
public ModelAndView login(@RequestParam("loginname") String loginname,@RequestParam("password") String password){
       return ...;
}

假设请求如下:

http://localhost:8080/context/login?loginname=jack&password=123456

以上代码会被请求中的loginname参数的值“jack”付给loginname变量,password参数的值“123456”赋给password变量。

@RequestParam还有如下写法:

@RequestParam(value="loginname",required=true,defaultValue=admin)

其中required参数不是必须的,默认值为true。

P38 @PathVariable注解

org.springframework.web.bind.annotation.PathVariable注解类型可以非常方便地获得请求URL中的动态参数。@PathVariable注解只支持一个属性value,类型为String,表示绑定的名称,如果省略则默认绑定同名参数。示例代码如下:

@RequestMapping(value="/pathVariableTest/{userId}")
public void pathVariableTest(@PathVariable Integer userId)

加入请求的URL为“http://localhost:8080/DataBindingTest/pathVariable/1”,则自动将URL中模板变量{userId}绑定到通过@ParhVariable注解的同名参数上,即userId变量将被赋值为1。

2018.8.1

P38 @RequestHeader注解 

org.springframework.web.bind.annotation.RequestHeader注解类型用于将请求的头信息数据映射到功能处理方法的参数上。

@RequestHeader注解支持的属性
属性 类型 是否必要 说明
name String 指定请求头绑定的名称

value

String name属性的别名
required boolean 指示参数是否必须绑定
defaultValue String 如果没有传递参数而使用的默认值

@RequestHeader注解示例代码如下:

@RequestMapping(value="/requestHeaderTest")
public void requestHeaderTest(@RequestHeader("User-Agent") String userAgent,@RequestHeader(value="Accept") String[] accepts)

以上配置自动将请求头“User-Agent”的值赋到userAgent变量上,并将“Accept”请求头的值赋到accepts上。

P38 @CookieValue注解

org.springframework.web.bind.annotation.CookieValue注解类型用于将请求的Cookie数据印书馆河道功能处理方法的参数上。

@CookieValue注解支持的属性
属性 类型 是否必要 说明
name String 指定请求头绑定的名称
value String 那么属性的别名
required boolean 只是参数是否必须绑定
defaultValue String 如果没有传递参数而使用的默认值

@CookieValue注解示例代码如下:

@RequestMapping(value="/cookieValueTest")
public void cookieValueTest(@CookieValue(value="JSESSIONID",defaultValue="") String sessionId)

 以上配置会自动将JSESSIONID值设置到sessionId参数上,defaultValue表示Cookie中没有JSESSION时默认为空。

P41 @SessionAttributes注解

org.springframework.web.bind.annotation.SessionAttributes注解类型允许我们有选择地指定Model中的哪些属性需要转存到HttpSession对象当中。

@SessionAttributes注解支持的属性
属性 类型 是否必要 说明
names String[] Model中属性的名称,即存储在HttpSession当中的属性
value String[] names属性的别名
types Class<?>[] 指示参数是否必须绑定

@SessionAttributes只能声明在类上,不能声明在方法上。

P42 @ModelAttribute注解

org.springframework.web.bind.annotation.ModelAttribute注解类型将请求参数绑定到Model对象。

@ModelAttribute注解只支持一个属性value,类型为String,表示绑定的水星名称。

被@ModelAttribute注释的方法会在Controller每个方法执行前被执行,因此在一个Controller映射到多个URL时,要谨慎使用。

 @ModelAttribute注解的使用方式:

  • @ModelAttribute(value="")注释返回具体类
  • @ModelAttribute注释void返回值
  • @ModelAttribute注释具体类的方法
  • @ModelAttribute和@RequestMapping同时注释一个方法
  • @ModelAttribute注释一个方法的参数 

P49 信息转换

P49 HttpMessageConverter<T>接口 

HttpMessageConverter<T>是Spring3.0之后新增的一个重要接口,他负责将请求信息转换为一个对象(类型为T),并将对象(类型为T)绑定到请求方法的参数中或输出为响应信息。

DispatcherServlet默认已经装配了RequestMappingHandlerAdapter作为Handler组建的实现类,即HttpMessageConverter由RequestMappingHandlerAdapter使用,将请求信息转换为对象,或将对象转换为响应信息。

HttpMessageConverter<T>接口中定义了以下几个方法:

  • boolean canRead(Class<?> clazz,MediaType mediaType)。该方法指定转换器可以读取的对象类型,即转换器可将请求信息转换为clazz类型的对象,同时指定支持的MIME类型(text/html、application/json等)。
  • boolean canWrite(Class<?> clazz,MediaType mediaType)。该方法指定转换器可以将clazz类型为对象写到响应流当中,相应流支持的媒体类型在mediaType中定义。
  • List<MediaType> getSupportedMediaTypes()。该方法返回当前转换器支持的媒体类型。
  • T read(Class<? extends T> clazz,HttpInputMessage inputmessage)。该方法将请求信息六转换为T类型的对象。
  • void write(T t,MediaType contentType,HttpOutputMessage outputMessage).该方法将T类型的对象写到响应流当中,同时指定响应的媒体类型为contentType。

 Spring为HttpMessageConverter<T>提供了多个实现类,这些实现类组成了一个功能强大、用途广泛的信息转换家族。详细说明如下:

  • StringHttpMessageConverter。将请求信息转换为字符串。
  • FormHttpMessageConverter。将表单数据读取到MultiValueMap中。
  • XmlAwareFormHttpMessageConverter。继承自FormHttpMessageConverter,如果部分表单属性是XML数据,则可用该转换器进行转换。
  • ResourceHttpMessageConverter。读写org.springframework.core.io.Resource对象。
  • BufferedImageHttpMessageConverter。读写BufferedImage对象。
  • ByteArrayHttpMessageConverter。读写二进制数据。
  • SourceHttpMessageConverter。读写javax.xml.transform.Source类型的数据。
  • MarshallingHttpMessageConverter。通过Spring的org.springframework.oxm.Marshalling(将Java对象转换为XML)和Unmarshaller(将XML解析为Java对象)读写XML消息。
  • Jaxb2RootElementHttpMessageConverter。通过JAXB2(JAXB是Java Architecture for XML Binding的缩写,可以将一个Java对象转变成为XML格式,反之亦然。、、我们把对象与关系数据库之间的映射称为ORM, 其实也可以把对象与XML之间的映射称为OXM(Object XML Mapping). 原来JAXB是Java EE的一部分,在JDK6中,SUN将其放到了Java SE中,这也是SUN的一贯做法。JDK6中自带的这个JAXB版本是2.0, 比起1.0(JSR 31)来,JAXB2(JSR 222)用JDK5的新特性Annotation来标识要作绑定的类和属性等,这就极大简化了开发的工作量。实际上,在Java EE 5.0中,EJB和Web Services也通过Annotation来简化开发工作。另外,JAXB2在底层是用StAX(JSR 173)来处理XML文档。)读写XML消息,将请求消息转换到注解XmlRootElement和XmlType作用的类中。
  • MappingJackon2HttpMessageConverter。能够读写RSS种子消息。
  • AtomFeedHttpMessageConverter。能够读写RSS种子消息。

RequestMappingHandlerAdapter默认已经装配了以下的HttpMessageConverter:

  • StringHttpMessageConverter
  • ByteArrayHttpMessageConverter
  • SourceHttpMessageConverter
  • XmlAwareFromHttpMessageConverter

 如果需要装配其他类型的HttpMessageConverte,则可以在Spring的Web容器的上下文中自定义一个RequestMappingHandlerAdapter,如下所示:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
            
            <bean class="org.springframework.http.converter.xml.AbstractXmlHttpMessageConverter"/>
            //无法使用,会报错,可能不是用于此处,Spring5.0.7实践。

            <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
        </list>
    </property>
</bean>

备注:书中第二个Converter本来是XmlAwareFormHttpMessageConverter,实际实践时使用的Spring版本是Spring5.0.7,找不到该Converter,Spring4.1.5中该Converter可以找到,但是已经被添加中划线。Spring5.0.7中含有一个AbstractXmlHttpMessageConverter,但是添加后报错“abstract class not allowed for non-abstract bean”,使用方法不明。

如果在Spring Web容器中显式定义了一个RequestMappingHandlerAdapter,则Spring MVC的RequestMappingHandlerAdapter默认装配的HttpMessageConverter将不再起作用。

P51 转换JSON数据 

Spring MVC提供了处理JSON格式请求/响应的HttpMessageConverter:

  • MappingJackon2HttpMessageConverter。利用Jackson开源类包处理JSON格式的请求或响应数据。

因此只需要在Spring Web容器中为RequestMappingHandlerAdapter装配处理JSON的HttpMessageConverter,并在交互过程中通过请求的Accept指定MIME类型,Spring MVC就可以使服务端的处理方法和客户端JSON格式的消息进行通信了,开发者几乎无须关心通信层数据格式的问题,可以将精力集中到业务处理上面。

org.springframework.web.bind.annotation.RequestBody注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到Controller中方法的参数上。

当前台页面使用GET或POST方式提交数据时,数据编码格式由请求头的ContentType指定。可以分为以下几种情况:

  • application/x-www-form-urlencoded,这种情况的数据@RequestParam、@ModelAttribute也可以处理,并且很方便,当然@RequestBody也能处理。
  • multipart/form-data,@RequestBody不能处理这种格式的数据。
  • application/json,application/xml等格式的数据,必须使用@RequestBody来处理。

在实际开发工作中使用@RequestBody注解可以很方便地接受JSON格式的数据,并将其转换成对应地数据类型。

Spring的官方文档说明,Spring MVC默认使用MappingJackson2HttpMessageConverter转换JSON格式的数据,Jackson开源类包可以非常轻松地将Java对象转换成json对象和xml文档,同样也可以将java对象、xml文档转换成java对象。

P59 转换XML数据 

Spring MVC提供了处理XML格式请求/响应地HttpMessageConverter,如Jaxb2RootElementHttpMessageConverter通过JAXB2读写XML消息,并将请求消息转换到注解XmlRootElement和XmlType作用的类中。

因此只需要在Spring Web容器中为RequestMappingHandlerAdapter装配处理XML的HttpMessageConverter,并在交互过程中通过请求的Accept指定MIME类型,Spring MVC就可以使服务端的处理方法和客户端XML格式的消息进行通信了,开发者几乎无须关心通信层数据格式的问题,可以将精力集中到业务处理上面。

在Spring官方文档中,Spring MVC默认使用Jaxb2RootElementHttpMessageConverter转换XML格式的数据,JAXB(Java Architecture for XML Binding)可以很方便地生成XML,也能够很方便地生成JSON,这样一来可以更好地在XML和JSON之间进行转换。

JAXB是一个业界的标砖,是一项可以根据XML Schema产生Java类的技术。在该过程中,JAXB提供了将XML实力文档反向生成Java对象地方法,并能够将Java对象地内容重新写到XML实例文档中,从而使得Java开发作者在Java应用程序中能够很方便地处理XML数据。

JAXB常用的注解包括:@XmlRootElement、@XmlElement等。

2018.8.2

 Home Sweet Home—YUKI

世界既不白也不黑,而是一道精致的灰。

猜你喜欢

转载自blog.csdn.net/Altr1aPendrag0n/article/details/81173776
今日推荐