foreach
业务
在定义foreach标签时我们需要了解它的业务是什么:很显然foreach标签需要得到一个集合,然后再这个集合的基础上遍历这个集合。当我们清楚业务逻辑后就可以开始定义foreach标签了
既然是需要得到一个集合,然后再遍历这个集合。那我们就知道了需要两个属性,一个是得到一个集合属性,另一个是遍历这个集合的值。
定义助手类
public class ForeachTag extends BodyTagSupport{
//接收传进来的集合
private List<?> items;
//遍历输出的值
private String var;
public void setItems(List<?> items) {
this.items = items;
}
public void setVar(String var) {
this.var = var;
}
@Override
public int doStartTag() throws JspException {
if(this.items==null|"".equals(this.items)) {
return SKIP_BODY;
}
//使用迭代器
Iterator<?> iter = this.items.iterator();
//得带它的下一位
Object next = iter.next();
//把下一位的值赋值给var
this.pageContext.setAttribute(this.var, next);
this.pageContext.setAttribute("iterator", iter);
return EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
Iterator<?> iter=(Iterator<?>) this.pageContext.getAttribute("iterator");
if(iter.hasNext()) {
Object next= iter.next();
this.pageContext.setAttribute(this.var, next);
return EVAL_BODY_AGAIN;
}
return SKIP_BODY;
}
}
代码讲解
doStartTag()方法
在doStartTag()方法中,我们首先需要判断传进来的值是否有数据,如果连数据都没有的话那还怎么遍历呢。
if(this.items==null|"".equals(this.items)) {
return SKIP_BODY;
}
如果有数据,if条件为false的话,就可以继续开始编写我们的代码了。因为我们是要遍历数据,所以我们需要把集合里面的值一个一个输出,然后一个一个的赋值。在这里我们就使用到了iterator()也就是迭代器。在迭代器中如果有值,我们就把值赋值给var,也就是我定义的遍历输出的值。注意:在这里我们不能直接在dostartTag方法里面把当前集合给赋值完,因为dostartTag方法只是开始,它是不能直接处理标签体的。如果不懂可以看下我前面的一篇文章,在那里我写到过。所以接下来我们就需要把迭代器的值用pageContext存储起来,在doAfterBody方法中要使用到
//使用迭代器
Iterator<?> iter = this.items.iterator();
//得带它的下一位
Object next = iter.next();
//把下一位的值赋值给var
this.pageContext.setAttribute(this.var, next);
this.pageContext.setAttribute("iterator", iter);
doAfterBody方法
在doAfterBody方法里面我们首先要得到我们存储的迭代器,然后就可以开始判断迭代器中是否还有数据。如果有数据,就把数据赋值到var中,如果没有则结束
EVAL_BODY_AGAIN:表示再次进入循环体
if(iter.hasNext()) {
Object next= iter.next();
this.pageContext.setAttribute(this.var, next);
return EVAL_BODY_AGAIN;
}
现在我们的助手类已经编写完,接下来就可以开始定义我们的tld文件了
定义tld文件
<taglib >
<tlib-version>1.0</tlib-version><!-- tld版本号 -->
<jsp-version>1.2</jsp-version><!-- jsp版本号 -->
<short-name>Simple Tags</short-name>
<uri>/zking</uri><!-- 自己定义的路径 -->
<!-- foreach标签定义 -->
<tag>
<name>foreach</name>
<tag-class>com.zking.jee09.ForeachTag</tag-class>
<!--该标签有标签体-->
<body-content>jsp</body-content>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>var</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
</taglib>
tld文件的属性名是什么意思我就不在赘述了,这个也在我前面一篇文章里面讲解了。当我们tld文件定义好后就可以开始在页面上使用自定义jsp标签了
使用自定义jsp标签
<%
//获取数据
List<Book> ls=TestData.getBooks();
//把数据放到request里面
request.setAttribute("ls", ls);
%>
<!-- 使用foreach标签 -->
<z:foreach items="${ls}" var="book">
<p>${book.id}</p>
<p>${book.name }</p>
</z:foreach>
list集合是我定义的一个测试实体类,代码如下
public class Book {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
代码讲解
因为在我们自定义jsp标签中,我们是需要判断传入的集合是否有值。所以我们在使用jsp标签之前,需要得到一个集合。所以就需要在jsp页面中写入java代码
<%
//获取数据
List<Book> ls=TestData.getBooks();
//把数据放到request里面
request.setAttribute("ls", ls);
%>
之后我们再使用我们自己定义的jsp标签就可以了
<!-- 使用foreach标签 -->
<z:foreach items="${ls}" var="book">
<p>${book.id}</p>
<p>${book.name }</p>
</z:foreach>
这样我们的foreach标签就定义完了,接下来就开始定义我们的select标签
select标签
业务
使用select标签无疑就是要用到下拉按钮,在下来按钮中我们可以设置样式,可以设置id,可以设置name属性,还可以设置默认选中的值。所以这些都是我们在定义select标签中需要考虑的。那接下来就可以开始我们的助手类了
助手类
/**
* select option 助手类
* @author Administrator
*
*/
public class SelectTag extends BodyTagSupport{
//属性id
private int id;
//名称
private String name;
//读取数据库表
private List<?> items;
//提交值
private String value;
//表单名称
private String test;
//外部class样式
private String cssClass;
//内部样式
private String cssStyle;
//默认选中的值
private String selectValue;
//自动加载函数
private String onChange;
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setItems(List<?> items) {
this.items = items;
}
public void setValue(String value) {
this.value = value;
}
public void setTest(String test) {
this.test = test;
}
public void setCssClass(String cssClass) {
this.cssClass = cssClass;
}
public void setCssStyle(String cssStyle) {
this.cssStyle = cssStyle;
}
public void setSelectValue(String selectValue) {
this.selectValue = selectValue;
}
public void setOnChange(String onChange) {
this.onChange = onChange;
}
@Override
public int doStartTag() throws JspException {
JspWriter out =this.pageContext.getOut();
try {
out.println(html());
} catch (IllegalAccessException|InvocationTargetException|NoSuchMethodException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return super.doStartTag();
}
private String html() throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
StringBuilder sb=new StringBuilder();
sb.append("<select id='"+this.id+"' name='"+this.name+"'");
if(this.cssClass!=null|!"".equals(this.cssClass)) {
sb.append(" class='"+this.cssClass+"'");
}
if(this.cssStyle!=null|!"".equals(this.cssStyle)) {
sb.append(" style='"+this.cssStyle+"'");
}
if(this.onChange!=null|!"".equals(this.onChange)) {
sb.append(" onchange='"+this.onChange+"'");
}
sb.append(">");
for (Object obj : this.items) {
String val= BeanUtils.getProperty(obj, this.value);
String txt= BeanUtils.getProperty(obj, this.test);
boolean f=this.selectValue!=null&!"".equals(this.selectValue)&val.equals(this.selectValue);
if(f==true) {
sb.append("<option value='"+val+"' selected>" +txt+"</option>");
}else {
sb.append("<option value='"+val+"' >" +txt+"</option>");
}
}
sb.append("</select>");
return sb.toString();
}
}
在助手类中其实跟foreach差不多,如果你认真看来foreach标签应该就能理解。
代码讲解
dostartTag方法
在dostartTag方法中就只有一个功能,就是显示下拉款而且。
@Override
public int doStartTag() throws JspException {
JspWriter out =this.pageContext.getOut();
try {
out.println(html());
} catch (IllegalAccessException|InvocationTargetException|NoSuchMethodException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return super.doStartTag();
}
private String html()方法
在这个方法中我们需要显示下拉款功能。因为我们是需要使用在jsp页面中的,所以我们需要在这个方法中写入HTML代码。在java代码中要写入HTML代码的话就需要使用拼接的方式来完成。这里有三种方法,第一个StringBuilder,第二个String,第三个StringBuffer。这三个有什么区别呢?还真的有区别,
StringBuilder
线程不安全,但是在使用拼接的时候速度会很快
String
在每次new的时候会产生新的节点,但是在jdk8之后使用拼接是跟StringBuilder一样的效果
StringBuffer
线程安全,但是速度慢
所以我们是在局部变量里面使用的,这里我就使用了StringBuilder的拼接方式来完成。因为我们不清楚每个人想要实现的功能是什么,所以我们需要对可写,可不写的属性要进行判断。如果需要此功能则加进去,如果不需要就不用增加进去
StringBuilder sb=new StringBuilder();
sb.append("<select id='"+this.id+"' name='"+this.name+"'");
if(this.cssClass!=null|!"".equals(this.cssClass)) {
sb.append(" class='"+this.cssClass+"'");
}
if(this.cssStyle!=null|!"".equals(this.cssStyle)) {
sb.append(" style='"+this.cssStyle+"'");
}
if(this.onChange!=null|!"".equals(this.onChange)) {
sb.append(" onchange='"+this.onChange+"'");
}
sb.append(">");
接下来就要遍历我们的items了,为什么要遍历它呢?原因很简单。因为我们存储的是下拉框,那些数据是在数据库表里面的,所以我们需要定义一个集合来接收它。
在这里面我们需要进行判断默认选中的值,如果有默认选中的值则选中,没有则默认选中第一个。
for (Object obj : this.items) {
String val= BeanUtils.getProperty(obj, this.value);
String txt= BeanUtils.getProperty(obj, this.test);
boolean f=this.selectValue!=null&!"".equals(this.selectValue)&val.equals(this.selectValue);
if(f==true) {
sb.append("<option value='"+val+"' selected>" +txt+"</option>");
}else {
sb.append("<option value='"+val+"' >" +txt+"</option>");
}
}
sb.append("</select>");
定义tld文件
<!-- select标签定义 -->
<tag>
<name>select</name>
<tag-class>com.zking.jee09.SelectTag</tag-class>
<!--该标签有标签体-->
<body-content>empty</body-content>
<attribute>
<name>id</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>name</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>value</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>test</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>selectValue</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>cssClass</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>cssStyle</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>onChange</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
在页面上使用自定义jsp标签
<z:select name="aa" id="aa" test="name" items="${ls}" value="id" selectValue="2"/>
在这里我使用了我在上面定义的实体类,在这里value值就是book实体类中的id,items就是book实体类的集合,test是下拉框的名称,selectValue是默认选中的下拉框。这样直接复制代码区试一下,这样我们的select标签就出来了