(English version see README-English.md)
License: Apache 2.0
这是一个服务端(支持JSP和FreeMaker)页面布局工具,特点是简单,无XML,仅用500行源码实现了与Apache Tiles类似的页面布局功能。
在项目的pom.xml中添加如下内容:
<dependency>
<groupId>com.github.drinkjava2</groupId>
<artifactId>jwebbox</artifactId>
<version>2.1.2</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里运行。
服务端代码如下:
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是主模板文件,主要内容如下:
<%@ taglib prefix="box" uri="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);
%>
示例1的输出:
服务端代码:
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模板(源码见示例)。
示例2的输出:
服务端代码:
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有三种数据准备方式:
各个准备方法及页面输出的顺序如下:
prepareStaticMethod -> prepareBeanMethod -> PrepareURL -> text output -> page
示例3输出:
服务端代码:
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实例并依次显示。
示例4输出:
从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" />
使用FreeMaker,需要在web.xml中添加如下配置:
<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>
示例5输出:
这个例子展示了利用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");
}
}
}
示例6截图:
以上即为jWebBox的全部说明文档,如有不清楚处,可以查看项目源码或示例项目的源码。
jWebBox2.1 添加FreeMaker模板支持;增加一个JSP标签;添加了表格、分页、表单处理的演示;更正WebLogic不能运行的bug。
jWebBox2.1.1 添加了beforeShow、beforeexecute、execute、afterExecute、afterShow、afterPrepared几个空方法作为回调函数给子类用。示例详见jBooox项目。
jWebBox2.1.2 show()方法原来为void类型,现改为WebBox实例,便方便使用。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
1. 开源生态
2. 协作、人、软件
3. 评估模型