jeesite,其框架主要为:

后端

  • 核心框架:Spring Framework 4.0

  • 安全框架:Apache Shiro 1.2

  • 视图框架:Spring MVC 4.0

  • 服务端验证:Hibernate Validator 5.1

  • 布局框架:SiteMesh 2.4

  • 工作流引擎:Activiti 5.15、FoxBPM 6

  • 任务调度:Spring Task 4.0

  • 持久层框架:MyBatis 3.2

  • 数据库连接池:Alibaba Druid 1.0

  • 缓存框架:Ehcache 2.6、Redis

  • 日志管理:SLF4J 1.7、Log4j

  • 工具类:Apache Commons、Jackson 2.2、Xstream 1.4、Dozer 5.3、POI 3.9

2、前端

  • JS框架:jQuery 1.9。

  • CSS框架:Twitter Bootstrap 2.3.1。

  • 客户端验证:JQuery Validation Plugin 1.11。

  • 富文本:CKEcitor

  • 文件管理:CKFinder

  • 动态页签:Jerichotab

  • 手机端框架:Jingle

  • 数据表格:jqGrid

  • 对话框:jQuery jBox

  • 下拉选择框:jQuery Select2

  • 树结构控件:jQuery zTree

  • 日期控件: My97DatePicker

这里对于jeesite,感觉其功能还是挺强大的,但是有一点致命缺点,就是其缓存机制,本来缓存是为了提速,但是,当这里的缓存加上了MVC,并且在前端进行请求后,不适时宜地将请求的相关类对象进行缓存,这就导致了单例化和伪持久化。怎么说来?就是说,当前端修改Person对象实例,并提交到服务端试图保存时,由于某些原因,如权限不足导致保存失败,这本来应该是很正常的,但是,偏偏由于在这之前,缓存将Person对象实例更新了,从而缓存中的该实例是修改后的,这样,后来再次获取该对象,由于缓存存在,优先取缓存而不是从DB里获取,导致,后来获取的对象的数据都是错误的(修改但保存失败的),这就变相单例化,而且是无法获得正确数据了。

例如如下的接口

[java] view plain copy
  1. @RequiresPermissions("sys:user:edit")
  2. @RequestMapping(value = "save")
  3. public String save(User user, HttpServletRequest request, Model model, RedirectAttributes redirectAttributes) {
  4. //判断是否有权限修改用户信息
  5. //先清缓存:因为框架原因,只要更新了该用户,则会同步更新该用户缓存,从而无法获得真正的该用户信息,所以需要清除掉该缓存,这里先注释掉,看问题
  6. //UserUtils.clearCache(user);
  7. User oldUser = systemService.getUser(user.getId());
  8. List<String>roleIdListOld = oldUser.getRoleIdList();
  9. User operator = UserUtils.getUser();
  10. List<String>roleIdListOperator = operator.getRoleIdList();
  11. //自己不能修改自己的权限
  12. //      if(user.getId().equals(operator.getId())){
  13. //          addMessage(model, "修改用户信息失败, 不能修改自己的权限");
  14. //          UserUtils.clearCache();
  15. //          return form(oldUser, model);
  16. //          }
  17. if(!roleIdListOperator.containsAll(roleIdListOld)){
  18. addMessage(model, "修改用户信息失败, 您的权限不足");
  19. UserUtils.clearCache();
  20. return form(oldUser, model);
  21. }
  22. user.setRoleList(roleList);
  23. // 保存用户信息
  24. systemService.saveUser(user);
  25. // 清除当前用户缓存
  26. if (user.getPhone().equals(UserUtils.getUser().getPhone())){
  27. UserUtils.clearCache();
  28. //UserUtils.getCacheMap().clear();
  29. }
  30. addMessage(redirectAttributes, "保存用户'" + user.getPhone() + "'成功");
  31. return "redirect:" + adminPath + "/sys/user/list?repage";
  32. }

再看下getUser:

