1. 首先在在web.xml文件中,加入SiteMesh和shiro的过滤器,保证SiteMesh的过滤器配置放在shiro的过滤器后面,不然的话,shiro的标签不能正确处理。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <display-name>ems</display-name> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:config/spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:config/applicationContext.xml</param-value> </context-param> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- shiro 安全过滤器 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <async-supported>true</async-supported> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <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> <session-config> <session-timeout>30</session-timeout> <!-- 单位:分钟 --> </session-config> </web-app>
2. pom.xml中引入sitemesh的依赖
<dependency> <groupId>org.sitemesh</groupId> <artifactId>sitemesh</artifactId> <version>3.0.1</version> </dependency>
3. 在WEB-INF下加入sitemesh的配置文件(sitemesh3.xml):
<?xml version="1.0" encoding="UTF-8"?> <sitemesh> <!-- Map default decorator. This shall be applied to all paths if no other paths match. --> <mapping path="/*" decorator="/main.jsp" exclude="false" /> <!-- Exclude path from decoration. --> <mapping path="/js/*" exclude="true" /> <mapping path="/img/*" exclude="true" /> <mapping path="/images/*" exclude="true" /> <mapping path="/css/*" exclude="true" /> <mapping path="/font-awesome/*" exclude="true" /> <mapping path="/login" exclude="true" /> <mapping path="/login.jsp" exclude="true" /> </sitemesh>
main.jsp 为模板页面,<mapping exlude /> 表示不经过sitemesh处理的资源和页面。
4. 模板页面的书写
在模板页面中可以使用下面的标签作为占位符:
<sitemesh:write property='title' />
<sitemesh:write property='head' />
<sitemesh:write property='body' />
被装饰的页面,可以使用自己页面中的对应部分(title, head, body),填充在这些标签的位置。
下面看一个模板页面的例子:
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %> <%@ taglib prefix="s" uri="http://www.springframework.org/tags" %> <!DOCTYPE html> <html> <head> <title><sitemesh:write property='title' /></title> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.min.css" /> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap-responsive.min.css" /> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/fullcalendar.css" /> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/matrix-login.css" /> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/matrix-style.css" /> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/matrix-media.css" /> <link rel="stylesheet" href="${pageContext.request.contextPath}/font-awesome/css/font-awesome.css" /> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/jquery.gritter.css" /> <link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Open+Sans:400,700,800' /> <style type="text/css"> #top_header{ margin-left:80px; margin-right:80px; padding-top:9px; font-size:30px; display:block; width:500px; } #top_logout{ margin-right:2px; } #cur_user{ margin-top:9px; display:block; } .tc{ background-color:#e6e6e6; border:#016574 2px solid; display:none; position:fixed; top:39%; left:40%; -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; padding:19px 35px; font-size:14px; } </style> <sitemesh:write property='head' /> </head> <body> <!--Header-part--> <div id="header"> <h1><a href="javascript:;">Admin</a></h1> </div> <!--close-Header-part--> <!--top-Header-menu--> <div id="user-nav" class="navbar navbar-inverse"> <ul class="nav"> <li class=""><span id="top_header">XXX系统</span></li> <li><span id="cur_user">当前登陆用户:${user.username}</span></li> <li id="top_logout" style="float:right;"><a title="" href="/ems/logout"><i class="icon icon-share-alt"></i> <span class="text">Logout</span></a></li> </ul> </div> <!--close-top-Header-menu--> <!--sidebar-menu--> <div id="sidebar"><a href="javascript:;" class="visible-phone"><i class="icon icon-home"></i> Dashboard</a> <ul> <shiro:hasAnyRoles name="student,teacher"> <li id="li_queryScore"><a href="/ems/user/queryScore"><i class="icon icon-home"></i><span>查询成绩</span></a></li> </shiro:hasAnyRoles> <shiro:hasAnyRoles name="teacher,admin"> <li id="li_showStudentInfo"><a href="/ems/student/showStudentInfo"><i class="icon icon-home"></i><span>查询学生信息</span></a></li> </shiro:hasAnyRoles> <shiro:hasAnyRoles name="admin"> <li id="li_showTeacherInfo"><a href="/ems/teacher/showTeacherInfo"><i class="icon icon-home"></i><span>查询教师信息</span></a></li> </shiro:hasAnyRoles> <shiro:hasAnyRoles name="teacher,admin"> <li><a href="/ems/html/tables.html"><i class="icon icon-th"></i><span>统计</span></a></li> </shiro:hasAnyRoles> <shiro:hasAnyRoles name="student,teacher,admin"> <li><a href="/ems/html/grid.html"><i class="icon icon-fullscreen"></i><span>打印</span></a></li> <li id="li_password"><a href="/ems/user/password"><i class="icon icon-inbox"></i><span>密码修改</span></a> </li> </shiro:hasAnyRoles> <shiro:hasRole name="admin"> <li id="li_showPrivilege"><a href="/ems/priv/showPrivilege"><i class="icon icon-fullscreen"></i><span>权限设置</span></a></li> </shiro:hasRole> <shiro:hasAnyRoles name="teacher,admin"> <li id="li_setting"><a href="/ems/set/setting"><i class="icon icon-tint"></i><span>成绩比例和录入设置</span></a></li> </shiro:hasAnyRoles> <shiro:hasAnyRoles name="student,teacher"> <li id="li_queryReExam"><a href="/ems/user/queryReExam"><i class="icon icon-pencil"></i><span>补考名单</span></a></li> <li id="li_queryReLearn"><a href="/ems/user/queryReLearn"><i class="icon icon-pencil"></i><span>重修名单</span></a></li> </shiro:hasAnyRoles> </ul> </div> <!--sidebar-menu--> <!--main-container-part--> <sitemesh:write property='body' /> <!-- end-Footer-part --> </body> </html>
上面的模板页面使用了:<sitemesh:write property='title' />, <sitemesh:write property='head' />,<sitemesh:write property='body' />
然后我们看下被装饰的页面:
<%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <title>index</title> </head> <body> <!--main-container-part--> <div id="content"> <!--breadcrumbs--> <div id="content-header"> <div id="breadcrumb"> <a href="tables.html" title="Go to Home" class="tip-bottom"><i class="icon-home"></i> Home</a></div> </div> <!--End-breadcrumbs--> <!--Action boxes--> <div class="container-fluid"> <shiro:hasAnyRoles name="student,teacher"> <input type="hidden" name="user_type" id="user_type" value="${user.userType}" /> 学年:<select id="learn_time" name="learn_time"> <option value="2014">2014</option> <option value="2015" selected = "selected">2015</option> <option value="2016">2016</option> <option value="2017">2017</option> </select> 学期:<input type="radio" name="which_term" value="1" />上学期 <input type="radio" name="which_term" value="2" />下学期 </shiro:hasAnyRoles> <c:if test="${user.userType == '1'}"> <input type="button" value="查询" id="queryScoreForStudent"/> </c:if> <c:if test="${user.userType == '2'}"> <br/> 班级:<input type="text" name="className" id="class_name" /> 课程: <select id="course_type_select" name="courseId"> <c:forEach items="${courseList }" var="course" varStatus="status"> <c:if test="${status.index == 0}"> <option selected="selected" value="${course.id}"><c:out value="${course.name}"/></option> </c:if> <c:if test="${status.index > 0}"> <option value="${course.id}"><c:out value="${course.name}"/></option> </c:if> </c:forEach> </select> <input type="button" value="查询课程成绩" id="queryScoreForTeacher"/> </c:if> <div class="row-fluid"> <div class="span12"> <div class="widget-box"> <div class="widget-content nopadding"> <table class="table table-bordered table-striped" id="score_table"> </table> </div> </div> </div> </div> </div> <!--End-Action boxes--> </div> <!--end-main-container-part--> <!--Footer-part--> <div class="row-fluid"> <div id="footer" class="span12"> 2013 © Matrix Admin. Brought to you by <a href="http://themedesigner.in/">Themedesigner.in</a> </div> </div> <!-- end-Footer-part --> <script src="${pageContext.request.contextPath}/js/jquery.min.js"></script> <script src="${pageContext.request.contextPath}/js/highLight.js"></script> <script type="text/javascript"> $.namespace("ems.index"); ems.index = function(){ var divShow = $("#DivShow"); return { queryScoreForStudent : function(){ var time = $.trim($("#learn_time").val()); var term = $.trim($("input[name='which_term']:checked").val()); var indata = {time:time, term:term}; $.post("/ems/user/queryScoreForStudent",indata, function(data){ $("#score_table").empty(); if(data != null && data.result == 'ok'){ var d = data.data; console.log(d); if(data.data != null){ var score_html = '<thead><tr><th>课程</th><th>分数</th><th>老师</th><th>时间</th></tr></thead><tbody>'; for(var i=0; i<d.length; i++){ score_html += '<tr class="odd gradeX"><td>' + d[i].courseName + '</td>'; score_html += '<td>' + d[i].score + '</td>'; score_html += '<td>' + d[i].teacherName + '</td>'; score_html += '<td>' + new Date(d[i].learnTime).format("yyyy-MM-dd"); + '</td>'; } score_html += '</tbody>'; $("#score_table").empty().append(score_html); } } },'json'); }, queryScoreForTeacher : function(){ var courseId = $.trim($("#course_type_select").val()); if(courseId == null || courseId == '') return; var className = $.trim($("#class_name").val()); var time = $.trim($("#learn_time").val()); var term = $.trim($("input[name='which_term']:checked").val()); var indata = {courseId:courseId, time:time, term:term, className:className}; $.post("/ems/user/queryScoreForTeacher", indata, function(data){ $("#score_table").empty(); if(data != null && data.result == 'ok'){ var d = data.data; console.log(d); if(data.data != null){ var score_html = '<thead><tr><th>学号</th><th>姓名</th><th>专业</th><th>课程</th>' + '<th>分数</th><th>时间</th><th>录入成绩</th></tr></thead><tbody>'; for(var i=0; i<d.length; i++){ score_html += '<tr class="odd gradeX"><td>' + d[i].no + '</td>'; score_html += '<td>' + d[i].studentName + '</td>'; score_html += '<td>' + d[i].major + '</td>'; score_html += '<td>' + d[i].courseName + '</td>'; score_html += '<td>' + d[i].score + '</td>'; score_html += '<td>' + new Date(d[i].learnTime).format("yyyy-MM-dd"); + '</td>'; score_html += '<td><input type="button" id="'+ d[i].id + '" name="'+ d[i].flag + '" value="录入成绩" onclick="ems.index.showDiv(this)"/></td>'; } score_html += '</tbody>'; $("#score_table").empty().append(score_html); } } },'json'); }, showDiv : function(myThis){ divShow.find("#student_course_id").val(myThis.id); divShow.find("#student_course_flag").val(myThis.name); divShow.show(); }, closeDiv : function(){ divShow.find("#student_course_id").val(""); divShow.find("#student_course_flag").val(""); divShow.hide(); }, updateStudentScore : function(){ var value1 = divShow.find("#value1").val(); var value2 = divShow.find("#value2").val(); var value3 = divShow.find("#value3").val(); var id = divShow.find("#student_course_id").val(); var flag = divShow.find("#student_course_flag").val(); var indata = {id:id,flag:flag,score1:value1,score2:value2,score3:value3}; $.post("/ems/user/updateStudentScore", indata, function(data){ if(data != null && data.result == 'ok'){ console.log(data.msg); ems.index.queryScoreForTeacher(); }else{ alert(data.msg); } }, 'json'); ems.index.closeDiv(); }, createLearnTimeSelect : function(){ var begin = 2008; var current_year = new Date().format("yyyy"); var sel_html = ''; for(var i=0; i<20; i++){ if(begin+i == current_year) sel_html +='<option value="' + (begin+i) +'" selected = "selected">'+ (begin+i) +"</option>"; sel_html += '<option value="' + (begin+i) +'">'+ (begin+i) +"</option>"; } $("#learn_time").empty().append(sel_html); } }; }(); $(document).ready(function(){ ems.index.createLearnTimeSelect(); // 生成学年下拉框 $(document).on('click', '#queryScoreForTeacher', ems.index.queryScoreForTeacher); $(document).on('click', '#queryScoreForStudent', ems.index.queryScoreForStudent); $(document).on('click', '#btnCancel', ems.index.closeDiv); $(document).on('click', '#btnOK', ems.index.updateStudentScore); }); </script> </body> </html>
我们看到被装饰页面的整个 body 部分,会填充到装饰页面中的 <sitemesh:write property='body' /> 处。
正好是注释: <!--main-container-part--> 和 <!-- end-Footer-part --> 相匹配和对应。
注意:模板页面的 <sitemesh:write property='head' /> 最好放置head标签的最后面,因为被装饰页面中的head部分由可能存在依赖于模板页面中的js库。
我们看到sitemesh的使用还是十分简单的。