spring boot补习系列之几种scope详解

 更新时间:2018年07月22日 15:28:09   作者:美码师  
这篇文章主要给大家介绍了关于spring boot补习系列之几种scope的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用spring boot具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

目标

  • 了解HTTP 请求/响应头及常见的属性;
  • 了解如何使用SpringBoot处理头信息 ;
  • 了解如何使用SpringBoot处理Cookie ;
  • 学会如何对 Session 进行读写;
  • 了解如何在不同请求间传递 flash参数

一、Http 头信息

HTTP 头(Header)是一种附加内容,独立于请求内容和响应内容。

HTTP 协议中的大量特性都通过Header信息交互来实现,比如内容编解码、缓存、连接保活等等。

如下面的一个请求响应:

Request

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
Host: www.cnblogs.com
If-Modified-Since: Wed, 18 Jul 2018 13:47:45 GMT
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36

名称 用途
Accept 客户端期望的MIME 类型列表
Accept-Encoding 客户端期望的编解码方式
Accept-Language 客户端期望的语言
Cache-Control 缓存控制
Connection 连接行为(keep-alive)
Host 请求访问的主机
If-Modified-Since 缓存控制
Upgrade-Insecure-Requests 支持安全加密标记
User-Agent 用户代理(客户端标识)

Response

Cache-Control: private, max-age=10
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Wed, 18 Jul 2018 13:47:51 GMT
Expires: Wed, 18 Jul 2018 13:48:01 GMT
Last-Modified: Wed, 18 Jul 2018 13:47:51 GMT
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Frame-Options: SAMEORIGIN
X-UA-Compatible: IE=10

名称 用途
Cache-Control 缓存控制
Connection 连接行为(keep-alive)
Content-Encoding 编解码方式
Content-Type 内容类型(MIME)
Date 当前响应时间
Expires 文档过期时间
Last-Modified 最后一次更新时间
Transfer-Encoding 传输编码方式
Vary 需要刷新的请求Header
X-Frame-Options FRAME展示策略(用于同源控制)
X-UA-Compatible IE兼容属性

更多的** Http Header **可以从这里找到

二、SpringBoot 处理头信息

前面的内容中已经讲过如何完成Controller方法及请求的映射。

在SpringBoot可通过@RequestHeader注解方式

将请求头信息映射到参数,如下面的片段:

 @GetMapping("/some")
 @ResponseBody
 public String someHeader(@RequestHeader(value = "Host") String host,
  @RequestHeader(value = "User-Agent") String userAgent,
  @RequestHeader(value = "Cache-Control", required = false) String cacheControl,
  HttpServletResponse response) {

 logger.info("host:{}", host);
 logger.info("User-Agent:{}", userAgent);
 logger.info("Cache-Control:{}", cacheControl);

 // 设置响应头
 response.setHeader("Cache-Control", "no-cache,no-store,must-revalidate");
 response.setHeader("Pragma", "no-cache");
 response.setDateHeader("Expires", 0);
 return "OK";
 }

而响应头呢,可以通过声明一个HttpServletResponse参数后,

通过该对象进行设置,上面的代码非常容易理解。

如果希望获得全部的请求头,可以使用HttpHeaders对象:

 @GetMapping("/all")
 public ResponseEntity<Map<String, List<String>>> allHeaders(@RequestHeader HttpHeaders headers) {

 Map<String, List<String>> valueMap = new HashMap<String, List<String>>();
 for (String header : headers.keySet()) {
  valueMap.put(header, headers.get(header));
  logger.info("header[{}]={}", header, headers.get(header));
 }

 // 通过ResponseEntity设置响应头
 ResponseEntity<Map<String, List<String>>> entity = ResponseEntity.status(HttpStatus.OK)
  .header("new header", UUID.randomUUID().toString()).body(valueMap);
 return entity;
 }

上面的一段代码中,可以将所有请求头信息全部打印出来。

此外还须注意到,返回响应使用了ResponseEntity对象,这是一个用于直接表示

响应信息头、内容的对象,利用ResponseEntity可以很方便的设置响应头信息。

三、Cookie处理

Cookie一开始服务器用于辨别用户信息而记录在浏览器上的信息。
到目前为止Cookie作为客户端的存储有了非常多的应用场景。

SpringBoot 提供了@CookieValue以支持参数方式注入,如下:

 @GetMapping("/some")
 @ResponseBody
 public String someCookie(@CookieValue(value = "counter", defaultValue = "0") int counter,
  HttpServletResponse response) {

 logger.info("counter:{}", counter);
 counter += 1;

 String newValue = counter + "";

 // 设置Cookie
 response.addCookie(new Cookie("counter", newValue));
 return newValue;
 }

