SpringMVC中的@RequestMapping注解的详细介绍过程~

简介: SpringMVC中的@RequestMapping注解的详细介绍过程~

@RequestMapping注解的功能:

从注解名称上我们可以看出,@RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系,SpringMVC接收到指定的请求,就会来找到在映射关系中对应的控制方法来处理这个请求。


@RequestMapping注解的位置:

@RequestMapping标识一个类:设置映射请求的请求路径的初始信息

@RequestMapping标识一个方法:设置映射请求,请求路径的具体信息

如下所示:

当前我们Protal方法的访问路径是hello

package AnnotationController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class ProtalController {
    @RequestMapping("/hello")
    public String Protal(){
        return "index";
    }
}

当前的控制层,我们只给控制层中的Protal方法加上了@RequestMapping注解,而并没有给该控制层的类上加,因此我们可以直接通过Protal方法上的请求路径访问。


假设我们此时也给类加上@RequestMapping注解,访问地址不变化,如下所示:

@RequestMapping("test")
public class ProtalController {

访问结果如下所示,我们会发现当前资源无法被找到

要想资源 被正确的访问,我们需要进行如下操作:

在路径的具体信息之前添加路径的初始信息,因为当在类上添加了请求路径的初始信息之后,我们想访问该类中的某个方法,就必须先正确的访问到该类。

而这样做的目的在于,在实际开发中,我们往往会给请求方法设置较为简单的路径请求具体信息,例如查询学生的方法,我们会将其请求路径具体的信息设置select,删除学生的方法,我们会将其我们会将其请求路径具体的信息设置delete,而需求往往不是适合于一类人而已,对于除学生以外的其他用户,都会有增删的操作,这样就导致了,系统也不知道该访问哪一个,因此,我们需要在类上添加请求路径的初始化信息。


@RequestMapping注解value属性值:

我们通过查看@RequestMapping注解:

它的匹配方式有很多种,通过请求路径,通过请求方法…,而比较常用的就是通过path和method

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
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 org.springframework.core.annotation.AliasFor;
@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 {};
}

@RequestMapping注解value属性:

通过查看源码可知,value的类型为String[],如下所示:

我们将@RequestMapping的值设置为多个

package AnnotationController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class ProtalController {
  //当匹配方式中只有value时,value可以省略不写
    @RequestMapping({"/hello","/abc"})
    public String Protal(){
        return "index";
    }
}

那么我们是否可以根据数组中任意的一个值来访问到正确的资源呢?

我们将项目重新部署:

由此可知,@RequestMapping注解value属性的作用是通过请求的请求路径匹配请求value属性是数组类型,即当前浏览器所发送请求的请求路径匹配value属性中的任何一个值,则当前请求就会被注解所标识的方法进行处理

@RequestMapping注解method属性:

通过查看源码如下所示,我们知道method属性是ReuestMethod类型的:

RequestMethod[] method() default {};

继续跟进查看ReuestMethod的源码,如下所示:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.web.bind.annotation;
public enum RequestMethod {
    GET,
    HEAD,
    POST,
    PUT,
    PATCH,
    DELETE,
    OPTIONS,
    TRACE;
    private RequestMethod() {
    }
}

我们发现它是一个枚举类型,列举了所有的请求方式,其中get和post是我们已经学过的,那么接下来我们就以post和get请求为例演示起作用。

创建实现页面跳转的模块

首页请求控制器

package AnnotationController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class ProtalController {
    @RequestMapping("/")
    public String Protal(){
        return "index";
    }
}

跳转页面请求控制器

package AnnotationController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class JumpPageController {
  @RequestMapping(value = {"/hello","/abc"},method= RequestMethod.GET)
    public String Page(){
        return "success";
    }
}


index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>成功进入首页!</h1>
<a th:href="@{/hello}">测试@RequestMapping注解所标识的位置</a><br>
<a th:href="@{/abc}">测试@RequestMapping注解的value属性</a><br>
<form th:action="@{/hello}">
    <input type="submit" value="测试@RequestMapping注解的method属性">
</form>
</body>
</html>


success.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>成功</title>
</head>
<body>
<h1>成功进入!</h1>
</body>
</html>

此时运行服务器,如下所示:

