持续学习&持续更新中…

守破离


【Java从零到架构师第③季】【49】会话管理—Token_ehcache

  • 基于Cookie、Session
  • 基于Token
  • ehcache
    • 简单使用
    • 项目使用:登录、登出
  • 补充:简单的分布式架构介绍
  • 参考

基于Cookie、Session

基于Token

ehcache

简单使用

依赖:

 <!-- 缓存 --><dependency><groupId>org.ehcache</groupId><artifactId>ehcache</artifactId></dependency>

标签:

    <!-- <persistence directory="F:/ehcache"/> --><cache alias="test"><expiry><!-- none:永不过期 --><none/><!-- tti:time to idle(空闲时间)=> 10月1号登录,默认10月8号就会失效。但是,如果10月3号登陆了,那么10月10号才失效;如果10月4号又登录了,那么再延长7天,10月11号才失效。也就是说,只要7天内不访问,就失效。 --><!-- <tti unit="days">7</tti> --><!-- ttl:time to live(存活时间)=> 10月1号登录,10月8号就失效 --><!--  <ttl unit="days">7</ttl> --></expiry><resources><!--  <offheap unit="MB"/>  堆外内存 --><!--  <disk unit="MB" persistent="true" /> 磁盘 需要搭配persistence标签  --><heap unit="entries">1000</heap> <!-- 放到堆内内存,堆内内存就是new的对象存放的地方 --><!-- <heap>1000</heap> unit="entries" 缓存个数 是默认的 --><!-- <heap unit="MB">1000</heap> 缓存大小:GB、MB、KB、... --></resources></cache>

使用:

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'xmlns='http://www.ehcache.org/v3'xsi:schemaLocation="http://www.ehcache.org/v3http://www.ehcache.org/schema/ehcache-core.xsd"><cache-template name="common"><key-type>java.lang.Object</key-type><value-type>java.lang.Object</value-type><resources><heap>10000</heap></resources></cache-template><!--11月1号~11月7号,11月8号过期11月6号~11月12号,11月13号过期11月12号~11月18号,11月19号过期--><!-- 存放token的缓存:只要7天内不访问,就失效 --><cache alias="token" uses-template="common"><expiry><tti unit="days">7</tti></expiry></cache><!-- 默认缓存:永不过期 --><cache alias="default" uses-template="common"><expiry><none/></expiry></cache>
</config>
public class Caches {private static final CacheManager MGR;private static final Cache<Object, Object> DEFAULT_CACHE;private static final Cache<Object, Object> TOKEN_CACHE;static {// 初始化缓存管理器URL url = Caches.class.getClassLoader().getResource("ehcache.xml");assert url != null;Configuration cfg = new XmlConfiguration(url);MGR = CacheManagerBuilder.newCacheManager(cfg);MGR.init();// 缓存对象DEFAULT_CACHE = MGR.getCache("default", Object.class, Object.class);TOKEN_CACHE = MGR.getCache("token", Object.class, Object.class);}public static void put(Object key, Object value) {if (key == null || value == null) return;DEFAULT_CACHE.put(key, value);}public static void remove(Object key) {if (key == null) return;DEFAULT_CACHE.remove(key);}public static <T> T get(Object key) {if (key == null) return null;return (T) DEFAULT_CACHE.get(key);}public static void clear() {DEFAULT_CACHE.clear();}public static void putToken(Object key, Object value) {if (key == null || value == null) return;TOKEN_CACHE.put(key, value);}public static void removeToken(Object key) {if (key == null) return;TOKEN_CACHE.remove(key);}public static <T> T getToken(Object key) {if (key == null) return null;return (T) TOKEN_CACHE.get(key);}public static void clearToken() {TOKEN_CACHE.clear();}
}

项目使用:登录、登出

