后台管理页面(bootdo)

项目源码:bootdo: 面向学习型的开源框架,简洁高效,减少过渡封装,展现技术本质

左边的菜单栏分析

数据库结构

样式实例 

 用树结构封装菜单数据,方便获取前后节点,通过自身id和父id相匹配,构建菜单。通过type确定类型,perms控制权限。

将菜单转换成树结构

import com.bootdo.common.domain.Tree;
import com.bootdo.common.utils.BuildTree;
import com.bootdo.system.dao.MenuDao;
import com.bootdo.system.dao.RoleMenuDao;
import com.bootdo.system.domain.MenuDO;
import com.bootdo.system.service.MenuService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
@Transactional(readOnly = true,rollbackFor = Exception.class)
public class MenuServiceImpl implements MenuService {
	@Autowired
	MenuDao menuMapper;
	@Autowired
	RoleMenuDao roleMenuMapper;

	/**
	 * @param
	 * @return 树形菜单  树结构方便获取父节点,子节点,节点属性
	 */
	@Cacheable
	@Override
	public Tree<MenuDO> getSysMenuTree(Long id) {
		List<Tree<MenuDO>> trees = new ArrayList<Tree<MenuDO>>();
		List<MenuDO> menuDOs = menuMapper.listMenuByUserId(id);
		for (MenuDO sysMenuDO : menuDOs) {
			Tree<MenuDO> tree = new Tree<MenuDO>();
			tree.setId(sysMenuDO.getMenuId().toString());
			tree.setParentId(sysMenuDO.getParentId().toString());
			tree.setText(sysMenuDO.getName());
			Map<String, Object> attributes = new HashMap<>(16);
			attributes.put("url", sysMenuDO.getUrl());
			attributes.put("icon", sysMenuDO.getIcon());
			tree.setAttributes(attributes);
			trees.add(tree);
		}
		// 默认顶级菜单为0,根据数据库实际情况调整
		Tree<MenuDO> t = BuildTree.build(trees);
		return t;
	}

	@Override
	public List<MenuDO> list(Map<String, Object> params) {
		List<MenuDO> menus = menuMapper.list(params);
		return menus;
	}

	// 开启事务,rollbackFor设置事务回滚的异常类型
	@Transactional(readOnly = false,rollbackFor = Exception.class)
	@Override
	public int remove(Long id) {
		int result = menuMapper.remove(id);
		return result;
	}
	@Transactional(readOnly = false,rollbackFor = Exception.class)
	@Override
	public int save(MenuDO menu) {
		int r = menuMapper.save(menu);
		return r;
	}

	@Transactional(readOnly = false,rollbackFor = Exception.class)
	@Override
	public int update(MenuDO menu) {
		int r = menuMapper.update(menu);
		return r;
	}

	@Override
	public MenuDO get(Long id) {
		MenuDO menuDO = menuMapper.get(id);
		return menuDO;
	}

	@Override
	public Tree<MenuDO> getTree() {
		List<Tree<MenuDO>> trees = new ArrayList<Tree<MenuDO>>();
		List<MenuDO> menuDOs = menuMapper.list(new HashMap<>(16));
		for (MenuDO sysMenuDO : menuDOs) {
			Tree<MenuDO> tree = new Tree<MenuDO>();
			tree.setId(sysMenuDO.getMenuId().toString());
			tree.setParentId(sysMenuDO.getParentId().toString());
			tree.setText(sysMenuDO.getName());
			trees.add(tree);
		}
		// 默认顶级菜单为0,根据数据库实际情况调整
		Tree<MenuDO> t = BuildTree.build(trees);
		return t;
	}