[java] view plain copy
  1. public static User getUser(String id){
  2. User user = (User)CacheUtils.get(USER_CACHE, USER_CACHE_ID_ + id);
  3. if (user ==  null){
  4. user = userDao.get(id);
  5. if (user == null){
  6. return null;
  7. }
  8. user.setRoleList(roleDao.findList(new Role(user)));
  9. CacheUtils.put(USER_CACHE, USER_CACHE_ID_ + user.getId(), user);
  10. CacheUtils.put(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getPhone(), user);
  11. }
  12. return user;
  13. }

这里的

[java] view plain copy
  1. systemService.getUser(user.getId());

会一直拿到该对象实例的缓存值,而该值,在修改提交到服务端时,框架已经更新了,再进到controller中。

所以,即使在

[java] view plain copy
  1. if(!roleIdListOperator.containsAll(roleIdListOld)){
  2. addMessage(model, "修改用户信息失败, 您的权限不足");
  3. UserUtils.clearCache();
  4. return form(oldUser, model);
  5. }

这里返回了,其他地方获取该user的值

[java] view plain copy
  1. getUser(user.getId());

还是会是缓存的值。

也相当于单例的、全局的实例值

解决方法:

在关系到修改等的地方,每次都需要对该实例进行缓存的清空。同时,在修改时,修改对象最好就是拿出db的该记录,逐个参数进行修改替换:

[java] view plain copy
  1. @RequiresPermissions("user:list:edit")
  2. @RequestMapping(value = "editUserInfoSave")
  3. public String editUserInfoSave(User user,Model model, RedirectAttributes redirectAttributes) {
  4. //先清除该user的缓存,防止干扰到其他地方的引用。其实还是会有并发问题,会在清除之前被引用到
  5. UserUtils.clearCache(user);
  6. //从db中获取user,注意这个userSave 是修改前的,与user的值不一样,注意一点:如果直接从getUser(user.getId());中获取,同时并没有清缓存的前提下
  7. //UserUtils.clearCache(user);则会导致拿到的user并非DB里的user,而是缓存前端提交的
  8. User userSave = systemService.getUserFromDB(user.getId());
  9. /**
  10. * 替换更新修改信息
  11. */
  12. userSave.setName(user.getName());
  13. userSave.setFirstnameStr(user.getFirstnameStr());
  14. userSave.setLastnameStr(user.getLastnameStr());
  15. userSave.setIdStr(user.getIdStr());
  16. userSave.setUsername(user.getUsername());
  17. userSave.setBirthdateStr(user.getBirthdateStr());
  18. userSave.setEmail(user.getEmail());
  19. userSave.setUserType(user.getUserType());
  20. userSave.setGenderStr(user.getGenderStr());
  21. // 保存用户信息
  22. systemService.saveUser(userSave);
  23. addMessage(redirectAttributes, "保存用户'" + user.getPhone() + "'成功");
  24. return "redirect:" + adminPath + "/user/user/list?repage";
  25. }

这里的getUserFromDB:

[java] view plain copy
  1. /**
  2. * 根据ID获取用户——通过DB
  3. * @param id
  4. * @return 取不到返回null
  5. */
  6. public static User getUserFromDB(String id){
  7. User user = userDao.get(id);
  8. user.setRoleList(roleDao.findList(new Role(user)));
  9. return user;
  10. }

因此特别需要注意缓存的使用,不是任何地方都适合使用缓存。

0