  • 只要近7天登录过,就不会失效,就不用重新登录
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'xmlns='http://www.ehcache.org/v3'xsi:schemaLocation="http://www.ehcache.org/v3http://www.ehcache.org/schema/ehcache-core.xsd"><cache-template name="common"><key-type>java.lang.Object</key-type><value-type>java.lang.Object</value-type><resources><heap>10000</heap></resources></cache-template><!--11月1号~11月7号,11月8号过期11月6号~11月12号,11月13号过期11月12号~11月18号,11月19号过期--><!-- 存放token的缓存:只要7天内不访问,就失效 --><cache alias="token" uses-template="common"><expiry><tti unit="days">7</tti>
<!--            <tti unit="seconds">7</tti>--></expiry><listeners><listener><class>programmer.lp.jk.common.cache.TokenCacheListener</class><!-- 异步回调 --><event-firing-mode>ASYNCHRONOUS</event-firing-mode><!-- 不用按顺序处理事件 --><event-ordering-mode>UNORDERED</event-ordering-mode><!-- 哪些操作会触发监听器:添加、过期、删除 --><events-to-fire-on>CREATED</events-to-fire-on><events-to-fire-on>EXPIRED</events-to-fire-on><events-to-fire-on>REMOVED</events-to-fire-on></listener></listeners></cache><!-- 默认缓存:永不过期 --><cache alias="default" uses-template="common"><expiry><none/></expiry></cache>
</config>
public class TokenCacheListener implements CacheEventListener<Object, Object> {@Overridepublic void onEvent(CacheEvent cacheEvent) {String token = (String) cacheEvent.getKey();switch (cacheEvent.getType()) {case CREATED: {// 添加了一个新的token(说明有一个用户刚登录)SysUserDto user = (SysUserDto) cacheEvent.getNewValue();// 以便将来通过用户id找到他对应的tokenCaches.put(user.getUser().getId(), token);break;}case EXPIRED:case REMOVED: { // token被移除或者过期了SysUserDto user = (SysUserDto) cacheEvent.getOldValue();Caches.remove(user.getUser().getId());break;}default: break;}}
}
@Overridepublic RespLogin login(ReqLogin reqVo) {// 根据用户名查询用户MPLambdaQueryWrapper<SysUser> wrapper = new MPLambdaQueryWrapper<>();wrapper.eq(SysUser::getUsername, reqVo.getUsername());SysUser po = baseMapper.selectOne(wrapper);// 用户名不存在if (po == null) {return JSONResults.exception(CodeMsg.WRONG_USERNAME);}// 密码不正确if (!po.getPassword().equals(reqVo.getPassword())) {return JSONResults.exception(CodeMsg.WRONG_PASSWORD);}// 账号锁定if (po.getStatus() == Constants.SysUserStatus.LOCKED) {return JSONResults.exception(CodeMsg.USER_LOCKED);}/** 登录成功 **/// 更新登录时间po.setLoginTime(new Date());baseMapper.updateById(po);SysUserDto dto = new SysUserDto();dto.setUser(po);// 根据用户id查询所有的角色:sys_role,sys_user_roleList<SysRole> roles = roleService.listByUserId(po.getId());// 根据角色id查询所有的资源:sys_resource、sys_role_resourceif (!CollectionUtils.isEmpty(roles)) {dto.setRoles(roles);List<Short> roleIds = Streams.map(roles, SysRole::getId);List<SysResource> resources = resourceService.listByRoleIds(roleIds);dto.setResources(resources);}// 生成Token,发送Token给用户String token = UUID.randomUUID().toString();// 存储token到缓存中Caches.putToken(token, dto);// 返回给客户端的具体数据RespLogin vo = MapStruct.INSTANCE.po2loginVo(po);vo.setToken(token);return vo;}
    @PostMapping("/logout")@ApiOperation("退出登录")public JSONResult logout(@RequestHeader(TokenFilter.HEADER_TOKEN) String token) {Caches.removeToken(token);return JSONResults.ok(CodeMsg.LOGOUT_OK);}
    @Overridepublic boolean saveOrUpdate(ReqSaveSysUser entity) {// 转成POSysUser po = MapStruct.INSTANCE.vo2po(entity);// 保存用户信息if (!saveOrUpdate(po)) return false;Integer id = entity.getId();if (id != null && id > 0) {// 如果是做更新// 将更新成功的用户从缓存中移除(让token失效,用户必须重新登录)Caches.removeToken(Caches.get(id));
//            Caches.remove(id);// 删除当前用户的所有角色信息userRoleService.removeByUserId(entity.getId());}// 保存角色信息String roleIdsStr = entity.getRoleIds();if (Strings.isEmpty(roleIdsStr)) return true;String[] roleIds = roleIdsStr.split(",");List<SysUserRole> userRoles = new ArrayList<>();Integer userId = po.getId();for (String roleId : roleIds) { // 构建SysUserRole对象SysUserRole userRole = new SysUserRole();userRole.setUserId(userId);userRole.setRoleId(Short.parseShort(roleId));userRoles.add(userRole);}return userRoleService.saveBatch(userRoles);}
// 角色信息被更新了也要让用户重新登录.
// 重新登录是为了去查用户的权限(资源),让其配合Shiro使用@Overridepublic boolean saveOrUpdate(ReqSaveSysRole entity) {// 转成POSysRole po = MapStruct.INSTANCE.vo2po(entity);// 保存角色信息if (!saveOrUpdate(po)) return false;Short id = entity.getId();if (id != null && id > 0) {MPLambdaQueryWrapper<SysUserRole> wrapper = new MPLambdaQueryWrapper<>();wrapper.select(SysUserRole::getUserId);wrapper.eq(SysUserRole::getRoleId, id);List<Object> userIds = userRoleMapper.selectObjs(wrapper);if (!CollectionUtils.isEmpty(userIds)) {for (Object userId : userIds) {// 将拥有这个角色的用户从缓存中移除(让token失效,用户必须重新登录)Caches.removeToken(Caches.get(userId));}}// 删除当前角色的所有资源信息roleResourceService.removeByRoleId(id);}// 保存角色信息String resourceIdsStr = entity.getResourceIds();if (Strings.isEmpty(resourceIdsStr)) return true;String[] resourceIds = resourceIdsStr.split(",");List<SysRoleResource> roleResources = new ArrayList<>();Short roleId = po.getId();for (String resourceId : resourceIds) { // 构建SysUserRole对象SysRoleResource roleResource = new SysRoleResource();roleResource.setRoleId(roleId);roleResource.setResourceId(Short.parseShort(resourceId));roleResources.add(roleResource);}return roleResourceService.saveBatch(roleResources);}

补充:简单的分布式架构介绍

参考

小码哥-李明杰: Java从0到架构师③进阶互联网架构师.


本文完,感谢您的关注支持!


【Java从零到架构师第③季】【49】会话管理—Token_ehcache相关推荐

  1. 【Java从零到架构师第③季】【48】SpringBoot-Swagger

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][48]SpringBoot-Swagger 接口文档-Swagger 基本使用 不使用starter 使用starter(Swa ...

  2. 【Java从零到架构师第③季】【26】SpringMVC-反射获取方法参数名_SpringMVC是如何获取方法的参数名的

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][26]SpringMVC-反射获取方法参数名_SpringMVC是如何获取方法的参数名的 利用反射获取方法的参数名 直接编译 修 ...

  3. 【Java从零到架构师第③季】【24】SpringMVC-概述_入门

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][24]SpringMVC-概述_入门 Spring.SpringMVC.MyBatis之间的关系 SpringMVC简介 Spr ...

