AdminLTE是一个优秀的bootstrap框架,前端展现很美观,是个github的开源项目,demo的地址为:https://almsaeedstudio.com/preview 说明文档的地址为:https://almsaeedstudio.com/themes/AdminLTE/documentation/index.html
AdminLTE每个页面都是单独存在的,头部和左边菜单是重复的,需要进行框架改造。
最近在研究使用AdminLTE框架化,本文讲解使用sitemesh3使AdminLTE框架化的过程。系统架构为:SpringMVC+Spring+Hibernate+Maven+FreeMarker+Sitemesh(本项目集成并二次开发了许多bootstrap组件,目前正在持续开发中,将会在10.1之前完成所有的框架功能)
先看一下实现的效果图:
用户列表:
用户编辑:
字典管理:
图标选择器:
回到正题,下面详细讲解sitemesh3在这个项目上的使用:(sitemesh3的配置可参考本人上篇博客)
1、Maven中引入Sitemesh3
<dependency> <groupId>org.sitemesh</groupId> <artifactId>sitemesh</artifactId> <version>3.0.0</version> </dependency>
2、web.xml中配置sitemesh3过滤器
<filter> <filter-name>sitemesh</filter-name> <filter-class>org.sitemesh.config.ConfigurableSiteMeshFilter</filter-class> </filter> <filter-mapping> <filter-name>sitemesh</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3、在web.xml的同级目录配置sitemesh3.xml
<?xml version="1.0" encoding="UTF-8"?> <sitemesh> <mapping path="/*" decorator="/decorator"></mapping> <mapping path="/*/*edit" exclue="true"></mapping> <!-- <mapping path="/*/*addUpdate" exclue="true"></mapping> <mapping path="/*/*add" exclue="true"></mapping> <mapping path="/*/*update" exclue="true"></mapping> --> <mapping path="/resources/*" exclue="true" /> <mapping path="/*/nodecorator/*" exclue="true"/> <mapping path="/nodecorator/*" exclue="true"/> <!-- 自定义 tag 规则 --> <!-- Sitemesh 3 默认只提供了 body,title,head 等 tag 类型,我们可以通过实现 TagRuleBundle 扩展自定义的 tag 规则: --> <content-processor> <tag-rule-bundle class="com.cnpc.framework.tags.CSSTagRuleBundle" /> <tag-rule-bundle class="com.cnpc.framework.tags.ScriptTagRuleBundle" /> </content-processor> </sitemesh>
上面定义了两个自定义标签,主要是将子页面的样式和脚本渲染到装饰页面
CSSTagRuleBundle.java
package com.cnpc.framework.tags; import org.sitemesh.SiteMeshContext; import org.sitemesh.content.ContentProperty; import org.sitemesh.content.tagrules.TagRuleBundle; import org.sitemesh.content.tagrules.html.ExportTagToContentRule; import org.sitemesh.tagprocessor.State; public class CSSTagRuleBundle implements TagRuleBundle { @Override public void install(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) { defaultState.addRule("myCSS", new ExportTagToContentRule(siteMeshContext, contentProperty.getChild("myCSS"), false)); } @Override public void cleanUp(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) { // TODO Auto-generated method stub } }
ScriptTagRuleBundle.java
package com.cnpc.framework.tags; import org.sitemesh.SiteMeshContext; import org.sitemesh.content.ContentProperty; import org.sitemesh.content.tagrules.TagRuleBundle; import org.sitemesh.content.tagrules.html.ExportTagToContentRule; import org.sitemesh.tagprocessor.State; public class ScriptTagRuleBundle implements TagRuleBundle { @Override public void install(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) { defaultState.addRule("myScript", new ExportTagToContentRule(siteMeshContext, contentProperty.getChild("myScript"), false)); } @Override public void cleanUp(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) { // TODO Auto-generated method stub } }
4、其中/decorator跳转的路径
@RequestMapping(method = RequestMethod.GET, value = "/decorator") public String decorator(HttpServletRequest request) { return "decorator"; }
decorator.html即为“母版页”,其代码如下,请主要下面<sitemesh:write 部分
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>AdminLTE | <span style="color:#FF0000;"> <sitemesh:write property='title' /></span></title> <!-- Tell the browser to be responsive to screen width --> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <!-- --> <link rel="shortcut icon" type="image/ico" href="http://www.datatables.net/favicon.ico" media="screen"> <!-- <link rel="shortcut icon" type="image/x-icon" href="${basePath}/resources/adminlte/base/img/ysd.ico" media="screen" />--> <!-- Bootstrap 3.3.6 --> <link rel="stylesheet" href="${basePath}/resources/adminlte/bootstrap/css/bootstrap.min.css"> <!-- Font Awesome --> <link rel="stylesheet" href="${basePath}/resources/adminlte/css/font-awesome.min.css"> <!-- Ionicons --> <link rel="stylesheet" href="${basePath}/resources/adminlte/css/ionicons.min.css"> <!-- Theme style --> <link rel="stylesheet" href="${basePath}/resources/adminlte/dist/css/AdminLTE.min.css"> <!-- AdminLTE Skins. Choose a skin from the css/skins folder instead of downloading all of them to reduce the load. --> <link rel="stylesheet" href="${basePath}/resources/adminlte/dist/css/skins/_all-skins.min.css"> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> <!-- 加入页面的样式 --> <span style="color:#FF0000;"> <sitemesh:write property='myCSS' /></span> </head> <body class="hold-transition skin-blue sidebar-mini"> <div class="wrapper"> <header class="main-header"> <!-- Logo --> <a href="${basePath}/main" class="logo"> <!-- mini logo for sidebar mini 50x50 pixels --> <span class="logo-mini"> <b>A</b>LT</span> <!-- logo for regular state and mobile devices --> <span class="logo-lg"> <b>Admin</b>LTE</span> </a> <!-- Header Navbar: style can be found in header.less --> <nav class="navbar navbar-static-top"> <!--此处为顶部导航功能 代码略--> </nav> </header> <!-- Left side column. contains the logo and sidebar --> <aside class="main-sidebar"> <!--此处为左部菜单功能 代码略--></aside> <!-- Content Wrapper. Contains page content --> <div class="content-wrapper"> <sitemesh:write property='body' /></div> <!-- /.content-wrapper --> <footer class="main-footer"> <!--此处为底部版权声明功能 代码略--> </footer> <!-- Control Sidebar --> <aside class="control-sidebar control-sidebar-dark"> <!--此处为右侧浮动配置功能 代码略--> </aside> <!-- /.control-sidebar --> <!-- Add the sidebar's background. This div must be placed immediately after the control sidebar --> <div class="control-sidebar-bg"></div> </div> <!-- ./wrapper --> <script type="text/javascript">var basePath = "${basePath}"; //给外部js文件传递路径参数 </script> <!-- jQuery 2.2.0 --> <script src="${basePath}/resources/adminlte/plugins/jQuery/jQuery-2.2.0.min.js"></script> <!-- Bootstrap 3.3.6 --> <script src="${basePath}/resources/adminlte/bootstrap/js/bootstrap.min.js"></script> <!-- FastClick --> <script src="${basePath}/resources/adminlte/plugins/fastclick/fastclick.js"></script> <!-- AdminLTE App --> <script src="${basePath}/resources/adminlte/dist/js/app.min.js"></script> <!-- Sparkline --> <!-- AdminLTE for demo purposes --> <script src="${basePath}/resources/adminlte/dist/js/demo.js"></script> <script type="text/javascript" src="${basePath}/resources/common/js/base.js"></script> <script type="text/javascript" src="${basePath}/resources/common/js/base-modal.js"></script> <!-- 加入页面的的脚本 --> <sitemesh:write property='myScript' /></body> </html>
5、一个“子页面”的配置,如用户管理列表界面 user_list.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>用户列表</title> <!-- Tell the browser to be responsive to screen width --> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <!-- Bootstrap 3.3.6 --> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> <myCSS> <link rel="stylesheet" href="${basePath}/resources/adminlte/plugins/datatables/dataTables.bootstrap.css"> <link rel="stylesheet" href="${basePath}/resources/adminlte/plugins/datatables/select.bootstrap.min.css"> <link rel="stylesheet" href="${basePath}/resources/adminlte/plugins/bootstrap-validator/dist/css/bootstrap-validator.css"/> <link rel="stylesheet" href="${basePath}/resources/adminlte/plugins/iCheck/all.css"> <link rel="stylesheet" href="${basePath}/resources/adminlte/plugins/datepicker/datepicker3.css"> </myCSS> </head> <body class="hold-transition skin-blue sidebar-mini"> <!-- Content Header (Page header) --> <section class="content-header"> <h1> 用户管理 <small>列表</small> </h1> <ol class="breadcrumb"> <li><a href="#"><i class="fa fa-dashboard"></i> 首页</a></li> <li><a href="#">系统管理</a></li> <li class="active">用户管理</li> </ol> </section> <!-- Main content --> <section class="content"> <div class="row"> <div class="col-xs-12"> <div class="box"> <!-- /.box-header --> <div class="dataTables_filter" id="searchDiv"> <input placeholder="请输入姓名" name="name" class="form-control" type="search" likeOption="true" /> <input placeholder="请输入登录名" name="loginName" class="form-control" type="search" likeOption="true" /> <div class="btn-group"> <button type="button" class="btn btn-primary" action_type="search">查询</button> <button type="button" class="btn btn-default" action_type="reset">重置</button> </div> <div class="btn-group"> <button type="button" class="btn btn-default" action_type="add">新增</button> <button type="button" class="btn btn-default" action_type="edit" >编辑</button> <button type="button" class="btn btn-default" action_type="delete">删除</button> </div> </div> <div class="box-body"> <table id="user_table" class="table table-bordered table-striped table-hover"> </table> </div> <!-- /.box-body --> </div> </div> <!-- /.col --> </div> <!-- /.row --> </section> <myScript> <script src="${basePath}/resources/adminlte/plugins/datatables/jquery.dataTables.js"></script> <script src="${basePath}/resources/adminlte/plugins/datatables/dataTables.bootstrap.min.js"></script> <script src="${basePath}/resources/common/js/dataTables.js"></script> <!-- form --> <script src="${basePath}/resources/adminlte/plugins/bootstrap-validator/dist/js/bootstrap-validator.js"></script> <script src="${basePath}/resources/adminlte/plugins/iCheck/icheck.min.js"></script> <script src="${basePath}/resources/adminlte/plugins/datepicker/bootstrap-datepicker.js"></script> <script> //tableId,queryId,conditionContainer var userTable; var winId="userWin"; $(function() { //init table and fill data userTable = new CommonTable("user_table", "user_list", "searchDiv"); //button event $('button[action_type]').click(function() { var action = $(this).attr('action_type'); var rowId=userTable.getSelectedRowId(); switch (action) { case 'add': modals.openWin({ winId:winId, title:'新增用户', top:'auto', width:'900px', url:basePath+"/user/edit" /*, hideFunc:function(){ modals.info("hide me"); }, showFunc:function(){ modals.info("show me"); } */ }); break; case 'edit': if(!rowId){ modals.info('请选择要编辑的行'); return false; } modals.openWin({ winId:winId, title:'编辑用户【'+userTable.getSelectedRowData().name+'】', top:'auto', width:'900px', url:basePath+"/user/edit?id="+rowId }); break; case 'delete': if(!rowId){ modals.info('请选择要删除的行'); return false; } modals.confirm("是否要删除该行数据?",function(){ ajaxPost(basePath+"/user/delete/"+rowId,null,function(data){ if(data.success){ //modals.correct("已删除该数据"); userTable.reloadRowData(); } }); }) break; } }); //form_init(); }) </script> </myScript> </body> </html>
以上过程完成了AdminLTE的框架化,但是存在一个性能问题,即每次需要访问/decorator路径,会重置顶部导航和左侧菜单,导致不能记住顶部导航和左侧当前菜单。后续可能不会使用Sitemesh3,可能会用jquery 的load方法。
当然有人说,sitemesh3太折腾了,用iframe不就可以吗?确实可以,但iframe的高度自适应的问题是在太恶心了,也存在一些其他问题。