jeesite缓存问题相关推荐

  1. 企业信息化快速开发平台JeeSite

    为什么80%的码农都做不了架构师?>>>    平台简介 JeeSite是基于多个优秀的开源项目,高度整合封装而成的高效,高性能,强安全性的开源Java EE快速开发平台. JeeS ...

  2. Jeesite信息化快速开发平台

    平台简介 JeeSite是基于多个优秀的开源项目,高度整合封装而成的高效,高性能,强安全性的开源Java EE快速开发平台. JeeSite是您快速完成项目的最佳基础平台解决方案,JeeSite是您想 ...

  3. javaweb项目搭建ehcache缓存系统

    转载自  javaweb项目搭建ehcache缓存系统 EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认的CacheProvider,同时在项目开发中 ...

  4. java企业级快速开发平台jeeadminlte(jeesite大胖老师修改版)

    JeeAdminlte码云下载地址:https://gitee.com/dptc/jeeadminlte 此JeeAdminlte是大胖老师在开源平台企业级Java快速开发平台jeesite的基础上进 ...

  5. jeesite集群和负载均衡配置

    jeesite是支持集群和负载均衡配置的,其实步骤非常简单.我们只需修改jeesite.properties的配置项,将ehcache.configFile=cache/ehcache-local.x ...

  6. JeeSite 是什么、概述

    见JeeSite官网:http://jeesite4.mydoc.io/ 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 总体概述 快速访问 Jee ...

  7. jeesite 框架的简单应用

    jeesite 框架的简单应用 一个讲解jeesite的网站 https://www.w3cschool.cn/jeesite/ jeesite官网 http://jeesite.com/ 公司项目都 ...

  8. JeeSite系列之一_JeeSite简介

    JeeSite简介 最近想研究一下JeeSite这个"企业信息化快速开发平台". 它是这么说的: JeeSite是基于多个优秀的开源项目,高度整合封装而成的高效,高性能,强安全性的 ...

  9. jeesite框架学习

    写在前面 如果你没有能力自己独立写一套框架,那就放下你的架子,认真去学习看看别人是怎么设计框架的. jeesite简要 首先jeesite是开源,遵守 Apache License 2.0协议: 需要 ...

最新文章

  1. 哈佛、MIT等顶级名校全套CS课程资源!
  2. 多项式相关操作学习笔记
  3. Java-逻辑运算符、位运算符
  4. 2011年倒数第三天,下雪,第一次写博客
  5. ZMQ == 服务端创建,接受请求的过程
  6. Windows 7 专业版如何安装英文、中文语言包
  7. 用Proj.4进行坐标系转换(以北京54坐标系转WGS84投影坐标系为例)
  8. 【PPT模板】甄选100套时间轴精品
  9. linux主机独立显卡切换,Linux Deepin 2013 设置双显卡之关闭独显
  10. 批量ping多个IP地址
  11. 1038: 角谷猜想
  12. Aspose.Slides使用教程:使用 C++ 在 PowerPoint 演示文稿中添加幻灯片切换
  13. NAM: Normalization-based Attention Module,一种新的注意力计算方式,无需额外的参数...
  14. 灰色马尔科夫链matlab,基于灰色-马尔科夫模型的电力功率预测
  15. 谷歌地图 替代_Google地图的替代品
  16. R语言|clusterprofile超几何分布富集分析 GO,KEGG富集分析,循环Fisher‘s test
  17. autocad.net将Geometry对象转换为Database对象
  18. web项目前后端使用MD5验证密码
  19. 什么是交换机?描述一下工作过程?交换机基本功能、交换机是如何转发数据包的,什么是三层交换机?和二层交换机有什么区别?三层交换机是否可以代替路由器?为什么?
  20. HBuilder开发小程序,如何实现在微信开发者工具中实时更新

热门文章

  1. 《位运算技巧以及Leetcode的一些位运算题目》
  2. string concat_Java String concat()方法与示例
  3. java 方法 示例_Java Collectionsfrequency()方法与示例
  4. UVA 10891——Game of Sum
  5. C++ STL 迭代器5种类型 简介
  6. 【剑指offer】_09二叉搜索树的后序遍历序列
  7. c++多态--2(计算器,纯虚函数和抽象类)
  8. 网络层网络层服务及其 IP 地址
  9. 【蓝桥杯】BASIC-8 回文数(2020-06-08)
  10. Linux 简单打印日志(二)