SpringMVC@RequestMapping 注解

742 阅读7分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第25天,点击查看活动详情

@RequestMapping 注解

1、功能

从注解名称上我们可以看到,@RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系

SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求

控制器中有多个方法对应同一个请求的情况

这是一种特殊情况,我们定义至少两个控制类,其中定义的控制器方法上@ReqeustMapping指定同一请求路径

@Controller
public class HelloController {
    @RequestMapping("/")
    public String index() {
        return "index";
    }
}
@Controller
public class RequestMappingController {
    @RequestMapping("/")
    public String index() {
        return "target";
    }
}

如果存在两个或多个控制器,其控制器方法的@RequestMapping一致,即多个控制器方法试图都想要处理同一个请求时,这时启动 Tomcat 时会抛出BeanCreationException异常,并指明There is already 'helloController' bean method即 helloController 中存在处理同意请求的控制器方法

但是这显然是不合理的,当一个系统方法很多,很难完全避免两个或多个同名方法的存在

@RequestMapping不仅可以在控制器方法上进行使用,也可以在控制器类上进行使用。那两种方式有什么区别呢?

  • @RequestMapping标识一个类:设置映射请求的请求路径的初始信息
  • @RequestMapping标识一个方法:设置映射请求的请求路径的具体信息
@Controller
@RequestMapping("/requestMappingController")
public class RequestMappingController {
    @RequestMapping("/success")
    public String success() {
        return "success";
    }
}

前台创建超链接,超链接跳转路径 = 控制器上@RequestMapping映射请求的初始路径 + 控制器方法上@RequestMapping映射请求的具体路径,即/requestMappingController/success

这样就可以为不同的控制器方法,在设置映射请求的请求路径时,指定不同的初始信息,从而避免控制器中有多个方法对应同一个请求的情况

指定请求方式

method属性可以用来指定可处理的请求方式。

1、常用的请求方式有 4 种:GET、POST、PUT、DELETE

  • GET 用于查询数据
  • POST 用于添加数据
  • PUT 用于更新数据
  • DELETE 用户删除数据

但是很多情况下,习惯上会让 POST 承担更多的职责,即通过 POST 进行增、删、改的操作,可以说是“一个人揽了三个人的活”

2、还有 4 种不常用的请求:HEAD、PATCH、OPTIONS、TRACE

  • HEAD 获取响应的报头,检查超链接的有效性、网页是否被修改,多用于自动搜索机器人获取网页的标志信息,获取 rss 种子信息,或者传递安全认证信息等
  • PATCH 用于更新数据
  • OPTIONS 用于测试服务器,解决同源策略和跨域请求问题
  • TRACE 用于测试或诊断

例如:

我们期望让请求的资源路径为 /test/testMethodPOST请求能够被testMethod方法处理。则可以写如下代码

@Controller
@RequestMapping("/test")
public class TestController {
​
    @RequestMapping(value = "/testMethod",method = RequestMethod.POST)
    public String testMethod(){
        System.out.println("testMethod处理了请求");
        return "/success.jsp";
    }
}
​

注意:我们可以也可以运用如下注解来进行替换

  • @PostMapping 等价于 @RequestMapping(method = RequestMethod.POST)
  • @GetMapping 等价于 @RequestMapping(method = RequestMethod.GET)
  • @PutMapping 等价于 @RequestMapping(method = RequestMethod.PUT)
  • @DeleteMapping 等价于 @RequestMapping(method = RequestMethod.DELETE)

例如:

上面的需求我们可以使用下面的写法实现

@Controller
@RequestMapping("/test")
public class TestController {
​
    @PostMapping(value = "/testMethod")
    public String testMethod(){
        System.out.println("testMethod处理了请求");
        return "/success.jsp";
    }
}

不满足 method 会怎样

若当前请求的请求地址满足请求映射的value属性,但是请求方式不满足method属性,则浏览器报错

image.png

value 属性

@RequestMapping注解的value属性有哪些用途呢?

  • 请求映射:通过请求的请求地址匹配请求映射
  • 匹配多个请求:是一个字符串类型的数组,表示该请求映射能够匹配多个请求地址所对应的
  • 必须设置:至少通过一个请求地址匹配请求映射

匹配多个请求

查看@RequestMapping注解的源码,会发现其value属性返回值为 String 类型的数组,这也说明了之所以@RequestMapping注解的value属性可以匹配多个请求的原因。通过为value属性指定多个值的方式,就可以对个多个请求建立请求映射

image.png

指定请求参数

我们可以使用params属性来对请求参数进行一些限制。可以要求必须具有某些参数,或者是某些参数必须是某个值,或者是某些参数必须不是某个值

例如:

我们期望让请求的资源路径为 /test/testParamsGET请求,并且请求参数中具有code参数的请求能够被testParams方法处理。则可以写如下代码

