自学内容网 自学内容网

Spring Boot 学习之路 -- 处理 HTTP 请求

前言

  1. 最近因为业务需要,被拉去研究后端的项目,代码基于 Spring Boot,对我来说完全小白,需要重新学习研究…
  2. 出于个人习惯,会以 Blog 文章的方式做一些记录,文章内容基本来源于「 Spring Boot 从入门到精通(明日科技) 」一书,做了一些整理,更易于个人理解和回顾查找,所以大家如果希望更系统性的学习,可以阅读此书(比较适合我这种新手)。

HTTP 请求是指从客户端到服务器的请求消息。对于一个 Spring Boot 项目而言,服务器就是 Spring Boot,客户端就是用户本地的浏览器。启动 Spring Boot 项目后,首先用户通过 URL 地址发送请求,然后 Spring Boot 通过解析 URL 地址处理请求,最后 Spring Boot 把处理结果返回给用户。

HTTP 请求有 3 种很常见的请求类型,它们分别是 GET、POST 和 DELETE

其中:

  • GET:表示请求从服务器获取特定资源;
  • POST:表示在服务器上创建一个新的资源;
  • DELETE:表示从服务器删除特定的资源。

本文将介绍 Spring Boot 是如何使用注解解析 URL 地址,进而处理上述 3 种类型的 HTTP 请求的。


一、处理 HTTP 请求的注解

在开发 Spring Boot 项目的过程中,Spring Boot 的典型应用是处理 HTTP 请求。所谓处理 HTTP 请求,就是 Spring Boot 把用户通过 URL 地址发送的请求交给不同的业务代码进行处理的过程。

1.1 使用 @Controller 声明控制器类

Spring Boot 提供了用于声明控制器类的 @Controller 注解。也就是说,在 Spring Boot 项目中,把被 @Controller 注解标注的类称作控制器类。控制器类在 Spring Boot 项目中发挥的作用是处理用户发送的 HTTP 请求。Spring Boot 会把不同的用户请求交给不同的控制器进行处理,而控制器则会把处理后得到的结果反馈给用户。

说明:

控制器(controller)定义了应用程序的行为,它负责对用户发送的请求进行解释,并把这些请求映射成相应的行为。

因为 @Controller 注解本身被 @Component 注解标注,所以控制器类属于组件。这说明在启动 Spring Boot 项目时,控制器类会被扫描器自动扫描。这样,程序开发人员就可以在控制器类中注入 Bean。例如,在控制器中注入 Environment 环境组件,代码如下:

​​​​@Controller
​​​​public class TestController {
​​​​    @Autowired
​​​​    Environment env;
​​​​}​​

1.2 使用 @RequestMapping 映射 URL 地址

Spring Boot 提供了用于映射 URL 地址的 @RequestMapping 注解。@RequestMapping 注解可以标注类和方法。如果一个类或者方法被 @RequestMapping 注解标注,那么这个类或者方法就能够处理用户通过 @RequestMapping 注解映射的 URL 地址发送的请求。

下面将首先介绍 @RequestMapping 注解的属性,然后介绍如何使用 @RequestMapping 注解映射包含层级关系的 URL 地址。

注意:

@Controller 注解要结合 @RequestMapping 注解一起使用。

1.2.1 @RequestMapping 注解的属性

@RequestMapping 有几个常用属性,下面分别对这些属性予以介绍。

value 属性

value 属性是 @RequestMapping 注解的默认属性,用于指定映射的 URL 地址。在单独使用 value 属性时,value 属性可以被隐式调用。调用 value 属性的语法如下:

​​​​@RequestMapping("test")
​​​​@RequestMapping("/test")
​​​​@RequestMapping(value= "/test")
​​​​@RequestMapping(value={"/test"})​​

上面这 4 种语法所映射的 URL 地址均为“域名/test”。其中,域名指的是当前 Spring Boot 项目所在的域。如果在 IntelliJ IDEA 中启动一个 Spring Boot 项目,那么域名就是 127.0.0.1:8080。

比如我们修改之前文章的 BeanTestController:

@Controller
public class BeanTestController {
    @RequestMapping("/index")       // 映射的 URL 地址为 /index
    @ResponseBody                   // 直接将字符串显示在页面上 
    public String test(){
        return "欢迎访问我的主页!";
    }
}

在浏览器上访问 http://127.0.0.1:8080/index 地址:

在这里插入图片描述

说明:

如果一个方法被 @ResponseBody 注解标注,那么由这个方法返回的字符串将被直接显示在浏览器的页面上。

@RequestMapping 注解映射的 URL 地址可以是多层的。例如:

​​​​@RequestMapping("/shop/books/computer")​​