点击其中的任何一个连接,都会出现如下字样:

通过输出结果,我们不难发现将@RequestMapping注解中的method属性值设置为

RequestMethod.GET,也就是匹配get请求的方式是没有任何问题的,那么如果我们将其匹配的是post还会如此吗?


修改@RequestMapping注解中的method属性值为RequestMethod.POST,再次运行:


出现下述异常:


tomcat告诉我们是因为方法不被支持


那为什么当我们将将@RequestMapping注解中的method属性值设置为RequestMethod.GET就能正确的处理请求?原因是:无论是超链接还是表单,默认的提交方式都是get请求,因此当我们没有设置其值的情况情况下,默认的就是get请求方式

我们可以将表单的提交方式设置为POST,这样就可以处理POST请求了:

<form th:action="@{/hello}" method="post">
    <input type="submit" value="测试@RequestMapping注解的method属性">
</form>

如下所示,通过method属性,将其表单提交的方式设置为post

此时点击该按钮就可以成功的进入success.html页面啦

但是需要注意的是,如果我们把当前可以访问成功的地址复制,直接在浏览器中访问,如下所示:

还是出现了405错误,原因是我们将地址复制直接通过地址栏访问,实际上是get请求,但是我们又在注解中将其请求方法设置为post请求,由于未能匹配,所以出现了405错误

通过查看它的源码,我们得知其method是一个数组类型的,那么我们就可以利用这一特性,让它既能匹配get请求,又能匹配post请求,设置如下所示:

@RequestMapping(value = {"/hello","/abc"},method= {RequestMethod.POST,RequestMethod.GET})

此时我们刷新刚刚复制地址,而导致报错的页面,就能成功访问啦,只要是get、post中的任意一个都能被成功访问


@RequestMapping注解的method属性的作用是通过请求的请求方式匹配请求,它RequestMethod类型的数组,即当前浏览器所发送请求的请求方式匹配method属性中的任何一个请求,如果匹配成功,那么当前请求就会被注解所标识的方法进行处理,若浏览器所发送的请求的请求路径和@RequestMapping注解value属性匹配,但是请求方式不匹配,页面会报错,如下所示:

在@ResquestMapping的基础上,结合请求方式的一些派生注解:

@GetMapping,@PostMapping,@DeleteMapping,@PutMapping,关于这些注解在后续的学习中会使用。

@RequestMapping注解params属性:

String[] params() default {};

@RequestMapping注解params属性的作用是通过请求的请求参数匹配请求,即浏览器发送的请求的请求参数必须满足params属性的设置,params可以使用四种表达式:

“param”:表示当前所匹配请求的请求参数中必须携带param参数

测试如下所示:

在注解中,我们添加param属性,并给定一个值为username

package AnnotationController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class JumpPageController {
    @RequestMapping(value = {"/hello","/abc"},
            method= {RequestMethod.POST,RequestMethod.GET}
    ,params = {"username"})
    public String Page(){
        return "success";
    }
}

再重新进行项目的部署,点击超链接或者表单中的按钮,出现以下错误:

原因是,我们在注解中设置了其参数的值,而在地址栏中并没有该参数的值,所以会报错。

解决方法如下所示:

<!--以下两种方式毫无区别,唯一的区别是第一种写法在源文件中会报错,但是该报错不影响代码的编译和执行 -->
<a th:href="@{/hello?username=admin}" >测试@RequestMapping注解的param属性</a><br>
<a th:href="@{/hello(username='admin')}" >测试@RequestMapping注解的param属性</a>

通过这种方式,浏览器会在地址栏自动为我们添加其值,如下所示:

此时页面也能被成功的访问到!

但需要注意的是,param属性和method属性以及value属性可不一样哦,当我们将method属性和value属性中设置有多个值时,只要能匹配到其中的任意一个即可,但是对于param属性来说,如果设置的值有多个必须同时匹配,测试如下:

给param属性值增加password,其他地方不做任何的变动

@RequestMapping(value = {"/hello","/abc"},
            method= {RequestMethod.POST,RequestMethod.GET}
    ,params = {"username","password"})

测试结果如下所示:

