在开发jsp页面时,有很多网页使用的部分页面结构相同,这些相同的页面结构不仅添加时每个页面都要添加,而且如果要修改这些相同的地方都要修改,给开发及维护带来了工作量。
通过面向对象的问题思考问题:如果相同的部分抽离出来,使用继承的关系,基本的有父类定义,子类可以重写父类的变化的内容。父类可以有多个子类,子类只有一个父类,子类可以有很多子类,这样多层次的继承,可以解决以上问题。
对于页面也是一样,如果把相同的部分页面结构抽离成一个父页面,使用到这个页面的子页面就可以继承这个父页面,可以覆盖自己与主页面不同的页面内容,也可以自己定义让子页面的子页面覆写。添加时 只要引入父页面并修改针对自己的内容就行不再关心相同的页面结构。在要修改相同页面结构时只要修改父页面内容,其下面引用的子孙页面都会得到相应的更新。
下面介绍一下用的到这种技术:rapid中的一种功能 原理和上面说的差不多
我主要用在了jsp页面中,所以只介绍下在jsp中的使用 所需要引入的jar 包:rapid-core-4.0.jar
因为这个功能主要在jsp页面中使用的,所以使用的标签库方式来实现的,因此先在jsp中引用标签库
<%@taglib uri="http://www.rapid-framework.org.cn/rapid" prefix="rapid" %>
主要页面:base.jsp child.jsp grandChildA.jsp grandChildB.jsp
先来看base.jsp即父页面 ,页面中使用了rapid:block定义了四个可以让子页面重写的内容块 head top content footer
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib uri="http://www.rapid-framework.org.cn/rapid" prefix="rapid" %> <%@taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <rapid:block name="head"> <title>base head</title> </rapid:block> </head> <body> <rapid:block name="top"> base top </rapid:block> <rapid:block name="content"> base content </rapid:block> <rapid:block name="footer"> base footer </rapid:block> </body> </html>base.jsp生成后的页面:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>base head</title> </head> <body> base top base content base footer </body> </html>下面是child.jsp这里面使用include引用了base.jsp,这样代表了直接使用了base.jsp页面,又使用rapid:override重写了header和content,并在content创建了一个mychild内容块
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib uri="http://www.rapid-framework.org.cn/rapid" prefix="rapid" %> <rapid:override name="head"> <title>child head</title> </rapid:override> <rapid:override name="content"> child content <rapid:block name="mychild"> child mychild </rapid:block> </rapid:override> <%@include file="base.jsp" %>
child.jsp生成后的页面
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <span style="white-space:pre"> </span><title>child head</title> </head> <body> <span style="white-space:pre"> </span>base top child content <span style="white-space:pre"> </span>base footer </body> </html>grandChildA.jsp grandChildB.jsp使用了多层错乱使用的例子:
grandChildA.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib uri="http://www.rapid-framework.org.cn/rapid" prefix="rapid" %> <rapid:override name="top"> grandChildA top </rapid:override> <rapid:override name="footer"> grandChildA footer </rapid:override> <%@include file="base.jsp"%>
grandChildA生成的页面:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>base head</title> </head> <body> grandChildA top base content <span style="white-space:pre"> </span>grandChildA footer </body> </html>grandChildB.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib uri="http://www.rapid-framework.org.cn/rapid" prefix="rapid" %> <rapid:override name="top"> grandChildB top </rapid:override> <rapid:override name="mychild"> grandChildB mychild </rapid:override> <rapid:override name="footer"> grandChildB footer </rapid:override> <%@include file="child.jsp"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>child head</title> </head> <body>
<span style="white-space:pre"> </span>grandChildB top child content grandChildB mychild grandChildB footer </body> </html>通过灵活多变的使用可以达到各种复用的效果。
看下源码中标签库中的定义吧:
<?xml version="1.0" encoding="UTF-8" ?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd" version="2.0"> <description>rapid-framework tag library</description> <display-name>rapid-framework tag</display-name> <tlib-version>1.0</tlib-version> <short-name>rapid</short-name> <uri>http://www.rapid-framework.org.cn/rapid</uri> <tag> <description> block tag </description> <name>block</name> <tag-class>cn.org.rapid_framework.web.tags.BlockTag</tag-class> <body-content>JSP</body-content> <attribute> <description> block name </description> <name>name</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> <tag> <description> override desc </description> <name>override</name> <tag-class>cn.org.rapid_framework.web.tags.OverrideTag</tag-class> <body-content>JSP</body-content> <attribute> <description> override name, must be equals block name for override </description> <name>name</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>这里主要有两个tag: block 和override
block: 有个name属性,如果使用的页面修改了name在pageContent中的内容值,则使用重新定义的内容,否则不改变。
override: 会将标签中的内容保存为pageContent中的name对应的一个变量,名称为:__jsp_override__name
代码如下:
package cn.org.rapid_framework.web.tags; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.TagSupport; /** * * @author badqiu * */ public class BlockTag extends TagSupport{ private static final long serialVersionUID = -8246166191638588615L; private String name; public void setName(String name) { this.name = name; } /** * @return EVAL_BODY_INCLUDE or EVAL_BODY_BUFFERED or SKIP_BODY */ @Override public int doStartTag() throws JspException { return getOverriedContent() == null ? EVAL_BODY_INCLUDE : SKIP_BODY; } /** * @return EVAL_PAGE or SKIP_PAGE */ @Override public int doEndTag() throws JspException { String overriedContent = getOverriedContent(); if(overriedContent == null) { return EVAL_PAGE; } try { pageContext.getOut().write(overriedContent); } catch (IOException e) { throw new JspException("write overridedContent occer IOException,block name:"+name,e); } return EVAL_PAGE; } private String getOverriedContent() { String varName = Utils.getOverrideVariableName(name); return (String)pageContext.getRequest().getAttribute(varName); } }
package cn.org.rapid_framework.web.tags; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyContent; import javax.servlet.jsp.tagext.BodyTagSupport; /** * @author badqiu */ public class OverrideTag extends BodyTagSupport{ private static final long serialVersionUID = -8379959647039117369L; private String name; public void setName(String name) { this.name = name; } @Override public int doStartTag() throws JspException { return isOverrided() ? SKIP_BODY : EVAL_BODY_BUFFERED; } @Override public int doEndTag() throws JspException { if(isOverrided()) { return EVAL_PAGE; } BodyContent b = getBodyContent(); // System.out.println("Override.content:"+b.getString()); String varName = Utils.getOverrideVariableName(name); pageContext.getRequest().setAttribute(varName, b.getString()); return EVAL_PAGE; } private boolean isOverrided() { String varName = Utils.getOverrideVariableName(name); return pageContext.getRequest().getAttribute(varName) != null; } }
package cn.org.rapid_framework.web.tags; /** * @author badqiu */ class Utils { public static String BLOCK = "__jsp_override__"; static String getOverrideVariableName(String name) { return BLOCK + name; } }