上述代码映射的完整URL地址是 http://127.0.0.1:8080/shop/books/computer。需要特别注意的是,这个 URL 地址中的任何一层都是不可或缺的,否则将引发 404 错误。

@RequestMapping 注解允许一个方法同时映射多个 URL 地址。其语法如下:

​​​​@RequestMapping(value = { "/address1", "/address2", "/address3", ....... })​​

method 属性

method 属性能够指定用户通过 @RequestMapping 注解映射的 URL 地址发送的请求的类型。这样,使用 method 属性就能够让不同的方法处理由相同 URL 地址发送的不同类型的请求。

下面将通过一个实例演示 method 属性的用法,我们修改 controller 类,如果由 “/index” 地址发送的请求的类型是 GET,则打印“处理 GET 请求”;如果由 “/index” 地址发送的请求的类型是 POST 请求,则打印“处理 POST 请求”,代码如下:

@Controller
public class BeanTestController {
    @RequestMapping(value = "/index", method = RequestMethod.GET)
    @ResponseBody
    public String get(){
        return "处理 GET 请求";
    }

    @RequestMapping(value = "/index", method = RequestMethod.POST)
    @ResponseBody
    public String post(){
        return "处理 POST 请求";
    }
}

使用 Postman 模拟 GET 请求和 POST 请求,所示结果如下。如果发送的请求既不是 GET 类型也不是 POST 类型,则会触发 405 错误。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

由 URL 地址发送的请求具有多种类型,详见 RequestMethod 枚举类。

RequestMethod 枚举类的代码如下:

public enum RequestMethod {
​​​​    GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
​​​​}

params 属性

params 属性能够指定在用户通过 @RequestMapping 注解映射的 URL 地址发送的请求中须包含哪些参数。因为 params 属性的类型是字符串数组,所以通过 params 属性能够同时指定多个参数。

下面将通过一个实例演示 params 属性的用法,我们修改 Controller:

@Controller
public class BeanTestController {
    @RequestMapping(value = "/index", params = { "name", "id" })
    @ResponseBody
    public String haveParams(){
        return "欢迎回来~";
    }

    @RequestMapping(value = "/index")
    @ResponseBody
    public String noParams(){
        return "忘传参数了...";
    }
}

使用 Postman 模拟用户通过 URL 地址发送的请求。查看结果:

在这里插入图片描述
在这里插入图片描述

headers 属性

headers 属性能够指定在用户通过 @RequestMapping 注解映射的 URL 地址发送的请求中须包含哪些指定的请求头。也就是说,在一个 headers 属性中,可以包含若干个请求头。通过这些请求头,服务器能够得知客户端环境以及与请求正文相关的一些信息,例如浏览器的版本、请求参数的长度等。

headers 属性在 @RequestMapping 注解中的格式如下:

​​​​@RequestMapping(headers = {"键1=值1", "键2=值2", ......})​​

说明:

请求头指的是 HTTP 请求中的头部信息,即用于 HTTP 通信的操作参数。

从 headers 属性在 @RequestMapping 注解中的格式,能够非常清晰地看到请求头在 headers 属性中的格式:

​​​​"键=值"​​

我们测试下,修改 Controller,在控制器类中编写 noParams() 和 haveParams() 这两个方法。如果用户通过 URL 地址发送的请求包含 headers 属性,就交由 noParams() 方法处理,让用户直接进入欢迎界面;否则,就交由 haveParams() 方法处理,让用户进入登录界面。

@Controller
public class BeanTestController {
    @RequestMapping(value = "/index")
    @ResponseBody
    public String haveParams(){
        return "请重新登录!";
    }

    @RequestMapping(value = "/index", headers = { "Cookie=JSESSIONID=123456789"})
    @ResponseBody
    public String noParams(){
        return "欢迎回来~";
    }
}

说明:

Cookie 是某些网站为了辨别用户身份、进行 Session 跟踪而储存在用户本地终端上的数据。Cookie 会被暂时地或永久地保存在用户客户端计算机中。

对于本示例,如果用户在某个登录界面选择了“自动登录”选项,那么服务器就会将用户登录的 session id 写在浏览器的 Cookie 中。

使用 Postman 模拟用户通过 URL 地址发送的请求。

  1. 如果在请求中不包含 headers 属性,直接访问 http://127.0.0.1:8080/index 地址:

在这里插入图片描述

  1. 如果为请求头添加 Cookie,值为“JSESSIONID=123456789”,再访问同一个地址:

在这里插入图片描述

consumes 属性

consumes 属性能够指定用户通过 @RequestMapping 注解映射的 URL 地址发送的请求的数据类型。其中,常见的类型有 “application/json”、“text/html” 等。

