一,请求
10,获取Cookie/Session
Cookie
HTTP协议自身是属于"无状态"协议.
"无状态"的含义指的是:
默认情况下HTTP协议的客户端和服务器之间的这次通信,和下次通信之间没有直接的联系
但是实际开发的过程中,很多时候是需要直到请求和请求之间的关联关系的
例如登陆网站成功的时候,第二次访问的时候服务器就能知道该请求是否已经登录过了
比如去医院挂号
-
看病之前先挂号,挂号时候需要提供身份证号,同时得到了⼀张"就诊卡",这个就诊卡就相当于患者的"令牌".
-
后续去各个科室进行检查,诊断,开药等操作,都不必再出示身份证了,只要凭就诊卡即可识别出当前患者的⾝份.
-
看完病了之后,不想要就诊卡了,就可以注销这个卡.此时患者的⾝份和就诊卡的关联就销毁了.(类 似于网站的注销操作)
-
又来看病,可以办⼀张新的就诊卡,此时就得到了⼀个新的"令牌"
"令牌"通常就存储在Cookie字段中
在服务器这边就需要记录"令牌"信息,以及令牌对应的用户信息,这个就是Session机制所做的工作
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返回
Session 默认是保存在内存中的.如果重启服务器则Session数据就会丢失
Cookie 和Session的区别
• Cookie是客户端保存用户信息的⼀种机制,Session是服务器端保存用户信息的⼀种机制.
• Cookie和Session之间主要是通过SessionId关联起来的,SessionId是Cookie和Session之间的桥梁
• Cookie和Session经常会在⼀起配合使用,但是不是必须配合.
完全可以用Cookie来保存⼀些数据在客户端,这些数据不⼀定是⽤⼾⾝份信息,也不⼀定是 SessionId
Session中的sessionId也不需要非得通过Cookie/Set-Cookie传递,比如通过URL传递
获取Cookie
传统获取Cookie
javascript
@RequestMapping("/request2")
@RestController
public class Request2 {
@RequestMapping("/getCookie")
//HttpServletRequest可以理解为HTTP请求里面有什么,这个对象里面就有什么,比如Cookie,参数,header
//HttpServletResponse可以理解为HTTP响应里面有什么,或者说可以返回什么,这个对象就可以设置成什么,比如:
//content-type,header,正文,状态码等等
public String getCookie(HttpServletRequest request){
Cookie[] cookies = request.getCookies();
if(cookies != null){
for(Cookie cookie:cookies){
System.out.println(cookie.getName() + ":" + cookie.getValue());
}
}
return "获取cookie成功";
}
}
其中,cookie存储在客户端中,可以伪造。
session存储在服务器中,不可以伪造


Spring MVC是基于ServletAPI构建的原始Web框架,也是在Servlet的基础上实现的 HttpServletRequest , HttpServletResponse 是Servlet提供的两个类,是Spring MVC⽅法的内置对象.需要时直接在⽅法中添加声明即可.
HttpServletRequest 对象代表客⼾端的请求,当客⼾端通过HTTP协议访问服务器时,HTTP请 求头中的所有信息都封装在这个对象中,通过这个对象提供的⽅法,可以获得客⼾端请求的所有信息.
HttpServletResponse 对象代表服务器的响应.HTTP响应的信息都在这个对象中,⽐如向客⼾ 端发送的数据,响应头,状态码等.通过这个对象提供的⽅法,可以获得服务器响应的所有内容
Spring MVC在这两个对象的基础上进⾏了封装,给我们提供更加简单的使⽤⽅法.
简洁获取Cookie
javascript
@RequestMapping("/getCookie2")
public String getCookie2(@CookieValue("test") String test){
return "获取Cookie成功,test:"+test;
}
获取Session
Session 存储和获取
Session是服务器端的机制,我们需要先存储,才能再获取
Session 也是基于HttpServletRequest来存储和获取
Session存储
javascript
@RequestMapping("/setSession")
public String setSession(HttpServletRequest request){
HttpSession session = request.getSession(true);
session.setAttribute("name","zhangsan");
return "设置session成功";
}
这个代码中看不到SessionId这样的概念的,getSession操作内部提取到请求中的Cookie里的 SessionId,,然后根据SessionId获取到对应的Session对象,Session对象用HttpSession来描述
获取Session有两种方式:
1,HttpSession getSession(boolean create);
2,HttpSession getSession();
第一种,参数如果为true,则当不存在会话时新建会话;参数如果为false,则当不存在会话时返回null
第二种,和getSession(true) 含义⼀样, 默认值为true.
void setAttribute(String name, Object value): 使用指定的名称绑定⼀个对象到该session会话
Session读取
javascript
@RequestMapping("/getSession")
public String getSession(HttpServletRequest request){
HttpSession session = request.getSession(true);
String name = (String)session.getAttribute("name");
return "获取session成功,name:"+name;
}
还有第二种获取session的方式如下:
javascript
@RequestMapping("/getSession2")
public String getSession2(HttpSession session){
String name = (String)session.getAttribute("name");
return "获取session成功,name:"+name;
}
第三种:
javascript
@RequestMapping("/getSession3")
public String getSession3(@SessionAttribute("name") String name){
return "获取session成功,name:" + name;
}
11,获取Header
javascript
@RequestMapping("getHeader")
public String getHeader(HttpServletRequest request){
String userAgent = request.getHeader("user-Agent");
return "获取header成功,userAgent:"+userAgent;
}
javascript
@RequestMapping("getHeader2")
public String getHeader2(@RequestHeader("user-Agent") String userAgent){
return "获取header成功,userAgent:"+userAgent;
}
二,响应
Http响应结果可以是数据,也可以是静态⻚⾯,也可 以针对响应设置状态码,Header信息等
2.1 返回静态页面
javascript
@RestController
@RequestMapping("/return")
public class ReturnController {
@RequestMapping("/re1")
public String re1(){
return "/test.html";
}
}
结果却发现,页面未正确返回,http响应把 "/test.html" 当做了http响应正文的数据那SpringMVC如何才能识别出来 test.html 是⼀个静态页面,并进行返回呢? 我们需要把@RestController 改为 @Controller
Q:@RestController 和 @Controller 有着什么样的关联和区别呢?

