【spring注解】Spring MVC 中的基于注解的 Controller

准备阶段:

<context:compnent-scan>中默认扫描的注解类型是@Component,在其基础上细化的@Repository, @Service 和 @Controller 也同样扫到;

<context:component-scan base-package="org.zachary.spring3.anno.web" />  


handlerMapping:

        handler:根据url通过通过 HandlerMapping 来映射出相应的 handler 并调用相应的方法以响应请求;

        定义了(比其他HandlerMapping 优先级高的)DefaultAnnotationHandlerMapping,请求来的url可以和被注解了@@RequesMapping 的值进行匹配

        没有定义但是定义了其他的HandlerMapping,请求过来的 url 和注解了的@RequestMapping 里的值正好能匹配上,@Controller一样可被捕获到

——————————————————————————————————————————————————————————————

HandlerAdaptor :

        如果没有注册任何 HandlerAdaptor 到容器中,那么 DispatcherServlet 将启用后备的几个默认使用的 HandlerAdaptor 实现:

org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter   
  org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter   
  org.springframework.web.servlet.mvc.AnnotationMethodHandlerAdaptor   

如果注册了某个HandlerAdaptor,框架只会启用注册的那个,所以别忘了把其他的 HandlerAdaptor 也注册进来,除非你确保你真的只需要那一个你注册进容器的 HandlerAdaptor

————————————————————————————————————————————————————

 @Controller

        类级别上的注解。我们定义的类可以只是一个 javabean,不需要实现任何接口。标注了@Controller,借助 <context:component-scan>,框架就能自动识别到这就是一个 Controller,springboot是不需要的,我没有配置包扫描机制吧,所以没有额外的配置,上传一副结构图


补:springboot不需要设置包扫描,只要保证入口类在类的上层包就行

————————————————————————————————————————————————————————————————

 @RequestMapping 

    可加在类级别上(不是必需的),也可在方法上。如果出现在类级别上,那请求的 url 为 类级别上的 @RequestMapping + 方法级别上的 @RequestMapping,否则直接取方法级上的 @RequestMapping。 

属性:value、params、method、headers

  /** 
     * @RequestMapping 还有一个参数化 headers,它和 params 非常相似,也有两种表达式,只不过它是对 
     * 请求头做限制罢了。大家可以通过 telnet 或 http-client 来发类似的请求以检验。以 telnet 为例: 
     *  
     * telnet localhost 8080 
     * POST /contextPath/my HTTP/1.1 
     * Host: localhost 
     * hello: world # 这个就是自定义请求头,和标准的请求头的写法别无二致 
     * 【回车】 
     * 【回车】 
     */  
    @RequestMapping(headers="hello=world", method={RequestMethod.POST})  
    public String cplusplus() {...}  

返回值:

    ModelAndView:视图和模型信息

    String,代表逻辑视图名,模型数据需要以其它形式提供(如modelmap类型的参数)

        返回null、框架从请求路径中提取视图信息;想返回空白页,writer.write("")

    ModelMap:模型数据信息没有视图信息,根据请求路径提取视图信息

    void:从请求路径中提取视图信息,模型数据以其他形式提供

        补:从请求路径提取视图信息:截取请求路径中的最后一个 / 后面的内容,并去掉后缀名,剩下来的内容就是视图名。

————————————————————————————————————————————————————————————--——

 @RequestParam(将请求参数绑定到方法参数) 

    请求参数与方法中参与名要对应,没有传递给方法则出现异常,类型不知框架借助PropertyEditor   类型转换失败,ExceptionResolver 会接手处理