  4. 【Java从零到架构师第③季】【28】SpringMVC-Servlet的URL匹配_path-matching suffix-pattern

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][28]SpringMVC-Servlet的URL匹配_path-matching suffix-pattern Servlet的 ...

  5. 【Java从零到架构师第二季】【07】JDBC FOR MySQL

    持续学习&持续更新中- 学习态度:守破离 JDBC FOR MySQL 什么是JDBC 如何通过Java操作数据库 JDBC是属于JavaSE的一部分 下载MySQL的JDBC实现 JDBC细 ...

  6. 【Java从零到架构师第二季】【14】AJAX

    持续学习&持续更新中- 学习态度:守破离 AJAX 同步请求和异步请求 未学AJAX之前向服务器提交请求的方式 同步和异步 AJAX 什么是AJAX AJAX的常见使用方式 原生 jQuery ...

  7. 【Java从0到架构师】项目实战 - 会话管理、EhCache、JWT、权限管理 Shiro、打包部署

    项目实战 - 权限管理 会话管理 客户端身份认证 - 基于 Cookie.Session 客户端身份验证 - 基于 token EhCache - 简单的缓存框架 JWT - 基于 JSON 的 to ...

  8. 【Java从零到架构师第1季】【并发 Concurrent 03】线程间通信_ReentrantLock_线程池

    持续学习&持续更新中- 守破离 [Java从零到架构师第1季][并发 Concurrent 03]线程间通信_ReentrantLock_线程池 线程间通信 线程间通信-示例 可重入锁Reen ...

  9. 【Java从0到架构师】Linux 应用 - 软件包管理、软件安装

    Linux 应用 - 软件包管理.软件安装 软件包管理器 rpm yum 软件的安装 jdk 1.8 mysql 5.7 tomcat8 Java 从 0 到架构师目录:[Java从0到架构师]学习记 ...

最新文章

  1. JavaScript中的正则表达式解析
  2. 用switch写收水费的c语言程序,超级新手,用switch写了个计算器程序,求指导
  3. 互联网协议 — OSPF 开放式最短路径优先协议
  4. Linux 6.8 root密码丢失找回
  5. SQL SERVER 常用日期计算
  6. Oracle 备份还原
  7. qt 关闭对话框 提醒_qt5信息提示框QMessageBox用法
  8. 数据库经典文章!(必备)
  9. Could not load the Tomcat server configuration at \Servers\Tomcat v7.0 Server at localhost-config
  10. C#操作SQLite数据库
  11. OpenShift 4 之Service Mesh教程(2)- 用Kiali监控微服务运行
  12. 开课吧Java课堂:什么是线程优先级?
  13. /usr/bin/ld: 找不到 -lglut
  14. ghost for linux 教程,今天解决了ghost for linux的问题
  15. 你们要的最小样本量计算来了。
  16. JAVA里面一加到一百等于多少_从1加到100等于多少 【求和算法汇总】
  17. Java Instrument实践应用:运行中修改程序的Class
  18. 高仿淘宝首页 - 刚把CSS和JS弄出成了外部,原本写的时候都在HTML一个文件里哈
  19. Altium Designer 3D元件库,PCB封装库,极为全面一份足以
  20. 读书感受 之 《冰与火之歌》

热门文章

  1. 通过google插件Thumbnails实现图片指定大小压缩
  2. 彻底卸载并重装Anaconda环境与Python的方法
  3. 简述计算机用二进制的原因,简述计算机采用二进制的原因
  4. register_chrdev_region、alloc_chrdev_region、register_chrdev区别
  5. ArrayDeque集合的妙用
  6. Presto 在字节跳动的应用
  7. 2019计算机小高考成绩,小高考没过怎么办 2021小高考难度如何
  8. 代价函数,损失函数,目标函数区别
  9. 用python做网站开发的课程_腾讯课堂:Flask Python Web 网站开发
  10. 卫星遥感加持,农业更高效精准