react + spring boot 菜单权限控制-动态加载二级菜单

首先是给路径建表,存在数据库里

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `route_config`
-- ----------------------------
DROP TABLE IF EXISTS `route_config`;
CREATE TABLE `route_config` (
  `id` int(11) NOT NULL,
  `key` varchar(255) DEFAULT NULL,
   #图标
  `icon` varchar(255) DEFAULT NULL,
   #父路径id
  `parent_id` int(11) DEFAULT NULL,
   #路径
  `url` varchar(255) DEFAULT NULL,
   #路径对应的文本
  `title` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

路径表和权限表的连接表

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `route_permission`
-- ----------------------------
DROP TABLE IF EXISTS `route_permission`;
CREATE TABLE `route_permission` (
  `id` int(11) NOT NULL,
   #路径id
  `rid` int(11) DEFAULT NULL,
   #权限id
  `pid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

权限表

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `permission`
-- ----------------------------
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID,主键',
  `name` varchar(64) DEFAULT NULL COMMENT '权限名',
  `parent_id` int(10) unsigned DEFAULT NULL COMMENT '上级权限ID',
  `abbreviation` varchar(32) DEFAULT NULL COMMENT '简称',
  `type` varchar(32) DEFAULT NULL COMMENT '权限类型',
  `description` varchar(255) DEFAULT NULL COMMENT '描述',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8 COMMENT='权限';

关于RouteConfig的mapper





	
		
		
		
		
		
		
		
		
	
	
	
	

后台用shiro框架来管理权限,在RouteServiceImpl中实现getRoutes(),流程可以概括为 先获取当前登录的用户,从用户对象中取到用户所对应的角色, 再遍历角色,得到对应的权限,根据权限查询到对应的路径信息,再调用getTree方法生成菜单树。

@Service
public class RouteServiceImpl implements RouteService{
	@Autowired
	private CurrentUser currentUser;
	@Autowired
	RouteConfigMapper routeConfigMapper;
	@Override
	public List getRoutes() {
		List list = new ArrayList();
		if(currentUser.getCurrentUser()!=null) {
			List permission = new ArrayList();
			List roles =  currentUser.getCurrentUser().getRoles();
			for(int i=0;i permissions = roles.get(i).getPermissions();
				for(int j=0;j routes = routeConfigMapper.selectRouteConfig(permission);
			List parentRoute = routeConfigMapper.selectByPid(0);
			//给数组加入父路径
			for(int i=0;i routeList = new ArrayList(routes);
			//按id排序
			Collections.sort(routeList);
			list = RouteConfigTree.getTree(routeList);
		}
		return list;
	}
}

RouteConfigTree类

public class RouteConfigTree {
	/**
	 * 计数
	 */
	private static int length = 0;
	/**
	 * 递归构造树
	 */
	public static void buildTree(Tree parentTree, List list) {
		List childList = new ArrayList<>();
		for(int i = 0; i < list.size(); i++) {
			if(list.get(i).getParentRouteConfig()!= null && 
					list.get(i).getParentRouteConfig().getId() == parentTree.getId()) {
				Tree tree = new Tree();
				tree.setId(list.get(i).getId());
				tree.setKey(list.get(i).getKey());
				tree.setTitle(list.get(i).getTitle());
				tree.setParentKey(parentTree.getId());
				tree.setIcon(list.get(i).getIcon());
				tree.setUrl(list.get(i).getUrl());
				childList.add(tree);
				length--;
			}
		}
		if(childList.size() > 0) {
			parentTree.setRoute(childList);
		}
		
		if(length > 0) {
			for(int i = 0; i < childList.size(); i++) {
				buildTree(childList.get(i), list);
			}
		}
	}
	/**
	 * 构造树
	 */
	public static List getTree(List list) {
		System.out.println("routes"+list);
		List treeList = new ArrayList<>();
		length = list.size();
		
		//先找根
		for(int i = 0; i < list.size(); i++) {
			if(list.get(i).getParentRouteConfig()== null) {
				Tree tree = new Tree();
				tree.setId(list.get(i).getId());
				tree.setKey(list.get(i).getKey());
				tree.setTitle(list.get(i).getTitle());
				tree.setIcon(list.get(i).getIcon());
				tree.setParentKey(null);
				tree.setUrl(list.get(i).getUrl());
				treeList.add(tree);
				length--;
			}
		}
		
		//再找子
		for(int i = 0; i < treeList.size(); i++) {
			buildTree(treeList.get(i), list);
		}
		//把没有子节点的根节点删除
		for(int i = 0; i < treeList.size(); i++) {
			System.out.println(treeList.get(i));
			if(treeList.get(i).getRoute()==null) {
				treeList.remove(i);
			}
		}
		return treeList;
	}
}

Tree类

public class Tree implements Serializable {
	
	private static final long serialVersionUID = 1L;
	//key
	private String key;
	//当前节点id
	private Integer Id;
	//父id
	private Integer parentKey;
	//路径文本内容
	private String title;
	private List route;
	private String icon;
	private String url;
	
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public String getIcon() {
		return icon;
	}
	public void setIcon(String icon) {
		this.icon = icon;
	}
	public Integer getId() {
		return Id;
	}
	public void setId(Integer id) {
		Id = id;
	}
	public String getKey() {
		return key;
	}
	public void setKey(String key) {
		this.key = key;
	}
	public static long getSerialversionuid() {
		return serialVersionUID;
	}
	public Integer getParentKey() {
		return parentKey;
	}
	public void setParentKey(Integer parentKey) {
		this.parentKey = parentKey;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public List getRoute() {
		return route;
	}
	public void setRoute(List route) {
		this.route = route;
	}
	@Override
	public String toString() {
		return "Tree [key=" + key + ", Id=" + Id + ", parentKey=" + parentKey + ", title=" + title + ", route=" + route
				+ ", icon=" + icon + ", url=" + url + "]";
	}
}

Controller中,把菜单树转成json形式返回前端,到这里,后端部分就结束了

@RequestMapping("/getSliderList")
@ResponseBody
public String getSliderList() {
	List routes = routeService.getRoutes();
	JSONObject resultJS = new JSONObject();
	resultJS.put("list", routes);
	return resultJS.toJSONString();
}

前端 react + redux 

代码结构如图

react + spring boot 菜单权限控制-动态加载二级菜单_第1张图片

首先是store下的index.js

import { createStore, compose, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers(
	applyMiddleware(thunk)
));

export default store;

store下的reducer.js

import { combineReducers } from 'redux';
import CommonReducer from './CommonReducer/reducer'
const reducer = combineReducers({
	common:CommonReducer
});

export default reducer;

app.js

import Leftsider from './pages/left'
class App extends Component {
  render() {
    return (
      
      
            
            
          
); } } export default App;

left.js 侧边栏部分,每次加载这个组件,都会从后台请求侧边栏数据,存在store中

class Leftsider extends React.Component{
  componentDidMount(){
    this.props.initSliderList();
  }
  render(){
    return(
      
{ this.props.list.map(function(item,index){ return ( {item.title}}> { item.route.map(function(item1,number){ return ( {item1.title} ); }) } ); } ) }
); } } const mapStateToProps = (state)=>({ list:state.common.list }) const mapDispatch = (dispath)=>{ return { initSliderList(){ let list=[] axios.get('getSliderList').then(res=>{ list = res.data.list dispath({ type:'init_slider_list', list:list }) }) } } } export default connect(mapStateToProps,mapDispatch)(withRouter(Leftsider));

commonReducer-reducer.js


const defaultState = {
    list:[]
}

export default function CommonReducer(state = defaultState,action){
    switch(action.type){
        case 'init_slider_list':
            return initSliderList(state,action);
        case 'reset_slider_list':
            return resetSliderList(state,action);
        default:
            return state
    }
}
const initSliderList=(state,action)=>{
    return {
        ...state,...{list:action.list}
    }
}

const resetSliderList=(state,action)=>{
    return {
        ...state,...{list:[]}
    }
}

到这里,前端部分结束,完成动态加载菜单

你可能感兴趣的:(web,react,java)