@RequestParam(value = "per_page", required = false,defaultValue = "10"

     @InitBinder:绑定复杂对象,类型转换、字符串对象转换==》自定义数据绑定规则

            对一个 Controller 对应的 WebBinder 做定制


   在整个应用中共享绑定规则,可以为 AnnotationMethodHandlerAdapter 指定一个自定义的 org.springframework.web.bind.support.WebBindingInitializer 实例,这样可以避免在每个 Controller 中都重复定义几乎相同逻辑的 @InitBinder 的初始化方法


@PathVariable(将 url template 里的参数绑定到方法参数) 

    是url 模板,需要和 @RequestMapping 配合起来使用,这是 Spring 3.0 之后引入的;

@PathVariable 和 @RequestParam 的区别在于:  
   *   @PathVariable 的 url:/my/user/zhangsan/18  
   *   @RequestParam 的 url:/my/user?nickname=zhangsan&age=18  

————————————————————————————————————————------------------------------

@RequestBody(将请求正文绑定到方法参数) 

/**  
 * 来看一个 http 请求:  
 * (请求行) POST /my HTTP/1.1  
 * (请求头) Host: localhost  
 * (请求头) Content-Type: text/plain  
 * (请求头) Content-Length: 5  
 *  
 * (请求体) hello  
 *  
 * 这里的 hello,就是请求体,也称 request message。若有请求体,则必须提供请求体的类型和长度,这些信  
 * 息是写在请求头里的,即 Content-Type 和 Content-Length  
 */  
    Spring MVC 是通过 HttpMessageConverter来完成这种转换,

        AnnotationMethodHandlerAdapter 默认注册了一些 HttpMessageConverters(可以双向convert),HttpMessageConverter 用于从请求正文绑定到对象和把对象序列化成 String 予客户端响应
   
                 不管正文内容是什么,对于客户端和服务器而言,它们只是用文本来互相通信;在定义 HttpMessageConverters 时,我们可以为其指定 supportedMediaTypes。对于将请求正文转为对象这个方向上的操作,HttpMessageConverters 会从请求头得到 Content-Type 头信息,看其是否隶属于其定义的 supportedMediaTypes。若没有匹配上,则会使用下一个 HttpMessageConverter 做同样的判断。只要某个 HttpMessageConverter 支持请求头中的 Content-Type,那么就会应用此 HttpMessageConverter来将 String 转为 Object。当然,若请求正文并没有按照 Content-Type 所规定的格式来编写,必然要收到500 的响应。同时请注意,请求头中还必须提供 Content-Length,否则拿不到请求正文;如果所有的 HttpMessageConverters 中定义的 supportedMediaTypes 均不能匹配上 Content-Type 请  求头中的类型,那么就会收到 415 Unsupported Media Type 响应。
————————————————————————————————————————————————————————————————


@ResponseBody(将处理完请求后返回的对象绑定到响应正文) 

    HttpMessageConverter 用于将处理完请求后返回的对象序列化成字符串,该注解将告知框架对象作为响应正文返回,HttpMessageConverter 在这里起了作用,根据请求头的 Accept 头决定对象要转成什么样的String(Accept 头可以使用逗号分隔定义多个类型,用以告知服务器我只接受哪些类型的响应)

        遍历Accept头中每种媒体类型,在定义的多个HttpMessageConverters中依次匹配;

                匹配上使用该HttpMessageConverter(匹配到HttpMessageConverter定义的supportedMediaTypes中的第一个类型)完成序列化并响应头的Content-Type;

                均匹配不上,收到406Not Acceptable响应;

————————————————————————————————————————————————————————————————

 @ModelAttribute 为视图渲染提供更多的模型数据

    可标注在方法(存数据)上,标注在方法参数(取数据)上

 @SessionAttributes :数据存放于session或从session中取数据

    

————————————————————————————————————————————————————————————————

配置:

 <mvc:annotation-driven /> 会做以下几件事: 

    向 spring 容器中注册 DefaultAnnotationHandlerMapping。
    向 spring 容器中注册 AnnotationMethodHandlerAdapter。
    配置一些 messageconverter。

    解决了 @Controller 注解的使用前提配置,即 HandlerMapping 能够知道谁来处理请求。

<context:component-scan/>

    启用了对类包进行扫描以实施注解驱动 Bean 定义的功能

    启用了注解驱动自动注入的功能(即还隐式地在内部注册了 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor)

    因此当使用 <context:component-scan /> 后,除非需要使用PersistenceAnnotationBeanPostProcessor 和 RequiredAnnotationBeanPostProcessor 两个 Processor 的功能(例如 JPA 等),否则就可以将 <context:annotation-config /> 移除了。

<context:annotation-config /> : 

    向 spring 容器中注册 AutowiredAnnotationBeanPostProcessor。
    向 spring 容器中注册 CommonAnnotationBeanPostProcessor。
    向 spring 容器中注册 PersistenceAnnotationBeanPostProcessor。
    向 spring 容器中注册 RequiredAnnotationBeanPostProcessor。
    使用 <context:annotationconfig />之前,必须在 <beans> 元素中声明 context 命名空间 <context:component-scan />。<context:component-scan /> 对包进行扫描,实现注解驱动 Bean 定义。即,将 @Controller 标识的类的 bean 注册到容器中。


Spring MVC 中的基于注解的 Controller


扩展:    

    @Configuration可理解为用spring的时候xml里面的<beans>标签

    @Bean可理解为用spring的时候xml里面的<bean>标签

猜你喜欢

转载自blog.csdn.net/ma15732625261/article/details/80273677