JSP自定义标签之元素分割显示标签
JSP自定义标签admin 发布于:2015-10-14 11:32:42
阅读:loading
自定义标签在一些后台管理系统中其实还是很有用途的,至少在做一些基础数据维护的功能上开发效率能够得到非常大的提高,比如说可以有:自定义标签查询分页、查询一条数据、查询一个下拉框,以及联动下拉框等等,完全可以是一个标签,一条sql语句搞定,没有不好维护,只能是标签写的不好,这里走一波实际应用中的自定义标签吧,不从基础示例开始,只是分享下实现方案,以及能够解决哪种问题。
请允许我叫这个玩意儿“元素分割显示标签”,实在是不知道标准术语是什么,在很多时候我们的一个功能在显示时是动态查询出来的数据,记得以前在学校有一个类似于商城的项目,其中有一个模块是显示所有物品信息的,我们使用table-tr-td来显示布局的,由于内容数据是动态查询出来的,故涉及到一行显示多少个商品的运算,当时老师给的算法类似是:(current- 1) % n == 0 开始新行,current % n == 0 结束一行,如右图中意义是每行显示5个元素,正好1,6,11,16这些数字减去1,再取模5等于0,故开始新行,也就是说在循环处理时,满足这种的逻辑就创建一个<tr>的开始标记;
然而在5,10,15,20这些数字直接取模5等于0,故直接创建一个<tr/>的结束标记,来实现这种布局方式的展示。当时大家应该都是这么干的,忽视了一个小小的问题,当总数据数不是每页行显示数的整数倍时呢,此时最后一次出现的<tr>则无法有结束的<tr/>标记,虽然一般的浏览器在处理这种有问题的标记时照样可以解析,(如今html5的规范中,很多个标记是可以省略结束标记的,tr包括在内),但是从程序的严谨性上来讲,我们还是应该给补上N个空白的表格,以及最后一行所缺失的tr结束标记。
此种运算逻辑也算是经常遇到的,相当于数据的行转列显示,如果是每条数据显示一行,就直接循环数据,如果是N条数据显示一行,就需要使用到此种方式来处理了,说自定义标签,那么就按照封装一个标签的方式来实现这种业务逻辑上的运算,既然是自定义标签,首先定义了几个参数:
count:没行显示的列数,相当于上图中的每行显示5个,必选参数;
fillStart:用于生成匹配字符串分割的前缀,该值默认为<td>;
fillEnd:用于生成匹配字符串分割的后缀<td>;
fill:如果当前分割出的总个数与count相除结果不为1,则此时填充上去的字符串,默认为空格nbsp;
separator:要隔行显示的分隔符,类似于String.split函数的参数,默认为<td>;
运算逻辑比较简单,沿用上述的判断逻辑,再加上取模是否为0时的一个补充动作即可,相关代码参考如下:
package com.frame.base.tags.trwrap;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import org.apache.commons.lang3.StringUtils;
import com.frame.base.contants.CommonConstants;
import com.frame.base.tags.BaseTag;
public class WordWrapTag extends BaseTag {
private static final long serialVersionUID = 1L;
private String separator;
private Integer count;
private String fill;
private String fillStart;
private String fillEnd;
/**
* 设置参数的默认值
*/
public void initPropertys(){
if(StringUtils.isEmpty(separator)){
this.separator = CommonConstants.TAG_WORD_WRAP_SEPARATOR;
}
if(StringUtils.isEmpty(fill)){
this.fill = "<td> </td>";
}
if(StringUtils.isEmpty(fillStart)){
this.fillStart = CommonConstants.TAG_WORD_WRAP_START;
}
if(StringUtils.isEmpty(fillEnd)){
this.fillEnd = CommonConstants.TAG_WORD_WRAP_END;
}
}
@Override
public int doEndTag() throws JspException {
initPropertys();
String content = super.getBodyContent().getString();
String items[] = content.split(separator);
int lens = items.length - 1;
int mod = lens % count;
//正好被整除
StringBuilder builder = new StringBuilder();
for(int i=0;i<lens;i++){
if(i % this.count == 0){
builder.append(this.fillStart);
}
builder.append(items[i]).append(this.separator);
if((i + 1) % this.count == 0){
builder.append(this.fillEnd);
}
}
//如果当前没有被整除,则填充几项默认数据
if(mod != 0){
int fill = count - mod;
for(int i=0;i<fill;i++){
builder.append(this.fill);
}
builder.append(this.fillEnd);
}
try {
JspWriter out = pageContext.getOut();
out.print(builder.toString());
} catch (IOException e) {
e.printStackTrace();
}
return super.doEndTag();
}
public String getSeparator() {
return separator;
}
public void setSeparator(String separator) {
this.separator = separator;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public String getFill() {
return fill;
}
public void setFill(String fill) {
this.fill = fill;
}
public String getFillStart() {
return fillStart;
}
public void setFillStart(String fillStart) {
this.fillStart = fillStart;
}
public String getFillEnd() {
return fillEnd;
}
public void setFillEnd(String fillEnd) {
this.fillEnd = fillEnd;
}
}
<!-- 自动换号Tag -->
<tag>
<name>countGroup</name>
<body-content>JSP</body-content>
<tag-class>com.frame.base.tags.trwrap.WordWrapTag</tag-class>
<info>每行显示N个元素</info>
<attribute>
<name>separator</name>
<description>要隔行显示的分隔符,类似于String.split函数的参数,默认为<td></description>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>count</name>
<description>要隔行显示的个数,类似于每行显示多少个TD,无默认值,必输项参数</description>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>fill</name>
<description>如果当前分割出的总个数与count的比结果不为1,则此时填充上去的字符串,默认为空格nbsp;</description>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>fillStart</name>
<description>用于生成匹配字符串分割的前缀,该值默认为<td></description>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>fillEnd</name>
<description>用于生成匹配字符串分割的后缀</td></description>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="my" uri="/tags" %>
<!DOCTYPE HTML>
<html>
<head>
<title>元素自动折行</title>
<style type="text/css">
body{
font-size: 13px;
}
.default_td{
background-color: #abcdef;
}
ul{
list-style: none;
}
li{
display: inline-block;
width: 140px;
}
</style>
<%
String total = request.getParameter("total");
Integer totalInt = 10;
if(total != null && !"".equals(total)){
totalInt = Integer.valueOf(total);
}
Integer currentInt = 5;
String current = request.getParameter("current");
if(current != null && !"".equals(current)){
currentInt = Integer.valueOf(current);
}
%>
</head>
<body>
<form action="autoWarp.jsp">
td个数:
<select name="total">
<c:forEach begin="10" step="5" end="100" var="item">
<option value="${item }" <c:if test="${param.total == item }"> selected="selected" </c:if>>一共${item }个td</option>
</c:forEach>
</select>
每行显示个数:
<select name="current">
<c:forEach begin="5" end="10" var="item">
<option value="${item }" <c:if test="${param.current == item }"> selected="selected" </c:if>>每行显示${item }个</option>
</c:forEach>
</select>
<input type="submit" value="提交显示" />
</form>
<hr/>
<h3 style="color: red;">这是table布局时的td分割</h3>
<table width="100%" border="1" style="border-collapse: collapse;">
<my:countGroup count="<%=currentInt %>" fill="<td class='default_td'>填补</td>"
fillStart="<tr>" separator="</td>"
fillEnd="</tr>">
<c:forEach var="item" begin="1" end="<%=totalInt %>">
<td>这是表格${item }</td>
</c:forEach>
</my:countGroup>
</table>
<hr/>
<h3 style="color: red;">这是ul-li等其他方式布局时的示例</h3>
<div>
<my:countGroup count="<%=currentInt %>" fill="<li class='default_td'>填补</li>"
fillStart="<ul>" separator="</li>"
fillEnd="</ul>">
<c:forEach var="item" begin="1" end="<%=totalInt %>">
<li>这是表格${item }</li>
</c:forEach>
</my:countGroup>
</div>
<hr/>
<p style="font-size: 20px;">
本次共有<%=totalInt %>个元素,每行显示<%=currentInt %>个元素,
<%
if(totalInt % currentInt == 0){
%>正好显示<%=totalInt / currentInt %>行<%
}else{
int rows = totalInt % currentInt + 1;
%>显示<%=rows %>行,其中最后一行需要补充<%=currentInt - totalInt % currentInt %>个元素<%
}
%>
</p>
</body>
</html>
(分别展示使用table与ul两种布局的示例)
说明:当前示例原始为JSP页面的动态示例,可从博客V1版本中开放的源码中获取,dmeo页面路径为“/demo/myTag/autoWarp.jsp”。
点赞