记录学习 SpringBoot 中的 MVC 常用注解的使用方法和特点

  • @RestController
  • @RequestMapping
  • @PathVariable
  • @RequestParam
  • @RequestBody

学习的过程中参考了 跟武哥一起学习Spring Boot,以及 Spring Boot + Vue 全栈实战 等内容,结合自己的理解总结而来

一、@RestController

1.1 注解解释

作用:

这个注解是 SpringBoot 里面新增的注解,其实 RestController = RequestBody + Controller 注解,我们可以擦看这个注解的源码

image.png
我们学习过 SpringMVC 的时候就知道了

  • Controller 标注的类,其中的方法,如果没有被 Controller 修饰的话,一般都是返回一个视图(一个具体的 页面),这个视图回合模板引擎结合在一起使用
  • RequestBody 注解的功能是将返回的数据结构转换为 JSON 格式

在前后端分离的项目中,使用 @RestController 就可以直接返回 JSON 数据了,比如下面这个例子:

  1. public String Test() {
  2. return "hello";
  3. }

如果它的类是由 controller 修饰的,那么会返回 hello.html 页面
否则返回的就是一个 JSON 字符串 “hello”

二、@RequestMapping

作用:

处理请求地址映射的注解,它可以用于类上,也可以用于方法上。在类的级别上的注解会有一个特定请求或请求模式映射到一个控制器上,表示该类的所有请求方法都是以该路径作为父路径的;在方法的级别

2.1 三个常用属性

  • value 属性:指定请求的实际地址,value 可以省略
  • method 属性:指定请求的类型,主要有 GET PUT POST DELETE 默认为 get
  • produces属性:只当返回内容类型,入 produces = “application/json;charset=UTF-8”
  1. @RequestMapping(value = "/test",method = RequestMethod.GET)
  2. public String test () {
  3. return "这是一个测试";
  4. }

2.2 常见的请求方法

method 属性支持的方法:查看它的源码
除了 get,post 等常见方法,还有 head,options 等我们很少见到的方法

  1. package org.springframework.web.bind.annotation;
  2. public enum RequestMethod {
  3. GET,
  4. HEAD,
  5. POST,
  6. PUT,
  7. PATCH,
  8. DELETE,
  9. OPTIONS,
  10. TRACE;
  11. private RequestMethod() {
  12. }
  13. }

还有另一种注解的形式,它可以直接指定请求体 和 路径
@GetMapping(“/test”) 就等价于 @RequestMapping(value = “/test”,method = RequestMethod.GET)

2.3 其它的请求方式

常见类似的还有

  • @PutMapping
  • @DeleteMapping
  • @PostMapping
  • @GetMapping(“/test1”)

三、@PathVariable

作用:

用来获取 url 参数的,SpringBoot 支持 restful 风格的 url,比如 GET 请求 袖带一个 id 参数,我们将 id 参数进行接收,可以使用该注解

3.1 试试 get 请求携带参数

  1. @GetMapping("/user/{id}")
  2. public String testPathVarible(@PathVariable Integer id) {
  3. System.out.println("获取到的 id 为:"+id);
  4. return "请求成功";
  5. }

然后我们在 API 测试工具中测试 http://localhost:8081/user/12
image.png
image.png

3.2 试试 post 请求携带参数

  1. @PostMapping("/user/{id}")
  2. public String testPathVarible1(@PathVariable Integer id) {
  3. System.out.println("获取到的 id 为:"+id);
  4. return "请求成功";
  5. }

image.png
image.png

3.3 请求参数与接收参数不一致的情况

我们希望 url 中的占位符的 id 值能直接赋值到参数 id 中,需要保证 url 中的参数和方法接收参数一致,如果不一致,否则就无法就收。但是不一致的话,可以通过 @PathVariable 中的 value 属性指定

  1. @RequestMapping(value = "/testUser/{ida}",method = RequestMethod.GET)
  2. public String testPathVariable2(@PathVariable(value = "ida") Integer id) {
  3. System.out.println("id为:"+ id);
  4. return "请求成功";
  5. }

image.png

3.4 携带多个请求参数

在 url 中,占位符的位置可以在任何位置,不一定非要在最后,比如 /xxx/{id}/user。url 也可以穿插多个 占位符,方法参数同样采用相同数量来接收,接收原理是一样的。

  1. @RequestMapping("/books/{id}/{authorName}")
  2. public String testBook(@PathVariable Integer id, @PathVariable(value = "authorName") String name) {
  3. System.out.println("获得的书籍的编号是:" + id);
  4. System.out.println("获取的书籍的名字是:" + name);
  5. return "获取成功";
  6. }

image.png
image.png
总之:接收不同的参数的时候,当 url 中的参数 和 方法中的参数名不一致的话,就可以使用 value 来指定参数。

四、@RequestParam

该注解根据名字翻译得来即可知道,也是用于获取请求参数的,上面的方法同样是获取请求参数的,但是区别在哪里呢?