	@Override
	public Tree<MenuDO> getTree(Long id) {
		// 根据roleId查询权限
		List<MenuDO> menus = menuMapper.list(new HashMap<String, Object>(16));
		List<Long> menuIds = roleMenuMapper.listMenuIdByRoleId(id);
		List<Long> temp = menuIds;
		for (MenuDO menu : menus) {
			if (temp.contains(menu.getParentId())) {
				menuIds.remove(menu.getParentId());
			}
		}
		List<Tree<MenuDO>> trees = new ArrayList<Tree<MenuDO>>();
		List<MenuDO> menuDOs = menuMapper.list(new HashMap<String, Object>(16));
		for (MenuDO sysMenuDO : menuDOs) {
			Tree<MenuDO> tree = new Tree<MenuDO>();
			tree.setId(sysMenuDO.getMenuId().toString());
			tree.setParentId(sysMenuDO.getParentId().toString());
			tree.setText(sysMenuDO.getName());
			Map<String, Object> state = new HashMap<>(16);
			Long menuId = sysMenuDO.getMenuId();
			if (menuIds.contains(menuId)) {
				state.put("selected", true);
			} else {
				state.put("selected", false);
			}
			tree.setState(state);
			trees.add(tree);
		}
		// 默认顶级菜单为0,根据数据库实际情况调整
		Tree<MenuDO> t = BuildTree.build(trees);
		return t;
	}

	@Override
	public Set<String> listPerms(Long userId) {
		List<String> perms = menuMapper.listUserPerms(userId);
		Set<String> permsSet = new HashSet<>();
		for (String perm : perms) {
			if (StringUtils.isNotBlank(perm)) {
				permsSet.addAll(Arrays.asList(perm.trim().split(",")));
			}
		}
		return permsSet;
	}

	@Override
	public List<Tree<MenuDO>> listMenuTree(Long id) {
		List<Tree<MenuDO>> trees = new ArrayList<Tree<MenuDO>>();
		List<MenuDO> menuDOs = menuMapper.listMenuByUserId(id);
		for (MenuDO sysMenuDO : menuDOs) {
			Tree<MenuDO> tree = new Tree<MenuDO>();
			tree.setId(sysMenuDO.getMenuId().toString());
			tree.setParentId(sysMenuDO.getParentId().toString());
			tree.setText(sysMenuDO.getName());
			Map<String, Object> attributes = new HashMap<>(16);
			attributes.put("url", sysMenuDO.getUrl());
			attributes.put("icon", sysMenuDO.getIcon());
			tree.setAttributes(attributes);
			trees.add(tree);
		}
		// 默认顶级菜单为0,根据数据库实际情况调整
		List<Tree<MenuDO>> list = BuildTree.buildList(trees, "0");
		return list;
	}

}

关于@Transactional

后台管理页面源码

整个页面通过页面嵌套组成,由index_v1.html和main.html组成

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="renderer" content="webkit">
    <title>面向学习型的开源框架,简洁高效,减少过渡封装,展现技术本质</title>
    <meta name="keywords" content="面向学习型的开源框架,简洁高效,杜绝过渡封装,展现技术本质本质">
    <meta name="description" content="面向学习型的开源框架,简洁高效,杜绝过渡封装,展现技术本质本质">
    <!--[if lt IE 9]>
    <meta http-equiv="refresh" content="0;ie.html"/>
    <![endif]-->
    <link rel="shortcut icon" href="favicon.ico">
    <link href="/css/bootstrap.min.css?v=3.3.6" rel="stylesheet">
    <link href="/css/font-awesome.min.css?v=4.4.0" rel="stylesheet">
    <link href="/css/plugins/toastr/toastr.min.css" rel="stylesheet">
    <link href="/css/animate.css" rel="stylesheet">
    <link href="/css/style.css?v=4.1.0" rel="stylesheet">
</head>
<body class="fixed-sidebar full-height-layout gray-bg"
      style="overflow: hidden">
