做过Java Web项目的开发工程师都知道,如果单纯的使用jsp脚本开发,糅合内容和行为逻辑与一体是一个非常不好的体验,更不易于维护。所以采用了JSTL标签库,用于分离数据显示和业务逻辑,简易开发,带来优雅编程体验。JSTL 即:JSP Standard Tag Library
,一个JSP标签集合,它封装了JSP应用的通用核心功能。他依赖于standard.jar和jstl.jar两个jar包。
JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。尽量只是用核心标签,包括<c:if>、<c:choose>、<c:when>、<c:otherwise>、<c:forEach>
等,主要用于构造循环和分支结构以控制显示逻辑。标签引用:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
格式化标签一般用于日期相关的数据处理。函数标签一般用于字符串相关的数据处理。当然,这次要记录的是如何自定义标签,增强自己的数据处理需要。这里以自定义分页标签为例。
1、实现Tag接口或者继承缺省适配的Tag相关类。
开发中通常不直接实现这些接口而是继承TagSupport/BodyTagSupport/SimpleTagSupport
类,重写doStartTag()、doEndTag()
等方法,定义标签要完成的功能。
现在已自定义分页标签为例,继承BodyTagSupport类,重写doStartTag方法。定义了一些属性。
PageData pageData; // 分页类
String funcName; // js 回调函数名
String formId; // 表单的ID名
String formUrl; // 表单提交的URL
重写doStartTag方法:
@Override
public int doStartTag() throws JspException {
JspWriter out = this.pageContext.getOut();
try {
if (pageData == null) {
return Tag.SKIP_BODY;
}
out.println(getPageHtml());
} catch (IOException e) {
throw new JspException(e);
}
return Tag.EVAL_BODY_INCLUDE;
}
在getPageHtml方法里根据逻辑拼接html分页列表,如一个简单的例子:
private String getPageHtml() {
if (pageData == null) {
return “”;
}
StringBuilder sBuilder = new StringBuilder();
if (pageData.hasNext()) {
sBuilder.append(“<li><a href=\”javascript:void(0)\” onclick=\””).append(this.funcName)
.append(“(“).append(pageData.getPageNo()+1).append(“,”).append(pageData.getPageSize()).append(“,'”).append(formId).append(“‘,'”).append((formUrl == null || “”.equals(formUrl)?“”:formUrl))
.append(“‘);\”>下一页</a></li>”);
} else {
sBuilder.append(“<li class=\”disabled\”>下一页</li>”);
}
if (pageData.hasPrevious()) {
sBuilder.append(“<li><a href=\”javascript:void(0)\” onclick=\””).append(this.funcName)
.append(“(“).append(pageData.getPageNo()-1).append(“,”).append(pageData.getPageSize()).append(“,'”).append(formId).append(“‘,'”).append((formUrl == null || “”.equals(formUrl)?“”:formUrl))
.append(“‘);\”>上一页</a></li>”);
} else {
sBuilder.append(“<li class=\”disabled\”>上一页</li>”);
}
return sBuilder.toString();
}
2、编写扩展名为tld的标签描述文件对自定义标签进行定义。
pages.tld
自定义标签描述了标签名,标签处理类、和相关属性定义描述:
<tag>
<name>page</name>
<tag-class>com.common.test.PageTag</tag-class>
<description>分页标签–power by wenqy.com</description>
<attribute>
<name>pageData</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>封装分页数据类</description>
</attribute>
<attribute>
<name>funcName</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>选择页签触发的js函数名</description>
</attribute>
<attribute>
<name>formId</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>选择页签后要提交表单的ID</description>
</attribute>
<attribute>
<name>formUrl</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>选择页签后要跳转的页面URL</description>
</attribute>
</tag>
3、在JSP页面中使用taglib指令引用该标签库
Jsp头部引用tld标签描述文件。
<%@ taglib prefix="fns" uri="/WEB-INF/tlds/pages.tld" %>
调用自定义标签,formUrl属性非必须。
<fns:page pageData="${requestScope.pageData }" funcName="page" formId="myForm" />
4、js方法
表单里定义pageNo、pageSize两个隐藏域,并重写页签调用方法,使用jquery方法。
<script type=“text/javascript”>
// 参数: 页数、页大小、form ID、submit URL
function page(no, size,form,url) {
var re = /^[0-9]*$/;
if(!re.test(size)){
alert(‘页大小为数字’);
return;
}
if(!re.test(no)){
alert(‘页数为数字’);
return;
}
if (no) {
$(“#pageNo”).val(no);
}
if (size) {
$(“#pageSize”).val(size);
}
if (url) {
$(“#” + form).attr(“action”,url);
}
$(“#” + form).submit();
return false;
}
</script>
5、pageData分页类
/**
*
* @author wenqy
*
*/
public class PageData implements Serializable {
private static final long serialVersionUID = 8040968899344110256L;
protected static final int DEFAULT_PAGE_NO = 0;
protected static final int DEFAULT_PAGE_SISE = 0;
protected static final int DEFAULT_INDEX_BEGIN = 0;
protected static final int DEFAULT_INDEX_END = 0;
protected List<?> items; // 页数据
protected Object[][] results;
protected int pageNo; // 当前页
protected int pageSize; // 页大小
protected int pageCount; // 页数
protected int totalCount;
protected int handleCount;
protected int lastPageSize;
protected int columnCount;
protected int beginIndex;
protected int endIndex;
protected int[] indexes; // 记录每页的起始下标
protected String orderField; // 排序字段
protected boolean isOrderAsc; // 升降排序
protected String resInfo;
protected String pageCode;
public boolean hasNext() {
return (this.pageNo < this.pageCount);
}
public boolean hasPrevious() {
return (this.pageNo > 0);
}
public static int convertFromPageToStartIndex(int paramInt1, int paramInt2) {
return ((paramInt1 – 1) * paramInt2);
}
public int currentPageNo() {
return getPageNo();
}
public int getNextIndex() {
int i = getBeginIndex() + this.pageSize;
if (i >= this.totalCount)
return getBeginIndex();
return i;
}
public int getPreviousIndex() {
int i = getBeginIndex() – this.pageSize;
if (i < 0)
return 0;
return i;
}
public List<?> getItems() {
return this.items;
}
public void setItems(List<?> paramList) {
this.items = paramList;
}
public int getPageNo() {
return this.pageNo;
}
public void setPageNo(int paramInt) {
this.pageNo = paramInt;
}
public int getPageSize() {
return this.pageSize;
}
public void setPageSize(int paramInt) {
this.pageSize = paramInt;
}
public int getPageCount() {
if (this.totalCount < 0)
return –1;
if (this.totalCount == 0)
return 0;
if (this.pageSize > 0) {
int i = this.totalCount / this.pageSize;
if (this.totalCount % this.pageSize > 0)
;
this.pageCount = (++i);
} else {
this.pageCount = 1;
this.pageSize = this.totalCount;
}
return this.pageCount;
}
public void setPageCount(int paramInt) {
this.pageCount = paramInt;
}
public int getTotalCount() {
return this.totalCount;
}
public void setTotalCount(int paramInt) {
if (paramInt > 0) {
this.totalCount = paramInt;
if (this.pageSize <= 0)
return;
int i = this.totalCount / this.pageSize;
if (paramInt % this.pageSize > 0)
;
this.indexes = new int[++i];
for (int j = 0; j < i; ++j)
this.indexes[j] = (this.pageSize * j);
} else {
this.totalCount = 0;
}
}
public int getBeginIndex() {
return this.beginIndex;
}
public void setBeginIndex(int paramInt) {
if (this.totalCount <= 0)
this.beginIndex = 0;
else if (paramInt >= this.totalCount)
this.beginIndex = this.indexes[(this.indexes.length – 1)];
else if (paramInt < 0)
this.beginIndex = 0;
else if (this.pageSize > 0)
this.beginIndex = this.indexes[(paramInt / this.pageSize)];
else
this.beginIndex = paramInt;
}
public int getEndIndex() {
return this.endIndex;
}
public void setEndIndex(int paramInt) {
this.endIndex = paramInt;
}
public int getLastPageSize() {
if (this.totalCount < 0)
return –1;
if (this.totalCount == 0)
return 0;
int i = this.totalCount % this.pageSize;
if (i > 0)
return i;
return this.pageSize;
}
public void setLastPageSize(int paramInt) {
this.lastPageSize = paramInt;
}
public int getColumnCount() {
return this.columnCount;
}
public void setColumnCount(int paramInt) {
this.columnCount = paramInt;
}
public int getHandleCount() {
return this.handleCount;
}
public void setHandleCount(int paramInt) {
this.handleCount = paramInt;
}
public int[] getIndexes() {
return this.indexes;
}
public void setIndexes(int[] paramArrayOfInt) {
this.indexes = paramArrayOfInt;
}
public String getOrderField() {
return this.orderField;
}
public void setOrderField(String paramString) {
this.orderField = paramString;
}
public boolean isOrderAsc() {
return this.isOrderAsc;
}
public void setOrderAsc(boolean paramBoolean) {
this.isOrderAsc = paramBoolean;
}
public Object[][] getResults() {
return this.results;
}
public void setResults(Object[][] paramArrayOfObject) {
this.results = paramArrayOfObject;
}
public String getResInfo() {
return this.resInfo;
}
public void setResInfo(String paramString) {
this.resInfo = paramString;
}
}
封装Dao层的分页方法,传入pageData。Jsp会被Java容器,如:Tomcat翻译成Servlet,获取pageContext对象,调用doStartTag方法。
使用标签库可以对内容显示和业务逻辑的解耦有很大帮助,如果觉得现有标签库不能满足需要还可以自定义标签。当然也是可以选择其他模板引擎,如freemarker、velocity等等。
参考:
http://tomcat.apache.org/taglibs/standard/ Standard Taglib
本文由 wenqy 创作,采用 知识共享署名4.0
国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Nov 8,2020