从请求到响应:初探spring web
引入:
首先小编想分享下一些开发小知识
2000年——手写servlet/JSP时代
在这个阶段中,那时候写后端代码,可谓是个麻烦事。
毕竟什么都要自己干
发来的请求都要写extends HttpServlet的类,手动在web.xml配置
<servlet>、<servlet-mapping>……
JDBC连接、SQL、事务都得自己写,配置全靠XML。
产生的痛点可太多了,比如xml配置多、代码臃肿、模块耦合高。
JSP:全称JavaServer Pages(Java服务端页面),它是基于Java的动态网页技术,允许开发者在HTML页面中嵌入Java代码,用于生成动态内容。
2004——Spring FrameWork1.0诞生
此时的框架,引入很多东西,比如
IOC(控制反转):Bean的创建、依赖由Spring容器负责,代码里不在到处new
DI(依赖注入):可以用XML、注解(@Atutowired)声明依赖
AOP(面向切面):用来做事务,日志,权限等横切逻辑
模块化:把核心容器拆成spring-core、spring-beans、spring-context、spring-app、spring-tx、spring-jdbc……
这些东西进入进来后,起到了配置简化的作用,至少有了统一的对象管理和切面支持。
2005——spring web mvc :基于servlet的web框架
引入DispatcherServlet:接收所有的请求并分发
注解驱动:后续版本支持@Controller、@RequestMapping,彻底替代web.xml中<servlet>映射.
视图解析:整合JSP、FreeMarker、Velocity、Thymeleaf等多种模板。
数据绑定/校验:支持@RequestParam、@ModelAttribute、@valid等注解
2006——2013:Spring 生态快速扩张
Spring Security:全面安全框架。
Spring Data:简化JPA、MonggoDB、Redis、Elasticsearch等数据访问。
Spring Integration / Batch / AMQP:消息、批处理、集成解决方案。
Spring Cloud:进一步演化,提供微服务的配置中心,注册中心,断路器、网关等
引入了这么多,但还是有痛点:因为还需要每次都要大量配置XML或JavaConfig,项目的脚手架都要自己搭建。
脚手架:是一个用于快速创建和搭建项目基础结构的工具或模板。
脚手架工具,目前来说也有是比较多的
比如 Spring Boot Initializr、Yeoman、JHipster……
2014——Spring Boot 1.0:开箱即用,约定优于配置
自动配置:根据classpath下依赖和定义好的”条件“自动装配Bean,绝大部分配置”不用写“
starters:一组起步依赖,比如spring-boot-starter-web(包含SpringMVC、Jackson、Tomcat),
spring-boot-starter-data-jpa。
内嵌容器:默认内嵌Tomcat(可选Jetty、Undertow),打成可执行Jar,运维更简单
外部配置:统一使用application.properties / application.yml,支持Profile
Actuator:一组监控 / 健康检查断点,自动暴露/actuator/heath、/metrics
2016——目前:Spring Boot 2.x/3.x 支持微服务和云原生
Spring Boot 2.x:升级到5.x,支持Reactive WebFlux,Kotlin
Spring Boot 3.x:基于Spring Framework6.x,要求Java17、JakartaEE9
SPring Cloud:与Boot紧密集成,Netfilx OSS,Consul、Nacos、Gateway、Sleuth/Zipkin/Brave分布式链路追踪
CLI / DevTools:命令行工具、热重载,开发体验进一步提示。
那么对于以上这些呢,算是小编分享基于Spring开发的时间线。
对于讲到Spring而言
它本质上就是个容器,它里面存储有很多核心组件,这些核心组件负责各自的内容。
MVC:
它是Model View Controller的缩写,它是软件工程中的一种软件架构设计模式
它把软件系统分为模型、视图和控制器三个基本部分:
既然MVCVC是一种架构设计模式,那么人人也是可以实现它的,所以SpringMVC就是实现了它
除此之外,SpringMVC还是个web框架。
SpringMVC 结合了自身的特点,做出了些改变,不过整体还是以Model——View——Controller为基准的
这幅图或许是更加形象些:
刚刚分享到时间线中,提到注解
所以接下来小编分享下SpringMVC的注解吧
注解学习:
跟注解名字相像的,还有一个叫注释的
注释:
注释是写给程序员看的文字,不会被编译器或程序执行的,是起到解释说明作用
作用:
1.帮助别人或自己理解代码
2.暂时屏蔽部分代码
3.提供文档说明
注解:
注解是写给编译器或运行时看的结构化信息,它是一种元数据,用来对代码进行标记,指示行为,甚至自动生成代码。
作用:
1.在编译、类加载、运行时被读取,用来执行特定逻辑
2.框架大量依赖注解来完成”自动配置“和控制反转
元数据:
元数据是”描述数据的数据“,它本身不是一个业务数据,而是用来描述、标记、解释其他数据的信息
看起来比较抽象,那么可以举个这样的例子
在现实生活中,你拍了一张照片,照片内容是一个风景图(这个就是一份数据)
当然这个文件中,还有很多内在信息:
- 拍摄时间
- 拍摄地点
- 使用设备
- 分辨率
……
这些信息呢,就是元数据
在代码中呢,元数据就是来描述代码的”额外信息“,比如
- 一个类是干啥的
- 一个类是否重写了父类
- 一个字段是否需要注入
………………
这类信息不是程序主要逻辑,但是框架/工具/编译器会看这些注解来”做事”。
其实注解,我们开始学习Java语法基础的时候,也是接触过的
比如:
Java |
这个注解@Override就是注解,它是表示对父类方法的重写,编译器会检查方法签名是否是正确
那么注解也是有类型的。
注解类型:
一.运行时注解
这种注解,编译完后,不仅是存在于.class文件中,程序运行的时候还可以通过反射读取到
特点:
- 必须用@Retention(RetentionPolicy RUNTIME)中声明
- 运行时用反射去拿到它的内容
- 常用于Spring、Mybatis、Junit框架做自动处理
二.编译期注解
这种注解,只会在编译阶段有用,比如校验、生成代码,或者 抛出编译错误;但是运行时是看不到的
特点:
- 用@Retention(RetentionPolicy SOURCE)或者@Retention(RetentionPolicy CLASS)声明
- 靠Annotation Processor(注解处理器),在编译阶段扫描处理
- 常用于Lombok、MapStruct、AutoValue等这类工具
注解还有生效类型,它有Retention策略来决定:
类型 | 用法 | 是否可以通过反射获取 | 举例 |
SOURCE | 只存在于源码中,编译时丢弃 | 否 | Lombok(自动生成代码) |
CLASS | 编译后存在于class文件中,但运行后不保存 | 否 | 常用于框架预编译扫描 |
RUNTIME | 编译后保留,并且运行时可反射获取 | 是 | Spring、Junit中常见注解 |
接下来我们来看看SpringMVC中,有哪些注解吧
一:RestController、RequestMapping
RequestMapping这个注解是用来处理请求映射路径的,
可以用来类上,此时称为父路径,可以用在方法上,此时称为子路径
注意:如若没有加上路径中,没有加上/,那么RequestMapping会自动帮我们加上
常用属性:
属性 | 说明 | 示例 |
value / path | 请求路径 | @RequestMapping("/login") |
method | HTTP方法 | RequestMethod.GET,POST,PUT,DELETE |
params | 请求参数过滤 | params="id=10" |
headers | 请求头过滤 | headers="ContentType=application/json" |
对于RestController而言,这个是复合注解,由@Controller+@ResposeBody而成
Controller注解:
它是用来标识一个类是控制器,当前端请求发送来后,这个类的方法就会接收并处理这些请求
它通常用来返回页面视图
比如:
Java |
ResponseBody注解
这个注解就是把方法返回值直接写到HTTP响应体,不会再找视图页面,进行返回
常用于返回JSON、字符串等数据
比如:
Java |
所以对于RestController注解而言,它标注在类上,表示这个类是一个REST风格的控制器,方法返回的是JSON或XML,而不是跳转页面。
REST风格控制器
它是一种软件架构风格,强调资源的唯一标识和标准HTTP方法(GET、PUT、DEPETE、POST等操作)。
所以基于这两个注解,我们就可以写上一小段代码:
Java |
此时我们运行程序后,访问http:127.0.0.1:8080/user/v2
结果:
值得注意的是RequestMapping中,是默认支持get和post请求的,所以在v1中我这样写,意思是仅支持post请求
当然,此时我们要是觉得写RequestMapping里面的参数太长,代码还可以这样写:
Java |
这两个注解,其实就是代表仅支持GET和POST请求
此时,我们还可以发现个问题,如若我们每次测试代码返回结果,都要浏览器输入的话,那么岂不是很麻烦?
所以,小编后面就会使用构造http请求的软件,这里小编使用的是Postman,文章后面会附上如何下载
刚刚讲到的代码是无参数的,接下来分享是有参数的
单个参数:
typescript |
通过postman构造请求,返回结果:
要值得注意的是,参数名字要一一对应
多个参数:
Java |
构造请求,返回结果:
对象形式:
首先编写一个对象:
Java |
然后通过idea生成的setter/getter/toString方法,这里就省略了。
Java |
构造请求,返回结果:
为什么传输对象可以得到正确数据呢?
这是因为在Springboot中,使用@RequestMapping接收参数时,如果是一个自定义对象,Spring会自动进行参数绑定,将http请求中的查询参数或表单数据映射到对象的属性上。
二.@RequestParam
刚刚说到我们请求过来的参数是要一致的,那么这是不是必须的呢?
当然不是,前端传过来的参数和方法中的参数是可以不一致的,此时,就使用RequestParam注解这个注解用于从
http请求参数中获取值的,就类似于参数重命名.
参数重命名
比如:
Java |
构造请求返回结果:
那么可以看到username与代码中的name是对应,userAge和代码中的age是一一对应。
这个RequesParam注解也是可以设置参数的,此时呢,我在代码中写required=f=alse,这个是说明这个age参数不是必传的,而name参数中,没有设置,那么它就是默认为true它就是要必传的,还有,如若这个注解中,什么参数都没有,此时就可以默认为前端传来的参数和方法中的参数是一致的。
此时,使用这个参数后,我们还可以传输数组内容了
Java |
构造请求返回结果:
当然,数据还可以这样传输:
传递集合类:
Java |
构造请求返回结果:
传递json对象:
此时前端传递json对象,使用的注解,就是RequestBody,这个在一开始讲到,这里就不做解释
Java |
构造请求返回结果
三.@PathVariable
这个注解是将URL路径中的一部分变量映射到方法参数上
代码:
Java |
构造请求返回结果
获取多个参数:
Java |
构造请求返回结果:
当然,我们也可以发现这个注解也是可以参数重命名了,同时我们还得注意的是,参数类型要传输正确,比如
id是Integer,name是String,如若反过来传输,就会出现以下错误:
四.@RequestPart
这个注解是用于从multipart/form-data类型的请求中获取请求的一部分,通常用于上传文件+其他字段的组合场景
typescript |
此时呢,一般是要和搭配一个类进行,使用,这个类是MultipartFile
这个是Spring提供的一个接口,用来处理文件上传的内容
当前端以multipart/form-data方式去提交表单(或者使用FromData)上传文件的时候,Spring会自动将文件封装为
MultipartFile对象,交给控制器处理
它有一些常见方法:
方法名 | 作用方法 |
getOriginalFilename() | 获取原始文件名 |
getContentType() | 获取文件MIME类型(如image/png) |
getSize() | 获取文件大小 |
getInputStream() | 获取输入流,可用于保存到磁盘 |
getBytes() | 获取文件的字节数组 |
transferTO(File dest) | 将文件直接保存到目标位置 |
构造请求返回结果
五.操作请求头
学习前面的一些请求头后,那么可以对请求头中一些参数进行操作了,比如cookie ,session
cookie:
cookie是存储在客户端(通常是浏览器)上的小数据片段,每个cookie都有一个名称,值以及一些可选的属性
如过期时间、路径、域等
作用:
- 存储用户的偏好设置(例如语言,主题等)
- 跟踪用户的活动
- 维持登录状态,通过在客户端保存会话ID或令牌s
特点:
- 客户端存储,可以被用户查看和修改
- 每次请求都会自动发送到服务器(符合path和domain条件)
- 可以设置HttpOnly标记来防止JavaScript访问,提高安全性
- 有大小限制(通常为4kb)
Session:
session是一种服务端机制,用来跟踪用户状态。当用户访问网站时,服务器会生成一个唯一的会话ID,并将
其存储在服务器上。通常这个Cookie传递给客户端,以便后续请求能够识别用户
- 作用:
存储敏感信息,这些数据是保存在服务器,不会暴露在客户端
- 管理会话状态,如用户登录后的行为,购物车内容等
特点:
- 数据存储在服务器端,更加安全
- 不直接向客户端暴露具体数据内容,仅通过会话ID关联
- 生命周期可以与用户的交互挂钩,也可以设定固定的超时时间
举个例子:
当用户进行首次登录的时候,服务器收到请求,创建一个SessionID,并通过Cookie返回到客户端中
在后续的请求中,浏览器将自动包含SessionID发送到服务器中,服务器根据这个ID恢复用户的会话状态。
那么先来讲讲这个cookie吧
代码:
typescript |
这个HttpServletRequest 是Java Web开发常用接口,简单而言他代表的是客户端发来的请求
而且也比较万能,因为它可以得到请求中的很多信息
比如请求方式,请求路径,请求参数,请求头,cookie,session……
请求:
不要慌张!我们通过chrome浏览器来设置cookie即可
首先点击:
然后:
再刷新:
服务器中也得到结果:
此时如若出现,chrome浏览器无法把cookie带过去,那么可以使用以下命令回车:
document.cookie = "key=value; path=/; domain=127.0.0.1; SameSite=None; Secure";
在控制台输入
当然,这个获取cookie内容,不止可以使用原生api,还可以使用注解:
这个注解就是:@CookieValue
该注解自动帮你从请求里的cookie中,按照名字,拿出某个值,直接注入你的方法参数中
代码:
typescript |
结果是差不多,这里不做结果展示。
接下来,讲下session
首先分享的是如何设置session:
代码:
typescript |
生成后,此时呢我们就可以去得到session了
代码:
typescript |
此时我们访问SetSession路径:
可以观察到,下面的cookie中,是带有了sessionID了
访问getSession,就可以获得结果:
当然,获取的方法也不是只有这一个,还可以通过HttpSesstion 来获取
代码:
Java |
甚至还可以通过注解来获得:
Java |
六.操作响应内容
之前大多讲解的是请求的内容,接下来看看是如何操作这个响应内容的。
1.返回视图(比如网页)
用到的注解是controller,这个注解在上面讲过了,所以就不做过多讲解
typescript |
此时返回视图的话,那么就是通过Controller注解,而不是RestController
此时,我们Welcome.html是在项目resource/static目录下
访问内容:
此时它为什么可以直接展示出网页内容,大致流程如下:
浏览器请求/response/returnHtml
Controller返回字符串“Welome.html”
SpringMVC的视图解析器会拿到这个字符串,去找该/Welcome.html这个资源
找到了,就会把该/Welcome.html的内容渲染成HTTP响应,浏览器自然就会拿到内容。
2.返回内容:
此时呢,使用了Controller后,返回的是视图了,那么我就是要返回内容呢?
可以使用这个ResponseBody,这个注解,前面也是讲过,就不做过多解释
代码:
Java |
请求返回结果:
值得注意的是,返回的字符串内容会被浏览器自动解析为html内容
如何查看?
刷新页面:
然后点击这个后,会出现以下页面:
这里的text/html说明了,浏览器把该内容解析为这样的类型。
当然返回内容,也是可以返回为html格式内容:
Java |
此时呢,网页会按照返回内容,进行一级标题渲染。
当然,对于这个ResponseBody来说,它还可以返回json内容
json:
它是一种轻量级的数据交换格式,易于人类阅读和编写,同时也是易于机器解析和生成。
基本语法:
- 数据以键/值对的方式存储,例如"name":"John"
- 键必须是字符串,使用双括号括起来,值可以是字符串、数字、对象、数组、布尔值或者null
- 对象使用花括号{}括起来,数组用方括号[]括起来
代码:
Java |
此时,它是以对象形式返回,那么spring mvc消息转换器会自动把它转换为Json格式
postman构造请求返回结果:
此时可以看到返回内容为JSON格式内容了
那么字符串也是可以返回为JSON格式的
代码:
Java |
通过设置produces参数,就可以返回想要格式,同样的想返回JSON,那么就写成application/json,就可以了。
构造请求返回结果
请求头有HttpServletRequest,那么响应头中,也有HttpServletResponse,这个也是原生的API,可以说是万能的。它同样可以设置/得到响应头的内容,比如状态码、cookie……
那么举个例子,设置状态码
Java |
构造请求,返回结果
同样的,可以看到即使的得到结果了,也是返回404,这是因为我们手动设置了。
ok,对于springmvc中,一些常见的注解,就分享到这里。
postman下载
postman是一个流行的API开发工具,简化了构建、测试和文档化RESTful APIs的过程,对于开发人员还是测试人员等等,它都可以提高工作效率。
它功能,可是有很多的,比如
发送请求、环境和变量管理、自动化测试、监控、Mock Server、文档生成功能、团队协作、安全性测试……
这是它的下载地址:
https://www.postman.com/downloads/
下载后,它是一个压缩包,然后找个地方解压,运行即可。
接下来介绍一下,基本使用。
简单使用
首先打开后,可能会让你进行注册登录,那么你就按照提示进行注册登录即可
在构建请求区域中,有这些选项,小编这里简单解释下:
1.Param
Params这一行指的是“Query Params”部分,它允许你在发送HTTP请求时添加查询参数。具体来说:
- Key:这是参数的名称,用来标识这个参数代表什么信息。
- Value:这是与Key对应的值,表示该参数的具体内容。
2.body
Body 标签页用于定义请求体的内容,这对于 POST, PUT, PATCH 等需要发送数据到服务器的请求非常重要。它支持多种格式的数据输入:
- form-data:用于模拟HTML表单提交,通常用于上传文件或发送键值对数据。
- x-www-form-urlencoded:与form-data类似,但是不支持文件上传。适合发送简单的键值对数据。
- raw:允许你手动输入请求体内容。支持多种格式,如JSON、XML、Text、JavaScript等。当你需要发送结构化的数据(如JSON对象)时非常有用。
- binary:用于上传任意类型的文件。例如,上传图片、视频或其他二进制文件。
3.Headers
Headers 标签页让你可以为你的请求添加自定义头部信息。这可以包括认证令牌(如Bearer Token)、内容类型(Content-Type)、接受类型(Accept)以及其他任何你想要传递给服务器的元数据。
4.Authorization
Authorization 标签页提供了一个简单的方式来设置请求的授权方法。你可以选择不同的授权类型,如No Auth, Basic Auth, Bearer Token, OAuth 1.0, OAuth 2.0等,并根据所选类型填写相应的凭证。
5.Script
这个标签允许你在发送请求之前执行一段脚本。这可以用来设置环境变量、发送额外的HTTP请求或者做任何你需要在请求前完成的事情。例如,生成一个动态的时间戳并将其存储在一个变量中,以便在请求体中使用。
6.Setting
虽然不是直接参与构建请求的部分,但Settings选项提供了配置Postman行为的方式,比如SSL证书验证、代理设置等
但是还有一个值得注意的是,像前面所说的上传文件中
你要是觉得英文版,不太好用,那么这里提供国产同类型产品,功能强大,界面友好
下载地址:https://apifox.com/
对于spring mvc注解的分享,小编就分享到这里