4.1 get 携带参数

  1. @RequestMapping("/order")
  2. public String testOrder(@RequestParam Integer id) {
  3. System.out.println("获取的订单编号为:"+id);
  4. return "获取成功";
  5. }

访问:http://localhost:8081/order?id=1231231123

控制台打印结果
image.png
响应结果
image.png

4.2 @RequestParam 参数解释

和上面一样的, @RequestParam 也具有 value 属性,除了 value属性,还有一个 required 属性,defaultValue 属性,下面我们看下他们的功能

  • value:当传入的参数 和 方法参数名不一致时,可以使用 value 指定传入的参数名
  • required:是布尔值,用来表示改参数是否为必须传入
  • defaultValue 属性:默认值,表示请求中没有同名参数的时的默认值
  1. // 这里就表示,我可以传入一个名为 idd 的参数(非必须传),并使用 value 指定为 idd
  2. @RequestMapping("/cat")
  3. public String testCat(@RequestParam(value = "idd", required = false) Integer id) {
  4. return "传入的参数为 id:"+ id;
  5. }

然后访问:http://localhost:8081/cat?idd=1231231123
响应结果
image.png

4.3 处理 post 请求

该注解处理 get 请求,接收拼接在 url 上的参数,除此之外,还可以用于 post 请求,接收前端表单提交的参数,假设前端提交两个参数,分别是 username 和 password,我们就可以用 @RequestParam 进行接收

先在 static 页面撸一个表单出来

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <form action="/form" method="post">
  9. <label for="username">账户:</label>
  10. <input type="text" name="username" id="username"><br>
  11. <label for="password">密码:</label>
  12. <input type="password" name="password" id="password"><br>
  13. <input type="submit">
  14. </form>
  15. </body>
  16. </html>

编写 controller

//    处理 form 的
    @RequestMapping(value = "/form",method = RequestMethod.POST)
    public String testForm(@RequestParam String username, @RequestParam String password) {
        System.out.println("账户:"+username);
        System.out.println("密码:"+password);
        return "请求成功";
    }

访问:http://localhost:8081/form.html
image.png
image.png
但是如果出现参数过多的情况,我们要如何解决呢?总不能每一个参数前面都加上 @RequestParam 注解把

4.4 封装实体接收参数

表单数据过多时,我们就可以封装实体类来接收这些参数,因此我们可以编写一个名为 User 的实体类

public class User {
    private String username;
    private Integer age;
    private String password;

    // getter 和 setter 省略,必须要加上,不然数据无法注入进去,构造方法也不要加,就默认的就可以了
}

修改前端表单

    <h3>封装参数</h3>
    <form action="/form2" method="post">
        账户:<input type="text" name="username"><br>
        年龄:<input type="text" name="age"><br>
        密码:<input type="password" name="password" ><br>
        <input type="submit">
    </form>

编写 controller

    @RequestMapping("/form2")
    public String testForm2(User u) { // 直接传入一个对象即可,表单的数据会通过 setter 注入
        System.out.println("账户:"+ u.getUsername());
        System.out.println("年龄:" + u.getAge());
        System.out.println("密码:"+ u.getPassword());
        return "OK";
    }

image.png
总结:在实际的项目当中,一般都是封装一个实体来接收表单数据

五、 @RequestBody

5.1 作用解释

作用:

该注解用于接收前端传来的实体,接收参数也是对应的实体,比如前端通过 JSON 提交过来两个参数 username 和 password,此时我们需要在后端接收一个实体来接收,在传递参数比较多的情况下,使用 @RequestBody 会比较好

5.2 代码测试

我们编写前端 内容

    <h3>requestBody 测试</h3>
    <button id="btn" value="发送">发送</button>

    <script type="text/javascript">
        let btn = document.getElementById("btn");
        btn.addEventListener("click", ()=> {
            fetch("/form3",{
                method: "POST",
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    username: "coco",
                    age: 19,
                    password: "1231ada"
                })
            }).then((data) => {
               return  data.text();
            }).then((res) => {
                console.log(res);
            })
        })
    </script>

controller 编写

    @RequestMapping("/form3")
    public String testForm3(@RequestBody  User u) {
        System.out.println("账户:"+ u.getUsername());
        System.out.println("年龄:" + u.getAge());
        System.out.println("密码:"+ u.getPassword());
        return "success";
    }

5.3 响应结果

代码给大家解释一下,我这里发送数据没有使用表单,而是使用的 fetch API 发起 ajaxx 请求,使用了 ES6 语法,为了保证我传输的数据是 JSON 格式的,因此我使用了 JSON.stringify() 方法,将请求参数 JSON 化,然后将得到的相应结果通过 控制台打印出来。

响应结果
image.png

哈哈,不知不觉又想到了前后端交互,理论 + 实践 得到真理

六、总结

以上的 五个注解是我们学习 Spring MVC 一定会遇到了,现在学习 SpringBoot 再加深一遍理解,这也是为自己以后写项目打下坚实的基础。