中国队世界杯_2014世界杯德国 - dyhdcw.com

javaweb回顾第八篇如何创建自定义标签

前言:在javaweb开发中自定义标签的用处还是挺多的。今天和大家一起看自定义标签是如何实现的。

1:什么是标签

标签是一种XML元素,通过标签可以使JSP页面变得简介易用,而且标签具有很好的复用性。

2:自定义标签的标签库主要的接口以及类的继承实现关系图

3:一步步实现自定义标签

3.1:Tag接口

我们先看一个标签这个标签有开始标签和结束标签,而且还有这样的父标签,那么实现一个简单的标签需要什么呢

第一:开始标签 第二:结束标签第三:资源释放3个方法,而且还有父标签,如果我们要得到这个JSP上的内容我们还需要一个PageContext那么现在我们应该清晰了实现一个标签需要的元素。ok我们来看看Tag接口都有哪些内容

3.1.1:int doStartTag() throws JspException;这个是开始执行的起始方法

3.1.2:int doEndTag() throws JspException;这个是即将结束的结束方法

3.1.3:void release();释放对象的资源

3.1.4:void setPageContext(PageContext pc);设置当前页的上下文对象

3.1.5: void setParent(Tag t);设置父标签

3.1.6:Tag getParent();获取父标签

通过上面的介绍我们现在应该知道怎么去写一个标签了,我们小试牛刀一下

