Request
是请求的意思,而
Mapping
是映射的意思,合起来就是请求映射,什么是请求映射,http://localhost:8080/student/get 这个很明显是一个请求的url吧,通过url我们要调用到代码当中的方法,方法那么多,怎么知道调用哪个呢?没错就是依靠
@RequestMapping
,可以在方法当中使用
@RequestMapping("/student/get")
,这样就可以通过
/student/get
这个
url
调用到这个方法了,一句话:
用于建立请求的URL 和 处理请求方法之间的对应关系。
目录
一. @RequestMapping的源码
@RequestMapping是属于springmvc当中的注解,由于现在都流行springboot,减少了springmvc相关的配置文件以致于,很多人都淡化了springmvc的认识,基本上都只知道spring,spring给我们提供了IOC容器还有AOP切面等等,而springmvc主要是帮我们处理请求映射相关,比如前端的传的值,到controller之后直接可以映射到实体类当中,其实这些都是springmvc的功劳。
@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documented@Mappingpublic@interfaceRequestMapping{Stringname()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注解的作用有两点:
- 将同一个注解类的属性设置互为别名
- 将一个注解上的属性值传递给另一个注解
但这并不是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><ahref="#">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 根目录
@ControllerpublicclassUserController{@RequestMapping("/login")publicStringlogin(){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")publicclassUserController{@RequestMapping("/login")publicStringlogin(){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")publicclassUserController{@RequestMapping(path ="/login", method=RequestMethod.GET)publicStringlogin(){return"success";}}
这时,如果浏览器发来的请求不是GET的话,将收到浏览器返回的错误提示,也就是得通过链接的方式而不是表单的方式:
<a href="user/login>User Login</a>
3)通过
@RequestMapping(value="/login",method=RequestMethod.POST)
来指定 login()方法 仅处理通过 POST 方式发来的请求
@Controller@RequestMapping(path ="/user")publicclassUserController{@RequestMapping(path ="/login", method=RequestMethod.POST)publicStringlogin(){return"success";}}
这时,必须通过表单的方式发送请求,否则将收到浏览器返回的错误提示
<form action="user/login" method="post">
<input type="submit" value="使用Post发送请求"/>
</form>
4)由于在 RequestMapping 注解类中 method() 方法返回的是 RequestMethod 数组,所以可以给 method 同时指定多个请求方式,例如:
@Controller@RequestMapping(path ="/user")publicclassUserController{// 该方法将同时接收通过GET和POST方式发来的请求@RequestMapping(path ="/login", method={RequestMethod.POST,RequestMethod.GET})publicStringlogin(){return"success";}}
3.4. 测试 params 属性
该属性表示请求参数,也就是追加在URL上的键值对,多个请求参数以&隔开,例如:
http://localhost/user/login?username=admin&password=123456
则这个请求的参数为username=admin以及password=123456,@RequestMapping 中可以使用 params 来限制请求参数,来实现进一步的过滤请求,举个例子:
@Controller@RequestMapping(path ="/user")publicclassUserController{// 该方法将接收 /user/login 发来的请求,且请求参数必须为 username=kolbe&password=123456@RequestMapping(path ="/login", params={"username=admin","password=123456"})publicStringlogin(){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")publicclassUserController{// 表示只接收本机发来的请求@RequestMapping(path ="/login", headers="Host=localhost:8888")publicStringlogin(){return"success";}}
3.6. 带占位符的URL
1)带占位符的URL是Spring 3.0 新增的功能,可以通过 @PathVariable 将 URL 中的占位符绑定到控制器的处理方法的参数中,占位符使用{}括起来
2)带占位符的URL示例:需要配合@PathVariable接受参数
@Controller@RequestMapping(path ="/user")publicclassUserController{@RequestMapping(value="/{id}", method=RequestMethod.GET)publicStringshow(@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><ahref="user/login?username=admin&password=123456">User Login</a><!-- 得到id为1的user --><ahref="user/1">Test Rest GET</a><!-- 新建id为1的user --><formaction="user"method="post"><inputtype="hidden"name="_method"value="POST"/><inputtype="submit"value="Test Rest POST"/></form><!-- 删除id为1的user --><formaction="user/1"method="post"><inputtype="hidden"name="_method"value="DELETE"/><inputtype="submit"value="Test Rest DELETE"/></form><!-- 更新id为1的user --><formaction="user/1"method="post"><inputtype="hidden"name="_method"value="PUT"/><inputtype="submit"value="Test Rest PUT"/></form></body></html>
5)添加控制器
@Controller@RequestMapping("/user")publicclassUserController{@RequestMapping(value="/{id}", method=RequestMethod.GET)publicStringshow(@PathVariable("id")Integer id){System.out.println("查看id为:"+ id +"的user");return"success";}@RequestMapping(value="/{id}", method=RequestMethod.PUT)publicStringupdate(@PathVariable("id")Integer id){System.out.println("更新id为:"+ id +"的user");return"success";}@RequestMapping(value="/{id}", method=RequestMethod.DELETE)publicStringdestroy(@PathVariable("id")Integer id){System.out.println("删除id为:"+ id +"的user");return"success";}@RequestMapping(value="", method=RequestMethod.POST)publicStringcreate(){System.out.println("新建user");return"success";}}
6)启动测试:DELETE和PUT请求,到达控制器后,返回时(forward)会报HTTP 405的错误提示,但是请求已经到达了后台。说明是在转发到success的时候进行报错的!
@RestController就代表这个控制器 不会根据返回值 去寻找视图,代表的是返回的Json数据,或者
@ResponseBody+@Controller
注解,同样也是,而我们并没有用
@RestController
,只用了@Controller,每个方法都是返回的String,SpringMvc会根据这个返回的String去寻找对应的页面,然后他默认是请求转发的,而success请求需要通过
get
或
post
才能转发成功,
put和delete
就会报405,解决方案:
- 将请求转发(forward)改为请求重定向(redirect)
- 自己手动写一个Filter来包装HttpRequest中的getMethod()方法
@RequestMapping(value="/{id}", method=RequestMethod.PUT)publicStringupdate(@PathVariable("id")Integer id){System.out.println("更新id为:"+ id +"的user");return"redirect:/success.jsp";}@RequestMapping(value="/{id}", method=RequestMethod.DELETE)publicStringdestroy(@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")@ResponseBodypublicModelAndViewgetUser(){ModelAndView view =newModelAndView();return view;}
3.9. produces属性
指定返回的内容类型,返回的内容类型必须是request请求头(Accept)中所包含的类型
@RequestMapping(value ="login",produces ="application/json")@ResponseBodypublicStringlogin(){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)
,说白了就是想帮助我们省代码,没有其他用途!功能都是一样的!
版权归原作者 怪 咖@ 所有, 如有侵权,请联系我们删除。