当前位置: 首页 > news >正文

@RequestMapping用法详解

Request是请求的意思,而Mapping是映射的意思,合起来就是请求映射,什么是请求映射,http://localhost:8080/student/get 这个很明显是一个请求的url吧,通过url我们要调用到代码当中的方法,方法那么多,怎么知道调用哪个呢?没错就是依靠@RequestMapping,可以在方法当中使用@RequestMapping("/student/get"),这样就可以通过/student/get这个url调用到这个方法了,一句话: 用于建立请求的URL 和 处理请求方法之间的对应关系。

目录

    • 一. @RequestMapping的源码
      • 1.1. @Target作用
      • 1.2. @Retention(RetentionPolicy.RUNTIME)
      • 1.3. @Documented
      • 1.4. @Mapping
      • 1.5. @AliasFor
    • 二. @RequestMapping的属性
    • 三. 实战应用
      • 3.1. 搭建项目
      • 3.2. 测试 value 和 path 属性
      • 3.3. 测试 method 属性
      • 3.4. 测试 params 属性
      • 3.5. 测试 headers 属性
      • 3.6. 带占位符的URL
      • 3.7. REST 风格的 URL 请求
      • 3.8. consumers属性
      • 3.9. produces属性
    • 四. @RequestMapping扩展注解

一. @RequestMapping的源码

@RequestMapping是属于springmvc当中的注解,由于现在都流行springboot,减少了springmvc相关的配置文件以致于,很多人都淡化了springmvc的认识,基本上都只知道spring,spring给我们提供了IOC容器还有AOP切面等等,而springmvc主要是帮我们处理请求映射相关,比如前端的传的值,到controller之后直接可以映射到实体类当中,其实这些都是springmvc的功劳。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    String name() default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
}

可以看到注解中的属性除了 name() 返回的字符串,其它的方法均返回数组,也就是可以定义多个属性值,例如 value() 和 path() 都可以同时定义多个字符串值来接收多个URL请求

RequestMapping注解当中用到了三个元注解:@Documented、@Target、@Retention

1.1. @Target作用

里面用到了一个@Target注解,他是干什么的?

@Target在 java中 是注释类。@Target作用于修饰的注释可以修饰的类型范围。

  • @Target(ElementType.TYPE) —— 接口、类、枚举、注解
  • @Target(ElementType.FIELD) —— 字段、枚举的常量
  • @Target(ElementType.METHOD) —— 方法
  • @Target(ElementType.PARAMETER) —— 方法参数
  • @Target(ElementType.CONSTRUCTOR) —— 构造函数
  • @Target(ElementType.LOCAL_VARIABLE) —— 局部变量
  • @Target(ElementType.ANNOTATION_TYPE) —— 注解
  • @Target(ElementType.PACKAGE) —— 包

比如@Target({ElementType.TYPE, ElementType.METHOD}),就代表着@RequestMapping可以用在 接口、类、枚举、注解上、还可以用在方法上!

1.2. @Retention(RetentionPolicy.RUNTIME)

注解按生命周期来划分可分为3类:

  • RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;也就是编译时有效。
  • RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;加载时被抛弃。
  • RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;一直有效!

lombok可以通过@Data注解省去get set 方法,实际上@Data的生命周期就是RetentionPolicy.SOURCE,他是通过注解来标记这个方法要生成get set方法,然后在编译的时候直接会生成get set。生成过后,就被抛弃了。

在这里插入图片描述

1.3. @Documented

@Documented@Deprecated注解长得有点像,@Deprecated是用来标注某个类或者方法不建议再继续使用,@Documented只能用在注解上,如果一个注解@B,被@Documented标注,那么被@B修饰的类,生成文档时,会显示@B。如果@B没有被@Documented标注,最终生成的文档中就不会显示@B。这里的生成文档指的JavaDoc文档!

@Deprecated注解基本上所有框架自定义的注解都会添加,所谓javadoc其实就是JDK给我们提供的一个生成文档的工具!

由于篇幅问题,@Documented详解请看这篇文章:https://blog.csdn.net/weixin_43888891/article/details/126981711

1.4. @Mapping

这个注解应该就是具有真正功能性的注解了,当然我们实际开发当中一般也不会用这个注解。

1.5. @AliasFor

@RequestMapping("student")等同于@RequestMapping(value = "student"),而@RequestMapping注解当中path属性又使用了@AliasFor("value"),也就意味着我们设置了value属性,就算不设置path属性,也可以通过path属性获取到value的值!

