package com.basic.x01.systemMenu; import java.io.IOException; import java.util.LinkedList; import java.util.List; import javax.annotation.Resource; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import com.basic.x01.base.BaseController; import com.basic.x01.helper.UserHelper; import com.basic.x01.system.mapper.SystemMapper; import com.basic.x01.system.model.TSysUser; import framework.startup.FrameUtil; /** * 菜单请求过滤器 * * * @company 北京贝思科技术有限公司 * @author liuyajun, 8384503@qq.com * @date 2016年1月11日 * @time 下午9:45:42 */ public class MenuFilter extends org.springframework.web.filter.DelegatingFilterProxy { Logger log = Logger.getLogger(getClass()); private String exceptSuffix; public void setExceptSuffix(String exceptSuffix){ if(exceptSuffix==null){ return; } this.exceptSuffix = exceptSuffix; this.exceptSuffix = this.exceptSuffix.replace("\n", ""); this.exceptSuffix = this.exceptSuffix.replace("\r", ""); this.exceptSuffix = this.exceptSuffix.replace(",", ""); this.exceptSuffix = this.exceptSuffix.replace(" ", ""); this.exceptSuffix = this.exceptSuffix.trim(); this.suffix = this.exceptSuffix.split("/"); } /** * 不处理的路径结尾 */ String[] suffix = new String[]{}; @Resource private SystemMapper userService; public final static String FRAME_REQUEST_ACTION_LIST = "FRAME_REQUEST_ACTION_LIST"; public void doFilter(ServletRequest requ, ServletResponse resp, FilterChain chain) throws ServletException, IOException { HttpServletRequest req = (HttpServletRequest)requ; HttpServletResponse res = (HttpServletResponse)resp; String uri = req.getRequestURI(); String root = req.getContextPath(); //检查是否根目录请求,如果是,跳过 if(! uri.endsWith("/")) { uri = uri + "/"; } if(! root.endsWith("/")) { root = root + "/"; } if(uri.equals(root)) { //请求的是根目录 chain.doFilter(requ, resp); return; } String urlRoot = FrameUtil.getURLRoot(req); //检查请求路径,只处理权限 uri = req.getRequestURI(); int lastPos = uri.lastIndexOf("/"); String actionId = uri.substring(lastPos+1); if(actionId.trim().length()==0) { chain.doFilter(req, resp); return; } for(String s : suffix){ if(actionId.endsWith("."+s)){ chain.doFilter(req, resp); return; } } //至此得到actionId log.info("Coming action: "+actionId); req.setAttribute("currentRequestActionId", actionId); //默认不需要显示菜单 boolean hasMenu = ! "y".equals(req.getParameter("noMenu")); req.setAttribute("hasMenu1", "n"); List menu1List = new LinkedList(); List menu2List = new LinkedList(); List menu3List = new LinkedList(); MenuItem currentMenu1 = null; MenuItem currentMenu2 = null; MenuItem currentMenu3 = null; List actionList = new LinkedList(); TSysUser user = BaseController.getLoingedUser(req); //不管当前请求如何,只要已登录了,先把第一级菜单显示 if(user !=null){ //已登录 actionList = userService.getUserRoleActionList(user.getUserId()); req.setAttribute(FRAME_REQUEST_ACTION_LIST, actionList); req.setAttribute("loginedUser", user); if(hasMenu){ //检查当前用户可以显示哪些一级菜单 for(MenuItem m : MenuUtil.menu1List){ if(checkActionTree(actionList, m)){ menu1List.add(m); } } req.setAttribute("hasMenu1", menu1List.size()>0?"y":"n"); req.setAttribute("menu1List", menu1List); req.setAttribute("hasMenu2", "n"); } } MenuItem menu = MenuUtil.menuActionMap.get(actionId); if(menu ==null){ chain.doFilter(requ, resp); return; //不是菜单权限,即登录后的权限,不需要登录 } req.setAttribute("currentMenuItem", menu); //此时菜单存在,则需要检查登录用户信息 if(user ==null){ res.sendRedirect(urlRoot+"login"); return; //是菜单,需要登录,但没有登录信息 } if((MenuUtil.isOrgMenu(menu) && UserHelper.isSchoolUser(user)) || (MenuUtil.isSchoolMenu(menu) && ! UserHelper.isSchoolUser(user))){ throw new RuntimeException("请求主体与权限所属主体不符, 请联系管理员"); } if(! checkActionTree(actionList, //如果是必须权限,则需检查其父级 menu.isRequired()?menu.getParent():menu)){ //没有权限 req.getRequestDispatcher("/loginedNoAccess").forward(req, res); return; } if(! hasMenu){ chain.doFilter(requ, resp); return; } //截至此,当前请求有权限 /* * 当前的请求,会返回一个页面,该页面大部分情况会包含导航菜单,也可能不包含菜单 * 需要找出该页面包含哪些一级菜单,当前是哪个一级;左侧包含哪些二级菜单,当前是哪个二级; * 同理三级; */ //得到对应最后一级菜单 MenuItem lastMenu = null; // if(! menu.isMenu()){ //不是菜单,往上找最后一级 MenuItem parent = menu; while(parent!=null && ! parent.isMenu()){ parent = parent.getParent(); } if(parent!=null){ lastMenu = parent; } //找到的有可能为空,为空则说明是主界面之上的全站搜索等 }else{ //是菜单,往下找,看是不是最后一级 if(menu.getLevel()==1){ //当前是一级 if(menu.getSubMenuList().size()>0){ //有二级,找二级 for(MenuItem mm : menu.getSubMenuList()){ //二级 boolean found = false; if(mm.getSubMenuList().size()>0){ //有三级,找三级 for(MenuItem mmm : mm.getSubMenuList()){ if(checkActionTree(actionList, mmm)){ lastMenu = mmm; found = true; break; } } } if(found){ break; } if(checkActionTree(actionList, mm)){ //没有三级,当前第一个二级作为最后菜单 lastMenu = mm; break; } } }else{ //没有二级 lastMenu = menu; } }else if(menu.getLevel()==2){ if(menu.getSubMenuList().size()>0){ //有三级,找三级 for(MenuItem mmm : menu.getSubMenuList()){ if(checkActionTree(actionList, mmm)){ lastMenu = mmm; break; } } }else{ //没有三级,当前第一个二级作为最后菜单 lastMenu = menu; } }else{ //肯定是三级 lastMenu = menu; } } //找到了最后级别的菜单,有可以为空 //为空时,则说明当前请求是菜单之外的功能,如全站搜索,没有权限提示等页面 //这些界面只需要显示一级菜单即可,而且不需要提示是呈个菜单 if(lastMenu !=null){ if(lastMenu.getLevel()==1){ currentMenu1 = lastMenu; }else if(lastMenu.getLevel()==2){ //二级菜单,需找到同级别的菜单 currentMenu1 = lastMenu.getParent(); currentMenu2 = lastMenu; menu2List.clear(); for(MenuItem mm : currentMenu1.getSubMenuList()){ if(checkActionTree(actionList, mm)){ menu2List.add(mm); } } }else if(lastMenu.getLevel()==3){ //三级菜单,需找到同级别的菜单,以及一二级菜单 currentMenu3 = lastMenu; currentMenu2 = lastMenu.getParent(); menu3List.clear(); for(MenuItem mmm : currentMenu2.getSubMenuList()){ if(checkActionTree(actionList, mmm)){ menu3List.add(mmm); } } currentMenu1 = currentMenu2.getParent(); menu2List.clear(); for(MenuItem mm : currentMenu1.getSubMenuList()){ if(checkActionTree(actionList, mm)){ menu2List.add(mm); } } } } req.setAttribute("hasMenu1", menu1List.size()>0?"y":"n"); req.setAttribute("menu1List", menu1List); req.setAttribute("currentMenu1", currentMenu1); req.setAttribute("hasMenu2", menu2List.size()>0?"y":"n"); req.setAttribute("menu2List", menu2List); req.setAttribute("currentMenu2", currentMenu2); req.setAttribute("hasMenu3", menu3List.size()>0?"y":"n"); req.setAttribute("menu3List", menu3List); req.setAttribute("currentMenu3", currentMenu3); if(lastMenu !=null){ //当前请求是二级菜单,需显示三级菜单 MenuItem par = lastMenu.getParent(); if(par!=null && par.equals(menu)){ res.sendRedirect(urlRoot + lastMenu.getActionId()); return; } if(par!=null){ //当前请求是一级菜单,需显示三级菜单 par = par.getParent(); if(par!=null && par.equals(menu)){ res.sendRedirect(urlRoot + lastMenu.getActionId()); return; } } } chain.doFilter(requ, resp); } /** * 检查权限树,输入的权限是否在数据库权限之内,也可能在数据库权限之上的父级权限 * @param dbActionList 数据库存储的权限列表 * @param menu 要检查的权限 * @return true: 有权限 */ public static boolean checkActionTree(List dbActionList, MenuItem menu){ List parList = new LinkedList(); parList.addAll(dbActionList); if(menu.isPublicMenu()){ return true; } String actionId = menu.getActionId(); boolean hasAction = false; while(parList.size()>0){ if(parList.contains(actionId)){ hasAction = true; break; } //如果没有权限,则查找以数据库权限为基础的权限树 List tempList = new LinkedList(); tempList.addAll(parList); parList.clear(); for(String s : tempList){ MenuItem m = MenuUtil.menuActionMap.get(s); MenuItem par = null; if(m!=null){ par = m.getParent(); } if(par !=null && ! parList.contains(par.getActionId())){ parList.add(par.getActionId()); } } } return hasAction; } }