下面将通过一个实例演示 consumes 属性的用法。

修改 Controller 类,将 @RequestMapping 注解的 consumes 属性设置为“application/json”。在控制器类中编写 formatError() 和 hello() 这两个方法。如果用户发送的请求的数据类型是 JSON,就交由 hello() 方法处理,并提示“成功进入接口”的信息;否则,就交由 formatError() 方法处理,并提示“数据格式错误!”的信息。

@Controller
public class BeanTestController {
    @RequestMapping(value = "/index")
    @ResponseBody
    public String formatError(){
        return "数据格式错误!";
    }

    @RequestMapping(value = "/index", consumes = "application/json")
    @ResponseBody
    public String hello(){
        return "成功进入接口";
    }
}

使用 Postman 模拟用户通过URL地址发送的请求。如果直接访问 http://127.0.0.1:8080/index 地址,结果如下:

在这里插入图片描述

如果在请求体(Body)中填写 JSON 数据,再访问上述地址就可以看到下图结果:

在这里插入图片描述

1.2.2 映射包含层级关系的 URL 地址

通常一个 URL 地址不只是简单的一层地址,而是根据业务分类形成的多层地址。那么,如何理解在一个 URL 地址中包含多层地址呢?例如,在某电商平台通过访问 “/shop/books” 地址查看图书信息;其中,“/shop” 是这个电商平台的地址,“/books” 表示图书类。那么,应该如何使用 @RequestMapping 注解映射这个包含层级关系的 URL 地址呢?代码如下:

@Controller
public class BeanTestController {
    @RequestMapping("/shop/books")
    @ResponseBody
    public String books() {
        return "图书类";
    }
}

不难发现,在表示电商平台的控制器类中包含一个 book() 方法。通过使用 @RequestMapping 注解标注这个 book() 方法,就能够实现映射一个多层的 URL 地址的功能。

如果这个电商平台还卖服装,那么就会含有表示服装类的 “/clothes” 地址。那么,又应该如何使用 @RequestMapping 注解既映射 “/shop/books” 地址,又映射 “/shop/clothes” 地址呢?代码如下:

@Controller
public class BeanTestController {
    @RequestMapping("/shop/clothes")
    @ResponseBody
    public String cloths() {
        return "服饰类";
    }

    @RequestMapping("/shop/books")
    @ResponseBody
    public String books() {
        return "图书类";
    }
}

不难发现,“/shop/books” 和 “/shop/clothes” 这两个地址具有相同的上层地址 “/shop”。那么,有没有什么编码方式能够优化上述代码呢?答案是使用 @RequestMapping(“/shop”) 注解标注表示电商平台的控制器类。

优化后的代码如下:

@Controller
@RequestMapping("/shop")
public class BeanTestController {
    @RequestMapping("/clothes")
    @ResponseBody
    public String cloths() {
        return "服饰类";
    }

    @RequestMapping("/books")
    @ResponseBody
    public String books() {
        return "图书类";
    }
}

说明:

@RequestMapping 注解不仅可以标注方法,还可以标注类。

在访问一个多层的 URL 地址时,输入的 URL 地址必须是完整的,比如下面的效果图:

在这里插入图片描述
在这里插入图片描述

1.3 @ResponseBody

在上文讲解的所有实例中,其中的方法都被 @RequestMapping 和 @ResponseBody 注解同时标注。在掌握了 @RequestMapping 注解的相关内容后,下面将介绍 @ResponseBody 注解的作用。

@ResponseBody 注解的作用是把被 @ResponseBody 注解标注的方法的返回值转换为页面数据。

  • 如果被 @ResponseBody 注解标注的方法的返回值是字符串,页面就会显示字符串;
  • 如果被 @ResponseBody 注解标注的方法的返回值是其他类型的数据,这些数据就会先被自动封装成 JSON 格式的字符串,再显示在页面中。

下面将介绍在使用 @ResponseBody 注解时会遇到的另外一种情况:如果控制器类中的某个方法被 @RequestMapping 注解标注,却没有被 @ResponseBody 标注,那么这个方法的返回值会是什么呢?

答案是即将跳转的 URL 地址。例如:

@Controller
public class BeanTestController {
    @RequestMapping("/index")                  // 映射 "/index" 地址,未标注 @ResponseBody
    public ModelAndView index(){
        return new ModelAndView("/welcome");   // 跳转至 "/welcome" 地址
    }
}

在上述代码中,index() 方法被 @RequestMapping 注解标注,却没有被 @ResponseBody 标注。该方法的返回值是 org.springframework.web.servlet.ModelAndView 类型。