<div id="wrapper">
    <!--左侧导航开始-->
    <nav class="navbar-default navbar-static-side" role="navigation">
        <div class="nav-close">
            <i class="fa fa-times-circle"></i>
        </div>
        <div class="sidebar-collapse">
            <ul class="nav" id="side-menu">
                <li class="nav-header">
                    <div>
                        <span><img alt="image" class="img-circle" height="60" width="60" th:src="${picUrl}"/></span>
                        <h3 class="" style="color: #ffffff">
                            </i>BootDo后台管理系统
                        </h3>
                    </div>
                    <div class="dropdown profile-element hidden">

                        <a data-toggle="dropdown" class="dropdown-toggle" href="#">
                            <span class="clear">
                            <span class="block m-t-xs"><strong class="font-bold"
                                                               th:text="${username}">admin</strong></span>
                            <span class="text-muted text-xs block">超级管理员<b class="caret"></b></span>
                             </span>
                        </a>
                        <ul class="dropdown-menu animated fadeInRight m-t-xs">
                            <li><a @click="personal" href="#">修改头像</a>
                            </li>
                            <li><a @click="personal" href="#">个人资料</a>
                            </li>
                            <li><a @click="personal" href="#">密码修改</a>
                            </li>
                            <li><a @click="personal" href="#">信箱</a>
                            </li>
                            <li class="divider"></li>
                            <li><a href="/logout">安全退出</a>
                            </li>
                        </ul>
                        <div class="logo-element">BootDo</div>
                    </div>
                </li>
                <li><a href="#"> <i class="fa fa-home"></i> <span
                        class="nav-label">主页</span> <span class="fa arrow"></span>
                </a>
                    <ul class="nav nav-second-level">
                        <li><a id="index001" class="J_menuItem" href="index_v1.html"
                               data-index="0" th:href="@{/main}">了解BootDo</a></li>
                    </ul>
                </li>
                <li th:each="menu : ${menus}"><a href="#"> <i
                        class="fa fa fa-bar-chart-o" th:class="${menu.attributes.icon}"></i>
                    <span class="nav-label" th:text="${menu.text}">基础信息</span> <span
                            class="fa arrow"></span>
                </a>
                    <ul class="nav nav-second-level">
                        <li th:each="cmenu : ${menu.children}"><a class="J_menuItem" href="graph_echarts.html"
                                                                  th:text="${cmenu.text}"
                                                                  th:href="${cmenu.attributes.url}">系统管理</a></li>
                    </ul>
                </li>
            </ul>
        </div>
    </nav>
    <!--左侧导航结束-->
    <!--右侧部分开始-->
    <div id="page-wrapper" class="gray-bg dashbard-1">
        <div class="row border-bottom">
            <nav class="navbar navbar-static-top" role="navigation"
                 style="margin-bottom: 0">
                <div class="navbar-header">

                    <a class="navbar-minimalize minimalize-styl-2 btn btn-default "
                       href="#" title="收起菜单"><i class="fa fa-bars"></i> </a>
                    <form role="search" class="navbar-form-custom"
                          method="post" action="">
                        <div class="form-group">
                            <input type="text" placeholder="请输入您需要查找的内容 …"
                                   class="form-control" name="top-search" id="top-search">
                        </div>
                    </form>
                </div>
                <ul class="nav navbar-top-links navbar-right">
                    <li class="hidden-xs"><a href="/blog" target="_Blank"
                                             class=""><i class="fa fa-rss-square"></i>博客</a></li>
                    <li class="dropdown"><a class="dropdown-toggle count-info"
                                            data-toggle="dropdown" href="#"> <i class="fa fa-envelope"></i>
                        <span class="label label-warning">{{total}}</span>通知
                    </a>
                        <ul class="dropdown-menu dropdown-messages">
                            <li v-for="row in rows" class="m-t-xs">
                                <div class="dropdown-messages-box">
                                    <a class="pull-left"> <i
                                            class="fa fa-server"></i>
                                    </a>
                                    <div class="media-body">
                                        <small class="pull-right">{{row.before}}</small>
                                        <strong>{{row.sender}}</strong>
                                        {{row.title}} <br>
                                        <small class="text-muted">{{row.updateDate}}</small>
                                    </div>
                                </div>
                                <div class="divider"></div>
                            </li>
                            <li>
                                <div class="text-center link-block">
                                    <a class="J_menuItem" href="/oa/notify/selfNotify"> <i
                                            class="fa fa-envelope"></i> <strong> 查看所有消息</strong>
                                    </a>
                                </div>
                            </li>
                        </ul>
                    </li>
                    <li class="hidden-xs"><a @click="personal" href="#" ><i class="fa fa-id-card"></i> 个人</a></li>
                    <li class="dropdown hidden-xs"><a
                            class="right-sidebar-toggle" aria-expanded="false"> <i
                            class="fa fa-tasks"></i> 主题
                    </a></li>
                </ul>
            </nav>
        </div>
        <div class="row content-tabs">
            <button class="roll-nav roll-left J_tabLeft">
                <i class="fa fa-backward"></i>
            </button>
            <nav class="page-tabs J_menuTabs">
                <div class="page-tabs-content">
                    <a href="javascript:;" class="active J_menuTab"
                       data-id="index_v1.html">首页</a>
                </div>
            </nav>
            <button class="roll-nav roll-right J_tabRight">
                <i class="fa fa-forward"></i>
            </button>
            <div class="btn-group roll-nav roll-right">
                <button class="dropdown J_tabClose" data-toggle="dropdown">
                    关闭操作<span class="caret"></span>
                </button>
                <ul role="menu" class="dropdown-menu dropdown-menu-right">
                    <li class="J_tabShowActive"><a>定位当前选项卡</a></li>
                    <li class="divider"></li>
                    <li class="J_tabCloseAll"><a>关闭全部选项卡</a></li>
                    <li class="J_tabCloseOther"><a>关闭其他选项卡</a></li>
                </ul>
            </div>
            <a href="/logout" class="roll-nav roll-right J_tabExit"><i
                    class="fa fa fa-sign-out"></i> 退出</a>
        </div>
        <div class="row J_mainContent" id="content-main">
            <iframe class="J_iframe" name="iframe0" width="100%" height="100%"
                    src="" th:src="@{/main}" frameborder="0" data-id="index_v1.html"
                    seamless></iframe>
        </div>
        <div class="footer">
            <div class="pull-right">BootDo面向学习型的开源框架</div>
        </div>
    </div>
    <!--右侧部分结束-->
    <!--右侧边栏开始-->
    <div id="right-sidebar">
        <div class="sidebar-container">
            <ul class="nav nav-tabs navs-3">

                <li class="active"><a data-toggle="tab" href="#tab-1"> <i
                        class="fa fa-gear"></i> 主题
                </a></li>
                <li class=""><a data-toggle="tab" href="#tab-2"> 通知 </a></li>
                <li><a data-toggle="tab" href="#tab-3"> 项目进度 </a></li>
            </ul>
            <div class="tab-content">
                <div id="tab-1" class="tab-pane active">
                    <div class="sidebar-title">
                        <h3>
                            <i class="fa fa-comments-o"></i> 主题设置
                        </h3>
                        <small><i class="fa fa-tim"></i>
                            你可以从这里选择和预览主题的布局和样式,这些设置会被保存在本地,下次打开的时候会直接应用这些设置。
                        </small>
                    </div>
                    <div class="skin-setttings">
                        <div class="title">主题设置</div>
                        <div class="setings-item">
                            <span>收起左侧菜单</span>
                            <div class="switch">
                                <div class="onoffswitch">
                                    <input type="checkbox" name="collapsemenu"
                                           class="onoffswitch-checkbox" id="collapsemenu"> <label
                                        class="onoffswitch-label" for="collapsemenu"> <span
                                        class="onoffswitch-inner"></span> <span
                                        class="onoffswitch-switch"></span>
                                </label>
                                </div>
                            </div>
                        </div>
                        <div class="setings-item">
                            <span>固定顶部</span>

                            <div class="switch">
                                <div class="onoffswitch">
                                    <input type="checkbox" name="fixednavbar"
                                           class="onoffswitch-checkbox" id="fixednavbar"> <label
                                        class="onoffswitch-label" for="fixednavbar"> <span
                                        class="onoffswitch-inner"></span> <span
                                        class="onoffswitch-switch"></span>
                                </label>
                                </div>
                            </div>
                        </div>
                        <div class="setings-item">
                            <span> 固定宽度 </span>
                            <div class="switch">
                                <div class="onoffswitch">
                                    <input type="checkbox" name="boxedlayout"
                                           class="onoffswitch-checkbox" id="boxedlayout"> <label
                                        class="onoffswitch-label" for="boxedlayout"> <span
                                        class="onoffswitch-inner"></span> <span
                                        class="onoffswitch-switch"></span>
                                </label>
                                </div>
                            </div>
                        </div>
                        <div class="title">皮肤选择</div>
                        <div class="setings-item default-skin nb">
								<span class="skin-name "> <a href="#" class="s-skin-0">
										默认皮肤 </a>
								</span>
                        </div>
                        <div class="setings-item blue-skin nb">
								<span class="skin-name "> <a href="#" class="s-skin-1">
										蓝色主题 </a>
								</span>
                        </div>
                        <div class="setings-item yellow-skin nb">
								<span class="skin-name "> <a href="#" class="s-skin-3">
										黄色/紫色主题 </a>
								</span>
                        </div>
                    </div>
                </div>
                <div id="tab-2" class="tab-pane">

                    <div class="sidebar-title">
                        <h3>
                            <i class="fa fa-comments-o"></i> 最新通知
                        </h3>
                        <small><i class="fa fa-tim"></i> 您当前有10条未读信息</small>
                    </div>
                </div>
                <div id="tab-3" class="tab-pane">

                    <div class="sidebar-title">
                        <h3>
                            <i class="fa fa-cube"></i> 最新任务
                        </h3>
                        <small><i class="fa fa-tim"></i> 您当前有14个任务,10个已完成</small>
                    </div>
                </div>
            </div>

        </div>
    </div>
