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<MenuItem> menu1List = new LinkedList<MenuItem>();
|
List<MenuItem> menu2List = new LinkedList<MenuItem>();
|
List<MenuItem> menu3List = new LinkedList<MenuItem>();
|
|
MenuItem currentMenu1 = null;
|
MenuItem currentMenu2 = null;
|
MenuItem currentMenu3 = null;
|
|
List<String> actionList = new LinkedList<String>();
|
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<String> dbActionList, MenuItem menu){
|
List<String> parList = new LinkedList<String>();
|
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<String> tempList = new LinkedList<String>();
|
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;
|
}
|
}
|