• Spring MVC (二)——控制器定义与@RequestMapping详解


    一、控制器定义

    控制器提供访问应用程序的行为,通常通过服务接口定义或注解定义两种方法实现。 控制器解析用户的请求并将其转换为一个模型。在Spring MVC中一个控制器可以包含多个Action(动作、方法)。

    使用注解@Controller定义控制器

    org.springframework.stereotype.Controller注解类型用于声明Spring类的实例是一个控制器(在讲IOC时还提到了另外3个注解);Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描。

    创建一个名了Bar的类,定义为一个控制器,类的具体实现如下:

    package com.zhangsan.springmvc01;
    
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @org.springframework.stereotype.Controller
    public class Controller {
        @RequestMapping("/bar")
        public String hi(Model model){
            model.addAttribute("msg","这是通过注解定义的一个控制器中的Action");
            return "hi";
        }
    }

    还要需要修改Spring mvc配置文件,启用自动组件扫描功能,在beans中增加如下配置:

    <!-- 自动扫描包,实现支持注解的IOC -->
        <context:component-scan base-package="com.zhangsan.springmvc01" />

    运行结果如下:

    小结:从代码与运行结果可以看出BarController与FooController同时都指定了一个视图hi.jsp,但是页面结果的结果是不一样的,从这里可以看出视图是被复用的,而控制器与视图之间是弱偶合关系。

    二、@RequestMapping详解

    @RequestMapping注释用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。该注解共有8个属性,注解源码如下:

    package org.springframework.web.bind.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.util.concurrent.Callable;
    
    import org.springframework.core.annotation.AliasFor;
    
    /**
     * 用于映射url到控制器类或一个特定的处理程序方法.
     */
    //该注解只能用于方法或类型上
    @Target({ ElementType.METHOD, ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Mapping
    public @interface RequestMapping {
    
        /**
         * 指定映射的名称
         */
        String name() default "";
    
        /**
         * 指定请求的路径映射,指定的地址可以是uri模板,别名为path
         */
        @AliasFor("path")
        String[] value() default {};
    
        /** 别名为value,使用path更加形象
         * 只有用在一个Servlet环境:路径映射URI(例如“/myPath.do”)。
         * Ant风格的路径模式,同时也支持(例如,“/myPath/*.do”)。在方法层面,在主要的映射在类型级别表示相对路径(例如,“edit.do”)
         * 的支持。路径映射的URI可能包含占位符(例如“/$ {}连接”)
         */
        @AliasFor("value")
        String[] path() default {};
    
        /**
         * 指定请求谓词的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE. 收窄请求范围 The
         * HTTP request methods to map to, narrowing the primary mapping: GET, POST,
         * HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.
         */
        RequestMethod[] method() default {};
    
        /**
         * 映射请求的参数,收窄请求范围 The parameters of the mapped request, narrowing the
         * primary mapping.
         */
        String[]params() default {};
    
        /**
         * 映射请求头部,收窄请求范围 The headers of the mapped request, narrowing the primary
         * mapping. RequestMapping(value = "/something", headers =
         * "content-type=text/*")
         */
        String[] headers() default {};
    
        /**
         * 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html,收窄请求范围 The
         * consumable media types of the mapped request, narrowing the primary
         * mapping.
         */
        String[] consumes() default {};
    
        /**
         * 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回 The producible media types
         * of the mapped request, narrowing the primary mapping. produces =
         * "text/plain" produces = {"text/plain", "application/*"} produces =
         * "application/json; charset=UTF-8"
         */
        String[] produces() default {};
    }

     从上面的源码可以发现除了name基本都是数组类型,在设置时我们可以指定单个值,如@RequestMapping(value="/foo");也可以同时指定多个值如:@RequestMapping(value={"/foo","/bar"})。

    2.1、指定具体路径字符

    2.1.1 只注解方法

    @Controller
    public class Controller {
        @RequestMapping("/h1")
        public String h1(){
            return "h1";
        }
    }

     访问路径:http://localhost:8080/h1

    2.1.2 同时注解类与方法

    @Controller
    @RequestMapping("/foo")
    public class Controller {
        @RequestMapping("/h1")
        public String h1(){
            return h1";
        }
    }

    访问路径:http://localhost:8080/foo/h1

     需要先指定类的路径再指定方法的路径

    2.1.3 @RequestMapping 来处理多个 URI

    @Controller
    @RequestMapping("/foo")
    public class Controller {
        @RequestMapping(value = {"/hi","/a/b/c"})
        public String h2(Model model){
            model.addAttribute("msg","@RequestMapping 来处理多个 URI!");
            return "hi";
        }
    }

    访问路径:1、http://localhost:8080/foo/hi

            2、http://localhost:8080/foo/a/b/c

    2.1.4、路径变量占位,URI模板模式

    在Spring MVC可以使用@PathVariable 注释方法参数的值绑定到一个URI模板变量。

    @Controller
    @RequestMapping("/foo")
    public class Controller {
        @RequestMapping(value = {"/h3/{name}/{id}"})
        public String h3(Model model, @PathVariable String name,@PathVariable int id){
            model.addAttribute("msg","路径变量占位,URI模板模式!
    名称:"+name+"
    编号:"+id);
            return "hi";
        }
    }

    访问路径:http://localhost:8080/foo/h3/张三/20

    2.1.5、正则表达式模式的URI模板

    @Controller
    @RequestMapping("/foo")
    public class Controller {
        @RequestMapping(value = "/h4/{id:\d{6}}-{name:[a-z]{3}}")
        public String h4(Model model, @PathVariable String name,@PathVariable int id){
            model.addAttribute("msg","正则表达式模式的URI模板!
    名称:"+name+"
    编号:"+id);
            return "hi";
        }
    }

    访问路径:http://localhost:8080/foo/h4/123456-abc

    正则要求id必须为6位的数字,而name必须为3位小写字母,访问结果如下:

    2.1.6、Ant风格路径模式
    @RequestMapping注解也支持ant风格的路径模式,如/foo/h5/*.do,示例代码如下:

    @Controller
    @RequestMapping("/foo")
    public class Controller {
        @RequestMapping(value = "/h5/*.do")
        public String h5(Model model){
            model.addAttribute("msg","Ant风格路径模式");
            return "hi";
        }
    }

    访问路径:http://localhost:8080/foo/h5/任意符号.do

    ANT通配符有三种:

     

    2.2、method属性指定谓词类型

    用于约束请求的谓词类型,可以收窄请求范围。指定请求谓词的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE,如下代码所示:

    @Controller
    @RequestMapping("/foo")
    public class Controller {
        @RequestMapping(value = "/h6",method = {RequestMethod.POST,RequestMethod.DELETE})
        public String h6(Model model){
            model.addAttribute("msg","请求谓词只能是POST与DELETE");
            return "hi";
        }
    }

     要访问h6请求谓词类型必须是POST或者为DELETE,当我们从浏览器的URL栏中直接请求时为一个GET请求,则结果是405,如下所示:

     如果将POST修改为GET则正常了,如下所示:

    @Controller
    @RequestMapping("/foo")
    public class Controller {
        @RequestMapping(value = "/h6",method = {RequestMethod.GET})
        public String h6(Model model){
            model.addAttribute("msg","请求谓词只能是GET");
            return "hi";
        }
    }

     

    Spring MVC 的 @RequestMapping 注解能够处理 HTTP 请求的方法, 比如 GET, PUT, POST, DELETE 以及 PATCH。

    所有的请求默认都会是 HTTP GET 类型的。

    为了能降一个请求映射到一个特定的 HTTP 方法,你需要在 @RequestMapping 中使用 method 来声明 HTTP 请求所使用的方法类型,如下所示:

    @RestController  
    @RequestMapping("/home")  
    public class IndexController {  
        @RequestMapping(method = RequestMethod.GET)  
        String get() {  
            return "Hello from get";  
        }  
        @RequestMapping(method = RequestMethod.DELETE)  
        String delete() {  
            return "Hello from delete";  
        }  
        @RequestMapping(method = RequestMethod.POST)  
        String post() {  
            return "Hello from post";  
        }  
        @RequestMapping(method = RequestMethod.PUT)  
        String put() {  
            return "Hello from put";  
        }  
        @RequestMapping(method = RequestMethod.PATCH)  
        String patch() {  
            return "Hello from patch";  
        }  
    }

    在上述这段代码中, @RequestMapping 注解中的 method 元素声明了 HTTP 请求的 HTTP 方法的类型。 
    所有的处理处理方法会处理从这同一个 URL( /home)进来的请求, 但要看指定的 HTTP 方法是什么来决定用哪个方法来处理。 
    例如,一个 POST 类型的请求 /home 会交给 post() 方法来处理,而一个 DELETE 类型的请求 /home 则会由 delete() 方法来处理。 
    你会看到 Spring MVC 将使用这样相同的逻辑来映射其它的方法。

    2.3、consumes属性指定请求的Content-Type

    @RequestMapping 注解的 produces 和 consumes 这两个元素来缩小请求映射类型的范围,达到处理生产和消费对象的目的。 

     指定处理请求的提交内容类型(Content-Type),例如application/json, text/html,收窄请求范围,如果用户发送的请求内容类型不匹配则方法不会响应请求,具体使用如下代码所示:

    @Controller
    @RequestMapping("/foo")
    public class Controller {
        @RequestMapping(value = "/h7",consumes = "text/html")
        public String h7(Model model){
            model.addAttribute("msg", "请求的提交内容类型(Content-Type)是text/html");
            return "hi";
        }
    }

    在h7的注解中约束发送到服务器的Content-Type必须是text/html类型,如果类型不一致则会报错(415),测试结果如下:

    请求的提交内容类型(Content-Type)是text/html 

    注意:可以使用!号,如consumes="!text/html"

    2.4、produces属性指定响应的Content-Type,约束Accept类型

    指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回,方法才处理客户端的请求否则会报406错误,常用设置如下:

    produces = "text/plain"  //客户端只接收纯文本

    produces = {"text/plain", "application/*"}   //客户端接收纯文本与application/*类型的内容

    produces = "application/json; charset=UTF-8"  //客户端接收json且编码为utf-8/;

    @Controller
    @RequestMapping("/foo")
    public class Controller {
        @RequestMapping(value = "/h8",produces = "application/json;charset=UTF-8")
        public String h8(Model model){
            model.addAttribute("msg", "客户端可以接收的类型是application/json; charset=UTF-8");
            return "hi";
        }
    }

     运行结果:

     注意:可以使用!号,如produces="!text/html"

  • 相关阅读:
    关于Windows 8 用户使用习惯调查结果
    Silverlight 可能迎来新版本
    项目总结(1)集中处理上下文
    VSS 团队 沟通
    中国程序员的迷茫?中国软件行业的悲哀?
    开始学点System.Net NameSpace的Class拉
    .Net FSO简单小结(简单到不能再简单了)
    DotNet Framework不协调的一面 ??
    几个开源项目配置信息的存储和处理的方式
    我对委托的一点理解,欢迎斧正
  • 原文地址:https://www.cnblogs.com/huoqin/p/9846181.html
Copyright © 2020-2023  润新知