深入解析SpringMVC:从入门到精通
上文了解到SpingBoot的相关知识,此文开启Sping家族下的新篇章
1. 什么是SpringWebMVC?
官方对于SpringMVC的描述是这样的:
什么是Servlet呢?
Servlet 是⼀种实现动态页面的技术.准确来讲Servlet是⼀套JavaWeb开发的规范,或者说是⼀套Java
Web开发的技术标准.只有规范并不能做任何事情,必须要有人去实现它.所谓实现Servlet规范,就是真正编写代码去实现Servlet规范提到的各种功能,包括类、方法、属性等.
Servlet 规范是开放的,除了Sun公司,其它公司也可以实现Servlet规范,目前常见的实现了Servlet
规范的产品包括Tomcat、Weblogic、Jetty、Jboss、WebSphere等,它们都被称为 “Servlet 容器”.Servlet 容器用来管理程序员编写的Servlet类.
从上述定义我们可以得出⼀个信息:
SpringWebMVC是⼀个Web框架.
1.1 MVC定义
MVC是Model View Controller的缩写,它是软件工程中的⼀种软件架构设计模式,它把软件系统分为模型、视图和控制器三个基本部分
- View(视图)指在应用程序中专门用来与浏览器进行交互,展示数据的资源.
- Model(模型)是应用程序的主体部分,用来处理程序中数据逻辑的部分.
- Controller(控制器)可以理解为⼀个分发器,用来决定对于视图发来的请求,需要用哪⼀个模型来处理,以及处理完后需要跳回到哪⼀个视图。即用来连接视图和模型
比如去饭店吃饭
客户进店之后,服务员来接待客户点餐,客户点完餐之后,把客户菜单交给前厅,前厅根据客户菜单给后厨下达命令.后厨负责做饭,做完之后,再根据菜单告诉服务员,这是X号餐桌客人的饭.
在这个过程中 服务员就是View(视图),负责接待客户,帮助客户点餐,以及给顾客端饭
前厅就是Controller(控制器),根据客户的点餐情况,来选择给哪个后厨下达命令.
后厨就是Model(模型),根据前厅的要求来完成客户的用餐需求
1.2 什么是SpringMVC?
MVC是⼀种架构设计模式,也是⼀种思想, 而SpringMVC是对MVC思想的具体实现.除此之外,Spring MVC还是⼀个Web框架.
总结来说,SpringMVC是⼀个实现了MVC模式的Web框架
在使用IDEA企业版的时候,创建SpingBoot项目后,我们勾选的依赖中就说明了SpringWeb框架其实就是SpringMVC框架
Spring Boot 可以添加很多依赖,借助这些依赖实现不同的功能.SpringBoot通过添加SpringWebMVC框架,来实现web功能
2. SpingMVC
因为是Web框架,所以当用户在浏览器中输入了url之后,我们的SpringMVC项目就可以感知到用户的请求,并给予响应.
SpingMVC通过浏览器和用户程序进行交互.
主要分以下三个方面:
- 建立连接: 将用户(浏览器)和Java程序连接起来,也就是访问⼀个地址能够调用到我们的Spring 程序。
- 请求: 用户请求的时候会带⼀些参数,在程序中要想办法获取到参数,所以请求这块主要是获取参数的功能.
- 响应: 执行了业务逻辑之后,要把程序执行的结果返回给用户,也就是响应.
比如用户去银行存款
- 建立连接:去柜台
- 请求:带着银行卡,身份证去存款
- 响应:银行返回⼀张存折.
2.1 项目准备
Spring MVC项目创建和SpringBoot创建项目相同,在创建的时候选择SpringWeb就相当于创建了Spring MVC的项目.
2.2 建立连接
在SpringMVC中使用@RequestMapping
来实现URL路由映射,也就是浏览器连接程序的作用
创建⼀个UserController类,实现用户通过浏览器和程序的交互,具体实现代码如下:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class UserController {@RequestMapping("/hello")public String hello(){return "hello,my 1st SpingMVC project";}
}
2.2.1 @RequestMapping注解
@RequestMapping
是SpringWebMVC应用程序中最常被用到的注解之⼀,它是用来注册接口的路由映射的.
表示服务收到请求时,路径为/hello的请求就会调用sayHi这个方法的代码.
路由映射: 当用户访问⼀个URL时,将用户的请求对应到程序中某个类的某个方法的过程就叫路由映射.
既然@RequestMapping 已经可以达到我们的目的了,我们为什么还要加 @RestController呢?
我们可以试着把@RestController 去掉,再来访问⼀次:
可以看到,程序报了404,找不到该页面,这就是@RestController 起到的作用. ⼀个项目中,会有很多类,每个类可能有很多的方法,Spring程序怎么知道要执行哪个方法呢?
Spring会对所有的类进行扫描,如果类加了注解@RestController
,Spring才会去看这个类里面的方法有没有加@RequestMapping
这个注解,当然他的作用不止这⼀点
2.2.2 @RequestMapping使用
@RequestMapping既可修饰类,也可以修饰方法,当修饰类和方法时,访问的地址是类路径+方法路径.
@RequestMapping标识⼀个类:设置映射请求的请求路径的初始信息
@RequestMapping标识⼀个方法:设置映射请求请求路径的具体信息
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/luo")
public class UserController {@RequestMapping("/hello")public String hello(){return "hello,my 1st SpingMVC project";}
}
访问地址:http://127.0.0.1:8080/luo/hello
注意:
@RequestMapping
的URL路径最前⾯加不加/
(斜杠)都可以,Spring程序启动时,会进行判断,如果前面没有加/
,Spring会拼接上⼀个/
@RequestMapping
的URL路径也可以是多层路径, 最终访问时,依然是类路径+方法路径
2.2.3 @RequestMapping是GET还是POST请求?
我们来测试⼀下就知道结论了
GET请求:
浏览器发送的请求类型都是get,通过以上案例,可以看出来@RequestMapping
支持get请求
POST请求:
我们通过form表单来构造请求:
创建test.html, html代码:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>@RequestMapping test</title>
</head>
<body>
<form action="/luo/hello" method="post"><input type="submit" value="提交">
</body>
</html>
从运行结果可以看出:@RequestMapping 既支持Get请求,又支持Post请求.同理,也支持其他的请求方式.
那么在实际开发过程中,我们希望可以自定义是POST请求还是GET请求又或是别的操作,该如何操作呢?
2.3 Postman介绍
前言: 从上面的案例中,也发现了⼀个新的问题,就是我们测试后端方法时,还需要去写前端代码.这对我们来说,是一件麻烦又痛苦的事情.
随着互联网的发展,也随着项目难度的增加,企业也按照开发的功能,把人员拆分成了不同的团队.界面显示交给"前端开发工程师",业务逻辑的实现交给"后端开发工程师".
后端开发工程师,不要求也不需要掌握前端技能了. 那后端开发工程师,如何测试自己的程序呢?
这时,我们就需要使用专业的接口测试工具Postman
2.3.1 Postman下载
Postman下载,相关下载问题,可以查询相关博客了解,此处不做介绍
2.3.2 创建请求
2.3.3 界面介绍
2.3.4 传参介绍
-
普通传参:通过查询字符串来传参
前面的文章HTTP时,介绍了通过URL来访问互联网上的某⼀个资源时,URL的格式如下:
其中,查询字符串就是请求的参数
-
form-data:(完整表示为:multipart/form-data)
表单提交的数据, 在form标签中加上 enctyped="multipart/form-data
通常用于提交图片/文件.对应Content-Type: multipart/form-data
- x-www-form-urlencoded
form表单,对应Content-Type: application/x-www-from-urlencoded
- raw
可以上传任意格式的文本,可以上传text、json、xml、html
等
2.4 请求
前言: 我们访问不同的路径,就是发送不同的请求.在发送请求时,可能会带一些参数,所以Spring的请求,主要是如何传递参数到后端以及后端如何接收.
传递参数,主要是使用浏览器和Postman来模拟. 后端开发人员无需过度关注如何传递参数,了解即可,实际开发中以Postman测试为主.
比如餐厅的厨师,不关注用户是在店里下单,还是外卖平台下单,或者小程序下单,只需要知道如何接收订单,根据订单做出对应的事物就可以了.
2.4.1 传递单个参数
接收单个参数,在SpringMVC中直接用方法中的参数就可以,比如以下代码:
@RestController
@RequestMapping("/luo")
@RequestMapping("/test1")
public String t1(String name) {return "接受到参数name:"+name;
}
使用浏览器发送请求并传参
如果参数不⼀致,是获取不到参数的.
比如请求URL:http://127.0.0.1:8080/luo/test1?name1=yududu
响应结果:
2.4.1.1 注意事项:
使用基本类型来接收参数时,参数必须传(除boolean类型),否则会报500错误
类型不匹配时,会报400错误.
@RequestMapping("/luo/test1")public Object t2(int age){return "接收到参数age:" + age;}
1. 正常传递参数
http://127.0.0.1:8080/luo/test2?age=18
浏览器响应情况:
通过Fiddler观察请求和响应,HTTP响应状态码为200
,Content-Type
为text/plain
2. 不传递age参数
http://127.0.0.1:8080/luo/test2?
浏览器响应情况:
通过Fiddler观察请求和响应,HTTP响应状态码为500
观察程序的错误日志:
⼀般看日志堆栈信息的首行,
报错信息显示:
int类型的参数’age’,虽然为可选的,但由于被声明为基本类型而不能转换为空值.考虑将其声明为对应基本类型的包装类型.我们只需按照错误信息解决错误即可
3. 传递参数类型不匹配
http://127.0.0.1:8080/luo/test2?age=abc
浏览器响应情况:
通过Fiddler观察请求和响应, HTTP响应状态码为400
对于包装类型,如果不传对应参数,Spring接收到的数据则为null
所以建议在企业开发中,对于参数可能为空的数据,建议使用包装类型
2.4.2 传递多个参数
@RequestMapping("/test3")public String t3(String name,int age) {return "接受到参数name:"+name+"接受到参数age:"+age;}
使用浏览器发送请求并传参
http://127.0.0.1:8080/luo/test3?name=yududu&age=18
当有多个参数时,前后端进行参数匹配时,是以参数的名称进行匹配的,因此参数的位置是不影响后端获取参数的结果
比如访问http://127.0.0.1:8080/luo/test3?age=18&name=yududu一样的拿到相同的结果
2.4.3 传递对象
如果参数比较多时,方法声明就需要有很多形参.并且后续每次新增⼀个参数,也需要修改方法声明.所以我们建议把这些参数封装为⼀个对象
Spring MVC也可以自动实现对象参数的赋值,比如Person对象:
public class Person {public String name;public int age;public int password;public String address;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public int getPassword() {return password;}public void setPassword(int password) {this.password = password;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Person(String address, int password, int age, String name) {this.address = address;this.password = password;this.age = age;this.name = name;}public Person() {}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", password=" + password +", address='" + address + '\'' +'}';}
}
说明:
1. SpringMVC 默认是通过get和set方法来绑定参数的,不能靠构造方法进行参数绑定,所以需要提供get和set方法
2. 在不给参数的情况下必须存在无参构造方法,否则就必须传递所有参数
传递对象代码:
@RequestMapping("/test4")public String t4(Person person) {return person.toString();}
可以看到,后端程序正确拿到了Person对象里各个属性的值
Spring会根据参数名称自动绑定到对象的各个属性上,如果某个属性未传递,则赋值为null(基本类型则赋值为默认初识值,比如int类型的属性,会被赋值为0)
2.4.4 后端参数重命名(后端参数映射)
某些特殊的情况下,前端传递的参数key和我们后端接收的key可以不⼀致,比如前端传递了⼀个birthday给后端,而后端是使用day字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使用@RequestParam
来重命名前后端的参数值.
不加@RequestParam注解的情况下:
@RequestMapping("/test5")public String t3(String birthday) {return "接受到参数birthday:"+birthday;}
加@RequestParam注解的情况下:
@RequestMapping("/test5")public String t3(@RequestParam("day") String birthday) {return "接受到参数birthday:"+birthday;}
可以看到,Spring可以正确的把浏览器传递的参数day绑定到了后端参数birthday参数上
1.
既然前后端参数绑定了,那么浏览器或者postman是否可以用后端参数birthday进行参数传递呢??
错误日志信息为:
控制台打印日志显示:请求参数’day’不存在2. 为什么不传递参数就报错呢??
可以看到required的默认值为true,表示含义就是:该注解修饰的参数默认为必传 此时只需将require的值改为false即可
@RequestMapping("/test5")
public String t3(@RequestParam(value = "day",required = false) String birthday) {return "接受到参数birthday:"+birthday;
}
此时我们发现可以被@RequestParam标记的注解不再是必传递参数了
总结:
1. 使用@RequestParam进行参数重命名时, 请求参数只能和使用@RequestParam 声明的名称⼀致,才能进行参数绑定和赋值.
2.@RequestParam 进行参数重命名时,参数就变成了必传参数.
2.4.5 传递数组
Spring MVC可以自动绑定数组参数的赋值
后端实现代码:
@RequestMapping("/test6")public String t6(String[] array) {return Arrays.toString(array);}
数组参数:请求参数名与形参数组名称相同且请求参数为多个,后端定义数组类型形参即可接收参数
请求方法如下多种:
-
http://127.0.0.1:8080/luo/test6array=yududu&array=luodudu&array=yuxiaomei&array=luoxiaoshuai
-
http://127.0.0.1:8080/luo/test6?array=yududu,luodudu,yuxiaomei,luoxiaoshuai
2.4.6 传递集合
集合参数: 和数组类似,同⼀个请求参数名有为多个,且需要使用@RequestParam
绑定参数关系,默认情况下,请求中参数名相同的多个值,是封装到数组.如果要封装到集合,要使用@RequestParam
绑定参数关系
错误示范:
@RequestMapping("/test7")public String t7(List<String> list) {return list.toString();}
不加注解就默认为数组,所以我们需要加上注解@RequestParam
正确示范:
@RequestMapping("/test7")public String t7(@RequestParam List<String> list) {return list.toString();}
2.4.7 传递JSON数据
2.4.7.1 JSON概念
JSON:JavaScript Object Notation 【JavaScript 对象表示法】
JSON是⼀种轻量级的数据交互格式.它基于ECMAScript(欧洲计算机协会制定的js规范)的⼀个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
简单来说:JSON就是⼀种数据格式,有自己的格式和语法,使用文本表示⼀个对象或数组的信息,因此JSON本质是字符串. 主要负责在不同的语言中数据传递和交换.
2.4.7.2 JSON的语法:
- 数据在
键值对(Key/Value)
中 - 数据由
逗号,
分隔 - 对象用
{}
表示 - 数组用
[]
表示 - 值可以为对象,也可以为数组,数组中可以包含多个对象
2.4.7.3 JSON的两种结构
- 对象:大括号
{}
保存的对象是⼀个无序的键值对集合.⼀个对象以左括号{
开始,右括号}
结束。每个"键"后跟⼀个冒号:
,键值对使用逗号,
分隔 - 数组:中括号
[]
保存的数组是值(value)的有序集合.⼀个数组以左中括号[
开始,右中括号]
结束,值之间使用逗号,
分隔。
以下就是一个简单的JSON文件:
{"sites": [{ "name":"菜鸟教程" , "url":"www.runoob.com" }, { "name":"google" , "url":"www.google.com" }, { "name":"微博" , "url":"www.weibo.com" }]
}
2.4.7.4 JSON字符串和Java对象互转
- JSON本质上是⼀个字符串,通过文本来存储和描述数据
- Spring MVC框架也集成了JSON的转换工具,我们可以直接使用,来完成JSON字符串和Java对象的互转
- 本质上是
jackson-databind
提供的功能,SpringMVC框架中已经把该工具包引入了进来,咱们直接使用即可,如果脱离SpringMVC使用,需要引入相关依赖 - JSON的转换工具包有很多,jackson-databind只是其中的⼀种.
- 使用ObjectMapper对象提供的两个方法,可以完成对象和JSON字符串的互转
writeValueAsString: 把对象转为JSON字符串
readValue: 把字符串转为对象
2.4.7.5 JSON优点
- 简单易用:语法简单,易于理解和编写,可以快速地进行数据交换
- 跨平台支持: JSON可以被多种编程语言解析和生成,可以在不同的平台和语言之间进行数据交换和传输
- 轻量级:相较于XML格式,JSON数据格式更加轻量级,传输数据时占用带宽较小,可以提高数据传输速度
- 易于扩展: JSON的数据结构灵活,支持嵌套对象和数组等复杂的数据结构,便于扩展和使用
- 安全性:JSON数据格式是⼀种纯文本格式,不包含可执行代码,不会执行恶意代码,因此具有较高的安全性
2.4.7.6 传递JSON对象
接受JSON对象,需要使用@RequestBody
注解
RequestBody: 请求正文,意思是这个注解作用在请求正⽂的数据绑定,请求参数必须在写在请求正文中
后端实现:
@RequestMapping("/test8")public String t7(@RequestBody Person person) {return person.toString();}
使⽤Postman来发送json请求参数:
如果去掉@RequestBody
注解,后端就获取不到值
2.4.8 获取URL中参数@PathVariable
path variable: 路径变量
和字面表达的意思⼀样,这个注解主要作用在请求URL路径上的数据绑定
默认传递参数写在URL上,SpringMVC就可以获取到
后端实现代码:
@RequestMapping("/test10/{id}/{name}")public String t10( @PathVariable int id ,@PathVariable("name") String username) {return "接受到参数id:"+id+",username:"+username;}
使用Postman发送请求
可以看到,后端正确获取到了URL中的参数
参数对应关系如下:
如果方法参数名称和需要绑定的URL中的变量名称⼀致时,可以简写,不用给@PathVariable的属性赋值,如上述例子中的id变量
如果方法参数名称和需要绑定的URL中的变量名称不⼀致时,需要@PathVariable的属性value赋值,如上述例子中的username变量.
2.4.9 上传文件@RequestPart
现在D盘下创建一个temp文件夹用于后续验证
后端代码实现:
@RequestMapping("/test11")public String t11( @RequestPart("file") MultipartFile file) throws IOException {//获取⽂件名称String fileName = file.getOriginalFilename();//⽂件上传到指定路径file.transferTo(new File("D:/temp/" + file.getOriginalFilename()));return " 接收到⽂件名称为: "+fileName;}
使用Postman发送请求
2.4.10 获取Cookie/Session
2.4.10.1 什么是Cookie?
首先我们知道HTTP协议自⾝是属于"无状态"协议.
"无状态"的含义指的是:
默认情况下HTTP协议下的客户端和服务器之间的这次通信,和下次通信之间没有直接的联系.
但是实际开发中,我们很多时候是需要知道请求之间的关联关系的.
例如登陆网站成功后,第二次访问的时候服务器就能知道该请求是否是已经登陆过了
上述图中的 “令牌” 通常就存储在Cookie字段中.
比如去医院挂号
- 看病之前先挂号.挂号时候需要提供身份证号,同时得到了⼀张"就诊卡",这个就诊卡就相当于患者的"令牌".
- 后续去各个科室进行检查,诊断,开药等操作,都不必再出示身份证了,只要凭就诊卡即可识别出当前患者的身份.
- 看完病了之后,不想要就诊卡了,就可以注销这个卡.此时患者的身份和就诊卡的关联就销毁了.(类似于网站的注销操作)
- 又来看病,可以办⼀张新的就诊卡,此时就得到了⼀个新的"令牌"
此时在服务器这边就需要记录"令牌"信息,以及令牌对应的用户信息,这个就是Session机制所做的工作.
2.4.10.2 什么是Session?
会话: 对话的意思在计算机领域, 会话是⼀个客户端与服务器之间的不中断的请求响应.对客户端的每个请求,服务器能够识别出请求来自于同⼀个客户端.当⼀个未知的客户端向Web应⽤程序发送第⼀个请求时就开始了⼀个会话.
当客户端明确结束会话或服务器在一个时限内没有接受到客户端的任何请求时,会话就结束了. 比如我们打客服电话,每次打客服电话,是⼀个会话.挂断电话,会话就结束了 下次再打客服电话,又是一个新的会话. 如果我们长时间不说话,没有新的请求,会话也会结束.
服务器同一时刻收到的请求是很多的.服务器需要清楚的区分每个请求是属于哪个客户端,也就是属于哪个会话,就需要在服务器这边记录每个会话以及与用户的信息的对应关系.
Session是服务器为了保存用户信息而创建的⼀个特殊的对象
Session的本质就是⼀个"哈希表",存储了一些键值对结构.Key就是SessionID,Value就是用户信息(用户信息可以根据需求灵活设计)
SessionId 是由服务器⽣成的⼀个"唯⼀性字符串",从Session机制的角度来看,这个唯⼀性字符串称为"SessionId". 但是站在整个登录流程中看待,也可以把这个唯⼀性字符串称为 “token”.
上述例子中的令牌ID,就可以看做是SessionId,只不过令牌除了ID之外,还会带⼀些其他信息,比如时间,签名等
说明:
- 当用户登陆的时候,服务器在Session中新增⼀个新记录,并把sessionId返回给客户端.(通过HTTP响应中的Set-Cookie字段返回).
- 客户端后续再给服务器发送请求的时候,需要在请求中带上sessionId.(通过HTTP请求中的Cookie字段带上).
- 服务器收到请求之后,根据请求中的sessionId在Session信息中获取到对应的用户信息,再进行后续操作.找不到则重新创建Session,并把SessionID返回.
2.4.10.3 Cookie 和Session的区别
- Cookie是客户端保存用户信息的⼀种机制.Session是服务器端保存用户信息的⼀种机制
- Cookie和Session之间主要是通过SessionId关联起来的,SessionId是Cookie和Session之间的桥梁
- Cookie和Session经常会在⼀起配合使用.但不是必须配合.
- 完全可以用Cookie来保存⼀些数据在客户端.这些数据不⼀定是用户身份信息,也不一定是
SessionId - Session中的sessionId也不需要非得通过Cookie/Set-Cookie传递,比如通过URL传递
2.4.10.4 Cookie的获取
2.4.10.4.1 传统获取Cookie
@RequestMapping("/test12")public String t12(HttpServletRequest request, HttpServletResponse response) {//获取Cookies信息Cookie[] cookies = request.getCookies();//打印Cookie信息StringBuilder builder = new StringBuilder();if (cookies!=null){for (Cookie ck:cookies) {builder.append(ck.getName()+":"+ck.getValue());}}return "Cookie信息:"+builder;}
Spring MVC是基于Servlet API构建的原始Web框架,也是在Servlet的基础上实现的
HttpServletRequest ,HttpServletResponse
是Servlet提供的两个类,是SpringMVC⽅法的内置对象.需要时直接在⽅法中添加声明即可.
HttpServletRequest
对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息.HttpServletResponse
对象代表服务器的响应.HTTP响应的信息都在这个对象中,比如向客户端发送的数据,响应头,状态码等.通过这个对象提供的方法,可以获得服务器响应的所有内容Spring MVC在这两个对象的基础上进行了封装,给我们提供更加简单的使用方法.
此时没有设置Cookie,通过浏览器访问:http://127.0.0.1:8080/luo/test12,得到Cookie为null
我们设置⼀下Cookie的值
从这个例子中,也可以看出Cookie是可以伪造的,也就是不安全的,所以使用Cookie时,后端需要进行Cookie校验
2.4.10.4.2 简单获取Cookie
@RequestMapping("/getCookie")public String cookie(@CookieValue("name") String username) {return "name: " + username;}
2.4.10.5 Session存储与获取
Session是服务器端的机制,我们需要先存储,才能再获取
Session也是基于HttpServletRequest来存储和获取的
2.4.10.5.1 Session 存储
@RequestMapping("/setSession")public String setSession(HttpServletRequest request) {//获取Session对象HttpSession session = request.getSession();if (session != null) {session.setAttribute("yududu", "18");}return "session存储成功";}
这个代码中看不到SessionId这样的概念.getSession操作内部提取到请求中的Cookie里的SessionId, 然后根据SessionId获取到对应的Session对象, Session对象用HttpSession来描述
2.4.10.5.2 Session 获取
读取Session可以使用HttpServletRequest
@RequestMapping("/getSession")public String getSession(HttpServletRequest request) {//如果session不存在,不会自动创建,因为getSession()方法默认值为true,表示没有就创建,false表示没有就也不会自动创建HttpSession session = request.getSession(false);String username = null;if (session != null && session.getAttribute("username") != null) {username = (String) session.getAttribute("username");}return "username: " + username;}
Object getAttribute(String name)
返回在该session会话中具有指定名称的对象,如果没有指定名
称的对象,则返回null.
说明:
获取Session有两种方式
HttpSession getSession(boolean create);HttpSession getSession();
- HttpSession getSession(boolean create) :
参数如果为true,则当不存在会话时新建会话
参数如果为false, 则当不存在会话时返回null - HttpSession getSession(): 和getSession(true) 含义⼀样, 默认值为true.
- void setAttribute(String name, Object value):使用指定的名称绑定⼀个对象到该session会话
简洁获取Session:
@RequestMapping("/getSess2")public String sess2(@SessionAttribute(value = "username",required = false)
String username) {return "username:"+username;}//通过SpringMVC内置对象HttpSession来获取
@RequestMapping("/getSess3")public String sess3(HttpSession session) {String username = (String)session.getAttribute("username");return "username:"+username;}
2.4.11 获取Header
2.4.11.1 传统获取Header
@RequestMapping("/getHeader")public String getHeader(HttpServletRequest request) {String userAgent = request.getHeader("User-Agent");return "Header: " +userAgent;}
2.4.11.2 简洁获取Header
@RequestMapping("/getHeader2")public String getHeader2(@RequestHeader("User-Agent") String userAgent) {return "Header: " +userAgent;}
2.5 响应
2.5.1 返回静态页面
首先我们在目录结构下创建一个普通的
前端页面代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>从前有座山,山里有座庙
</body>
</html>
请求代码:
@RequestMapping("/index")public Object returnHtml() {return "/index.html";}
此时,http响应把"/index.html" 当做了http响应正文的数据,这是注解的问题
我们只需要把@RestController
——>@Controller
这是为何呢??
我们发现@RestController=@Controller+@ResponseBody
说明:
@Controller :
定义⼀个控制器,Spring框架启动时加载,把这个对象交给Spring管理.
@ResponseBody :
定义返回的数据格式为非视图,返回⼀个text/html信息
2.5.2 返回数据@ResponseBody
- @ResponseBody 注解,该方法就会把"/index.html"当做⼀个数据返回给前端.
- @ResponseBody 既是类注解,⼜是方法注解
如果作用在类上,表示该类的所有方法,返回的都是数据,如果作用在方法上,表示该方法返回的是数据. - 如果在类上添加 @ResponseBody就相当于在所有的方法上添加了@ResponseBody
- 如果⼀个类的方法里,既有返回数据的,又有返回页面的,就把 @ResponseBody 注解添加到对应的方法上即可
2.5.3返回HTML代码片段
后端返回数据时,如果数据中有HTML代码,也会被浏览器解析
@RequestMapping("/returnLittleHtml")@ResponseBodypublic String returnLittleHtml() {return "<h1>返回了部分代码片段</h1>";}
响应中的 Content-Type
常见取值有以下几种:
- text/html :body数据格式是HTML
- text/css :body数据格式是CSS
- application/javascript :body数据格式是JavaScript
- application/json :body数据格式是JSON
- 如果请求的是js文件,SpringMVC会自动设置Content-Type为application/javascript
2.5.4返回JSON
@RequestMapping("/returnJson")@ResponseBodypublic HashMap<String, String> returnJson() {HashMap<String, String> map = new HashMap<>();map.put("yududu", "111");map.put("luodudu", "222");map.put("xiaoxiaobin", "333");return map;}
2.5.5设置状态码
Spring MVC会根据我们⽅法的返回结果⾃动设置响应状态码,程序员也可以⼿动指定状态码
通过SpringMVC的内置对象HttpServletResponse提供的⽅法来进⾏设置
@RequestMapping(value = "/setStatus")@ResponseBodypublic String setStatus(HttpServletResponse response) {response.setStatus(401);return " 设置状态码成功 ";}