上述代码中,访问/some 可以获得一个counter的cookie值,

且每访问一次则自增一次,这是一个简单的访问计数器功能。

如果希望获取全部的Cookie,可以参考以下代码:

 @GetMapping("/all")
 public ResponseEntity<Map<String, String>>allCookies(HttpServletRequest request, HttpServletResponse response) {

 Map<String, String> valueMap = new HashMap<String, String>();
 for (Cookie cookie : request.getCookies()) {

  valueMap.put(cookie.getName(), cookie.getValue());
  logger.info("cookie[{}]={}", cookie.getName(), cookie.getValue());
 }

 // 设置Cookie
 response.addCookie(new Cookie("key", UUID.randomUUID().toString()));
 return new ResponseEntity<Map<String, String>>(valueMap, HttpStatus.OK);
 }

清理全部Cookie

 @GetMapping("/clear")
 public ResponseEntity<Map<String, String>> clearCookies(HttpServletRequest request, HttpServletResponse response) {

 Map<String, String> valueMap = new HashMap<String, String>();
 for (Cookie cookie : request.getCookies()) {

  valueMap.put(cookie.getName(), cookie.getValue());
  logger.info("cookie[{}]={}", cookie.getName(), cookie.getValue());

  // 清除
  cookie.setMaxAge(0);
  response.addCookie(cookie);
 }

 return new ResponseEntity<Map<String, String>>(valueMap, HttpStatus.OK);
 }

Cookie机制存在一定的缺陷,尽可能在考虑一些风险后使用

安全性无法保证,除非使用HTTPS;

浏览器端只有4KB大小的存储上限;

四、Session处理

Session 指的是会话,是建立于Cookie机制上的一种身份识别方式。

由于Cookie自身的安全性和容量限制,大多数应用中是在Cookie中存放一个唯一凭证;

服务侧通过凭证再进行身份信息的存取,这就是会话的由来。

不同的语言、框架采用的实现方式有些差异,比如JavaEE采用JSESSION_ID,而PHP则是PHPSESSID

Session的交互原理可以参考下面一个图:


Springboot 内嵌了Servlet容器,则是沿用的JSESSION_ID。因此在浏览一些JavaWeb站点时会发现该Cookie。

使用@SessionAttribute可以将会话中的属性映射到方法参数;

如果希望对Session属性进行操作,可以在Controller上声明@SessionAttributes注解以指定想要变更的属性;
之后,通过Model参数进行写入即可(由框架自动检测并修改Session)

@SessionAttributes("seed")
public class SessionController {

 private static final Logger logger = LoggerFactory.getLogger(SessionController.class);
 @GetMapping("/some")
 @ResponseBody
 public String someSession(@SessionAttribute(value = "seed", required = false) Integer seed, Model model) {

  logger.info("seed:{}", seed);
  if (seed == null) {
   seed = (int) (Math.random() * 10000);
  } else {
   seed += 1;
  }
  model.addAttribute("seed", seed);

  return seed + "";
 }

上面的例子与Cookie实现访问计数器的功能是一样的!

如果希望获取全部会话,可以使用HttpSession

 @GetMapping("/all")
 public ResponseEntity<Map<String, Object>> allSessions(HttpSession session) {

  Map<String, Object> valueMap = new HashMap<String, Object>();
  Enumeration<String> iSession = session.getAttributeNames();

  while (iSession.hasMoreElements()) {
   String sessionName = iSession.nextElement();
   Object sessionValue = session.getAttribute(sessionName);

   valueMap.put(sessionName, sessionValue);
   logger.info("sessoin[{}]={}", sessionName, sessionValue);
  }

  // 写入session
  session.setAttribute("timestmap", new Date());
  return new ResponseEntity<Map<String, Object>>(valueMap, HttpStatus.OK);
 }

清除会话

 @GetMapping("/clear")
 public ResponseEntity<Map<String, Object>> clearSessions(HttpSession session) {

  Map<String, Object> valueMap = new HashMap<String, Object>();
  Enumeration<String> iSession = session.getAttributeNames();

  while (iSession.hasMoreElements()) {
   String sessionName = iSession.nextElement();
   Object sessionValue = session.getAttribute(sessionName);

   valueMap.put(sessionName, sessionValue);
   logger.info("sessoin[{}]={}", sessionName, sessionValue);
   
   session.removeAttribute(sessionName);
  }
  
  return new ResponseEntity<Map<String, Object>>(valueMap, HttpStatus.OK);
 }

五、Flash参数传递

Flash的意思是一瞬间,一闪而过的,因此很好理解,这是一类仅用来消费一次的参数,有些类似阅后即焚。
试想这样的场景,你确认完购物车,完成订单支付后进入订单管理界面,而此时界面上提示你"下单成功,请等待发货"。
这便可以通过Flash传参来实现。

Flash的意义是用作请求之间的瞬时参数传递,仅消费一次后便不再用。

以下是一个示例:

