Cookie和Session简介。 Spring MVC的 2.请求 Cookie的设置和两种获取方式 Session的设置和三种获取方式。 3.响应 1.返回静态页面 2.返回数据 3.返回HTML片段 4.返回JSON 5.设置状态码 6.设置header
我们知道HTTP协议自身是“无状态”协议。
"无状态" 的含义指的是:
默认情况下 HTTP 协议的客⼾端和服务器之间的这次通信和下次通信之间没有直接的联系.
实际开发中,我们很多时候需要知道请求之间的关联关系。
例如登陆网站成功后,第二次访问的时候服务器就能知道该请求是否是已经登陆过了.
当用户输入用户名和密码点击登录后,服务器响应,这时候登陆成功后,服务器会给用户一个“令牌”,这样下次用户再访问,就会带上“令牌”。服务器就知道这个用户已经登陆过了。 "令牌" 通常就存储在 Cookie 字段中.
此时在服务器这边就需要记录"令牌"信息,以及令牌对应的用户信息,这个就是 Session 机制所做的工作.
此时在服务器这边就需要记录"令牌"信息,以及令牌对应的用户信息,这个就是 Session 机制所做的工作.
Session就是会话的意思,比如10个浏览器请求同一个服务器(同样的进程)。那么就会产生10个会话。这10个会话,服务器会通过Session来分辨出会话是哪个浏览器请求的。
服务器同⼀时刻收到的请求是很多的.服务器需要清楚的区分每个请求是从属于哪个用户,也就是属于哪个会话,就需要在服务器这边记录每个会话以及与用户的信息的对应关系. Session是服务器为了保存用户信息而创建的⼀个特殊的对象.
Session的本质就是⼀个 "哈希表",存储了⼀些键值对结构.Key就是SessionID,Value就是用户信息(用户信息可以根据需求灵活设计)。
SessionID就是由服务器生成的,“唯一性”字符。从Session机制角度看来,这个唯一性字符就是SessionID。如果站在登录流程中看待,也可以把这个唯一性字符称作“token”。
3.Cookie 和 Session之间的关系。(举例)
举一个生活中的例子,新生入学,学校会收录学生信息存储在教务系统,并为每一个学生设定学号 存储学生信息示例如下: 001 张三 18 计科1班 002 李四 19 计科1班 003 王五 18 计科1班 这里的信息就相当于Session
而学校存储信息之后,会给学生发学生证。 出入校园,使用学生证来证明学生身份。 这里的学生证就相当于Cookie 注意: 学生证(Cookie):是可以造假。 教务系统信息(Session):一定是真的
@RestController
@RequestMapping("/request")
public class RequestController {
/**
* 传统方法获取Cookie
* 每个方法都内置了HttpServletRequest request/HttpServletResponse response对象
* @param request
* @param response
* @return
*/
@RequestMapping("/getCookie")
public String getCookie(HttpServletRequest request, HttpServletResponse response){
Cookie[] cookies = request.getCookies();//通过这种方式可以获取Cookie
//我们使用lambda表达式的方式来打印Cookie。这种写法可以先了解一下。
// Arrays.stream(cookies).forEach(x->{
// System.out.println(x.getName() + ":" + x.getValue());
// });
//等价于使用foreach循环来打印Cookie
for (Cookie c: cookies){
System.out.println(c.getName()+":"+c.getValue());
}
return "获取Cookie成功!!!";
}
}
注意,如果Cookie为空,会报异常。因此写法如下。
@RequestMapping("/getCookie")
public String getCookie(HttpServletRequest request, HttpServletResponse response){
Cookie[] cookies = request.getCookies();//通过这种方式可以获取Cookie
//使用foreach循环来打印Cookie
if(cookies != null){
for (Cookie c: cookies){
System.out.println(c.getName()+":"+c.getValue());
}
return "获取Cookie成功!!!";
}
return "Cookie为空!";
}
运行结果
当我们添加Cookie之后,刷新一下
Cookie也被打印在控制台上。从这里也可以看出,Cookie是可以造假,除了通过浏览器造假,通过Postman也是可以造假的。
我们使用postman添加几个Cookie,当我们使用传统方式打印Cookie
我们得到了所有的Cookie。但是当我们用SpringBoot方式打印。我们只能通过注解 @CookieValue来或者指定key值的cookie。
@RequestMapping("getCookie2")
public String getCookie2(@CookieValue("yang")String yang){
return "yang:"+yang;
}
因此使用这两种方法取决于你想要获取 全部Cookie还是 只获得某些Cookie
@RequestMapping("setSession")
public String setSession(HttpServletRequest request){
HttpSession session = request.getSession();
session.setAttribute("student","zzx");
return "设置Session成功!";
}
@RequestMapping("getSession")
public String getSession(HttpServletRequest request){
HttpSession session = request.getSession();
//默认值为ture,如果Session为null,就创建一个空的Session
String student = (String) session.getAttribute("student");
return "登录用户:"+student;
}
@RequestMapping("getSession2")
public String getSession(HttpSession session){
String student = (String) session.getAttribute("student");
return "登录用户:"+student;
}
@RequestMapping("getSession3")
public String getSession(@SessionAttribute("student")String student){
return "登录用户:"+student;
}
虽然这样写如下代码非常的简短,但是也有一个问题就是如果直接getSession。会报错
没有找到student这个类型。这是因为加了注解之后,这个参数就变成了必传参数,因此不能为空。 如何修改呢,如下: @SessionAttribute(value = "student",required = false)
@RequestMapping("getSession3")
public String getSession(@SessionAttribute(value = "student",required = false)String student){
return "登录用户:"+student;
}
此时就不报错了。
我们请求打印Header。中的 User-Agent 的信息。 它表示用的哪个客户端去请求的。
@RequestMapping("/getHeader")
public String getHeader(HttpServletRequest request){
String userAgent = request.getHeader("User-Agent");
return "userAgent:"+userAgent;
}
@RequestMapping("/getHeader2")
public String getHeader2(@RequestHeader("User-Agent")String userAgent){
return "userAgent:"+userAgent;
}
上图:当我们使用Postman请求。
上图:当我们使用浏览器请求。
我们只想获取Header信息中的其中的一个,使用SpringBoot方式很方便。 当我们想要获取多个内容,使用SpringBoot方式就需要写很多参数。 因此我们可以使用传统方式更加方便的获取。
1.返回静态页面 2.返回数据 3.返回HTML片段 4.返回JSON 5.设置响应头(状态码,编码或者其他header)
我们可以
执⾏了业务逻辑之后,要把程序执⾏的结果返回给⽤⼾,也就是响应.
首先要有一个静态页面, 创建前端页面index.html(注意路径)。 如果要访问的目录在静态目录static下面,还有其他目录,那么路径url中需要带上这个目录
@Controller
@RequestMapping("/return")
public class ReturnController {
@RequestMapping("/r1")
public String r1(){
return "/index.html";
}
}
注意: 1.在SpringBoot中。@RequestMapping中的/是可以被省略的。而return中的/不能省略。 2.当我们想要访问静态页面时,我们需要把原先 @RestController注解改为@Controller
想要返回数据使用:@RestController 想要返回页面使用:@Controller @RestController = @ResponseBody + @Controller @Controller:告诉Spring帮我们管理哪些程序,默认返回的是页面 @ResponseBody:表示返回数据
我们看看注解@RestController的源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(
annotation = Controller.class
)
String value() default "";
}
注解解释 @Target:表示注解的使用范围如上:ElementType.TYPE 表示注解只能修饰类 @Retention:表示注解的生命周期
我们看看注解@Controller的源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
源码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
}
表示返回数据。响应正文里面的内容。
这里区别@RequestBody:是请求正文里面的内容。接收JSON的时候我们经常用到。
它既可以修饰类,也可以修饰方法。
修饰类:表示该类所有的方法,返回的都是数据
修饰方法:表示该方法的返回都是数据。
示例:
@ResponseBody
@RequestMapping("/r2")
public String r2(){
return "hello ,SpringMVC,我是返回的数据";
}
@ResponseBody
@RequestMapping("/r3")
public String r3(){
return "<h1>hello ,SpringMVC,我是HTML片段</h1>";
}
注意这里文本类型是html。
content-Type:text/html
无论返回的是页面,还是数据。content-Type类型都是html
如果让它返回JSON呢?请往下看。
get可以被缓存,get是幂等的。不管什么时候请求,得到响应是一样的。 post不可以被缓存。
JSON通常也是表示对象,我们返回一个对象试试。
@ResponseBody
@RequestMapping("/r4")
public UserInfo r4(){
UserInfo userInfo = new UserInfo();
userInfo.setName("zzx");
userInfo.setId(9);
userInfo.setAge(18);
return userInfo;
}
如上如,我们返回对象成功返回了JSON类型的文本。 content-Type:application/json
@ResponseBody
@RequestMapping("/r5")
public Map<String,String> r5(){
HashMap map = new HashMap<>();
map.put("k1","v1");
map.put("k2","v3");
map.put("k3","v3");
return map;
}
content-Type:application/json 如上如,使用Map也成功返回了JSON类型的文本。
@RequestMapping("/r6")
public String r6(){
return "/a.js";
}
content-Type:application/javascript 成功返回了页面a.js
@RequestMapping("/r7")
public String r7(){
return "/b.css";
}
content-Type:text/css 成功返回了页面b.css
总结: 在SpringBoot中, content-Type 不需要我们自己设置。 会自动根据我们的返回的结果自行设置。
状态码的设置不影响页面的展示。 错误显示可以自定义的图。也有很多公共的页面格式。
@ResponseBody
@RequestMapping("/r8")
public String r8(HttpServletResponse response){
response.setStatus(401);
return "设置状态成功!";
}
Http响应报头也会向客户端传递⼀些附加信息,
比如服务程序的名称,请求的资源已移动到新地址等
如:Content-Type、Local等.
这些信息通过@RequestMapping注解的属性来实现
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
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 {};
}
简单了解一下它的属性:(了解就好,不用记) 1.value:指定映射的URL 下面这些属性更多的是对请求的限制 2.method:指定请求的method类型,如GET,POST等 3.consumes:指定处理请求(request)的提交内容类型(Content-Type),例如application/json、text/html; 4.produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回 5.Params:指定request中必须包含某些参数值时,才让该方法处理 6.headers:指定request中必须包含某些指定的header值,才能让该方法处理请求
我们前面了解到,在Spring中,content-Type:的类型不需要我们自己设置,不过在工作中可能有时候还需要我们设置。 而且有些 Header 是自定义的。 什么都没写的时候,我们发现只有
这样的如 Content-Type: Content-Length: Data: Keep-Alive: Connection: 但是我们访问其他网站,就会发现会有许多。有些就是他们自定义的。
SpringBoot给我们默认的是 text/html 类型。要想我们自定义,我们就要用到
@RequestMapping的produce属性。下面是我们给它设置成json的代码:
@ResponseBody
@RequestMapping(value = "/r9",produces = "application/json")
public String r9(){
return "自定义Header中的Content-Type成功!";
}
那么我们返回的本身就不是json,如果不自定义,那么就是text/html 什么时候会使用这种情况呢? 比如当我们返回{"ok":1}这串数据,是json格式,但是Spring这里默认还是html。这样就可以会对前端造成一定的影响。不过现在前端框架也更新了,可以自动识别为json 通过这样我们也可以在后面写 @RequestMapping(value = "/r9",produces = "application/json;charset = utf-8") 因此也可以同步的设置编码。
@ResponseBody
@RequestMapping(value = "/r10")
public String r10(HttpServletResponse response){
response.setHeader("myHeader","myHeaderValue");
return "自定义Header成功!";
}
这就多了一个 myHeader:myHeaderValue
对于SpringMVC来说,掌握了以上3个功能(建立链接+请求+响应)就相当于掌握了SpringMVC.