前三个注解为元注解,即可以加在其他注解上的注解

通过上述图片可知,@RestController = @Controller + @ResponseBody
@Controller : 定义⼀个控制器,Spring框架启动时加载,把这个对象交给Spring管理
@ResponseBody: 定义返回的数据格式为非视图,返回⼀个text/html信息
这个注解既是类注解,又是方法注解
如果加在类上,表示该类的所有方法,都返回数据
如果加在方法上,表示该方法返回数据
也就是说:在类上添加 @ResponseBody 就相当于在所有的⽅法上添加了@ResponseBody 注解,同样,如果类上有@RestController 注解时:表⽰所有的⽅法上添加了 @ResponseBody 注 解,也就是当前类下所有的⽅法返回值做为响应数据
如果⼀个类的⽅法⾥,既有返回数据的,⼜有返回⻚⾯的,就把@ResponseBody注解添加到对应的方法上就行
Target代表可以加在什么类型上,通过上述图片可以得知Controller和RestController只可以加在类上
随着互联⽹的发展,⽬前项⽬开发流⾏"前后端分离"模式, Java主要是⽤来做后端项⽬的开发,所以也就 不再处理前端相关的内容了 MVC的概念也逐渐发⽣了变化,View不再返回视图,⽽是返回显⽰视图时需要的数据
2.2 返回HTML代码片段
javascript
@ResponseBody
@RequestMapping("/re3")
public String re3(){
return "<h1>你好</h1>";
}
后端返回数据时,如果数据中有HTML代码,也会被浏览器解析
响应中的Content-Type常⻅取值有以下⼏种:
• text/html :body数据格式是HTML
• text/css :body数据格式是CSS
• application/javascript :body数据格式是JavaScript
• application/json :body数据格式是JSON
javascript
@RequestMapping("/index3")
public Object index3(){
return "/b.css";
}
javascript
@RequestMapping("/index2")
public Object index2(){
return "/a.js";
}
2.3 返回JSON
Spring MVC也可以返回JSON 后端⽅法返回结果为对象
javascript
@ResponseBody
@RequestMapping("/re4")
public Person re4(){
Person person = new Person();
person.setId(12);
person.setAge(18);
person.setName("zhangsan");
person.setAddress("beijing");
return person;
}
@RequestMapping("/returnJson")
@ResponseBody
public HashMap<String, String> returnJson() {
HashMap<String, String> map = new HashMap<>();
map.put("Java", "Java Value");
map.put("MySQL", "MySQL Value");
map.put("Redis", "Redis Value");
return map;
}
2.4 设置状态码
Spring MVC会根据我们⽅法的返回结果⾃动设置响应状态码,程序员也可以⼿动指定状态码
通过SpringMVC的内置对象HttpServletResponse提供的⽅法来进⾏设置
2.5 设置Header
Http响应报头也会向客⼾端传递⼀些附加信息,⽐如服务程序的名称,请求的资源已移动到新地址等,如: Content-Type, Local等.
这些信息通过 @RequestMapping 注解的属性来实现
@RequestMapping的源码如下:
javascript
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
@Reflective({ControllerMappingReflectiveProcessor.class})
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
String version() default "";
}
-
value: 指定映射的URL
-
method:指定请求的method类型,如GET,POST等
-
consumes:指定处理请求(request)的提交内容类型(Content-Type),例如application/json, text/html;
-
produces: 指定返回的内容类型,还可以同时设置返回值的字符编码
-
Params:指定request中必须包含某些参数值时,才让该方法处理
-
headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求
2.6 设置Content-Type
通过设置produces属性的值,设置响应的报头Content-Type
2.7 设置其他Header
设置其他Header的话,需要使用SpringMVC的内置对象HttpServletResponse提供的⽅法来进⾏设置
javascript
@ResponseBody
@RequestMapping(value = "/re6")
public String re6(HttpServletResponse response){
response.setHeader("Header","HeaderValue");
return "sucess";
}