好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

目标

了解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注解方式

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

@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对象:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

@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作为客户端的存储有了非常多的应用场景。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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,可以参考以下代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

@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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

@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)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@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);

}

清除会话

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@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的意义是用作请求之间的瞬时参数传递,仅消费一次后便不再用。

以下是一个示例:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

/**

  * 执行跳转,并设置传值

  *

  * @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的实现方案。

总结

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

原文链接:https://www.cnblogs.com/littleatp/p/9345801.html

查看更多关于spring boot补习系列之几种scope详解的详细内容...

  阅读:41次