@AliasFor("path")
String[] value() default {};

@AliasFor("value")
String[] path() default {};

AliasFor是Spring提供的注解,Alias是别名的意思,For是为了,首先我们通过命名可以得出一个结论,他是为了别名而自定义的注解!

Spring中@AliasFor注解的作用有两点:

  1. 将同一个注解类的属性设置互为别名
  2. 将一个注解上的属性值传递给另一个注解

但这并不是java原生支持的,需要通过Spring中提供的工具类:org.springframework.core.annotation.AnnotationUtils或者org.springframework.core.annotation.AnnotatedElementUtils来解析。AnnotatedElementUtils内部还是调用的AnnotationUtils。

想要了解详情的可以看这篇文章:https://blog.csdn.net/weixin_43888891/article/details/126962698

二. @RequestMapping的属性

  • name:此处name属性,相当于方法的注释,使方法更易理解
  • path:用于指定请求的 URL。
  • method:用于指定请求的方式。
  • params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和配置的一模一样。
  • headers:用于指定限制请求消息头的条件。
  • value:用于指定请求的 URL。它和 path 属性的作用是一样的。
  • consumes:指定处理请求的提交内容类型(Content-Type),例如:application/json、text/html时,才能够让该方法处理请求
  • produces:指定返回的内容类型,返回的内容类型必须是request请求头(Accept)中所包含的类型

三. 实战应用

3.1. 搭建项目

主要搭建的是springboot+jsp项目

1.新建一个springboot项目

2.指定web资源目录

在src/main下创建webapp目录,用于存放jsp文件。这就是一个普通的目录

设置完成后,webapp文件夹就会多出一个像图中显示出来的蓝点,此时,便可在webapp中找到jsp的创建选项了。

3.添加pom依赖

使用jsp的话,tomcat-embed-jasper这个依赖一定要有!

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>

	<dependency>
		<groupId>org.apache.tomcat.embed</groupId>
		<artifactId>tomcat-embed-jasper</artifactId>
	</dependency>
</dependencies>

