最近剛入職新公司,瀏覽一下新公司項目,發現項目中大多數JSP頁面都是獨立的、完整的頁面,所以許多頁面都會有以下重複的代碼:javascript
<%@ page language="java" contentType="text/html; charset=UTF-8" import="java.util.Calendar" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> <%@ taglib uri="/common-tags" prefix="m"%> <c:set var="ctx" value="${pageContext.request.contextPath}"></c:set> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <title>${webModule.module.name} ---xxxx</title> <meta name="keywords" content="xxxx"/> <meta name="description" content="xxxx"/> <link rel="stylesheet" href="${ctx}/css/web-bbs.css"/> <link rel="stylesheet" href="${ctx}/css/page.css"/> <script type="text/javascript" src="${ctx}/js/jquery-1.7.2.min.js"></script> <script type="text/javascript" src="${ctx}/js/bbs.js"></script> <script type="text/javascript" src="${ctx}/js/webUtil.js"></script> <script type="text/javascript" src="${ctx}/js/index.js"></script> <script type="text/javascript" src="${ctx}/js/faces.js"></script>
小夥伴們每新添加一個頁面,就須要copy一份上面這坨代碼,還須要在各自頁面重複引入公共的頭尾文件(如header.jsp,footer.jsp等)。。。
對於這種開發方式,重複的工做量就很少描述了,更重要的問題是這種架構方式將來會致使更多的維護工做量、甚至是bug隱患。
舉兩個「栗子」:css
上面扯了那麼多,其實核心問題就是全部的jsp頁面都是各自爲戰,沒有一個統一的公共的模板來維護一些全局的信息,因此這裏就介紹一下咱們之前的實現方案:html
有了模板之後就能夠這樣寫頁面了:java
這樣的寫法好處顯而易見:jquery
模板內容大概是這個樣子的:web
實現原理其實很簡單,模板功能的實現主要是兩個自定義標籤(自定義標籤的開發步驟這裏就不講了)架構
該標籤主要用於在模板文件中定義相應的模塊(能夠看作一個佔位符),在渲染JSP頁面時會將標籤訂義的位置替換爲頁面重寫的內容,替換時根據標籤的name屬性加上特定的前綴做爲key值從request的attribute中讀取內容。jsp
/** * 自定義標籤,用於在Jsp模板中佔位 * * @author 逆風之羽 * */ public class BlockTag extends BodyTagSupport { /** * 佔位模塊名稱 */ private String name; private static final long serialVersionUID = 1425068108614007667L; @Override public int doStartTag() throws JspException{ return super.doStartTag(); } @Override public int doEndTag() throws JspException { ServletRequest request = pageContext.getRequest(); //block標籤中的默認值 String defaultContent = (getBodyContent() == null)?"":getBodyContent().getString(); String bodyContent = (String) request.getAttribute(OverwriteTag.PREFIX+ name); //若是頁面沒有重寫該模塊則顯示默認內容 bodyContent = StringUtils.isEmpty(bodyContent)?defaultContent:bodyContent; try { pageContext.getOut().write(bodyContent); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // TODO Auto-generated method stub return super.doEndTag(); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
該標籤主要用於在最終的頁面上重寫模板中的相應模塊,在頁面渲染時將標籤內部的內容寫入到當前request的attribute中,該標籤有一個必填參數name屬性做爲該內容的key值,這個name屬性必需要和模板中對應要重寫的block的name值相同。ide
/** * 自定義標籤,用於在jsp模板中重寫指定的佔位內容 * * 基本原理: * 將overwrite標籤內容部分添加到ServletRequest的attribute屬性中 * 在後續block標籤中再經過屬性名讀取出來,將其渲染到最終的頁面上便可 * * @author 逆風之羽 * */ public class OverwriteTag extends BodyTagSupport { private static final long serialVersionUID = 5901780136314677968L; //模塊名的前綴 public static final String PREFIX = "JspTemplateBlockName_"; //模塊名 private String name; @Override public int doStartTag() throws JspException { // TODO Auto-generated method stub return super.doStartTag(); } @Override public int doEndTag() throws JspException { ServletRequest request = pageContext.getRequest(); //標籤內容 BodyContent bodyContent = getBodyContent(); request.setAttribute(PREFIX+name, StringUtils.trim(bodyContent.getString())); // TODO Auto-generated method stub return super.doEndTag(); } public String getName() { return name; } public void setName(String name) { this.name = name; } }