此时报错原因依然为在注解中设置了Parma属性值password,但是未能匹配到该值,所以出现错误,解决方法有两种,一种是我们在html文件中设置该参数,由浏览器自动为我们匹配,如下所示:

index.html:

<a th:href="@{/hello(username=${admin},password=${1234})}" >测试@RequestMapping注解的param属性</a>
<a th:href="@{/hello(username='admin',password='12345')}">测试@RequestMapping注解的param属性</a>

重新部署项目,运行如下所示:

第二种方式是我们在地址栏通过手动添加缺失的参数,如下所示:

也可以成功进入到我们想访问的页面!

“!param”:表示当前所匹配请求的请求参数中一定不能携带param参数

假设此时我们将注解修改如下所示:

请求参数中不可以包含password,即使是只有password这个参数,没有值也不可以。

@RequestMapping(value = {"/hello","/abc"},
            method= {RequestMethod.POST,RequestMethod.GET}
    ,params = {"username","!password"})

重新部署项目如下所示,我们手动在地址栏添加了password,虽然只是添加了该参数没有给定具体的值,结果也报错了。

“param=value”:表示当前所匹配请求的请求参数中必须携带param参数且值必须为value

假设此时我们将注解修改如下所示:

添加请求参数,并将其值设置为20

@RequestMapping(value = {"/hello","/abc"},
            method= {RequestMethod.POST,RequestMethod.GET}
    ,params = {"username","!password","age=20"})

重新部署项目,如下所示,只有当注解中的设置的所有请求参数都被满足时,该请求才能被正确处理

“param!=value”:表示当前所匹配请求的请求参数中可以不携带param,若携带值一定不能是value

假设此时我们将注解修改如下所示:

添加新的请求参数gender,并设置其值不能为男

 @RequestMapping(value = {"/hello","/abc"},
            method= {RequestMethod.POST,RequestMethod.GET}
    ,params = {"username","!password","age=20","gender!=男"})

重新部署项目,测试如下所示:

手动添加其参数的值,gender的值可以是除了男以外的任何值,当然也可以不传值,或者不手动在地址栏添加该请求参数均可


@RequestMapping注解headers属性:

String[] headers() default {};

@RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射,它是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系,如下所示:


"header":要求请求映射所匹配的请求必须携带header请求头信息


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


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


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


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

例如:我们可以通过设置headers的referer属性来指明当前资源的来源地址,如下所示:

@RequestMapping(value = {"/hello","/abc"},
            method= {RequestMethod.POST,RequestMethod.GET},headers = {"referer"})

重新部署项目,在浏览器中右击打开检查,如下所示为我们为点击该超链接的请求头信息:

此时我们点击该超链接,如下图所示,与上图不同之处在于多了一个Referer属性,而该属性的值即为该页面的来源地址

注意:响应头和请求头中的键不区分大小写但是其键值区分大小写

@RequestMapping注解使用ant风格的路径:

?:表示任意的单个字符

举例如下:

**第一步:**编写新的测试方法,并将其RequestMapping的值设置为/a?a/test/ant

package AnnotationController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class JumpPageController {
    @RequestMapping("/a?a/test/ant")
    public String testAnt(){
        return "success";
    }
}

第二步:在index.html中为其添加超链接

<a th:href="@{/aaa/test/ant}">测试@RequestMapping注解支持ant风格的路径</a><br>

将项目重新部署,测试结果如下:

点击该超链接:

通过我们在index.html文件中设置的路径,此时资源被正确的访问到,既然?是代表一个任意的字符,那么我们可以将a和a中键的位置任意选择一个符号来代替,可以是数字,可以是其他字母,当然也可以是特殊字符,但是需要注意不能是英文的问号,中文的问号是可以的,否则如下所示:

原因是**?前面是请求路径,问号后面是请求参数**,/a?a/test/ant并不会被当做一个完整的请求路径,其替代?的字符也不能是/,因为它代表地址的分隔符,表示新的一层目录


*:表示任意的0个或多个字符

举例如下:

此时我们将上述注解中的?替换为*,如下所示:

@RequestMapping("/a*a/test/ant")

将项目重新部署后,刷新浏览器页面如下所示:

无论是一个字符还是多个字符,都能成功的访问地址