public class HelloTag implements Tag{

private PageContext pageContext;

private Tag parent;

public void setPageContext(PageContext pc) {

this.pageContext=pc;//这个方法由jsp页面的实现对象调用

}

public void setParent(Tag t) {

this.parent=t;

}

public Tag getParent() {

return parent;

}

public int doStartTag() throws JspException {

return SKIP_BODY;

}

public int doEndTag() throws JspException {

//利用pageContext来获取jspWriter对象

JspWriter out=pageContext.getOut();

try {

//利用JSPWriter向客户端输入信息

out.print("Hello Tag");

} catch (IOException e) {

e.printStackTrace();

}

return SKIP_PAGE;

}

public void release() {

}

其中SKIP_BODY表示忽略标签体内容,下面我们会说到。既然写完了一个标签体我们就开始配置了

首先在WEB-INFO创建一个tlds文件夹然后创建一个tld文件然后设置如下

hello

com.lp.tags.HelloTag

empty//表示标签没有内容

然后我们在创建一个jsp文件然后在jsp文件头部加上Taglib指令元素<%@ taglib uri="/WEB-INF/tlds/CustomTaglib.tld" prefix="hello"%>

在jsp页面就可以直接引用HelloTag标签了比喻我的是

启动运行结果如下

有人又问了如果这样的标签都有属性啊,如果有属性我怎么办呢,这个也简单没有属性我们就加入属性。我们来实现一个加法的自定义标签。这个我使用TagSupport类,从上面图中我们可以看出这个类实现了Tag接口,它会使我们写标签更加简单

public class AddTag extends TagSupport{

private int num1;

private int num2;

public int getNum2() {

return num2;

}

public void setNum2(int num2) {

this.num2 = num2;

}

public int getNum1() {

return num1;

}

public void setNum1(int num1) {

this.num1 = num1;

}

public int doEndTag() throws JspException

{

JspWriter out=pageContext.getOut();

int num=num1+num2;

try {

out.print(num);

} catch (IOException e) {

e.printStackTrace();

}

return EVAL_PAGE;

}

有人又问你为什么没有写doStartTag方法啊,其实TagSupport类已经帮我们实现了,它默认情况是忽略标签中的内容的。现在我们在此配置tld文件

add

com.lp.tags.AddTag

//表示属性

num1属性命名

true是否必须输入

true是否是可运行的表达式

num2

true

true

现在我们在jsp中加入以下代码

<%@ taglib uri="/WEB-INF/tlds/CustomTaglib.tld" prefix="addtaglib"%>

自定义的标签:

<%

int num1 = Integer.parseInt(request.getParameter("num1"));

int num2 = Integer.parseInt(request.getParameter("num2"));%>

算法:

再次运行我们看看结果

有人又说了,你这写的标签都没有标签内容,你能不能实现一个标签带有内容的呢,ok这个没问题,刚刚我们说了SKIP_BODY表示忽略标签内容那么有个相反的EVAL_BODY_INCLUDE表示带有标签中的内容,在这里我们一起实现一个Switch case default三个标签体联用的简单功能

我们先看SwitchTag标签

public class SwitchTag extends TagSupport{

private static final long serialVersionUID = 1L;

//用于判断子标签是否已执行

private boolean childTagExec;

public SwitchTag()

{

childTagExec=false;

}

public int doStartTag() throws JspException

{

//当遇到switch的起始标签的时候子标签还没执行

childTagExec=false;

return EVAL_BODY_INCLUDE;//此时开始执行Switch内部的Case标签了

}

/**

* 由子标签处理器对象调用,用于判断是否可以执行自身的标签体

* @return

*/

public synchronized boolean isExec()

{

return (!childTagExec);

}

/**

* 如果子标签任何一个满足条件就调用这个方法 通知父标签

* 这样其他子标签就忽略他们自身标签体,从而实现Switch case

*/

public synchronized void childTagSucceeded()

{

childTagExec=true;

}

public void release()

{

childTagExec=false;

}

CaseTag

public class CaseTag extends TagSupport{

private static final long serialVersionUID = 1L;

private boolean cond;//表示条件(比喻case:1此类)

public CaseTag()

{

cond=false;

}

public void setCond(boolean cond)

{

this.cond=cond;

}

public int doStartTag() throws JspException

{

Tag parent=getParent();//获取父标签

//判断是否可以执行自身标签

if(!((SwitchTag)parent).isExec())

{

return SKIP_BODY;

}

//如果条件为true,则通知父标签有一个子标签满足条件

//否则忽略标签体

if(cond)

{

((SwitchTag)parent).childTagSucceeded();

return EVAL_BODY_INCLUDE;

}

else {

return SKIP_BODY;

}

}

public void release()

{

cond=false;

}

DefaultTag

public class DefaultTag extends TagSupport{

private static final long serialVersionUID = 1L;

public int doStartTag() throws JspException

{

Tag parent=getParent();

if (!((SwitchTag)parent).isExec()) {

return SKIP_BODY;

}

((SwitchTag)parent).childTagSucceeded();//如果所有Case都不满足则执行Default标签

return EVAL_BODY_INCLUDE;

}

}

我们在次配置tld文件

switch

com.lp.tags.SwitchTag

jsp

case

com.lp.tags.CaseTag

jsp

cond

true

true

default

com.lp.tags.DefaultTag

jsp

其中jsp中jsp表示支持jsp具有的一切功能(比喻jsp9种内置对象)

<%

String userName = request.getParameter("userName");

%>

<%out.print("张三");%>

<%out.print("李四");%>

<%out.print("王五");%>

<%out.print("无");%>

现在开始执行效果如下

3.1:IterationTag接口

上面我们都一直说的标签内容都一次性完成,但是如果是循环标题体内容怎么办,那么就用到了IterationTag接口,此接口增加了一个方法

public int doAfterBody() throws JspException该方法表示每次对标签体处理之后被调用也就是说在doStartTag方法之后doEndTag方法之前被调用,如果没有的话就不执行。

新增加了一个常量EVAL_BODY_AGAIN表示再次执行标签体。现在我们实现一个获取多条用户信息展示的功能

public class UserBean implements Serializable{

private static final long serialVersionUID = 1L;

public UserBean(){}

public UserBean(String userName,int age,String email)

{

this.age=age;

this.email=email;

this.userName=userName;

}

private String userName;

private int age;

private String email;

public String getUserName() {

return userName;

}

public void setUserName(String userName) {

this.userName = userName;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String getEmail() {

return email;

}

public void setEmail(String email) {

this.email = email;

}

}

public class IterateTag extends TagSupport{

private static final long serialVersionUID = 1L;

private Iterator items;//获取集合

private String itemId;//对象的标识

private Object item;//迭代对象中的每一个对象

public IterateTag()

{

items=null;

}

public void release()

{

items=null;

}

/**

* 得到集合的迭代对象

*/

public void setItems(Collection cl)

{

if(cl.size()>0)

items=cl.iterator();

}

public void setVar(String var)

{

this.itemId=var;

}

public int doStartTag()throws JspException

{

if(items.hasNext())//首先被执行

{

item=items.next();

}

else{

return SKIP_BODY;

}

saveItems();//把迭代的对象保存在pageContext中

return EVAL_BODY_INCLUDE;

}

public int doAfterBody() throws JspException

{

if(items.hasNext())//直到把迭代对象中的每一项都放进pageContext中

{

item=items.next();

}

else{

return SKIP_BODY;

}

saveItems();

return EVAL_BODY_AGAIN;

}

public void saveItems()

{

if(item==null)

{

pageContext.removeAttribute(itemId,pageContext.PAGE_SCOPE);

}

else{

pageContext.setAttribute(itemId, item);//如果加入相同的id会进行覆盖

}

}

}

iterate

com.lp.tags.IterateTag

JSP

items

true

true

var

true

false

<%

ArrayList al = new ArrayList();

UserBean user1 = new UserBean("zhangsan", 25, "7808@outlook.com");

UserBean user2 = new UserBean("lisi", 15, "16455@qq.com");

UserBean user3 = new UserBean("wangwu", 35, "7808@outlook.com");

al.add(user1);

al.add(user2);

al.add(user3);

%>

用户名 年龄 邮箱
${user.age} ${user["email"]}

效果如下

4:简单标签开发

为了简化自定义标签开发,JSP2.0加入了简单标签的开发实现的接口是SimpleTag,我们一起看下SimpleTag的主要方法

4.1: public void setJspContext( JspContext pc )该方法被容器调用,设置JspContext,JspContext 是PageContext的基类

4.2:public void setParent( JspTag parent );设置父标签

4.3:public JspTag getParent();获取父标签

4.4:public void setJspBody( JspFragment jspBody );该方法用于设置标签体标签体,标签体由JspFragment对象提供,可以把JspFragment看做是一个对象封装一段JSP代码,可以被多次执行。

4.5:public void doTag(),主要处理标签和标签体的业务逻辑

public class WelcomeSimpleTag extends SimpleTagSupport{

private JspFragment jspFragment;

private String name;

public void setJspBody(JspFragment jspBody)

{

this.jspFragment=jspBody;

}

public void setName(String name)

{

this.name=name;

}

public void doTag() throws JspException, IOException

{

JspContext jspContext=getJspContext();

JspWriter out=jspContext.getOut();

out.print(name);

jspFragment.invoke(null);

}

然后在jsp页面之间调用即可。关于简单标签的开发,大家可以自行实践。

最新发表
友情链接

Copyright © 2022 中国队世界杯_2014世界杯德国 - dyhdcw.com All Rights Reserved.