什么是 Spring MVC?
官⽅对于 Spring MVC 的描述是这样的:
Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, “Spring Web MVC,” comes from the name of its source module (spring-webmvc), but it is more commonly known as “Spring MVC”.
翻译为中⽂:
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc),但它通常被称为“Spring MVC”。
题外话:
1、因为 Spring Web MVC 是基于 Servlet API,所以 Servlet 是 Spring MVC 的 “父亲”。
因此,Servlet 那一套编程方法,在 Spring MVC 中,也是可以使用的!!!
但是,一般不推荐使用 servlet 的编程方式。
因为,Spring MVC 更简单!
2、Spring Web MVC,从⼀开始就包含在 Spring 框架中。
即:Spring 是一个很大体系(框架),Spring MVC 只是属于 Spring 体系中的一个 Web 模块。
这也是为什么在学习 Spring 的时候,我们都都是通过 main 方法去访问bean方法的原因。因为我们没有引入 web 模块,因此想要通过 浏览器输入 URL 来访问 方法,是不行的。
从上述定义我们可以得出两个关键信息:
1、 Spring MVC 是⼀个 Web 框架。(基于 Servlet 实现的)
web框架,就是基于 HTTP 协议的。
通俗来说:当用户在浏览器上输入一个 URL 地址之后,URL 地址 能够和 程序映射起来。
能够让用户的请求 被 程序接受到。
并且,经过程序的处理,能把结果返回给前端(浏览器)。
这一次基于 HTTP 的交互,就可以认为是一个 web 项目。
Spring MVC 也是一个 web 框架(spring 的 一个 web 模块)。
那么,一个 web 项目,只做三件事:
1、实现用户请求 到 程序 的 链接。(用户请求 可以 被 程序接收到,也就是上面讲的)
2、在前后端建立联系的情况下,拿到用户请求的参数。
3、拿到参数之后,进行业务处理,并将其结果返回给前端。
这也是 本文讲解 Spring MVC 的重点。
如果有看过我前面博客的读者,回想一下:我在讲 spring 的时候,并没有涉及 前端。
只有在讲解 Spring Boot 的时候,涉及到 web内容。
我们不是引入了一个 spring web 嘛,那个就是 前端框架。
有了这个 框架的支持,那么,项目就是一个 Spring MVC 的项目。
也就是说:其实前面创建的 Spring Boot 项目 是 一个 Spring MVC 项目。
2、 Spring MVC 是基于 Servlet API 构建的。
然⽽要真正的理解什么是 Spring MVC?我们⾸先要搞清楚什么是 MVC?
MVC 定义
MVC 是 Model View Controller (模型视图控制器)的缩写,它是软件⼯程中的⼀种软件架构模式,它把软件系统分为模型、视图和控制器三个基本部分。
Model(模型) 是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
View(视图) 是应用程序中处理数据显示的部分,通常视图是依据模型数据创建的。
Controller(控制器) 是应⽤程序中处理⽤户交互的部分。通常控制器负责从视图读取数据,控制⽤户输⼊,并向模型发送数据。
下面我们来进一步分析 四者之间的关系。
通过这个 MVC 模型,就可以让 用户 与 程序 之间,是可以进行完美的交互的 。
间接来说:(忽略细节)
- 前端发送的请求数据,会先给 controller。
- controller 验证完数据之后,就会将其给 Model。
- Model 在和 数据库交互之后,将其得到的结果返回给 controller。
- 此时 controller 收到的数据,还不能直接返回给前端。
- controller 需要将数据 交给 服务器的视图(View),进行处理和渲染。
- 最终,将渲染得到的结果,返回给前端。
此时,用户就看到的源码 就是 html标签 的内容。(浏览器的开发者工具可以查看)
看到的页面,就是浏览器对 HTML标签内容的解析。
此时,我们基于 MVC 这三个部分,就可以实现一个 web 项目了。
web 项目:用户通过浏览器输入一个 URL,发送一个 HTTP请求,能够与 服务器 进行一次交互 和 响应。
MVC 和 Spring MVC 的关系
IOC 是思想,DI 是具体实现。
MVC 和 Spring MVC 的关系,也是如此。
MVC 是一种 设计思想(策略)。
Spring MVC 是 具体实现的框架。
总结
Spring MVC 是⼀个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架。既然是 Web 框架,那么当⽤户在浏览器中输⼊了 url 之后,我们的 Spring MVC 项 ⽬就可以感知到⽤户的请求。
同时 Spring MVC 又是 Spring 框架中的 一个 WEB 模块,它是随着 Spring 的 诞生 而 存在的一个框架。
Spring 和 Spring MVC 诞生的历史是比较久远的,在它们之后才有了 Spring Boot。
Spring 大概是在 2002 年 上市的,而 Spring Boot,大概比 Spring 晚 十年 诞生的。
Spring Boot 是在 2.0 版本的时候,占据了中国市场。
为什么要学 Spring MVC?
现在绝大部分的 Java 项目都是基于 Spring(或 Spring Boot)的,而 Spring 的核心就是 Spring MVC。
也就是说 Spring MVC 是 Spring 框架的核心模块,而 Spring Boot 是 Spring 的“脚手架”,
因此我们可以推断出,现在市面上绝大部分的 Java 项目 都是 Spring MVC 项目,这是我们要学 Spring MVC 的原因。
现在的项目,有两种:
1、PC,电脑上运行的项目
2、移动端,手机上的运行的项目。
PC 项目,又可以分为2种:1、网页版项目,2、客户端的项目
但是不管你 PC 项目 属于哪一种,只要你需要 数据持久化,就是用到 Spring MVC。
工作之后,不管是 做 哪一种 PC 开发,都是要连接数据库的。
只要是用到了 数据库的,那一定是前后端分离的。
所以说:我们提供的就是 后端程序。
那后端程序是基于什么协议呢?》》》 HTTP协议
所以说,HTTP协议 需要使用什么框架?
一定 web(Spring MVC) 框架嘛!
手机项目也是一样,拿着手机去刷抖音,看头条。。。
这些内容都是来自于数据库的。
数据库,这个东西实在我们手机上存的吗?很显然,不现实!
数据库,这东西一定是存储在服务器端的。
而服务器端是谁提供的?
是 手机开发工程师,他自己做后端开发吗?
肯定不做啊!手机开发工程师 做的是 PC时代的前端(做网页的)。
很早以前,PC 的前端是做网页的。
现在,PC 的前端是 做 APP的,就是说现在的网页,已经不是一个简简单单 HTML 页面,而是可以视为是一个 APP,具有很多复杂的功能。
但是,后端一定是调用 服务接口,而 服务接口 大部分调用额是 HTTP协议。HTTP 协议 就需要用到 Spring MVC 框架,因为它底层就是针对 Servlet 封装的。
因此 它 一定是一个 web 项目。
由此可知,我们到公司之后,大部分项目,大约 99% 都是 Spring MVC 项目。
那么,你觉得 Spring MVC 重不重要呢? 非常重要!!!!
这里简洁的说一下:APP 项目也可以分为两种。
1、基于 iOS 开发,最早使用 ObjectC,但是写法极其恶心。
所以,苹果公司,在后面又推出了 自己的语言 Swift。
2、安卓开发,最早是基于 Java 开发,但是现在 谷歌 被 Oracle 给搞了。
所以,自己 和 idea 的公司合作,做了一门新语言 Dart。
但是!底层也还是 基于 JVM 的。
与 java 编译生成的 字节码文件,可以视为是一样的。
而且,Dart 与 Java 是非常相似的!
可以说:这门语言就是为了 堵住 Oracle 的 “嘴”。
但是呢,现在APP发展的趋势,趋近两者的混合开发。
就是 苹果 和 安卓 手机,都能安装这个 APP。
关于 混合开发,已经是陈年旧事了。
最早推出的 是 Facebook 的 React Native。
也是属于 门面模式的一种实现。
你可以写 React Native 自己的语法,在项目打包的时候,它有一个选择平台的功能。
根据 我们写的代码,去生成 IOS 的 代码,或者是安卓 的 代码。
不同的平台,我给你生成不同的代码,就行了。
因此,移动端开发组 是很头疼的,做一个 APP,需要分2组(IOS,安卓)。
回过头,我们在创建 Spring Boot 项⽬时,我们勾选的 Spring Web 框架其实就是 Spring MVC 框架,如下图所示:
从宏观来说:
即使 Spring Boot 添加 Spring Web 框架,也可以说它是一个 Spring 项目,或者是 Spring Web 和 Spring MVC 项目,都可以!不算错!
从微观来说:
Spring MVC 项目,是基于 Spring Boot 框架 所实现的。
简单来说,咱们之所以要学习 Spring MVC 是因为它是⼀切项⽬的基础,我们以后创建的所有 Spring、Spring Boot 项⽬基本都是基于 Spring MVC 的。
Spring MVC 项目的创建
Spring MVC 项⽬创建和 Spring Boot 创建项⽬相同(Spring MVC 使⽤ Spring Boot 的⽅式创建),在创建的时候选择 Spring Web 就相当于创建了 Spring MVC 的项⽬
删除不常用文件。(可不删,根据实际情况决定)
学习 Spring MVC 的 三个目标
学习 Spring MVC 我们只需要掌握以下 3 个功能:
1、 连接的功能:将⽤户(浏览器)和 Java 程序连接起来,也就是访问⼀个地址能够调⽤到我们的Spring 程序。
2、 获取参数的功能:⽤户访问的时候会带⼀些参数,在程序中要想办法获取到参数。
3、输出数据的功能:执⾏了业务逻辑之后,要把程序执⾏的结果返回给⽤户。
对于 Spring MVC 来说,掌握了以上 3 个功能就相当于掌握了 Spring MVC
Spring MVC项目的连接(用户 和 程序 的 映射)
方法1:@RequestMapping(“/xx”)
在 Spring MVC 中使⽤ @RequestMapping 来实现 URL 路由映射.
这个我在讲 Spring Boot 知识的时候,已经用过了。
这里,我们再来稳固一下。注意: 一级路径,通常是为了辅助 二级路径。
因为一个项目,需要访问的东西有很多。
不可能全写在一个类里面,而且类也很多
为了避免混淆,所以通过这样的方式,来锁定要访问的类中方法。在这里,我再 给你们加强一下记忆。
@ResponseBody注解
1、放在方法上,表示该方法返回的数据,只是一个普通的数据,而非一个静态页面。
2、放在类上,表示该类中所有的方法返回的数据,都是一个普通的数据,而非静态页面。
3、如果未加上这个注解,在我们访问方法的时候,默认就会去寻找一个名称叫做 Hello World!的页面,它发现找不到之后,就会报错。问题来了:为什么默认情况下,返回的是一个静态页面呢?
请思考一个问题:
这就原因所在,Spring MVC 在诞生之初,还没有前后端分离的概念。
作为一个 Java 程序员,既要写 后端代码,还要去写前端的页面。
那个时候,模板用的非常多!!
那时候是没有前后端工程师的,只要有一个 Java 工程师,就够了。
最多,在配置一个美工(设计)就OK了。
所以,那个时候,不用多想,我肯定是返回的一个页面。
为什么默认返回一个静态页面,就是一个历史遗留问题。
到今天,格局全然不同!
前后端已经分离,再去返回一个静态页面,肯定是不行的,
但是!又不能舍弃 这个设置。
因为,前面开发的项目,你不能说 不要 就 不要啊!!
那都是钱砸出来的。
因此,保留这个机制,是为了以前的代码还可以用。
而 添加 @ResponseBody,即实现了前后端分离。又能保存以前返回页面的机制。
这样就实现 项目 与 时代的兼容!虽然不用返回界面了,但还是要写两个注解,稍微有点麻烦。
我们还要更简单的写法、是一个组合注解。
现在暂时放放,后面再讲。
先继续深入了解 @RequestMapping。
@RequestMapping 是 post 还是 get 请求?
@RequestMapping 默认是 get ⽅式的请求。
这一点其实在 浏览器通过 URL 访问方法的时候,就已经证明了这一点。
通过 直接向浏览器的地址栏输入URL,默认生成 get 请求。
不相信,可以使用postman 来验证。那么,@RequestMapping 支持 POST 方法吗?
答案:@RequestMapping,不仅支持 GET 方法,还支持 POST 方法的!
总结 && 拓展
@RequestMapping 特征:
1、既能修饰类(可选),也能修饰方法。
2、默认情况下,@RequestMapping 既支持POST 方法,也支持 GET 请求方法。
但是问题来了:如果公司制定只能使用 POST 方法,不能使用 GET 方法。
这种公司是存在的,目的就是为了方便管理 。
像 @RequestMapping 这种 两种都支持,就还好。
但是,有些接口只支持 一种 方法 的请求,可能是 POST,也可能是 GET,这都说不准。
主要看实际情况。
但是,这就会造成一个项目中,既有支持 get,又有支持post 的方法。
这就会导致一个问题:
每个人对代码的理解是不一样的。这就会增加程序员(前后端都包括)的负担。
因为 在看每个接口在进行调用的时候,他要去看 说明文档,然后,才能确定你当前这个接口是支持 GET,还是POST的 。
一些公司指定使用 一种 方法,就是为了避免这种情况。
程序不用去思考使用那种方法来写代码,直接按照公司的要求来。
那么,我的问题就是:能不能让 @RequestMapping 只支持一种方法。
答案是可以的!
通过设置属性值,就可以做到!!!
这个属性叫做 method
需要注意的是:@RequestMapping 直接给路由参数,默认就是给 value 属性赋值
还有一个细节:
类上的 RequestMapping 的路由参数,可以省略 / 的(虽然可以不加,但是还是建议加规范)
方法2 和 方法 3:@GetMapping 和 PostMapping
你想的没有错,就是@RequestMapping 分解出来的 两个注解。
意思很直白,你们应该是能懂的。
@GetMapping :只支持 Get 方法
@PostMapping:只支持 Post 方法。
获取用户请求参数
传递单个参数
在 Spring MVC 中可以直接⽤⽅法中的参数来实现传参.
在传递单个参数的时候,最常传递的参数是 id。
因为 id 通常是通过 primary key’(主键)来设置的,具有唯一性。
有助于我们获取到唯一的数据。
这里我们不去访问数据,直接通过访问方法来演示一下就行,
主要是了解用法
上述这种方式,只要 获取的参数名称,与前端传输的参数名称一致,就能获取到对应的参数值。
如果 前端参数名称 和 映射方法的参数名称,不一样。
不但获取不到,还会报错!
图中说到 映射方法的参数类型,不能使用基本数据类型。
虽然正常情况下,代码运行没问题,和 使用 包装类 的效果一样。
但是像遇到上述这种特殊问题(前端传输参数名称 和 映射方法名称 不相符),代码就会报错。
获取多个参数 / 表单参数传递(非对象)
我们简单实现 回显服务。
传递什么参数,就返回什么参数。
方法还是一样的,只要 前端传递的参数名称 和 后端映射方法参数名称相同,就能够获取一个,甚至多个参数。
但是目前这个代码存在很大的问题,就是参数一旦增加。
我们就得手动去添加,还可能漏掉某个参数,
而且,维护的时候,也很难看清楚代码,参数太多了!维护性极低。
那么,我们该怎么去处理呢?
接着往下看!
获取多个参数 / 获取对象
获取对象,那就很简单了!!!
映射方法 只需要 一个 对象参数 就行了。
获取对象参数的重点,还是在 前端传参的时候,参数名称 要与 对象中的属性名称相对应,Spring MVC 就会自动 对 对象的属性 进行赋值。
如果名称不匹配,那么,这个参数传输的毫无意义。
拓展
后端参数重命名(后端参数映射:@RequestParam )
跟给 Bean 对象重命名 是一样的意思。
就是给 参数 改个名字。
某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致!
⽐如前端传递了⼀个time 给后端,⽽后端⼜是由 createtime 字段来接收的,这样就会出现参数接收不到的情况.
如果出现这种情况,我们就可以使⽤ @RequestParam 来重命名前后端的参数值。
特殊情况,比如:
在将来的某一天,公司晚上突然加班,需要紧急添加一个需求。
更重要的是:产品明天就要上线了。
紧急加班嘛,代码就写的有点“粗”。
前后端,并没沟通好。
假设,做的一个登录功能的扩展
然后,产品是凌晨 2点上线的。
代码也就没有经过严格的测试。
因为 测试可能都下班,都是研发人员 去硬怼的。
第二天用的时候,运维发现了问题,通知 开发 / 测试 人员,某某功能有问题。
比如:无论用户怎么输入,一直提示填写用户名。
最终,排查出的问题:
前端在传输参数的时候,参数名字 叫做 name,而后端参数是叫做 username。
这样就会导致一直拿不到 用户名的值。
这个时候,我们有两种解决方案。
1、让后端的代码适应前端的代码,修改映射方法的参数名称(username >> name)。
但是一个问题也随之而来。
就是啊,这个 username 已经在映射方法中,使用了很多次了。
这一改,方法中的代码全都得动!
而且存在漏改的风险!
2、让前端的代码,适应后端的代码。
让前端传回的参数 name >> username
这也会存在一个问题,像这种做完一个大项目的时候。
前端的人都休假,回到家直接关手机睡觉了。
但是这个bug 又很紧急!
总结:前端失联,后端不想改。
这个时候,就可以使用 后端参数重命名了。
后端参数重命名,就是把前端传过来的参数名称,进行转移赋值。
就是说:前端参数名称不变,还是name;后端接收到之后,将其参数名称的数值,赋值到 后端的 username 参数上。
此时,对于 后端来说,前端的 name,就是 username 了。
因为两者的value 值,都是一样的。
具体的实现方法,还是通过注解的方式来解决。
使用 @RequestParam 注解,就可以搞定了。
虽然也有方法可以处理这种情况,但不是这个注解,是另一个。
(后面在 讲 MyBatis 的时候,会说这个)
但如果映射方法的参数是一个对象,那就没办法了。
这个你就只能和前端交流了,让他配合你的操作。
将 前端参数名称 修改成 和 后端对象中的属性名称 一样。
或者你配合他的代码。。。。
将类中的属性名修改成 和 前端参数一样的名称。
@RequestParam 的进一步理解: required属性
表单参数传递(对象)
表单传递对象参数,还是一样的。
接受对象参数时,前端参数该怎么传,就这么传。
上面是一个 get 方法的请求。
下面我们来通过 postman 构造一个 post 方法的 表单请求
@RequestBody 接收JSON对象 - 特殊
有的人看到这个,感觉so easy!
既然 JSON 也是一个对象,这跟上面没有区别嘛。
还是一样的,前端直接传输一个 JSON 对象,映射方法这边还是使用一个对象去接收。
下面,我就来验证一下,程序能不能接收一个 JSON 对象的数据?
通过获取普通对象的方法,来获取一个 json 格式的对象参数。显然是不行的!
由此,不难得出结论:
只要不是 json 格式的数据,无论是 GET 还是 POST 方法的请求,都没有问题!
这一点在前面的例子中,就已经充分体现出来了。
也就是说:想要通过接收 json 对象,需要通过其它的方法来实现。
当然还是注解,这个注解就是标题的 @ RequestBody 注解
PS:注意!不要迷糊了!!!!
我们使用的 @RequestBody,不是 @ResponseBody。。。
@ResponseBody: 表示返回的数据是一个非静态的页面。
而 @RequestBody,是告诉 映射方法接下来接收到的数据是一个JSON 格式的数据。
方便对 JSON 数据,进行解析。
结论:
服务器端想要实现 json 数据的接收,就需要使用 @RequestBody 注解。
获取URL中参数@PathVariable - 特殊
这个就厉害了,它不满足于从 请求的正文 和 URL 中的查询字符串 中 获取参数了。
而是从 URL 中获取参数。
注意!我的描述:
@PathVariable注解,不满足从 请求的正文 和 URL 中的查询字符串(参数部分),获取 参数。
而是直接从 URL地址 中 获取参数。举个例子:DOTA 都知道吧?一个推塔游戏。
比如,
我们现在想要获取到一个 英雄的信息。一般情况下,我们获取英雄信息的方式,都是同 URL 的 查询字符串部分来获取的。
如:http://data2.uuu9.com?heroname=影魔
而通过 URL地址的方式来获取英雄信息:http://data2.uuu9.com / 66 / 影魔 /
假设 66 是它的 ID。
那么,通过以往的方式去获取这个英雄的信息,可以吗?
很明显,是不可以!!!!
我们前面所学的方法,就没有一个针对 URL地址部分的!那么问题来了,为什么有正常的方式不用,用这种非主流的方式来获取参数呢?
这个就涉及到 SU(搜索引擎) 的优化。
什么是 SU 的优化呢?需要注意的是:
使用 第二种形式的URL,也是存在 " 缺点 " 的!不过 Spring MVC 又提供了一个新的注解 @PathVariable
其实也很好理解:path variable == 路径变量。
随之而来的是:路径肯定是存在两种形式的。
1、参数
2、路径
那我们该如何区分 那个是参数,那个是路径呢?
路径的写法不变,还是 “/xxx”
而参数的,就是在 / 后面,加上 大括号,将其后面的内容括起来: “/{xxx}”需要注意的一点:
上传文件 - @RequestPart
现在不是之前那种简单数据了,它可能是一个数据流。
它传过来的是一个 “流”。
比如:
我们在进行用户注册的时候,要上传一个头像(图片)。
也就是说:上传的数据,就是这个图片的字节流。
类似于这种上传文件的形式,我应该怎么去获取呢?
通过 @RequestPart 注解,并将 文件名称 作为 参数放入其中,同时还需要借助 Spring 提供 MultipartFile对象。
MultipartFile,就是专门用来接收文件的。还没完,其实上述操作,还存在问题。
问题就出在 图片 和 存储路径,都被写死了。
我们再来想象一个场景。
所以,不能这么去写!!!
拓展:不同平台运行的配置文件设置 - 优化存储目录
首先,我们先来补充 关于日志文件的知识补充。
这样做的好处:
哪怕配置文件再多,我们也就只需要修改 主配置文件中的一个参数,就可以调用对应的配置文件了 。总结:
1、针对各个平台,创建专属的配置文件
2、配置文件的命名规则:application + 分隔符“ - ” + 平台名称(可简写) + .格式【必须这么去写 】
3、在主配置文件中设置 运行的配置文件。【spring.profiles.active】
图片名称不能重复 && 获取原图格式 问题
先把 主配置文件中 的 参数 改成 develop (开发环境)
要不然识别不了,毕竟我们现在是在本地操作。
下面,我们先来解决 图片名称 问题。
第一种:时间戳
通过 时间戳 来命名图片,是存在问题的。
其实 “巧合”,在互联网中是很常见的。
因此,很有可能就有那么几个人,同时,上传图片。
还是会造成 图片名称 的重复,导致 原先的图片被覆盖。
只是发生的概率要小一些。
因此,不可取的。
因为 它不适合用于 并发执行的情况。
第二种:UUID(全局唯一标识符)
UUID就不会从出现 时间戳的情况。
UUID 会使用 你的网卡,随机数,等等,,,各种各样的信息来对 文件 进行命名。
在这种条件下,命名重复的概率,几乎不可能出现。
现在 存储路径的问题 搞定了,图片名称重复的问题 搞定了。
就剩下 获取 原上传图片 的 格式 了。
其实 MultipartFile 对象中,提供了 一个 API(getOriginalFilename)。
getOriginalFilename:获取原始的文件名称
名称里面都有什么?有文件后缀啊!
想办法截取文件后缀,不就可以了嘛。
问题都有了解决方案,接下来就是实施环节。
注意!我们通过取巧的方式,来做的。
其实 uid 来也可以进行操作。
但是 局限性很强!
使用 uid 来 命名 图片,只能使用一次。【唯一性】
但是!可能还有其它图片,都是与用户相关的。
当然,你可以通过添加前缀的方式来实现。
总的来说:还是更推荐使用 UUID 的方式,因为它更通用性更强。
获取Cookie/Session/header
这三个是比较特殊,在有些场合,才会用到,
其中 获取 Session 是比较常见的。
这三项,通常都不是(使用的一方)用户 自动去上传的。
都是由 前端工程师,或者是由系统给我们上传的。
比如说:
Cookie,是浏览器自身去实现的。
它会在每一次请求中,都会把域名底下所有的 cookie 都带上。
这都属于 浏览器自身的行为。
当然,如果前端工程师愿意的话,他也可以 发送 cookie 给后端。
Session,也是一样。
也是前端的浏览器自动发送给后端的。
但是后端是需要获取到 Session 的。
毕竟,它用的比较多。
因为,用户在登录的时候,是需要通过 session 来验证用户信息的。
header,有些场景下,前端还会在 header 里面,设置自定义的header。
然后,传递到后端。
系统的header信息,有些时候,也是需要获取的。
至于为什么要获取 header,因为 header 里面有一个 userAge。
userAge 里面就记录了当前访问用户的操作系统信息,以及他所使用的浏览器信息。
那我就可以每一次请求一个接口的时候,统计用户 的 浏览器 和 操作系统 的信息。
在拿到 用户 浏览器 和 操作系统的信息之后,方便对其进行分析。
根据 分析的结果,做一个排列,看看哪种浏览器的永辉最多,那个操作系统的用户最多。
来进行针对性处理和优化。
就是说:产品能够更好的兼容这些比较热门的操作系统 和 浏览器。
总之,一句话:我可以不用,但是不能不会!
至少我是知道有这么几个东西的。
知识铺垫:获取 Request 和 Response 对象
因为 Spring MVC 就是 基于 Servlet API 来实现的。
也就是说:Servlet 那一套 是 完全适用于 Spring MVC 的。
在 Spring MVC 里面,每一个方法都有2个 “隐藏参数”、
【HttpServletRequest 和 HttpServletResponse】下面我们就来验证一下功能。
根据结果,更加证明了 Spring MVC 是 支持 Servlet API 的。
获取 Cookie
获取 Cookie 的方式有两种:
1、基于 Servlet 提供 的 API 来获取 Cookie
虽然,方法是可以的.。
但是这种读取的方式,其实是有点“繁琐的”!
因为需要先获取 请求对象,通过对象提供的方法,来获取 所有的cookie。
而 繁琐,就体现在这一步!
通常情况,我们获取 cookie 数据的时候,不会全拿,只拿取其中的一个。
由此,Spring MVC 提供一个新的注解,来往下看。
2、简洁的获取 Cookie - @CookieValue 这就很方便了!
想要那个 cookie 值,将其 cookieName 作为 @CookieValue 注解 的 参数,就能获取到对应的value值。
当然,你还需要准备一个 “参数” 来接收。
获取 header(获取请求头中的信息)
获取 header 的 方法,也有两种:
1、 基于 Servlet API
2、简洁获取 Header—@RequestHeader
相比于 Servlet API,注解的方式,还是更简单一点的.
存储 和 获取 Session
为什么 Session 多出一个 存储 的 操作呢?
原因很简单!
就跟获取 cookie 的 时候一样!
你都没有 session,我还获取干什么??
所以,才会多出这一步。
更特别的是:关于 存储 操作,只能通过 servlet API。
因为存储操作,是没有办法用参数来表示的。
读取操作,是有两种方法的。
1、servlet API
2、更简洁的获取 session - 使用 注解 :@SessionAttribute
至于为什么需要加上一个 required 属性,并置为 false!
这因为 在使用 注解 获取 session 对象的时候,没有判断句!
即:如果访问 getSession2 方法的时候,没有设置 session 会话,并且内置属性。
此时,它就直接报错!因为它找不到对应 key 值!
这是因为 @SessionAttribute 注解中,有required的属性。
这个前面在讲 @RequestParam 的时候,就讲了。
不会像 servlet 那样,返回一个 空值(页面什么都不显示)。
这个值,必须得有!!!
解决的方法,就是将 required 属性,置为false。
表示这个 key 值,并不是非要找到!
而是找不到就算了!