而需要注意的是和?占位符相同,此时替代*的字符不可以是/或者?(英文),否则会出现404,原因和?的是相通的

**:表示任意层数的任意目录

举例如下:

将路径中的具体信息修改为如下所示:

@RequestMapping("/**/test/ant")

需要注意的是**只能写在//中,前后都不能有任何的字符

错误实例:

@RequestMapping("/a**a/test/ant")
  @RequestMapping("/**a/test/ant")

重新部署项目,测试结果如下所示:

/**/所代表的的目录我们既可以设置为一层,也可以设置为多层

但需要注意的是,即使可以设置任意层,但是目录中依然不可以包含有英文的问号,否则如下所示:

注意:在使用**时,只能使用/**/xxx的方式

@RequestMapping注解使用路径中的占位符:

通过路径传值的传统方式为:

/deleteUser?id=1

下面我们要介绍一种简单的方式:需要在@RequestMapping注解的value属性中所设置的路径中使用{xxx}的方式表示路径中的数据,在通过@PathVariable注解,将占位符所标识的值和控制器方法的形参进行绑定,具体操作如下所示:

第一步:编写对应的控制器方法

package AnnotationController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class JumpPageController {
    //注意:有几个参数需要写几个{xxx}{xxx}
    @RequestMapping("/test/rest/{username}/{id}")
    //@PathVariable注解的值必须与@RequestMapping注解路径具体信息中的参数名称相一致,否则会出现500错误
    public String testRest(@PathVariable("id") Integer id,@PathVariable("username") String  username){
        //获取对应参数的值
        System.out.println("id:"+id+","+"username:"+username);
        return "success";
    }
}

第二步:在index.html文件中,设置其参数的具体值

注意这里值的顺序应与@RequestMapping注解中的参数顺序保持一致,否则会因为类型不匹配导致出现400错误

<a th:href="@{/test/rest/admin/1}">测试@RequestMapping注解value属性中的占位符</a><br>

重新部署项目,测试结果如下:

在浏览器栏显示了其参数的值

在控制台,也将对应的参数信息显示出来了

相关文章
|
JSON 前端开发 Java
Spring MVC入门必读:注解、参数传递、返回值和页面跳转(下)
Spring MVC入门必读:注解、参数传递、返回值和页面跳转(下)
109 0
|
JSON 前端开发 Java
SpringMVC系列(二)之常用注解介绍及参数传递说明
SpringMVC系列(二)之常用注解介绍及参数传递说明
|
存储 JSON 前端开发
SpringMVC的注解、参数传递、页面跳转
SpringMVC的注解、参数传递、页面跳转
91 0
|
前端开发 Java Spring
39SpringMVC - 注解映射器和适配器
39SpringMVC - 注解映射器和适配器
54 0
SpringMVC入门到实战------3、@RequestMapping注解(超详细基础知识+实际代码案例)
该博客文章详细介绍了SpringMVC中`@RequestMapping`注解的使用方法,包括其功能、位置、value属性、method属性、params属性、headers属性以及支持的路径风格和占位符,并通过实际代码案例展示了如何建立请求与控制器方法之间的映射关系。
SpringMVC入门到实战------3、@RequestMapping注解(超详细基础知识+实际代码案例)
|
6月前
|
前端开发 Java Spring
请求映射掌握:探讨Spring MVC中@RequestMapping注解的妙用
请求映射掌握:探讨Spring MVC中@RequestMapping注解的妙用
148 1
请求映射掌握:探讨Spring MVC中@RequestMapping注解的妙用
|
缓存 前端开发 Java
【SpringMVC】JSR 303与拦截器注解使用
【SpringMVC】JSR 303与拦截器注解使用
73 0
|
前端开发 Java Spring
Spring MVC拦截器+注解方式实现防止表单重复提交
Spring MVC拦截器+注解方式实现防止表单重复提交
100 0
|
6月前
|
XML 前端开发 Java
【SpringMVC】 一文掌握 》》》 @RequestMapping注解
【SpringMVC】 一文掌握 》》》 @RequestMapping注解
67 1
|
6月前
|
前端开发 Java 应用服务中间件
SpringMVC之@RequestMapping注解
SpringMVC之@RequestMapping注解