?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里獲取,導致,后來獲取的對象的數據都是錯誤的(修改但保存失敗的),這就變相單例化,而且是無法獲得正確數據了。
例如如下的接口
- @RequiresPermissions("sys:user:edit")??
- ????@RequestMapping(value?=?"save")??
- ????public?String?save(User?user,?HttpServletRequest?request,?Model?model,?RedirectAttributes?redirectAttributes)?{??
- ??
- ??????????
- ????????//判斷是否有權限修改用戶信息??
- ??????????
- ????????//先清緩存:因為框架原因,只要更新了該用戶,則會同步更新該用戶緩存,從而無法獲得真正的該用戶信息,所以需要清除掉該緩存,這里先注釋掉,看問題??
- ????????//UserUtils.clearCache(user);??
- ????????User?oldUser?=?systemService.getUser(user.getId());??
- ????????List<String>roleIdListOld?=?oldUser.getRoleIdList();??
- ????????User?operator?=?UserUtils.getUser();??
- ????????List<String>roleIdListOperator?=?operator.getRoleIdList();??
- ????????//自己不能修改自己的權限??
- //??????if(user.getId().equals(operator.getId())){??
- //??????????addMessage(model,?"修改用戶信息失敗,?不能修改自己的權限");??
- //??????????UserUtils.clearCache();??
- //??????????return?form(oldUser,?model);??
- //??????????}??
- ????????if(!roleIdListOperator.containsAll(roleIdListOld)){??
- ????????????addMessage(model,?"修改用戶信息失敗,?您的權限不足");??
- ????????????UserUtils.clearCache();??
- ????????????return?form(oldUser,?model);??
- ????????}??
- ????????user.setRoleList(roleList);??
- ????????//?保存用戶信息??
- ????????systemService.saveUser(user);??
- ????????//?清除當前用戶緩存??
- ????????if?(user.getPhone().equals(UserUtils.getUser().getPhone())){??
- ????????????UserUtils.clearCache();??
- ????????????//UserUtils.getCacheMap().clear();??
- ????????}??
- ????????addMessage(redirectAttributes,?"保存用戶'"?+?user.getPhone()?+?"'成功");??
- ????????return?"redirect:"?+?adminPath?+?"/sys/user/list?repage";??
- ????}??
再看下getUser:
- public?static?User?getUser(String?id){??
- ????User?user?=?(User)CacheUtils.get(USER_CACHE,?USER_CACHE_ID_?+?id);??
- ????if?(user?==??null){??
- ????????user?=?userDao.get(id);??
- ????????if?(user?==?null){??
- ????????????return?null;??
- ????????}??
- ????????user.setRoleList(roleDao.findList(new?Role(user)));??
- ????????CacheUtils.put(USER_CACHE,?USER_CACHE_ID_?+?user.getId(),?user);??
- ????????CacheUtils.put(USER_CACHE,?USER_CACHE_LOGIN_NAME_?+?user.getPhone(),?user);??
- ????}??
- ????return?user;??
- }??
這里的
- systemService.getUser(user.getId());??
所以,即使在
- if(!roleIdListOperator.containsAll(roleIdListOld)){??
- ????????????addMessage(model,?"修改用戶信息失敗,?您的權限不足");??
- ????????????UserUtils.clearCache();??
- ????????????return?form(oldUser,?model);??
- ????????}??
- getUser(user.getId());??
也相當于單例的、全局的實例值
解決方法:
在關系到修改等的地方,每次都需要對該實例進行緩存的清空。同時,在修改時,修改對象最好就是拿出db的該記錄,逐個參數進行修改替換:
- @RequiresPermissions("user:list:edit")??
- ????@RequestMapping(value?=?"editUserInfoSave")??
- ????public?String?editUserInfoSave(User?user,Model?model,?RedirectAttributes?redirectAttributes)?{??
- ??????????
- ????????//先清除該user的緩存,防止干擾到其他地方的引用。其實還是會有并發問題,會在清除之前被引用到??
- ????????UserUtils.clearCache(user);??
- ????????????????//從db中獲取user,注意這個userSave?是修改前的,與user的值不一樣,注意一點:如果直接從getUser(user.getId());中獲取,同時并沒有清緩存的前提下??
- ????????????????//UserUtils.clearCache(user);則會導致拿到的user并非DB里的user,而是緩存前端提交的??????????????????
- ????????????????User?userSave?=?systemService.getUserFromDB(user.getId());??
- ????????/**?
- ?????????*?替換更新修改信息?
- ?????????*/??
- ????????userSave.setName(user.getName());??
- ????????userSave.setFirstnameStr(user.getFirstnameStr());??
- ????????userSave.setLastnameStr(user.getLastnameStr());??
- ????????userSave.setIdStr(user.getIdStr());??
- ????????userSave.setUsername(user.getUsername());??
- ????????userSave.setBirthdateStr(user.getBirthdateStr());??
- ????????userSave.setEmail(user.getEmail());??
- ????????userSave.setUserType(user.getUserType());??
- ????????userSave.setGenderStr(user.getGenderStr());??
- ????????//?保存用戶信息??
- ????????systemService.saveUser(userSave);??
- ????????addMessage(redirectAttributes,?"保存用戶'"?+?user.getPhone()?+?"'成功");??
- ????????return?"redirect:"?+?adminPath?+?"/user/user/list?repage";??
- ????}??
這里的getUserFromDB:
- /**?
- ?*?根據ID獲取用戶——通過DB?
- ?*?@param?id?
- ?*?@return?取不到返回null?
- ?*/??
- public?static?User?getUserFromDB(String?id){??
- ??
- ????User?user?=?userDao.get(id);??
- ????user.setRoleList(roleDao.findList(new?Role(user)));??
- ????return?user;??
- }??
因此特別需要注意緩存的使用,不是任何地方都適合使用緩存。
- 頂
- 0
- 踩