@Controller
@RequestMapping("/test")
public class TestController {
        //需要多个参数的时候
//    @RequestMapping(value = "/testParams",method = RequestMethod.GET,params = {"code","id"})
    //只要一个参数
    @RequestMapping(value = "/testParams",method = RequestMethod.GET,params = "code")
    public String testParams(){
        System.out.println("testParams处理了请求");
        return "/success.jsp";
    }
}

如果是要求不能有code这个参数可以把改成如下形式

@Controller
@RequestMapping("/test")
public class TestController {
    @RequestMapping(value = "/testParams",method = RequestMethod.GET,params = "!code")
    public String testParams(){
        System.out.println("testParams处理了请求");
        return "/success.jsp";
    }
}

如果要求有code这参数,并且这参数值必须是某个值可以改成如下形式

@Controller
@RequestMapping("/test")
public class TestController {
    @RequestMapping(value = "/testParams",method = RequestMethod.GET,params = "code=sgct")
    public String testParams(){
        System.out.println("testParams处理了请求");
        return "/success.jsp";
    }
}

如果要求有code这参数,并且这参数值必须不是某个值可以改成如下形式

@Controller
@RequestMapping("/test")
public class TestController {
    @RequestMapping(value = "/testParams",method = RequestMethod.GET,params = "code!=sgct")
    public String testParams(){
        System.out.println("testParams处理了请求");
        return "/success.jsp";
    }
}

指定请求头

们可以使用headers属性来对请求头进行一些限制。

@RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射

它是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系

  • header:要求请求映射所匹配的请求必须携带header请求头信息
  • header:要求请求映射所匹配的请求必须不能携带header请求头信息
  • header=value:要求请求映射所匹配的请求必须携带header请求头信息且header=value
  • header!=value:要求请求映射所匹配的请求必须携带header请求头信息且header!=value

若当前请求满足@RequestMapping注解的valuemethod属性,但是不满足headers属性,此时页面显示404错误,即资源未找到

例如:

我们期望让请求的资源路径为 /test/testHeaders的GET请求,并且请求头中具有deviceType的请求能够被testHeaders方法处理。则可以写如下代码

@Controller
@RequestMapping("/test")
public class TestController {
    
    @RequestMapping(value = "/testHeaders",method = RequestMethod.GET,headers = "deviceType")
    public String testHeaders(){
        System.out.println("testHeaders处理了请求");
        return "/success.jsp";
    }
}

如果是要求不能有deviceType这个请求头可以把改成如下形式

@Controller
@RequestMapping("/test")
public class TestController {
    
    @RequestMapping(value = "/testHeaders",method = RequestMethod.GET,headers = "!deviceType")
    public String testHeaders(){
        System.out.println("testHeaders处理了请求");
        return "/success.jsp";
    }
}

如果要求有deviceType这个请求头,并且其值必须是某个值可以改成如下形式

@Controller
@RequestMapping("/test")
public class TestController {
    
    @RequestMapping(value = "/testHeaders",method = RequestMethod.GET,headers = "deviceType=ios")
    public String testHeaders(){
        System.out.println("testHeaders处理了请求");
        return "/success.jsp";
    }
}

如果要求有deviceType这个请求头,并且其值必须不是某个值可以改成如下形式

@Controller
@RequestMapping("/test")
public class TestController {
    
    @RequestMapping(value = "/testHeaders",method = RequestMethod.GET,headers = "deviceType!=ios")
    public String testHeaders(){
        System.out.println("testHeaders处理了请求");
        return "/success.jsp";
    }
}

指定请求头Content-Type

我们可以使用consumes属性来对Content-Type这个请求头进行一些限制。

范例一

我们期望让请求的资源路径为 /test/testConsumes的POST请求,并且请求头中的Content-Type头必须为 multipart/from-data 的请求能够被testConsumes方法处理。则可以写如下代码

    @RequestMapping(value = "/testConsumes",method = RequestMethod.POST,consumes = "multipart/from-data")
    public String testConsumes(){
        System.out.println("testConsumes处理了请求");
        return "/success.jsp";
    }

范例二

如果我们要求请求头Content-Type的值必须不能为某个multipart/from-data则可以改成如下形式:

    @RequestMapping(value = "/testConsumes",method = RequestMethod.POST,consumes = "!multipart/from-data")
    public String testConsumes(){
        System.out.println("testConsumes处理了请求");
        return "/success.jsp";
    }

4.RestFul风格

RestFul是一种网络应用程序的设计风格和开发方式 。现在很多互联网企业的网络接口定义都会符合其风格。

主要规则如下:

  • 每一个URI代表1种资源
  • 客户端使用GET、POST、PUT、DELETE 4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源;
  • 简单参数例如id等写到url路径上 例如: /user/1 HTTP GET:获取id=1的user信息 /user/1 HTTP DELETE :删除id=1的user信息
  • 复杂的参数转换成json或者xml(现在基本都是json)写到请求体中。