 /**
  * 执行跳转,并设置传值
  *
  * @param counter
  * @param response
  * @return
  */
 @GetMapping("/first")
 public String first(final RedirectAttributes redirectAttrs) {

  logger.info("redirect start:{}");

  redirectAttrs.addFlashAttribute("flash", UUID.randomUUID().toString());
  return "redirect:/flash/second";
 }

 /**
  * 获取传值
  * 
  * @param session
  * @param response
  * @return
  */
 @GetMapping("/second")
 @ResponseBody
 public String second(@ModelAttribute("flash") String flash) {

  logger.info("redirect receive {}", flash);
  return flash;
 }

交互原理


Sprintboot中Flash机制也是利用Session实现的,其中FlashMapManager接口实现了Flash参数的管理。

默认的实现是SessionFlashMapManager,可以通过RequestContextUtils获得上下文中的FlashMapManager对象。

RequestContextUtils通过Request Scope(请求上下文)存取对象

这也是一个本文未提及的scope域,Request上下文是利用线程变量实现的,通常用于线程内业务处理的数据交互。

小结

HTTP 头信息是一种附加内容,用于实现HTTP协议中的各种特性,在开始部分介绍了常见的头信息定义。

本文主要介绍了几种常见的HTTP scope信息的存取方法,包括如何对header、cookie进行读取及修改。

springboot 内嵌了Servlet容器,会话处理机制上沿用了JSESSIONID,通过代码示例介绍了会话的处理方法;

Flash参数是一种阅后即焚的数据,其底层实现也用了session的实现方案。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

相关文章

  • 详细解读Druid数据库连接池的使用

    详细解读Druid数据库连接池的使用

    这篇文章主要介绍了Druid数据库连接池的使用,数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个,需要的朋友可以参考下
    2023-03-03
  • Java线程优先级和守护线程原理解析

    Java线程优先级和守护线程原理解析

    这篇文章主要介绍了Java线程优先级和守护线程原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • 关于Java的对象序列化流和反序列化流详细解读

    关于Java的对象序列化流和反序列化流详细解读

    这篇文章主要介绍了关于Java的对象序列化流和反序列化流,对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象,反之,自己序列还可以从文件中读取回来,重构对象,对它进行反序列化,需要的朋友可以参考下
    2023-05-05
  • Spring AOP + 注解实现统一注解功能

    Spring AOP + 注解实现统一注解功能

    本文我们通过Spring AOP和Java的自定义注解来实现日志的插入功能,非常不错,具有一定的参考借鉴价值,需要的朋友一起看看吧
    2018-05-05
  • JAVA入门教学之快速搭建基本的springboot(从spring boot到spring cloud)

    JAVA入门教学之快速搭建基本的springboot(从spring boot到spring cloud)

    本文主要入门者介绍怎么搭建一个基础的springboot环境,本文通过图文并茂的形式给大家介绍从spring boot到spring cloud的完美搭建过程,适用java入门教学,需要的朋友可以参考下
    2021-02-02
  • Java经典排序算法之快速排序代码实例

    Java经典排序算法之快速排序代码实例

    这篇文章主要介绍了Java经典排序算法之快速排序代码实例,快速排序实现的思想是指通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,需要的朋友可以参考下
    2023-10-10
  • 在Mac OS上安装Tomcat服务器的教程

    在Mac OS上安装Tomcat服务器的教程

    这篇文章主要介绍了在Mac OS上安装Tomcat服务器的教程,方便进行工作环境下的Java web开发,需要的朋友可以参考下
    2015-11-11
  • 浅谈常用字符串与集合类转换的工具类

    浅谈常用字符串与集合类转换的工具类

    下面小编就为大家带来一篇浅谈常用字符串与集合类转换的工具类。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-08-08
  • IDEA中使用Typora编辑md文件的方法

    IDEA中使用Typora编辑md文件的方法

    这篇文章主要介绍了IDEA中使用Typora编辑md文件的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • spring-boot 禁用swagger的方法

    spring-boot 禁用swagger的方法

    本篇文章主要介绍了spring-boot 禁用swagger的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02

最新评论