这是一个服务端(支持JSP和FreeMaker)页面布局工具,特点是简单,无XML,仅用400行源码实现了与Apache Tiles类似的页面布局功能。 目前一些服务端JSP页面布局工具的缺点:
JWebBox特点:
jWebBox2.1版本更新:添加FreeMaker模板支持;增加一个JSP标签;添加了表格、分页、表单处理的演示;更正WebLogic不能运行的bug. 使用方法:在项目的pom.xml中添加如下内容: <dependency> <groupId>com.github.drinkjava2</groupId> <artifactId>jwebbox</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <!-- 或其它版本 --> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> <!-- 或其它版本 --> <scope>provided</scope> </dependency> jWebBox运行于Java6或以上,依赖于javax.servlet-api和javax.servlet.jsp-api这两个运行期库(通常由Servlet容器提供)。 详细介绍以下通过对示例的解释来详细说明jWebBox的使用,示例项目源码位于项目的jwebbox-demo目录下,在项目的根目录,也有一个打包好的jwebbox-demo.war文件,可直接扔到Tomcat或WebLogic里运行。 示例1 - 一个带菜单和底脚的左右布局服务端代码如下: public static class demo1 extends WebBox {
{ this.setPage("/WEB-INF/pages/homepage.jsp");
this.setAttribute("menu",
new WebBox("/WEB-INF/pages/menu.jsp").setAttribute("msg", "Demo1 - A basic layout"));
this.setAttribute("body", new LeftRightLayout());
this.setAttribute("footer", "/WEB-INF/pages/footer.jsp");
}
}
public static class LeftRightLayout extends WebBox {
{ this.setPage("/WEB-INF/pages/left_right_layout.jsp");
ArrayList<Object> boxlist = new ArrayList<Object>();
boxlist.add("/WEB-INF/pages/page1.jsp");
boxlist.add("/WEB-INF/pages/page2.jsp");
this.setAttribute("boxlist", boxlist);
}
}其中homepage.jsp是主模板文件,主要内容如下: <#assign box=JspTaglibs["http://github.com/drinkjava2/jwebbox"] /> <html> <body> <div id="temp_content"> <div id="temp_menu"> <@box.show attribute="menu" /> </div> <@box.show attribute="body" /> <div id="temp_footer"> <@box.show attribute="footer" /> </div> </div> </body> </html> left_right_layout.jsp是一个布局模板,内容如下(其它的JSP文件类似,此处略,详见示例): <%@ taglib prefix="box" uri="http://github.com/drinkjava2/jwebbox"%>
<div id="temp_left" style="margin: 10px; width: 430px; float: left; background-color:#CCFFCC;">
<box:show target="${jwebbox.attributeMap.boxlist[0]}" />
</div>
<div id="temp_right" style="margin: 10px; float: right; width: 430px;background-color:#FFFFCC;">
<box:show target="${jwebbox.attributeMap.boxlist[1]}" />
</div>解释:
<box:show attribute="menu" />
<box:show target="${jwebbox.attributeMap.menu}" />
<% WebBox.showAttribute(pageContext,"menu");%>
<% WebBox.showTarget(pageContext, WebBox.getAttribute(pageContext,"menu"));%>
<% ((WebBox)WebBox.getAttribute(pageContext,"menu")).show(pageContext);%> //仅当menu属性为WebBox对象时后三种写法不推荐,但有助于理解WebBox的运作机制。每个被WebBox调用的页面,都在request中存在一个WebBox实例,可以用request.getAttribute("jwebbox")或EL表达式${jwebbox}获取。
<servlet> <servlet-name>htm2box</servlet-name> <jsp-file>/htm2box.jsp</jsp-file> </servlet> <servlet-mapping> <servlet-name>htm2box</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping> 其中htm2box.jsp当作Servlet来使用,作用类似于Spring MVC中的DispatcherServlet: <%@page import="org.apache.commons.lang.StringUtils"%><%@page import="com.github.drinkjava2.jwebbox.WebBox"%><%
String uri=StringUtils.substringBefore(request.getRequestURI(),".");
uri = StringUtils.substringAfterLast(uri, "/");
if (uri == null || uri.length() == 0)
uri = "demo1";
WebBox box = (WebBox) Class.forName("com.github.drinkjava2.jwebboxdemo.DemoBoxConfig$" + uri).newInstance();
box.show(pageContext);
%>示例2 - 布局的继承服务端代码: public static class demo2 extends demo1 {
{ ((WebBox) this.getAttribute("menu")).setAttribute("msg", "Demo2 - Change body layout");
this.setAttribute("body", new TopDownLayout());
}
}
public static class TopDownLayout extends LeftRightLayout {
{ this.setPage("/WEB-INF/pages/top_down_layout.jsp");
}
}demo2继承于demo1类,将"body"属性改成了一个上下布局top_down_layout.jsp模板(源码见示例)。 示例3 - 数据准备服务端代码: public static class demo3 extends demo1 {
{ setPrepareStaticMethod(DemoBoxConfig.class.getName() + ".changeMenu");
setAttribute("body", new WebBox().setText("<div style=\"width:900px\"> This is body text </div>")
.setPrepareURL("/WEB-INF/pages/prepare.jsp").setPrepareBean(new Printer()));
setAttribute("footer", new WebBox("/WEB-INF/pages/footer.jsp").setPrepareBean(new Printer())
.setPrepareBeanMethod("print"));
}
}
public static void changeMenu(PageContext pageContext, WebBox callerBox) throws IOException {
((WebBox) callerBox.getAttribute("menu")).setAttribute("msg",
"Demo3 - Prepare methods <br/>This is modified by \"changeMenu\" static method");
}
public static class Printer {
public void prepare(PageContext pageContext, WebBox callerBox) throws IOException {
pageContext.getOut().write("This is printed by Printer's default \"prepare\" method <br/>");
}
public void print(PageContext pageContext, WebBox callerBox) throws IOException {
pageContext.getOut().write("This is printed by Printer's \"print\" method <br/>");
pageContext.getOut().write((String) pageContext.getRequest().getAttribute("urlPrepare"));
}
}相比与普通的Include指令,Apache Tiles和jWebBox这类布局工具的优势之一在于可以在各个子页面加载之前进行数据准备工作,从而达到模块式开发的目的。jWebBox有三种数据准备方式:
各个准备方法及页面输出的顺序如下: 示例4 - 列表服务端代码: public static class demo4 extends demo1 {
{
((WebBox) this.getAttribute("menu")).setAttribute("msg", "Demo4 - List");
ArrayList<Object> child = new ArrayList<Object>();
for (int i = 1; i <= 3; i++)
child.add(new WebBox("/WEB-INF/pages/page" + i + ".jsp").setText(" "));
ArrayList<Object> mainList = new ArrayList<Object>();
for (int i = 1; i <= 3; i++) {
mainList.add("/WEB-INF/pages/page" + i + ".jsp");
if (i == 2)
mainList.add(child);
}
this.setAttribute("body", mainList);
}
}如果属性是一个列表,当JSP页面中调用<box:show attribute="xxx" />方法时,如果值是一个List,将假定List中属性为页面或WebBox实例并依次显示。 示例5 - FreeMaker模板支持从2.1版起,jWebBox开始支持FreeMaker,且可以与JSP混用,例如如下配置: public static class demo5 extends WebBox {
{ this.setPage("/WEB-INF/pages/homepage.ftl");
this.setAttribute("menu",
new WebBox("/WEB-INF/pages/menu.jsp").setAttribute("msg", "Demo5 - Freemaker demo"));
this.setAttribute("body", new FreemakerLeftRightLayout());
this.setAttribute("footer", new WebBox("/WEB-INF/pages/footer.jsp"));
}
}FreeMaker不支持直接在页面嵌入Java代码,语法也与JSP不同,引入标签要写成<#assign box=JspTaglibs["http://github.com/drinkjava2/jwebbox"] />, show标签要写成<@box.show attribute="menu" /> <servlet> <servlet-name>freemarker</servlet-name> <servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class> <init-param> <param-name>TemplatePath</param-name> <param-value>/</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>freemarker</servlet-name> <url-pattern>*.ftl</url-pattern> </servlet-mapping> 并在pom.xml中添加对FreeMaker库的依赖: <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.23</version> <!--或更新版--> </dependency> 示例6 - 表格和分页演示这个例子展示了利用WebBox配置的继承功能来创建表格和分页条组件,输出两个表格和分页条,并处理表单提交数据。因篇幅较长,此处只摘录布局部分代码: public static class demo6 extends demo1 {
{
setAttribute("menu",
((WebBox) this.getAttribute("menu")).setAttribute("msg", "Demo6 - Table & Pagination"));
List<WebBox> bodyList = new ArrayList<WebBox>();
bodyList.add(new TableBox());
bodyList.add(new TablePaginBarBox());
bodyList.add(new WebBox().setText(
"<br/>-----------------------------------------------------------------------------------"));
bodyList.add(new CommentBox());
bodyList.add(new CommentPaginBarBox());
bodyList.add(new WebBox("/WEB-INF/pages/commentform.jsp"));
this.setPrepareStaticMethod(DemoBoxConfig.class.getName() + ".receiveCommentPost");
this.setAttribute("body", bodyList);
}
class TableBox extends WebBox {
{
this.setPrepareBean(new PrepareForDemo6()).setPrepareBeanMethod("prepareTable");
setPage("/WEB-INF/pages/page_table.jsp");
setAttribute("pageId", "table");
setAttribute("targetList", tableDummyData);
setAttribute("row", 3).setAttribute("col", 4);
setAttribute("render", new WebBox("/WEB-INF/pages/render_table.jsp"));
}
}
class TablePaginBarBox extends TableBox {
{
this.setPrepareBean(new PrepareForDemo6()).setPrepareBeanMethod("preparePaginBar");
setPage("/WEB-INF/pages/pagin_bar.jsp");
}
}
class CommentBox extends TableBox {
{
setAttribute("pageId", "comment");
setAttribute("targetList", commentDummyData);
setAttribute("row", 3).setAttribute("col", 1);
setAttribute("render", new WebBox("/WEB-INF/pages/render_comment.jsp"));
}
}
class CommentPaginBarBox extends CommentBox {
{
this.setPrepareBean(new PrepareForDemo6()).setPrepareBeanMethod("preparePaginBar");
setPage("/WEB-INF/pages/pagin_bar.jsp");
}
}
}以上即为jWebBox的全部说明文档,如有不清楚处,可以查看项目源码或示例项目的源码。 |