当前位置: 首页 > news >正文

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)@ResponseBodypublic String get(){return "处理 GET 请求";}@RequestMapping(value = "/index", method = RequestMethod.POST)@ResponseBodypublic 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" })@ResponseBodypublic String haveParams(){return "欢迎回来~";}@RequestMapping(value = "/index")@ResponseBodypublic 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")@ResponseBodypublic String haveParams(){return "请重新登录!";}@RequestMapping(value = "/index", headers = { "Cookie=JSESSIONID=123456789"})@ResponseBodypublic 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")@ResponseBodypublic String formatError(){return "数据格式错误!";}@RequestMapping(value = "/index", consumes = "application/json")@ResponseBodypublic 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")@ResponseBodypublic String books() {return "图书类";}
}

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

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

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

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

优化后的代码如下:

@Controller
@RequestMapping("/shop")
public class BeanTestController {@RequestMapping("/clothes")@ResponseBodypublic String cloths() {return "服饰类";}@RequestMapping("/books")@ResponseBodypublic 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" 地址,未标注 @ResponseBodypublic 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" 地址,未标注 @ResponseBodypublic String index(){return "/welcome";                     // 跳转至 "/welcome" 地址}
}

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

@Controller
public class BeanTestController {@RequestMapping("/index")public String index(){return "/welcome";}@RequestMapping("/welcome")@ResponseBodypublic 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 地址,即可看到百度首页。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 20240924软考架构-------软考191-195答案解析
  • 英飞凌TC3xx -- Bootstrap Loader分析
  • 基于FPGA+GPU异构平台的遥感图像切片解决方案
  • 汽车端到端自动驾驶系统的关键技术与发展趋势
  • EasyGBD国标GB28181设备端,支持GB28181-2016、GB28181-2022
  • 基于C#+SQL Server2008实现(CS界面)学生宿舍管理系统
  • 【Docker】深入理解 Docker Compose 文件:构建和管理多容器应用的指南
  • 基于OpenCV的单目测距
  • uniapp map使用非CSS 定位和固定高度来设置,避免拉伸父容器的高度
  • 《AI办公类工具表格处理系列之一——办公小浣熊》
  • java 洛谷题单【算法1-7】搜索
  • 第一章 HTTP
  • frp内网穿透部署
  • MATLAB软件开发通用控制的软件架构参考
  • 【第十四章:Sentosa_DSML社区版-机器学习之时间序列】
  • 【Redis学习笔记】2018-06-28 redis命令源码学习1
  • es6(二):字符串的扩展
  • exports和module.exports
  • Javascript基础之Array数组API
  • Js基础知识(四) - js运行原理与机制
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • Mysql数据库的条件查询语句
  • Redis在Web项目中的应用与实践
  • Solarized Scheme
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • 翻译:Hystrix - How To Use
  • 反思总结然后整装待发
  • 后端_ThinkPHP5
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 深入 Nginx 之配置篇
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 我感觉这是史上最牛的防sql注入方法类
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • 学习JavaScript数据结构与算法 — 树
  • 一道闭包题引发的思考
  • 一份游戏开发学习路线
  • 再谈express与koa的对比
  • 责任链模式的两种实现
  • 第二十章:异步和文件I/O.(二十三)
  • ​HTTP与HTTPS:网络通信的安全卫士
  • # AI产品经理的自我修养:既懂用户,更懂技术!
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • #FPGA(基础知识)
  • #考研#计算机文化知识1(局域网及网络互联)
  • (2024,Flag-DiT,文本引导的多模态生成,SR,统一的标记化,RoPE、RMSNorm 和流匹配)Lumina-T2X
  • (二)Kafka离线安装 - Zookeeper下载及安装
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (四)鸿鹄云架构一服务注册中心
  • (四)汇编语言——简单程序
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (一)插入排序
  • (状压dp)uva 10817 Headmaster's Headache
  • .mysql secret在哪_MySQL如何使用索引
  • .net CHARTING图表控件下载地址
  • .NET Core 版本不支持的问题