<build>
	<!--告诉maven,src/main/webapp和src/main/resources都需要进行编译-->
	<resources>
		<resource>
			<directory>src/main/webapp</directory>
			<filtering>true</filtering>
			<includes>
				<include>**/*.*</include>
			</includes>
		</resource>
		<resource>
			<directory>src/main/resources</directory>
			<filtering>true</filtering>
		</resource>
	</resources>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
</build>

4.添加application配置

server.port=8888
# 配置SpringMVC视图解析器
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp

spring.mvc.view.prefix=/ 为什么要配置一个/呢?因为webapp其实就是设置的编译后的根目录,可以看到index.jsp就是在根目录!

在这里插入图片描述

5.新建一个index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Heelo word</h1>
    <p> <a href="#">User Login</a>
</body>
</html>

6.启动项目,测试访问: http://localhost:8888/

通过端口访问,他是默认会去找index.jsp

在这里插入图片描述

7.新建一个success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Welcome</h1>
</body>
</html>

3.2. 测试 value 和 path 属性

这两个属性作用相同,可以互换,如果仅有这一个属性,则可以省略,下面两个例子均采用省略的方式

示例一:

1.新建UserController

将 @RequestMapping 注解在 login 方法上,而UserController上不添加 @RequestMapping 注解,这时的请求 URL 是相对于 Web 根目录

@Controller
public class UserController {

    @RequestMapping("/login")
    public String login() {
        return "success";
    }
}

2.调整index.jsp

这时的方法 login() 能处理的 URL 请求路径是基于 Web 应用的,也就是 http://localhost:8888/login,也就是 index.jsp 页面中的 User Login 链接地址应该是:

<p> <a href="login">User Login</a>

示例二:

将 @RequestMapping 注解在 UserController 类上,这时类的注解是相对于 Web 根目录,而方法上的是相对于类上的路径

1.调整UserController

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/login")
    public String login() {
        return "success";
    }
}

2.调整index.jsp

这时的方法login()能处理的 URL 请求路径则是 http://localhost:8888/user/login,也就是 index.jsp 页面中的 User Login 链接地址应该是:

<p> <a href="user/login">User Login</a>

3.3. 测试 method 属性

1)简介:@RequestMapping 中的 method 主要用来定义接收浏览器发来的何种请求。在Spring中,使用枚举类
org.springframework.web.bind.annotation.RequestMethod来定义浏览器请求的方式。

Http规范定义了多种请求资源的方式,最基本的有四种,分别为:GET(查)、POST(增)、PUT(改)、DELETE(删),而URL则用于定位网络上的资源相当于地址的作用,配合四种请求方式,可以实现对URL对应的资源的增删改查操作。

在实际应用中,很多人并没有按照这个规范做,因为使用GET/POST同样可以完成PUT和DELETE操作。

如果不指定method属性,就代表着任何请求方式都能访问该方法!

2)通过 @RequestMapping(value="/login",method=RequestMethod.GET) 来指定 login()方法 仅处理通过 GET 方式发来的请求

@Controller
@RequestMapping(path = "/user")
public class UserController {
 
	@RequestMapping(path = "/login", method=RequestMethod.GET)
	public String login() {
		return "success";
	}
}

这时,如果浏览器发来的请求不是GET的话,将收到浏览器返回的错误提示,也就是得通过链接的方式而不是表单的方式:

<a href="user/login>User Login</a>

3)通过 @RequestMapping(value="/login",method=RequestMethod.POST) 来指定 login()方法 仅处理通过 POST 方式发来的请求

@Controller
@RequestMapping(path = "/user")
public class UserController {
 
	@RequestMapping(path = "/login", method=RequestMethod.POST)
	public String login() {
		return "success";
	}
}

这时,必须通过表单的方式发送请求,否则将收到浏览器返回的错误提示

<form action="user/login" method="post">
    <input type="submit" value="使用Post发送请求"/>
</form>

4)由于在 RequestMapping 注解类中 method() 方法返回的是 RequestMethod 数组,所以可以给 method 同时指定多个请求方式,例如:

@Controller
@RequestMapping(path = "/user")
public class UserController {
    // 该方法将同时接收通过GET和POST方式发来的请求
	@RequestMapping(path = "/login", method={RequestMethod.POST,RequestMethod.GET})
	public String login() {
		return "success";
	}
}

3.4. 测试 params 属性

该属性表示请求参数,也就是追加在URL上的键值对,多个请求参数以&隔开,例如:

http://localhost/user/login?username=admin&password=123456

则这个请求的参数为username=admin以及password=123456,@RequestMapping 中可以使用 params 来限制请求参数,来实现进一步的过滤请求,举个例子:

@Controller
@RequestMapping(path = "/user")
public class UserController {
        
        // 该方法将接收 /user/login 发来的请求,且请求参数必须为 username=kolbe&password=123456
	@RequestMapping(path = "/login", params={"username=admin","password=123456"})
	public String login() {
		return "success";
	}
}

该例中则表示 UserController 中的 login() 方法仅处理 /user/login 发来的请求,且必须带有 username=admin&password=123456 的请求参数,否则浏览器将返回HTTP 400的错误, 对应 index.jsp 中的键接地址为:

<a href="user/login?username=admin&password=123456">User Login</a>

3.5. 测试 headers 属性

该属性表示请求头,用于HTTP协义交互的信息被称为HTTP报文,客户端发送的HTTP报文被称为请求报文,服务器发回给客户端的HTTP报文称为响应报文,报文由报文头部报文体组成。

  • 请求头部(RequestHeaders):请求头包含许多有关客户端环境和请求正文的信息,例如浏览器支持的语言、请求的服务器地址、客户端的操作系统等。
  • 响应头部(Rsponse Headers):响应头也包含许多有用的信息,包括服务器类型、日期、响应内容的类型及编码,响应内容的长度等等。

如果你安装的是Chrome浏览器,可以通过在网页中 右击鼠标---->审查元素---->Network---->Name中点击网页---->右侧查看Headers即可,如果Name中没有出现网页,可以刷新一下即可,下边是我电脑中的一个请求头部示例:

在这里插入图片描述

回规正题,通过 @RequestMapping 中的 headers 属性,可以限制客户端发来的请求

@Controller
@RequestMapping(path = "/user")
public class UserController {
        // 表示只接收本机发来的请求
	@RequestMapping(path = "/login", headers="Host=localhost:8888")
	public String login() {
		return "success";
	}
}

3.6. 带占位符的URL

1)带占位符的URL是Spring 3.0 新增的功能,可以通过 @PathVariable 将 URL 中的占位符绑定到控制器的处理方法的参数中,占位符使用{}括起来

2)带占位符的URL示例:需要配合@PathVariable接受参数

@Controller
@RequestMapping(path = "/user")
public class UserController {
        
	@RequestMapping(value="/{id}", method=RequestMethod.GET)
	public String show(@PathVariable("id") Integer id) {
		return "success";
	}
}

在这个控制器中 show() 方法将可以接收 user/1、user/2、user/3等等的路径请求,请求的方法必须为GET,使用 @PathVariable 为应用实现 REST 规范提供了具大的便利条件。

3.7. REST 风格的 URL 请求

1)简介:REST(Representational State Transfer):(资源)表现层状态转化,它是目前最流行的一种软件架构,其结构清晰、易于理解、扩展方便且符合标准,正在越来越多的被实践到应用中。

2)REST 风格的 URL 请求

请求路径 请求方法 作用
-/user/1 HTTP GET 得到id为1的user
-/user/1 HTTP DELETE 删除id为1的user
-/user/1 HTTP PUT 更新id为1的user
-/user HTTP POST 新增user

3)JSP目前仅支持 发送GET 和 POST,那put和delete请求怎么办呢?使用带有附加隐藏表单字段 (_method) 的普通 POST 来传递“真正的”HTTP 方法。 然后由spring提供的org.springframework.web.filter.HiddenHttpMethodFilter这个过滤器来进行过滤,将请求转发到put和delete请求,请求参数的名称默认为 _method,可以通过HiddenHttpMethodFilter当中的setMethodParam来修改的。

# 启动HiddenHttpMethodFilter过滤器,以支持浏览器可以发送DELETE PUT 请求
spring.mvc.hiddenmethod.filter.enabled=true

4)由于表单无法发送 DELETE 和 PUT 请求,所以为了让 HiddenHttpMethodFilter 识别请求的方法,需要在表单中添加一个隐藏域,名字为 _method 值为 DELETE 或 POST 或PUT,修改后 index.jsp 页面代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Heelo word</h1>
    <a href="user/login?username=admin&password=123456">User Login</a>

    <!-- 得到id为1的user -->
    <a href="user/1">Test Rest GET</a>

    <!-- 新建id为1的user -->
    <form action="user" method="post">
        <input type="hidden" name="_method" value="POST"/>
        <input type="submit" value="Test Rest POST"/>
    </form>

    <!-- 删除id为1的user -->
    <form action="user/1" method="post">
        <input type="hidden" name="_method" value="DELETE"/>
        <input type="submit" value="Test Rest DELETE"/>
    </form>

    <!-- 更新id为1的user -->
    <form action="user/1" method="post">
        <input type="hidden" name="_method" value="PUT"/>
        <input type="submit" value="Test Rest PUT"/>
    </form>
</body>
</html>

5)添加控制器

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping(value="/{id}", method=RequestMethod.GET)
    public String show(@PathVariable("id") Integer id) {
        System.out.println("查看id为:" + id + "的user");
        return "success";
    }


    @RequestMapping(value="/{id}", method=RequestMethod.PUT)
    public String update(@PathVariable("id") Integer id) {
        System.out.println("更新id为:" + id + "的user");
        return "success";
    }

    @RequestMapping(value="/{id}", method=RequestMethod.DELETE)
    public String destroy(@PathVariable("id") Integer id) {
        System.out.println("删除id为:" + id + "的user");
        return "success";
    }

    @RequestMapping(value="", method=RequestMethod.POST)
    public String create() {
        System.out.println("新建user");
        return "success";
    }
}

6)启动测试:DELETE和PUT请求,到达控制器后,返回时(forward)会报HTTP 405的错误提示,但是请求已经到达了后台。说明是在转发到success的时候进行报错的!

在这里插入图片描述

@RestController就代表这个控制器 不会根据返回值 去寻找视图,代表的是返回的Json数据,或者@ResponseBody+@Controller注解,同样也是,而我们并没有用@RestController,只用了@Controller,每个方法都是返回的String,SpringMvc会根据这个返回的String去寻找对应的页面,然后他默认是请求转发的,而success请求需要通过getpost才能转发成功,put和delete就会报405,解决方案:

  1. 将请求转发(forward)改为请求重定向(redirect)
  2. 自己手动写一个Filter来包装HttpRequest中的getMethod()方法
@RequestMapping(value="/{id}", method=RequestMethod.PUT)
public String update(@PathVariable("id") Integer id) {
    System.out.println("更新id为:" + id + "的user");
    return "redirect:/success.jsp";
}

@RequestMapping(value="/{id}", method=RequestMethod.DELETE)
public String destroy(@PathVariable("id") Integer id) {
    System.out.println("删除id为:" + id + "的user");
    return "redirect:/success.jsp";
}

3.8. consumers属性

一般我们不会设置consumers和produces属性,了解即可!

指定处理请求的提交内容类型(Content-Type),例如:application/json、text/html时,才能够让该方法处理请求

@RequestMapping(value = "getUser",consumes = "application/json")
@ResponseBody
public ModelAndView getUser(){
    ModelAndView view = new ModelAndView();
    return view;
}

3.9. produces属性

指定返回的内容类型,返回的内容类型必须是request请求头(Accept)中所包含的类型

@RequestMapping(value = "login",produces = "application/json")
@ResponseBody
public String login() {
	return "success";
}

此外,produces属性还可以指定返回值的编码

@RequestMapping(value = "getUser",produces = "application/json,charset=utf-8"),则指明返回utf-8编码

四. @RequestMapping扩展注解

spring基于@RequestMapping又扩展出来了4个注解

@GetMapping
@PostMapping
@DeleteMapping
@PutMapping

看源码就可以看出来,连属性都是和@RequestMapping一样,@PutMapping就相当于是@RequestMapping(method = RequestMethod.PUT),说白了就是想帮助我们省代码,没有其他用途!功能都是一样的!

在这里插入图片描述

相关文章:

  • 【MATLAB教程案例20】关于优化类算法的改进方向探索及matlab仿真对比分析
  • [ vulhub漏洞复现篇 ] Apache Flink目录遍历(CVE-2020-17519)
  • mysql的聚簇索引和非聚簇索引
  • 【React项目】从0搭建项目,项目准备和基础构建
  • markdown数学公式编辑指令大全
  • ContentProvider 之 监听共享数据变化
  • 数字IC前端设计怎么学?薪资前景好吗?
  • IDEA+Java控制台实现房屋信息管理系统
  • 微服务项目:尚融宝(终)(核心业务流程:整合Rabbit MQ发送短信)
  • Python骚操作,实现驾考自动答题,这就直接满分了?
  • 【Gitee学习之路】Git概述安装教程基本操作指令
  • 一眼就看懂;Android App 开发前景介绍及学习路线规划
  • Python实现支持向量机SVM分类模型线性SVM决策过程的可视化项目实战
  • 想学习软件测试,求推荐看什么书或者教程?
  • Spring-事务管理
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • CentOS从零开始部署Nodejs项目
  • ERLANG 网工修炼笔记 ---- UDP
  • JSONP原理
  • JS学习笔记——闭包
  • Kibana配置logstash,报表一体化
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • Object.assign方法不能实现深复制
  • python 学习笔记 - Queue Pipes,进程间通讯
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • WebSocket使用
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 大快搜索数据爬虫技术实例安装教学篇
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 项目实战-Api的解决方案
  • 译自由幺半群
  • 云大使推广中的常见热门问题
  • Java数据解析之JSON
  • #Lua:Lua调用C++生成的DLL库
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (4)logging(日志模块)
  • (Pytorch框架)神经网络输出维度调试,做出我们自己的网络来!!(详细教程~)
  • (汇总)os模块以及shutil模块对文件的操作
  • (六)软件测试分工
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • (转)scrum常见工具列表
  • .NET 6 Mysql Canal (CDC 增量同步,捕获变更数据) 案例版
  • .Net IE10 _doPostBack 未定义
  • .NET/C# 如何获取当前进程的 CPU 和内存占用?如何获取全局 CPU 和内存占用?
  • .NET是什么
  • [Android 数据通信] android cmwap接入点
  • [Asp.net MVC]Asp.net MVC5系列——Razor语法
  • [BJDCTF2020]The mystery of ip
  • [BSGS算法]纯水斐波那契数列
  • [BT]BUUCTF刷题第4天(3.22)
  • [BT]小迪安全2023学习笔记(第15天:PHP开发-登录验证)
  • [C++]——带你学习类和对象
  • [CUDA手搓]从零开始用C++ CUDA搭建一个卷积神经网络(LeNet),了解神经网络各个层背后算法原理