因为上述代码的功能是当用户访问 “/index” 地址时,页面就会跳转至与 “/welcome” 地址对应的页面,所以可以把 index() 方法的返回值修改为字符串。修改后的代码如下:

@Controller
public class BeanTestController {
    @RequestMapping("/index")                  // 映射 "/index" 地址,未标注 @ResponseBody
    public String index(){
        return "/welcome";                     // 跳转至 "/welcome" 地址
    }
}

通过上述代码,是不是就能够实现跳转页面的功能了呢?答案是否定的。为了实现跳转页面的功能,还需要向上述代码添加用于映射 “/welcome” 地址的方法,并且这个方法要被 @RequestMapping 和 @ResponseBody 注解同时标注。添加用于映射 “/welcome” 地址的方法后的代码如下:

@Controller
public class BeanTestController {
    @RequestMapping("/index")
    public String index(){
        return "/welcome";
    }

    @RequestMapping("/welcome")
    @ResponseBody
    public String welcome(){
        return "欢迎来到我的主页";
    }
}

启动项目后,打开浏览器访问 http://127.0.0.1:8080/index 地址,即可看到页面会跳转至与 “/welcome” 地址对应的页面:

在这里插入图片描述

此外,在使用 @ResponseBody 注解时还需要特别注意一个问题:@ResponseBody 注解虽然也可以标注控制器类,但是控制器类中的所有方法的返回值都会直接显示在页面上。例如,把上述代码中的 @ResponseBody 注解标注在控制器类上,代码如下:

@Controller
@ResponseBody  // 将注解标注在类上
public class BeanTestController {
    @RequestMapping("/index")
    public String index(){
        return "/welcome";
    }

    @RequestMapping("/welcome")
    public String welcome(){
        return "欢迎来到我的主页";
    }
}

启动项目,打开浏览器访问 http://127.0.0.1:8080/index 地址,会发现页面没有发生跳转,并且显示的结果是index()方法的返回值:

在这里插入图片描述

1.4 @RestController

@RestController 注解虽然是 Spring Boot 的新增注解,但实质上是 @Controller 和 @ResponseBody 这两个注解的综合体。也就是说,当控制器类同时被 @Controller 和 @ResponseBody 这两个注解标注时,这两个注解可以被 @RestController 注解替代。这样就可以起到简化代码的作用。例如:

​​​​@Controller
​​​​@ResponseBody
​​​​public class TestController {
​​​​}​​

使用 @RestController 注解可以简化上述代码。简化后的代码如下:

​​​​@RestControlle
​​​​public class TestController {
​​​​}​​

二、重定向 URL 地址

重定向 URL 地址是指用户通过原始的 URL 地址发送的请求指向了新的 URL 地址,并且请求中的数据不会被保留。也就是说,通过重定向 URL 地址,服务器可以把用户推送到其他网站上。

下面将介绍 Spring Boot 用于实现重定向的两种方法。

2.1 redirect:

前面一节,我们已经明确了如果控制器类中的某个方法被 @RequestMapping 注解标注,却没有被 @ResponseBody 标注,且这个方法的返回值是字符串,那么这个方法的作用是实现页面跳转的功能,这个方法返回的字符串表示的是即将跳转的 URL 地址。如果在即将跳转的 URL 地址的前面加上“redirect:”,就表示用户通过原始的 URL 地址发送的请求指向了这个 URL 地址。

下面通过一个实例演示“redirect:”前缀的用法。

@Controller
public class BeanTestController {
    @RequestMapping("/bd")
    public String bd(){
        return "redirect:https://www.baidu.com";
    }
}

启动项目后,打开浏览器访问 http://127.0.0.1:8080/bd 地址,浏览器会自动跳转至百度首页,并且地址栏中 URL 地址显示的也是百度首页的 URL 地址,原始的 URL 地址已经在地址栏中看不到了。

在这里插入图片描述

2.2 response

response 对象指的是 HttpServletResponse 类型的对象,可用于实现重定向 URL 的功能。那么,Spring Boot 是如何使用 response 对象实现这个功能的呢?Spring Boot 可以直接在控制器类的某个方法中创建 response 对象,通过这个对象调用 sendRedirect() 方法就可以指定重定向的 URL 地址。只不过,如果这个方法具有返回值,那么上述操作会导致这个返回值失效。因此,程序开发人员通常会把这个方法的返回值的类型设置为 void。

@Controller
public class BeanTestController {
    @RequestMapping("/bd")
    public void bd(HttpServletResponse response){
        try {
            response.sendRedirect("https://www.baidu.com");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

启动项目后,打开浏览器访问 http://127.0.0.1:8080/bd 地址,即可看到百度首页。


原文地址:https://blog.csdn.net/pepsimaxin/article/details/142407135

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!