</div>
<!-- 全局js -->
<script src="/js/jquery.min.js?v=2.1.4"></script>
<script src="/js/bootstrap.min.js?v=3.3.6"></script>
<script src="/js/plugins/metisMenu/jquery.metisMenu.js"></script>
<script src="/js/plugins/slimscroll/jquery.slimscroll.min.js"></script>
<script src="/js/plugins/layer/layer.min.js"></script>
<!-- 自定义js -->
<script src="/js/app.js?v=4.1.0"></script>
<script type="text/javascript" src="/js/contabs.js"></script>
<!-- 第三方插件 -->
<script src="/js/plugins/pace/pace.min.js"></script>
<!-- vue -->
<script type="text/javascript"
        src="/js/vue.min.js">

</script>
<script src="/js/appjs/oa/webSocket/sockjs.min.js"></script>
<script src="/js/appjs/oa/webSocket/stomp.min.js"></script>
<!-- Toastr script -->
<script src="/js/plugins/toastr/toastr.min.js"></script>
<script type="text/javascript">
    var stompClient = null;
    $(function () {
        connect();
    });

    function connect() {
        var sock = new SockJS("/endpointChat");
        var stomp = Stomp.over(sock);
        stomp.connect('guest', 'guest', function(frame) {

            /**
 订阅了/user/queue/notifications 发送的消息,这里雨在控制器的 convertAndSendToUser 定义的地址保持一致,

             *  这里多用了一个/user,并且这个user 是必须的,使用user 才会发送消息到指定的用户。

             *  */
            stomp.subscribe("/user/queue/notifications", handleNotification);
            stomp.subscribe('/topic/getResponse', function (response) { //订阅/topic/getResponse 目标发送的消息。这个是在控制器的@SendTo中定义的。
                toastr.options = {
                    "closeButton": true,
                    "debug": false,
                    "progressBar": true,
                    "positionClass": "toast-bottom-right",
                    "onclick": null,
                    "showDuration": "400",
                    "hideDuration": "1000",
                    "timeOut": "7000",
                    "extendedTimeOut": "1000",
                    "showEasing": "swing",
                    "hideEasing": "linear",
                    "showMethod": "fadeIn",
                    "hideMethod": "fadeOut"
                }
                toastr.info(JSON.parse(response.body).responseMessage);
            });
        });
        function handleNotification(message) {
            wrapper.notify();
            toastr.info(message.body);
        }
    }

    var wrapper = new Vue({
        el: '#wrapper',
        data: {
            total: '',
            rows: '',
        },
        methods: {
            notify: function () {
                $.getJSON('/oa/notify/message', function (r) {
                    wrapper.total = r.total;
                    wrapper.rows = r.rows;
                });
            },
            personal: function () {
                layer.open({
                    type: 2,
                    title: '个人设置',
                    maxmin: true,
                    shadeClose: false,
                    area: ['800px', '600px'],
                    content: '/sys/user/personal'
                });
            }
        },
        created: function () {
            this.notify()
        }
    })
