java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringMVC @RequestMapping注解

SpringMVC中的@RequestMapping注解的使用详细教程

作者:从未止步..

@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>

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

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

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

以上就是SpringMVC中的@RequestMapping注解的使用详细教程的详细内容,更多关于SpringMVC @RequestMapping注解的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文