jeesite缓存问题

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

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

这里的getUserFromDB:

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


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

0
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
底层架构优化 Maven多项目依赖,模块及插件分项目,尽量松耦合,方便模块升级、增减模块。 模块化数据库自动升级程序,当模块升级代码需要更新时,自动对应版本执行SQL更新。 授权模块,支持CAS单点登录,简单properties配置即可,不用再写很多的xml。 支持多数据源,简单properties配置即可实现,为了安全性吧,暂不提供界面维护数据源,不存数据库。 数据表主键优化,如分类科目表,采用有意义的主键方式,让客户去自定义,减少后期运维维护成本。 实体@Table注解配置 a. 自动生成增删改通用SQL,不需要在mapper.xml里写重复又费时的SQL了,减少开发和后期维护成本。b. 这里所有定义@Column均放到类头,而不是分布到各个属性或方法上,这是如下原因:c. 一是,放到表头的好处是,可一览熟知该实体类对应的物理表结构是什么样,开发者思维从物理表结构到对象的映射转换,都是基于物理表结构的,@Column指定物理字段名,而不是指定类上的属性名,也是这个原因;d. 二是,生成的SQL和查询条件,列的排列顺序,可方便核查定义,优化查询;e. 三是,方便@JoinTable关联表和其它扩展信息的设置,如果分布到类的属性上就不太好管理列。 用户数据权限优化,不仅仅是角色,颗粒度细化到每个人员的身上,可自定义第三方数据权限,不仅仅是部门和公司,你可以扩展,如:地区,栏目分类,商品分类。 支持SAAS多租户模式,每个租户数据通过corp_code字段进行分离,数据互不干扰。 缓存EhCache统一管理,支持快速切换为Redis缓存,集群Session缓存共享。 安全方面优化 原有JeeSite1.2安全选项及安全考虑保留。 配置文件数据库密码及其它安全密钥自动加密。 所有请求参数获取,均通过XSS跨站脚本过滤方法。 乐观锁简单实现,必要情况下使用,提高数据安全性。 通过properties简单配置,限制是否允许JS跨域操作。 身份认证 a. 登录失败多少次后显示验证码b. 登录失败多少次后锁定账号及锁定账号时间c. 登录账号密码可加密后再提交后台d. 同设备是否允许账号多地登录 密码策略 a. 初始密码修改策略,提醒或强制用户修改初始密码。b. 账号密码修改策略,多长时间内未修改,则提醒或强制修改密码。c. 账号密码安全等级限制策略,很弱密码,弱密码,安全密码,很安全密码 安全审计(后期) a. 查询未修改初始密码的账号,使用简单密码的,定期未修改的,长期未登录的。b. 权限审计,按登录账号查询菜单和权限,按菜单和权限查询登录账号 用户界面优化 平面化界面设计,精细,更加美观、高端、大气、上档次。 支持手机或平板访问,响应式样式,根据屏幕分辨率自适应控件布局。 无刷新设计,除了进入功能页面和新页面,其它情况下全部采用Ajax交互,优化体验和性能。 支持一件换肤,只需在properties里修改下主题名称即可快速切换整个UI的风格,不仅仅是色调和样式,布局也可改变。支持自定义扩展项目独有的主题样式风格。 优化用户功能操作,大众思维模式,功能清晰,更加贴切和友好。 前端开发优化 采用当前比较流行的Beetl模板引擎,它的优点很多,大家可自行查阅看看,这里不多说了。 封装Beetl UI通用组件,简单实现基本表单控件、树选择,列表选择,文件上传,等等很多,总之是简化开发。 数据表格jqGrid组件封装,自动完成分页、排序、列宽、多表头、子表、编辑表、等。 功能及组件优化 工具类Utils封装优化,应有尽有,包分类层次分明,独立工具类项目。 强大的Excel导出导入工具封装,支持大数据量,注解定义,简单配置即可实现。 Job作业调度,界面化在线管理,可新增,编辑、删除、暂停、恢复、运行一次等操作 在线查询在线人员,强踢在线账号。 代码生成工具操作简化及优化。
(注:由于jar文件较大,需要jar请免费下载本人上传的lib.jar文件) JeeSite是基于多个优秀的开源项目,高度整合封装而成的高效,高性能,强安全性的**开源**Java EE快速开发平台。 JeeSite本身是以Spring Framework为核心容器,Spring MVC为模型视图控制器,MyBatis为数据访问层, Apache Shiro为权限授权层,Ehcahe对常用数据进行缓存,Activit为工作流引擎。 JeeSite主要定位于企业信息化领域,已内置企业信息化系统的基础功能和高效的**代码生成**工具, 包括:系统权限组件、数据权限组件、数据字典组件、核心工具组件、视图操作组件、工作流组件、代码生成等。 前端界面风格采用了结构简单、性能优良、页面美观大气的Twitter Bootstrap页面展示框架。 采用分层设计、双重验证、提交数据安全编码、密码加密、访问验证、数据权限验证。 使用Maven做项目管理,提高项目的易开发性、扩展性。 JeeSite目前包括以下三大模块,系统管理(SYS)模块、 内容管理(CMS)模块、在线办公(OA)模块、代码生成(GEN)模块。 系统管理模块 ,包括企业组织架构(用户管理、机构管理、区域管理)、 菜单管理、角色权限管理、字典管理等功能; 内容管理模块 ,包括内容管理(文章、链接),栏目管理、站点管理、 公共留言、文件管理、前端网站展示等功能; 在线办公模块 ,提供简单的请假流程实例。 JeeSite 提供了常用工具进行封装,包括日志工具、缓存工具、服务器端验证、数据字典、当前组织机构数据 (用户、机构、区域)以及其它常用小工具等。另外还提供一个强大的在线 代码生成 工具, 此工具提供简单的单表、一对多、树结构功能的生成,如果对外观要求不是很高,生成的功能就可以用了。 如果你使用了JeeSite基础框架,就可以很高效的快速开发出,优秀的信息管理系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值