</script>
</body>
</html>

嵌套

        <div class="row J_mainContent" id="content-main">
            <iframe class="J_iframe" name="iframe0" width="100%" height="100%"
                    src="" th:src="@{/main}" frameborder="0" data-id="index_v1.html"
                    seamless></iframe>
        </div>

了解链接

关于sockjs即时通信:SockJS实践:即时通信关键点 - 简书

关于iframe页面嵌套:Web前端之iframe详解 - 滥好人 - 博客园

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
授权方式: 开源软件 界面语言: 简体中文 文件大小: 12.3 MB 更新时间: 2020-08-12 资源类型: 国产软件 推荐等级: ★★★☆☆ 平台环境: JAVA 作者主页: 点击查看 演示地址: 点击查看 详细介绍 – [ BootDo后台管理系统 v1.0 ] BootDo 是高效率,低封装,面向学习型,面向微服的开源JavaEE开发框架。 BootDo是在SpringBoot基础上搭建的一个Java基础开发平台,MyBatis为数据访问层,ApacheShiro为权限授权层,Ehcahe对常用数据进行缓存。 BootDo主要定位于后台管理系统学习交流,已内置后台管理系统的基础功能和高效的代码生成工具,包括:系统权限组件、数据权限组件、数据字典组件、核心工具组件、视图操作组件、工作流组件、代码生成等。前端界面风格采用了结构简单、性能优良、页面美观大气的TwitterBootstrap页面展示框架。采用分层设计、双重验证、提交数据安全编码、密码加密、访问验证、数据权限验证。使用Maven做项目管理,提高项目的易开发性、扩展性。 BootDo目前包括以下四大模块,系统管理(SYS)模块、内容管理(CMS)模块、在线办公(OA)模块、代码生成(GEN)模块。系统管理模块,包括企业组织架构(用户管理、机构管理、区域管理)、菜单管理、角色权限管理、字典管理等功能;内容管理模块,包括内容管理(文章、链接),栏目管理、站点管理、公共留言、文件管理、前端网站展示等功能;在线办公模块,提供简单的请假流程实例;代码生成模块,完成重复的工作。 BootDo提供了常用工具进行封装,包括日志工具、缓存工具、服务器端验证、数据字典、当前组织机构数据(用户、机构、区域)以及其它常用小工具等。另外还提供一个强大的在线代码生成工具。 BootDo内置功能 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 机构管理:配置系统组织机构(公司、部门、小组),树结构展现,可随意调整上下级。 区域管理:系统城市区域模型,如:国家、省市、地市、区县的维护。 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 字典管理:对系统中经常使用的一些较为固定的数据进行维护,如:是否、男女、类别、级别等。 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 连接池监视:监视当期系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 工作流引擎:实现业务工单流转、在线流程设计器。 BootDo截图 相关阅读 同类推荐: 站长常用源码

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值