<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringSession實戰(zhàn)項目(基于SpringBoot項目)【附源碼】

          共 9874字,需瀏覽 20分鐘

           ·

          2020-11-21 02:09


          送書:
          《Java深度調(diào)試技術(shù)》
          《機(jī)器學(xué)習(xí)與深度學(xué)習(xí)算法基礎(chǔ)》
          《Python機(jī)器學(xué)習(xí)一本通》

          spring-boot 整合 spring-session 的自動配置可謂是開箱即用,極其簡潔和方便。這篇文章即介紹 spring-boot 整合 spring-session,這里只介紹基于 RedisSession 的實戰(zhàn)。

          考慮到 RedisSession 模塊與 spring-session v2.0.6 版本的差異很小,且能夠與 spring-boot v2.0.0 兼容,所以實戰(zhàn)篇是基于 spring-boot v2.0.0 基礎(chǔ)上配置 spring-session。

          配置 spring-session

          引入 spring-session 的 pom 配置,由于 spring-boot 包含 spring-session 的 starter 模塊,所以 pom 中依賴:


          ?org.springframework.session
          ?spring-session-data-redis


          編寫 spring boot 啟動類 SessionExampleApplication

          /**
          ?*?啟動類
          ?*
          ?*?@author?huaijin
          ?*/
          @SpringBootApplication
          public?class?SessionExampleApplication?{

          ????public?static?void?main(String[]?args)?{
          ????????SpringApplication.run(SessionExampleApplication.class,?args);
          ????}
          }

          配置 application.yml

          spring:
          ??session:
          ????redis:
          ??????flush-mode:?on_save
          ??????namespace:?session.example
          ??????cleanup-cron:?0?*?*?*?*?*
          ????store-type:?redis
          ????timeout:?1800
          ??redis:
          ????host:?localhost
          ????port:?6379
          ????jedis:
          ??????pool:
          ????????max-active:?100
          ????????max-wait:?10
          ????????max-idle:?10
          ????????min-idle:?10
          ????database:?0

          編寫 controller

          編寫登錄控制器,登錄時創(chuàng)建 session,并將當(dāng)前登錄用戶存儲 sesion 中。登出時,使 session 失效。

          /**
          ?*?登錄控制器
          ?*
          ?*?@author?huaijin
          ?*/
          @RestController
          public?class?LoginController?{

          ????private?static?final?String?CURRENT_USER?=?"currentUser";

          ????/**
          ?????*?登錄
          ?????*
          ?????*?@param?loginVo?登錄信息
          ?????*
          ?????*?@author?huaijin
          ?????*/
          ????@PostMapping("/login.do")
          ????public?String?login(@RequestBody?LoginVo?loginVo,?HttpServletRequest?request)?{
          ????????UserVo?userVo?=?UserVo.builder().userName(loginVo.getUserName())
          ????????????????.userPassword(loginVo.getUserPassword()).build();
          ????????HttpSession?session?=?request.getSession();
          ????????session.setAttribute(CURRENT_USER,?userVo);
          ????????System.out.println("create?session,?sessionId?is:"?+?session.getId());
          ????????return?"ok";
          ????}

          ????/**
          ?????*?登出
          ?????*
          ?????*?@author?huaijin
          ?????*/
          ????@PostMapping("/logout.do")
          ????public?String?logout(HttpServletRequest?request)?{
          ????????HttpSession?session?=?request.getSession(false);
          ????????session.invalidate();
          ????????return?"ok";
          ????}
          }

          編寫查詢控制器,在登錄創(chuàng)建 session 后,使用將 sessionId 置于 cookie 中訪問。如果沒有 session 將返回錯誤。

          /**
          ?*?查詢
          ?*
          ?*?@author?huaijin
          ?*/
          @RestController
          @RequestMapping("/session")
          public?class?QuerySessionController?{

          ????@GetMapping("/query.do")
          ????public?String?querySessionId(HttpServletRequest?request)?{
          ????????HttpSession?session?=?request.getSession(false);
          ????????if?(session?==?null)?{
          ????????????return?"error";
          ????????}
          ????????System.out.println("current's?user?is:"?+?session.getId()?+??"in?session");
          ????????return?"ok";
          ????}
          }

          編寫 Session 刪除事件監(jiān)聽器

          Session 刪除事件監(jiān)聽器用于監(jiān)聽登出時使 session 失效的事件源。

          /**
          ?*?session事件監(jiān)聽器
          ?*
          ?*?@author?huaijin
          ?*/
          @Component
          public?class?SessionEventListener?implements?ApplicationListener?{

          ????private?static?final?String?CURRENT_USER?=?"currentUser";

          ????@Override
          ????public?void?onApplicationEvent(SessionDeletedEvent?event)?{
          ????????Session?session?=?event.getSession();
          ????????UserVo?userVo?=?session.getAttribute(CURRENT_USER);
          ????????System.out.println("invalid?session's?user:"?+?userVo.toString());
          ????}
          }

          驗證測試

          編寫 spring-boot 測試類,測試 controller,驗證 spring-session 是否生效。


          /**
          ?*?測試Spring-Session:
          ?*?1.登錄時創(chuàng)建session
          ?*?2.使用sessionId能正常訪問
          ?*?3.session過期銷毀,能夠監(jiān)聽銷毀事件
          ?*
          ?*?@author?huaijin
          ?*/
          @RunWith(SpringRunner.class)
          @SpringBootTest
          @AutoConfigureMockMvc
          public?class?SpringSessionTest?{

          ????@Autowired
          ????private?MockMvc?mockMvc;

          ????@Test
          ????public?void?testLogin()?throws?Exception?{
          ????????LoginVo?loginVo?=?new?LoginVo();
          ????????loginVo.setUserName("admin");
          ????????loginVo.setUserPassword("admin@123");
          ????????String?content?=?JSON.toJSONString(loginVo);

          ????????//?mock登錄
          ????????ResultActions?actions?=?this.mockMvc.perform(post("/login.do")
          ????????????????.content(content).contentType(MediaType.APPLICATION_JSON))
          ????????????????.andExpect(status().isOk()).andExpect(content().string("ok"));
          ????????String?sessionId?=?actions.andReturn()
          ????????????????.getResponse().getCookie("SESSION").getValue();

          ????????//?使用登錄的sessionId?mock查詢
          ????????this.mockMvc.perform(get("/session/query.do")
          ????????????????.cookie(new?Cookie("SESSION",?sessionId)))
          ????????????????.andExpect(status().isOk()).andExpect(content().string("ok"));

          ????????//?mock登出
          ????????this.mockMvc.perform(post("/logout.do")
          ????????????????.cookie(new?Cookie("SESSION",?sessionId)))
          ????????????????.andExpect(status().isOk()).andExpect(content().string("ok"));
          ????}
          }

          測試類執(zhí)行結(jié)果:

          create?session,?sessionId?is:429cb0d3-698a-475a-b3f1-09422acf2e9c
          current's?user?is:429cb0d3-698a-475a-b3f1-09422acf2e9cin?session
          invalid?session'
          s?user:UserVo{userName='admin',?userPassword='admin@123'

          登錄時創(chuàng)建 Session,存儲當(dāng)前登錄用戶。然后在以登錄響應(yīng)返回的 SessionId 查詢用戶。最后再登出使 Session 過期。

          spring-boot 整合 spring-session 自動配置原理

          前兩篇文章介紹 spring-session 原理時,總結(jié) spring-session 的核心模塊。這節(jié)中探索 spring-boot 中自動配置如何初始化 spring-session 的各個核心模塊。

          spring-boot-autoconfigure 模塊中包含了 spinrg-session 的自動配置。包 org.springframework.boot.autoconfigure.session 中包含了 spring-session 的所有自動配置項。

          其中 RedisSession 的核心配置項是 RedisHttpSessionConfiguration 類。

          @Configuration
          @ConditionalOnClass({?RedisTemplate.class,?RedisOperationsSessionRepository.class?})
          @ConditionalOnMissingBean(SessionRepository.class)
          @ConditionalOnBean(RedisConnectionFactory.class)
          @Conditional(ServletSessionCondition.class)
          @EnableConfigurationProperties(RedisSessionProperties.class)
          class?RedisSessionConfiguration?{

          ?@Configuration
          ?public?static?class?SpringBootRedisHttpSessionConfiguration
          ???extends?RedisHttpSessionConfiguration?{

          ??//?加載application.yml或者application.properties中自定義的配置項:
          ??//?命名空間:用于作為session redis key的一部分
          ??// flushmode:session寫入redis的模式
          ??//?定時任務(wù)時間:即訪問redis過期鍵的定時任務(wù)的cron表達(dá)式
          ??@Autowired
          ??public?void?customize(SessionProperties?sessionProperties,
          ????RedisSessionProperties?redisSessionProperties)?{
          ???Duration?timeout?=?sessionProperties.getTimeout();
          ???if?(timeout?!=?null)?{
          ????setMaxInactiveIntervalInSeconds((int)?timeout.getSeconds());
          ???}
          ???setRedisNamespace(redisSessionProperties.getNamespace());
          ???setRedisFlushMode(redisSessionProperties.getFlushMode());
          ???setCleanupCron(redisSessionProperties.getCleanupCron());
          ??}

          ?}

          }

          RedisSessionConfiguration 配置類中嵌套 SpringBootRedisHttpSessionConfiguration 繼承了 RedisHttpSessionConfiguration 配置類。首先看下該配置類持有的成員。

          @Configuration
          @EnableScheduling
          public?class?RedisHttpSessionConfiguration?extends?SpringHttpSessionConfiguration
          ??implements?BeanClassLoaderAware,?EmbeddedValueResolverAware,?ImportAware,
          ??SchedulingConfigurer?{

          ?//?默認(rèn)的cron表達(dá)式,application.yml可以自定義配置
          ?static?final?String?DEFAULT_CLEANUP_CRON?=?"0?*?*?*?*?*";

          ?//?session的有效最大時間間隔,?application.yml可以自定義配置
          ?private?Integer?maxInactiveIntervalInSeconds?=?MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;

          ?//?session在redis中的命名空間,主要為了區(qū)分session,application.yml可以自定義配置
          ?private?String?redisNamespace?=?RedisOperationsSessionRepository.DEFAULT_NAMESPACE;

          ?//?session寫入Redis的模式,application.yml可以自定義配置
          ?private?RedisFlushMode?redisFlushMode?=?RedisFlushMode.ON_SAVE;

          ?//?訪問過期Session集合的定時任務(wù)的定時時間,默認(rèn)是每整分運(yùn)行任務(wù)
          ?private?String?cleanupCron?=?DEFAULT_CLEANUP_CRON;

          ?private?ConfigureRedisAction?configureRedisAction?=?new?ConfigureNotifyKeyspaceEventsAction();

          ?//?spring-data-redis的redis連接工廠
          ?private?RedisConnectionFactory?redisConnectionFactory;

          ?//?spring-data-redis的RedisSerializer,用于序列化session中存儲的attributes
          ?private?RedisSerializer?defaultRedisSerializer;

          ?//?session時間發(fā)布者,默認(rèn)注入的是AppliationContext實例
          ?private?ApplicationEventPublisher?applicationEventPublisher;

          ?//?訪問過期session鍵的定時任務(wù)的調(diào)度器
          ?private?Executor?redisTaskExecutor;

          ?private?Executor?redisSubscriptionExecutor;

          ?private?ClassLoader?classLoader;

          ?private?StringValueResolver?embeddedValueResolver;
          }

          該配置類中初始化了 RedisSession 的最為核心模塊之一 RedisOperationsSessionRepository。

          @Bean
          public?RedisOperationsSessionRepository?sessionRepository()?{
          ?//?創(chuàng)建RedisOperationsSessionRepository
          ?RedisTemplate?redisTemplate?=?createRedisTemplate();
          ?RedisOperationsSessionRepository?sessionRepository?=?new?RedisOperationsSessionRepository(
          ???redisTemplate);
          ?//?設(shè)置Session Event發(fā)布者。如果對此迷惑,傳送門:https://www.cnblogs.com/lxyit/p/9719542.html
          ?sessionRepository.setApplicationEventPublisher(this.applicationEventPublisher);
          ?if?(this.defaultRedisSerializer?!=?null)?{
          ??sessionRepository.setDefaultSerializer(this.defaultRedisSerializer);
          ?}
          ?//?設(shè)置默認(rèn)的Session最大有效期間隔
          ?sessionRepository
          ???.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
          ?//?設(shè)置命名空間
          ?if?(StringUtils.hasText(this.redisNamespace))?{
          ??sessionRepository.setRedisKeyNamespace(this.redisNamespace);
          ?}
          ?//?設(shè)置寫redis的模式
          ?sessionRepository.setRedisFlushMode(this.redisFlushMode);
          ?return?sessionRepository;
          }

          同時也初始化了 Session 事件監(jiān)聽器 MessageListener 模塊

          @Bean
          public?RedisMessageListenerContainer?redisMessageListenerContainer()?{
          ?//?創(chuàng)建MessageListener容器,這屬于spring-data-redis范疇,略過
          ?RedisMessageListenerContainer?container?=?new?RedisMessageListenerContainer();
          ?container.setConnectionFactory(this.redisConnectionFactory);
          ?if?(this.redisTaskExecutor?!=?null)?{
          ??container.setTaskExecutor(this.redisTaskExecutor);
          ?}
          ?if?(this.redisSubscriptionExecutor?!=?null)?{
          ??container.setSubscriptionExecutor(this.redisSubscriptionExecutor);
          ?}
          ?//?模式訂閱redis的__keyevent@*:expired和__keyevent@*:del通道,
          ?//?獲取redis的鍵過期和刪除事件通知
          ?container.addMessageListener(sessionRepository(),
          ???Arrays.asList(new?PatternTopic("__keyevent@*:del"),
          ?????new?PatternTopic("__keyevent@*:expired")));
          ?//?模式訂閱redis的${namespace}:event:created:*通道,當(dāng)該向該通道發(fā)布消息,
          ?//?則MessageListener消費消息并處理
          ?container.addMessageListener(sessionRepository(),
          ???Collections.singletonList(new?PatternTopic(
          ?????sessionRepository().getSessionCreatedChannelPrefix()?+?"*")));
          ?return?container;
          }

          上篇文章中介紹到的 spring-session event 事件原理,spring-session 在啟動時監(jiān)聽 Redis 的 channel,使用 Redis 的鍵空間通知處理 Session 的刪除和過期事件和使用 Pub/Sub 模式處理 Session 創(chuàng)建事件。

          關(guān)于 RedisSession 的存儲管理部分已經(jīng)初始化,但是 spring-session 的另一個基礎(chǔ)設(shè)施模塊 SessionRepositoryFilter 是在 RedisHttpSessionConfiguration 父類 SpringHttpSessionConfiguration 中初始化。

          @Bean
          public??SessionRepositoryFilter?springSessionRepositoryFilter(
          ??SessionRepository?sessionRepository)?{
          ?SessionRepositoryFilter?sessionRepositoryFilter?=?new?SessionRepositoryFilter<>(
          ???sessionRepository);
          ?sessionRepositoryFilter.setServletContext(this.servletContext);
          ?sessionRepositoryFilter.setHttpSessionIdResolver(this.httpSessionIdResolver);
          ?return?sessionRepositoryFilter;
          }

          spring-boot 整合 spring-session 配置的層次:

          RedisSessionConfiguration
          ?|_?_?SpringBootRedisHttpSessionConfiguration
          ???|_?_?RedisHttpSessionConfiguration
          ?????|_?_?SpringHttpSessionConfiguration

          回顧思考 spring-boot 自動配置 spring-session,非常合理。

          • SpringHttpSessionConfiguration 是 spring-session 本身的配置類,與 spring-boot 無關(guān),畢竟 spring-session 也可以整合單純的 spring 項目,只需要使用該 spring-session 的配置類即可。
          • RedisHttpSessionConfiguration 用于配置 spring-session 的 Redission,畢竟 spring-session 還支持其他的各種 session:Map/JDBC/MogonDB 等,將其從 SpringHttpSessionConfiguration 隔離開來,遵循開閉原則和接口隔離原則。但是其必須依賴基礎(chǔ)的 SpringHttpSessionConfiguration,所以使用了繼承。RedisHttpSessionConfiguration 是 spring-session 和 spring-data-redis 整合配置,需要依賴 spring-data-redis。
          • SpringBootRedisHttpSessionConfiguration 才是 spring-boot 中關(guān)鍵配置
          • RedisSessionConfiguration 主要用于處理自定義配置,將 application.yml 或者 application.properties 的配置載入。

          Tips:

          配置類也有相當(dāng)強(qiáng)的設(shè)計模式。遵循開閉原則:對修改關(guān)閉,對擴(kuò)展開放。遵循接口隔離原則:變化的就要單獨分離,使用不同的接口隔離。SpringHttpSessionConfiguration 和 RedisHttpSessionConfiguration 的設(shè)計深深體現(xiàn)這兩大原則。

          參考

          Spring Session參考文:https://spring.io/projects/spring-session#samples

          本文例子源碼

          https://github.com/lixyou/spring-boot-example/tree/master/session-example


          作者:懷瑾握瑜

          來源鏈接:

          https://www.cnblogs.com/lxyit/p/9720159.html


          最近熬夜給大家準(zhǔn)備了515套Java代碼,有一些是業(yè)務(wù)類的小項目,比如Java博客項目,也有腳手架、也有平時用一些的工具類、21套小程序代碼,也有一些游戲類的項目。

          掃以下二維碼并回復(fù)“828”即可獲取


          或者在本公眾號對話框回復(fù)【828】馬上獲取

          瀏覽 61
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    高清毛片AAAAAAAAA郊外 | 美国人A一级毛片 | aaa三级片久久久 | 大鸡巴操我骚逼 | 日批在线网站 |