【JavaEE】传递和接收数据,Spring MVC 注解搭建前后端交互的「隐形桥梁」
1.获取URL中的参数@PathVariable
1.1 @PathVariable的讲解
Path Variable
:路径变量
其实PathVariable
的意思和他的作用相似,在 Spring 框架里,@PathVariable
是一个常用的注解,其主要作用是从请求的 URL 路径里提取变量值,然后把这些值赋给控制器方法的参数。
1.2@PathVariable的使用
示例1:
绑定一个变量值
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@RestController
@RequestMapping("/path") //类的根路径
public class MyPathVariable {
@RequestMapping("/{name}") //类的子路径,也是将要获取的name
public String getUrl1(@PathVariable String name){
//将获取的name打印出来
return "从url中获取的变量name:"+name;
}
}
运行程序后,在浏览器中访问:localhost:8080/path/李华
注意:
如果没有设置视图文件,类上不能使用@Controller
注解,要使用@RestController
;或在类上使用@Controller
注解,同时在每个方法上使用@ResponseBody
注解。
否者,返回的String
参数将被视为试图,会去找对应的视图文件。
示例2:
绑定多个变量值
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/path")
public class testControler {
@RequestMapping("/{name}/{age}")//获取url中的name
public String myUrl3(@PathVariable String name,@PathVariable Integer age) {
//打印url中的name
return "url中的name是:" + name+", age是:"+age;
}
}
示例3:
url变量名和方法参数名不一样
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/path")
public class testControler {
@RequestMapping("/{name}")//获取url中的name
public String myUrl2(@PathVariable("name") String newName) {
//打印url中的name
return "url中的name是:" + newName;
}
}
运行结果:
1.3 总结
-
如果⽅法参数名称和绑定的URL中的变量名称⼀致时, 可以简写, 不⽤给@PathVariable的属性赋值:
-
如果⽅法参数名称和绑定的URL中的变量名称不⼀致时, 需要@PathVariable的属性value赋值:
2.上传文件@RequestPart
2.1@Request的讲解
@RequestPart
注解是 Spring 框架中的一个重要注解,主要用于处理multipart/form-data类型的请求 ,在文件上传方面的作用原理如下:
解析请求:当客户端发起一个包含文件的multipart/form-data类型请求时,服务器接收到的是一个多部分的请求体,其中包含了文件数据以及其他表单数据。@RequestPart注解可以帮助从这样的请求中,精准地提取出指定部分的数据,特别是文件数据。
绑定数据:可以将提取出的文件数据绑定到控制器方法中对应的参数上。一般会将上传的文件绑定到MultipartFile
(Spring 提供的表示上传文件的接口) 或FilePart(在 Spring WebFlux 中使用)类型的参数。
2.2@Request示例
上传文件需要借助Postman,Postman的下载和使用
后端代码:
@RequestMapping("/upload")
public String upload(@RequestPart("file") MultipartFile file)throws Exception{
//获取文件名称
String filename = file.getOriginalFilename();
//文件上传到指定路径
file.transferTo(new File("D:/temp/"+file.getOriginalFilename()));
return "接收到的文件名称为:"+filename;
}
运行结果:
看"D:/temp"中有该图片吗
3.获取Cookie和Session
3.1Cookie的作用
HTTP 协议⾃⾝是属于 “⽆状态” 协议.
“⽆状态” 的含义指的是:
默认情况下 HTTP 协议的客⼾端和服务器之间的这次通信, 和下次通信之间没有直接的联系.
但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的.
例如登陆⽹站成功后, 第⼆次访问的时候服务器就能知道该请求是否是已经登陆过了
上述图中的 “令牌” 通常就存储在 Cookie 字段中.
⽐如去医院挂号
- 看病之前先挂号. 挂号时候需要提供⾝份证号, 同时得到了⼀张 “就诊卡”, 这个就诊卡就相当于患
者的 “令牌”. - 后续去各个科室进⾏检查, 诊断, 开药等操作, 都不必再出⽰⾝份证了, 只要凭就诊卡即可识别出当
前患者的⾝份. - 看完病了之后, 不想要就诊卡了, 就可以注销这个卡. 此时患者的⾝份和就诊卡的关联就销毁了. (类
似于⽹站的注销操作) - ⼜来看病, 可以办⼀张新的就诊卡, 此时就得到了⼀个新的 “令牌”
此时在服务器这边就需要记录"令牌"信息, 以及令牌对应的⽤⼾信息, 这个就是 Session 机制所做的⼯作.
3.2Session的作用
Session:会话
怎么理解这个会话呢?
在计算机领域, 会话是⼀个客⼾与服务器之间的不中断的请求响应. 对客⼾的每个请求,服务器能够识别出请求来⾃于同⼀个客⼾. 当⼀个未知的客⼾向Web应⽤程序发送第⼀个请求时就开始了⼀个新的会话.当客⼾明确结束会话或服务器在⼀个时限内没有接受到客⼾的任何请求时,会话就结束了.
⽐如我们打客服电话
每次打客服电话, 是⼀个会话. 挂断电话, 会话就结束了下次再打客服电话, ⼜是⼀个新的会话.
如果我们⻓时间不说话, 没有新的请求, 会话也会结束.
服务器同⼀时刻收到的请求是很多的. 服务器需要清楚的区分每个请求是属于哪个⽤⼾, 也就是属于哪个会话, 就需要在服务器这边记录每个会话以及与⽤⼾的信息的对应关系.
Session是服务器为了保存⽤⼾信息⽽创建的⼀个特殊的对象
Session的本质就是⼀个 “哈希表”, 存储了⼀些键值对结构. Key 就是SessionID, Value 就是⽤⼾信息(⽤
⼾信息可以根据需求灵活设计).
SessionId 是由服务器⽣成的⼀个 “唯⼀性字符串”, 从 Session 机制的⻆度来看, 这个唯⼀性字符串称为 “SessionId”. 但是站在整个登录流程中看待, 也可以把这个唯⼀性字符串称为 “token”.
上述例⼦中的令牌ID, 就可以看做是SessionId, 只不过令牌除了ID之外, 还会带⼀些其他信息, ⽐如时间, 签名等.
1.当⽤⼾登陆的时候, 服务器在 Session 中新增⼀个新记录, 并把 sessionId返回给客⼾端. (通过 HTTP 响应中的 Set-Cookie 字段返回).
2.客⼾端后续再给服务器发送请求的时候, 需要在请求中带上 sessionId. (通过 HTTP 请求中的 Cookie 字段带上).
3.服务器收到请求之后, 根据请求中的 sessionId在 Session 信息中获取到对应的⽤⼾信息, 再进⾏后续操作.找不到则重新创建Session, 并把SessionID返回。
Session 默认是保存在内存中的. 如果重启服务器则 Session 数据就会丢失.
3.3Cookie和Session的区别
Cookie 和 Session 的区别:
- Cookie 是客⼾端保存⽤⼾信息的⼀种机制. Session 是服务器端保存⽤⼾信息的⼀种机制.
- Cookie 和 Session之间主要是通过 SessionId 关联起来的, SessionId 是 Cookie 和 Session 之间的桥梁
- Cookie 和 Session 经常会在⼀起配合使⽤. 但是不是必须配合.
- 完全可以⽤ Cookie 来保存⼀些数据在客⼾端. 这些数据不⼀定是⽤⼾⾝份信息, 也不⼀定是 SessionId
- Session 中的sessionId 也不需要⾮得通过 Cookie/Set-Cookie 传递, ⽐如通过URL传递.
3.4获取Cookie
3.4.1传统获取
@RequestMapping("/c")
public String getC(HttpServletRequest request, HttpServletResponse response){
//获取所有的Cookies
Cookie[] cookies = request.getCookies();
//所有的cookies放进builder
StringBuilder builder = new StringBuilder();
if(cookies!=null){
for(Cookie c:cookies){
builder.append(c.getName()+":"+c.getValue());
}
}
return "Cookie:"+builder.toString();
}
Spring MVC是基于 Servlet API 构建的原始 Web 框架, 也是在Servlet的基础上实现的MVC⽅法的内置对象. 需要时直接在⽅法中添加声明即可.
HttpServletRequest
和HttpServletResponse
是Servlet提供的两个类, 是Spring对象代表客⼾端的请求, 当客⼾端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象提供的⽅法,可以获得客⼾端请求的所有信息.
对象代表服务器的响应. HTTP响应的信息都在这个对象中, ⽐如向客⼾端发送的数据, 响应头, 状态码等. 通过这个对象提供的⽅法, 可以获得服务器响应的所有内容
Spring MVC在这两个对象的基础上进⾏了封装, 给我们提供更加简单的使⽤⽅法.
通过浏览器访问: http://127.0.0.1:8080/path/c ,得到Cookie为null
为什么没有Cookies呢?
我们看一看浏览器有没有传递Cookie
此时没有设置Cookie。
设置⼀下Cookie的值
再次访问: http://127.0.0.1:8080/path/c
可以看到Cookie中出现了我们设置的值
从这个例⼦中, 也可以看出Cookie是可以伪造的, 也就是不安全的, 所以使⽤Cookie时, 后端需要进⾏ Cookie校验
3.4.2简单获取
获取Cookie中的某个值:
@RequestMapping("/c")
public String getC(@CookieValue("test") String testValue){
return "Cookie中的test:"+testValue;
}
设置⼀下Cookie的值
访问: http://127.0.0.1:8080/path/c
3.5Session存储和获取
3.5.1Session存储
Session是服务器端的机制, 我们需要先存储, 才能再获取
Session 也是基于HttpServletRequest 来存储和获取的
Session存储:
@RequestMapping("/setS")
public String sets(HttpServletRequest request){
//获取Session对象
HttpSession session = request.getSession();
if(session!=null){
session.setAttribute("SessionTest","99");
}
return "Session设置成功";
这个代码中看不到 SessionId 这样的概念的. getSession 操作内部提取到请求中的Cookie ⾥的 SessionId, 然后根据SessionId获取到对应的Session 对象, Session 对象⽤HttpSession来描述
运行后访问:127.0.0.1:8080/path/setS
说明Session已经设置成功
上述的获取Session是一种方式,如果没有会话时会创建一个新的会话。
获取Session有两种⽅式
HttpSession getSession(boolean create);//这是源码中的方法
//我们使用
HttpSession session = request.getSession(); //默认是true
HttpSession session = request.getSession(false);
HttpSession getSession(boolean create) : 参数如果为 true, 则当不存在会话时新建会话; 参数如果为 false, 则当不存在会话时返回 null
void setAttribute(String name, Object value): 使⽤指定的名称绑定⼀个对象到该 session 会话
3.5.2传统获取Session
读取 Session 可以使⽤ HttpServletReques:
@RequestMapping("/getSS")
public String getSS(HttpServletRequest request){
//获取Session,没有Session返回空
HttpSession session =request.getSession(false);
//name变量
String name =null;
//检查将要获取的Session
if(session!=null&&session.getAttribute("name")!=null){
name = (String)session.getAttribute("name");
}
return "Session中的name:"+name;
}
Object getAttribute(String name): 返回在该 session 会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null.
运⾏
先设置Session: http://127.0.0.1:8080/path/setS
在获取Session中的name:http://127.0.0.1:8080/path/getSS
3.5.3简单获取Session
方法1:
后端代码:
@RequestMapping("/getSS")
public String getSS(@SessionAttribute(value="name",required=false) String name){
return "session中的name"+name;
}
运⾏
先设置Session: http://127.0.0.1:8080/path/setS
在获取Session中的name:http://127.0.0.1:8080/path/getSS
方法2:
后端代码:
通过Spring MVC内置对象HttpSession 来获取
@RequestMapping("/getSS")
public String getSS(HttpSession session){
String name = (String)session.getAttribute("name");
return "session中的name"+name;
}
注: HttpSession session = request.getSession();Session 不存在的话, 会⾃动进⾏创建
运⾏
在获取Session中的name:http://127.0.0.1:8080/path/getSS
停止运行
先设置Session: http://127.0.0.1:8080/path/setS
在获取Session中的name:http://127.0.0.1:8080/path/getSS
4.获取Header
4.1Header讲解
HTTP Header(HTTP 头部)
在 HTTP 协议中,HTTP 头部是客户端和服务器在发送请求和响应时附加的额外信息,用于传递关于请求或响应的元数据。HTTP 头部由键值对组成,每个键值对之间用冒号分隔,多个头部字段之间用换行符分隔。
分类:
- 通用头部:既可以出现在请求头,也可以出现在响应头中,例如Date(表示消息产生的日期和时间)、Connection(用于控制持久连接)等。
- 请求头部:只出现在请求中,提供关于请求的附加信息,例如User - Agent(标识客户端的类型和版本)、Accept(表示客户端能够处理的内容类型)等。
- 响应头部:只出现在响应中,提供关于响应的附加信息,例如Server(标识服务器的类型和版本)、Location(用于重定向)等。
- 实体头部:用于描述消息体的元数据,例如Content - Type(表示消息体的媒体类型)、Content - Length(表示消息体的长度)等。
4.2传统获取 Header
后端代码:
@RequestMapping("/header")
public String header(HttpServletRequest request){
String userAgent = request.getHeader("User-Agent");
return "User-Agent:"+userAgent;
}
使⽤HttpServletRequest 提供的getHeader⽅法来获取, 参数对应HTTP请求报头的"Key"
运⾏
获取User-Agent:http://127.0.0.1:8080/path/header
4.3 简洁获取
后端代码:
@RequestMapping("/header")
public String getHeader(@RequestHeader("User-Agent") String userAgent){
return "User-Agent:"+ userAgent;
}
@RequestHeader注解的参数值为HTTP请求报头中的"Key"
运⾏
获取User-Agent:http://127.0.0.1:8080/path/header