`
jianfulove
  • 浏览: 118266 次
  • 性别: Icon_minigender_1
  • 来自: 湛江
社区版块
存档分类
最新评论

JSP标签在tomcat中的运行原理

    博客分类:
  • JSP
阅读更多


        在网上找了很多关于jsp标签的文章,但大多数都是只是告诉你怎么去使用,怎么去编写一个jsp标签。几乎没有可以从源头上告诉你怎么去理解原理,它在tomcat中又是怎么样的呢?所以我花一点时间整理一编关于jsp标签原理的文章,如有什么不周祥之处还望各位大侠谅解。
     
        首先我们需要大致了解开发自定义标签所涉及到的接口与类的层次结构(其中SimpleTag接口与SimpleTagSupport类是JSP2.0中新引入的)。

  

         (一) JSP自定义标签的定义步骤:

            1  创建标记处理类

            2   创建TLD文件

            3   在jsp页面通

                过指令引入标签库

    

 

 

 

 

1、处理标签的类必须扩展javax.servlet.jsp.TagSupport 或 BodyTagSupport。先来讨论TagSupport

2、TagSupport类的主要属性:

A.parent属性:代表嵌套了当前标签的上层标签的处理类;

B.pageContex属性:代表Web应用中的javax.servlet.jsp.PageContext对象;

3、JSP容器在调用doStartTag或者doEndTag方法前,会先调用setPageContext和setParent方法,设置pageContext和parent。因此在标签处理类中可以直接访问pageContext变量;

4、在TagSupport的构造方法中不能访问pageContext成员变量,因为此时JSP容器还没有调用setPageContext方法对pageContext进行初始化。

 

先写一个扩展javax.servlet.jsp.TagSupport的标签类MyTag :

package com.common.tag;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

public class MyTag extends TagSupport
{
    int i=1;
    String first;
    String date;
    JspWriter jw;
public int doStartTag() throws JspException {
    jw=super.pageContext.getOut();
    try {
        jw.print("this is first field :"+getFirst() +"<br/>");
        jw.print("this is first date :"+getDate() +"<br/>");
    } catch (IOException e) {
        e.printStackTrace();
    }
    
    return TagSupport.EVAL_BODY_INCLUDE;
}
 
  public int doAfterBody() throws JspException {
      try {
        jw.println(i++ + "     :我想知道这里doafterbody都做了些什么了呢<br/>");
        
    } catch (IOException e) {
        e.printStackTrace();
    }
      if(5==i)return TagSupport.SKIP_BODY;
     return TagSupport.EVAL_BODY_AGAIN;
    }
  
  public int doEndTag() throws JspException {
      try {
        jw.print("最后的结束标签了,doendtag");
    } catch (IOException e) {
        e.printStackTrace();
    }
      return TagSupport.EVAL_PAGE;
    }
  public String getFirst() {
        return first;
    }
    public void setFirst(String first) {
        this.first = first;
    }
    public String getDate() {
        SimpleDateFormat sdf=new SimpleDateFormat(date);
        return sdf.format(new Date());
    }
    public void setDate(String date) {
        this.date = date;
    }
  
}
 

 

 

 我们以Tomcat 6.0.20服务器为例,来看看最简单的myTag.jsp是怎么运行的。

    我们仅以myTag.jsp中的 <my:mytag/>标签的解析为例进行分析,看容器是怎样把这个自定义标签解析成HTML输出的。

<%@ taglib prefix="my" uri="/my-tags" %>
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'index.jsp' starting page</title>
  </head>
  
  <body>
       <br>
    
    <my:mytag date="yyyy-MM-dd HH-mm-ss" first=" {这是我第一个属性}">
    
      中间体执行吧。
    
    </my:mytag>
    
  </body>
</html>

 

   先附上我执行的结果:

 

this is first field : {这是我第一个属性}
this is first date :2013-03-10 01-28-02
中间体执行吧。 1 :我想知道这里doafterbody都做了些什么了呢
中间体执行吧。 2 :我想知道这里doafterbody都做了些什么了呢
中间体执行吧。 3 :我想知道这里doafterbody都做了些什么了呢
中间体执行吧。 4 :我想知道这里doafterbody都做了些什么了呢
最后的结束标签了,doendtag

 

    让我们来看看Tomcat都做了什么。转到Tomcat的\work\Standalone\localhost\_目录下,可以找到如下的myTag_jsp.java,这个文件就是Tomcat解析myTag.jsp时生成的源文件:

 

public final class myTag_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent {

  private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();

  private static java.util.List _jspx_dependants;

  static {
    _jspx_dependants = new java.util.ArrayList(1);
    _jspx_dependants.add("/WEB-INF/myTag.tld");
  }

   //为所有的定制标签定义处理器池类的引用 
  private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fmy_005fmytag_0026_005ffirst_005fdate;

  private javax.el.ExpressionFactory _el_expressionfactory;
  private org.apache.AnnotationProcessor _jsp_annotationprocessor;
..................
.............
//为处理器池类赋值
 public void _jspInit() {
    _005fjspx_005ftagPool_005fmy_005fmytag_0026_005ffirst_005fdate = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
    _jsp_annotationprocessor = (org.apache.AnnotationProcessor) getServletConfig().getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());
  }
  public void _jspService(HttpServletRequest request, HttpServletResponse response)
        throws java.io.IOException, ServletException {

    PageContext pageContext = null;
    HttpSession session = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;
    Object page = this;
    JspWriter _jspx_out = null;
    PageContext _jspx_page_context = null;


    try {
      response.setContentType("text/html;charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
                  null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("\r\n");
      out.write("\r\n");

String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
        ................
     .......................
      out.write("  <body>\r\n");
      out.write("    This is my JSP page. <br>\r\n");
      out.write("    \r\n");
      out.write("    ");
      if (_jspx_meth_my_005fmytag_005f0(_jspx_page_context)) //标签的处理,请往下看方法的实现。
        return;
      out.write("\r\n");
      out.write("    \r\n");
      out.write("    \r\n");
      out.write("  </body>\r\n");
      out.write("</html>\r\n");
    } catch (Throwable t) {
      if (!(t instanceof SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try { out.clearBuffer(); } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
                 //真正处理标签<my:myTag  >方法
  private boolean _jspx_meth_my_005fmytag_005f0(PageContext _jspx_page_context)
          throws Throwable {
    PageContext pageContext = _jspx_page_context;
    JspWriter out = _jspx_page_context.getOut();
    //  my:mytag
    com.common.tag.MyTag _jspx_th_my_005fmytag_005f0 = (com.common.tag.MyTag) _005fjspx_005ftagPool_005fmy_005fmytag_0026_005ffirst_005fdate.get(com.common.tag.MyTag.class);
//JSP容器在调用doStartTag或者doEndTag方法前,会先调用setPageContext和setParent方法,设置pageContext和parent,而且也调用setFiled()方法设置标签的相关属性;
    _jspx_th_my_005fmytag_005f0.setPageContext(_jspx_page_context);
    _jspx_th_my_005fmytag_005f0.setParent(null);
    // /index.jsp(19,4) name = date type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
    _jspx_th_my_005fmytag_005f0.setDate("yyyy-MM-dd HH-mm-ss");
    // /index.jsp(19,4) name = first type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
    _jspx_th_my_005fmytag_005f0.setFirst(" {这是我第一个属性}");
    int _jspx_eval_my_005fmytag_005f0 = _jspx_th_my_005fmytag_005f0.doStartTag();   // JSP容器 处理                                                                                 //到自 定义标签的起始标志,就会调用doStartTag()方法
    if (_jspx_eval_my_005fmytag_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {  //如果doStartTag()方
                                                                                               // 法返回值不是Tag.SKIP_BODY就执行标签体
      do {
        out.write("\r\n");
        out.write("    \r\n");
        out.write("      中间体执行吧。\r\n");         
        out.write("    \r\n");
        out.write("    ");
        int evalDoAfterBody = _jspx_th_my_005fmytag_005f0.doAfterBody();              //看到这里你应该知道
                                                                                                      //tomcat是怎么处理doAfterBody(); 了吧。
        if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN) //如果doAfterBody()返
                                                      //回值是EVAL_BODY_AGAIN,则再次执行方法体和doAfterBody()方法,
                                                                                                                                 // 直到doAfterBody()返
                                                                                                                     //回值为SKIP_BODY才跳出循环
          break;
      } while (true);
    }               //do{}while(true)无论doAfterBody()返回值如何都会执行方法体一次
    if (_jspx_th_my_005fmytag_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
      _005fjspx_005ftagPool_005fmy_005fmytag_0026_005ffirst_005fdate.reuse(_jspx_th_my_005fmytag_005f0);
      return true;
    }
    _005fjspx_005ftagPool_005fmy_005fmytag_0026_005ffirst_005fdate.reuse(_jspx_th_my_005fmytag_005f0);
    return false;
  }
}

 

   生成的myTag_jsp.java继承于org.apache. jasper.runtime.HttpJspBase。研究这个文件为我们了解定制标签的运行机理提供了途径。

   从上面可以看出,Tomcat在解析一个JSP页面时,首先为每一个定制标签定义并实例化了一个TagHandlerPool对象。页面的处理方法覆盖 父类的_ jspService()方法,_jspService方法首先初始化环境,为内置对象赋值。由于myTag.jsp页面整体由一 个<html:html/>标签包裹,Tomcat对每一个标签都产生一个私有方法加以实现。<html:html/>标签的处 理方法是_jspx_meth_html_html_0()。这个方法的命名规范大家也可以从这里看出,就是“_jspx_meth + 标签的前缀 + 标签名 + 该标签在JSP页面同类标签中出现的序号”。其它标签都被包含在该标签中,所以其它标签在_jspx_meth_html_html_0()方法中进行解 析。

  在_jspx_meth_html_html_0()方法中,首先从_jspx_tagPool_html_html_locale池中得到一个 org.apache.struts.taglib.html.HtmlTag的实例,然后设置这个tag实例的页面上下文及上级标签,由于 html:html标签是页面的最顶层标签,所以它的parent是null。然后对该标签的内容进行解析。HTML代码直接输出,下面主要看 看<html:html></html:html>标签之间包含的<my:mybodyTag count="5" >标签的解析。

                对<my:mytag>标签的解析类似于html:html,Tomcat也将其放入一个 单独的方法_jspx_meth_my_005fmytag_005f0()中进行。

在myTag.jsp中定义了一个<my:mytag>标签,并设置了一个属性: <my:mytag date="yyyy-MM-dd HH-mm-ss" first=" {这是我第一个属性}">。Tomcat在解析时,调用MyTag对象的date和first属性设置方法setDate()和setFirst(),将该属性置 入。然后调用MyTag的doStartTag()和doEndTag()方法,完成解析。如果doEndTag()方法的返回值为 javax.servlet.jsp.tagext.Tag. SKIP_PAGE,表明已经完成解析,返回true,Tomcat将立即停止剩余页面代码的执行,并返回。如果doEndTag()方法的返回值为TagSupport.EVAL_PAGE ,表明还没完成解析,返回false,继续解析这个标签后面的内容。并在最后把该MyTag的实例放回池 中。

  标签类对象实例的池化
  为了提高运行效率,Tomcat对所有的定制标签类进行了池化,池化工作由org.apache.jasper. runtime.TagHandlerPool类完成。TagHandlerPool类主要有两个方法,代码如下:

TagHandlerPool.java

public class TagHandlerPool {
private static final int MAX_POOL_SIZE = 5;
private Tag[] handlers;
public synchronized Tag get(Class handlerClass) throws JspException {……}
public synchronized void reuse(Tag handler) {……}
}
   TagHandlerPool简单地实现了对标签类的池化,其中MAX_POOL_SIZE是池的初始大小,handlers是一个Tag的数组,存储标 签类的实例。get(Class handlerClass)得到一个指定标签类的实例,如果池中没有可用实例,则新实例化一个。reuse(Tag handler)把handler对象放回池中。

  至此,我们对JSP在容器中的运行过程已经了然于胸 了。虽然每种JSP容器的解析结果会有差异,但其中的原理都雷同。对于编写JSP应用,我们并不需要干涉容器中的运行过程,但如果你对整个底层的运行机制 比较熟悉,就能对JSP/Servlet技术有更深的认识。

 

  

     二   我们再来讨论标签类继承BodyTagSupport

我们仅以myBodyTag.jsp中的 <my:mybody/>标签的解析为例进行分析,看容器是怎样把这个自定义标签解析成HTML输出的。

<%@ taglib prefix="my" uri="/my-tags" %>
            <html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'index.jsp' starting page</title>
  </head>
  
  <body>
    <br/>    
    <my:mybodyTag count="5" >
    
                              中间体执行吧。<br/>
    
    </my:mybodyTag>
  </body>
</html>
 

 

先附上执行后的结果:

---dostartTag---
---setBodyContent---
---doinitBody---

0 :---doAfterBody---

1 :---doAfterBody---

2 :---doAfterBody---

3 :---doAfterBody---

4 :---doAfterBody---

---doEndTag---
中间体执行吧。
中间体执行吧。
中间体执行吧。
中间体执行吧。
中间体执行吧。
中间体执行

 

          让我们来看看Tomcat都做了什么。转到Tomcat的\work\Standalone\localhost\_目录下,可以找到如下的myBodyTag_jsp.java,这个文件就是Tomcat解析myBodyTag.jsp时生成的源文件:

 

public final class myBodyTag_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent {

  private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();

  private static java.util.List _jspx_dependants;

  static {
    _jspx_dependants = new java.util.ArrayList(1);
    _jspx_dependants.add("/WEB-INF/myTag.tld"); //加载标签描述文件
  }
           //为所有的定制标签定义处理器池类的引用 
  private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fmy_005fmybodyTag_0026_005fcount;

  private javax.el.ExpressionFactory _el_expressionfactory;
  private org.apache.AnnotationProcessor _jsp_annotationprocessor;

  public Object getDependants() {
    return _jspx_dependants;
  }

  public void _jspInit() {
    _005fjspx_005ftagPool_005fmy_005fmybodyTag_0026_005fcount = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());//给处理池类赋值
    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
    _jsp_annotationprocessor = (org.apache.AnnotationProcessor) getServletConfig().getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());
  }

  public void _jspDestroy() {
    _005fjspx_005ftagPool_005fmy_005fmybodyTag_0026_005fcount.release();
  }

  public void _jspService(HttpServletRequest request, HttpServletResponse response)
        throws java.io.IOException, ServletException {

    PageContext pageContext = null;
    HttpSession session = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;
    Object page = this;
    JspWriter _jspx_out = null;
    PageContext _jspx_page_context = null;


    try {
      response.setContentType("text/html; charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
                  null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("\r\n");
      out.write("\r\n");

String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

      out.write("\r\n");
      out.write("\r\n");
      out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");
      out.write("<html>\r\n");
      out.write("  <head>\r\n");
      out.write("    <base href=\"");
      out.print(basePath);
      out.write("\">\r\n");
      out.write("    \r\n");
      out.write("    <title>My JSP 'index.jsp' starting page</title>\r\n");
      out.write("  </head>\r\n");
      out.write("  \r\n");
      out.write("  <body>\r\n");
      out.write("    <br/>    \r\n");
      out.write("    ");
      if (_jspx_meth_my_005fmybodyTag_005f0(_jspx_page_context))
        return;             //标签被处理的方法
      out.write("\r\n");
      out.write("    \r\n");
      out.write("    \r\n");
      out.write("  </body>\r\n");
      out.write("</html>\r\n");
    } catch (Throwable t) {
      if (!(t instanceof SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try { out.clearBuffer(); } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }

  private boolean _jspx_meth_my_005fmybodyTag_005f0(PageContext _jspx_page_context)
          throws Throwable {
    PageContext pageContext = _jspx_page_context;
    JspWriter out = _jspx_page_context.getOut();
    //  my:mybodyTag
    com.common.tag.MyBodyTag _jspx_th_my_005fmybodyTag_005f0 = (com.common.tag.MyBodyTag) _005fjspx_005ftagPool_005fmy_005fmybodyTag_0026_005fcount.get(com.common.tag.MyBodyTag.class);
    _jspx_th_my_005fmybodyTag_005f0.setPageContext(_jspx_page_context);
    _jspx_th_my_005fmybodyTag_005f0.setParent(null);
    // /myBodyTag.jsp(18,4) name = count type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
    _jspx_th_my_005fmybodyTag_005f0.setCount(5);
    int _jspx_eval_my_005fmybodyTag_005f0 = _jspx_th_my_005fmybodyTag_005f0.doStartTag();          //执行.doStartTag()
    if (_jspx_eval_my_005fmybodyTag_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {                           //继承BodyTagSupport处继承TagSupport不同之处就是以下标为棕色的代码了。
      if (_jspx_eval_my_005fmybodyTag_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {    
        out = _jspx_page_context.pushBody();   //如果dostartTag()返回BodyTagSupport.EVAL_BODY_BUFFERED; 注意了此时的out 引用已经被改赋值为BodyContent对象了。它会把它会通过out.print()设置标签体的内容缓存起来,
直到super.bodyContent.writeOut(getPreviousOut())执行到再输出标签体的内容
                                                                    
        _jspx_th_my_005fmybodyTag_005f0.setBodyContent((javax.servlet.jsp.tagext.BodyContent) out); //setBodyContent()方法用于设置标签体内容,如果在此之前要作一些初始化工作,
                                                                                                                                                                     //则在doInitBody()方法中完成
        _jspx_th_my_005fmybodyTag_005f0.doInitBody();
      }
      do {
        out.write("\r\n");
        out.write("    \r\n");
        out.write("                              中间体执行吧。<br/>\r\n");
        out.write("    \r\n");
        out.write("    ");
        int evalDoAfterBody = _jspx_th_my_005fmybodyTag_005f0.doAfterBody();           //这里在讲继承TagSupport处理类时是一样的,请看前面
        if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)
          break;
      } while (true);
      if (_jspx_eval_my_005fmybodyTag_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
        out = _jspx_page_context.popBody();
      }
    }
    if (_jspx_th_my_005fmybodyTag_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {  //这里执行了.doEndTag()方法//如果 此方法中没有super.bodyContent.writeOut(getPreviousOut());这一句时,
                                                                                                                                                               //则标签体内容没有输出!
      _005fjspx_005ftagPool_005fmy_005fmybodyTag_0026_005fcount.reuse(_jspx_th_my_005fmybodyTag_005f0);
      return true;
    }
    _005fjspx_005ftagPool_005fmy_005fmybodyTag_0026_005fcount.reuse(_jspx_th_my_005fmybodyTag_005f0);
    return false;
  }
}

 

 最后总结一下BodyTagSupport执行流程:

他们执行顺序如下:
doStartTag()—>doInitBody()-->setBodyContent()-->doAfterBody()-->doEndTag() 


doStartTag()方法可返回EVAL_BODY_INCLUDE或SKIP_BODY,还有EVAL_BODY_BUFFERED;
如果返回EVAL_BODY_INCLUDE则继续执行; 如果返回EVAL_BODY_BUFFERED; 注意了此时的out 引用已经被改赋值为BodyContent对象了。它会把它会通过out.print()设置标签体的内容缓存起来,

直到super.bodyContent.writeOut(getPreviousOut())执行到再输出标签体的内容
如果返回SKIP_BODY则接下来的setBodyContent(), doInitBody(),doAfterBody()三个方法不会被执行,
而直接执行doEndTag()方法。
setBodyContent()方法用于设置标签体内容,如果在此之前要作一些初始化工作,则在doInitBody()方法中完成。
标签体内容执行完后,会调用doAfterBody()方法,此方法可返回EVAL_BODY_TAG, SKIP_BODY,
EVAL_PAGE或SKIP_PAGE。
如果返回EVAL_BODY_TAG则会再次设置标签体内容,直到返回SKIP_BODY;
如果返回EVAL_PAGE则标签体执行完后会继续执行JSP页面中接下来的部分;
如果返回SKIP_PAGE,则JSP页面的后续内容将不再执行。

 

        附上MyBodyTag类:

          

 package com.common.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;

public class MyBodyTag extends BodyTagSupport
{
    int count;
    int iteraterCount;

    JspWriter jw;
    BodyContent bc;
  
    public int doStartTag() throws JspException {
        try {
            jw=super.pageContext.getOut();
            jw.print("---dostartTag---<br/>");
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        return BodyTagSupport.EVAL_BODY_BUFFERED;
    }
    
    public void doInitBody() throws JspException {
        try {
            jw.print("---doinitBody---<br/><br/>");
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }
    public void setBodyContent(BodyContent b) {
        try {
            jw.print("---setBodyContent---<br/>");
        } catch (IOException e) {
            e.printStackTrace();
        }
        super.setBodyContent(b);
   }
    public int doAfterBody() throws JspException {
      if(iteraterCount<count){
          try {
            jw.print(iteraterCount++ +" :---doAfterBody---<br/><br/>");
        } catch (IOException e) {
            e.printStackTrace();
        }
        
          
          return BodyTagSupport.EVAL_BODY_AGAIN;
      }else {
        return BodyTagSupport.SKIP_BODY;
    }
    
    }
    public int doEndTag() throws JspException {//如果 此方法没有,则标签体内容没有输出!
        try {
        jw.print("---doEndTag---<br/>");
    if(super.bodyContent!=null){
                super.bodyContent.writeOut(getPreviousOut());
        }
    
        } catch (IOException e) {
            e.printStackTrace();
        }
        iteraterCount=0;
        return BodyTagSupport.EVAL_PAGE;
    }


    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}

 

          附上myTag.TLD:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
  <description><![CDATA["To make it easier to access dynamic data;
                        the Apache Struts framework includes a library of custom tags.
                        The tags interact with the framework's validation and internationalization features;
                        to ensure that input is correct and output is localized.
                        The Struts Tags can be used with JSP FreeMarker or Velocity."]]></description>
  <display-name>"my Tags"</display-name>
  <tlib-version>1.0</tlib-version>
  <short-name>mytag</short-name>
  <uri>/my-tags</uri>
  
  <tag>
    <description><![CDATA[Execute an action from within a view]]></description>
    <name>mytag</name>
    <tag-class>com.common.tag.MyTag</tag-class>
    <body-content>JSP</body-content>
    <attribute>
      <description><![CDATA[Whether the result of this action (probably a view) should be executed/rendered]]></description>
      <name>first</name>
      <required>false</required>
      <rtexprvalue>false</rtexprvalue>
    </attribute>
    <attribute>
      <description><![CDATA[Whether the writer should be flush upon end of action component tag, default to true]]></description>
      <name>date</name>
      <required>false</required>
      <rtexprvalue>false</rtexprvalue>
    </attribute>
</tag>


<tag>
<name>mybodyTag</name>
<tag-class>com.common.tag.MyBodyTag</tag-class>
<body-content>JSP</body-content>

 <attribute>
      <name>count</name>
      <required>false</required>
      <rtexprvalue>false</rtexprvalue>
    </attribute>
</tag>
</taglib>
     
 

 

 

5
3
分享到:
评论
7 楼 sunrainstone 2013-03-11  
6 楼 shikui 2013-03-11  
终于可以说话了,这个必须得顶!富哥,牛!!!
5 楼 freezingsky 2013-03-11  
文章太长了,没有仔细看。但个人觉得,jsp标签,本身 就是用java代码来编写的,其实和servlet应该一样的,都会在tomcat下编译好,然后在页面中进行替换。
4 楼 宋建勇 2013-03-11  
宋建勇 写道
nice

手势反了,sorry
3 楼 宋建勇 2013-03-11  
nice
2 楼 jianfulove 2013-03-10  
laogao3232 写道
那么复杂,tag标签不是java代码写的?其实就行java代码吧,转成html代码。

     呵呵,tomcat中处理jsp标签原理是这样了,也不是很复杂吧。
1 楼 laogao3232 2013-03-10  
那么复杂,tag标签不是java代码写的?其实就行java代码吧,转成html代码。

相关推荐

    JavaServer Pages (JSP)

    Sun 在 J2EE SDK 中改装并集成了 Tomcat JSP 和 Java Servlet 实现。在应用程序部署和发布之前,可将J2EE SDK作为开发环境。Tomcat 是免费和开放源代码的 Java Servlet 和 JSP 技术的实现,它由 Apache Software ...

    教学、学习必备:jsp教案

    2.1.3JSP的运行原理 18 2.1.4JSP页面的成员变量和方法 18 2.1.5JSP代码 19 2.1.6 Java程序片 20 2.1.7Java表达式 22 2.1.8JSP中的注释 23 2.2HTML基础 24 2.2.1 HTML的基本概念 24 2.2.2HTML文件结构 26 2.2.3HTML的...

    java web技术开发大全(最全最新)

    5.2 JSP的运行原理 5.2.1 Tomcat如何处理JSP页 5.2.2 分析由JSP生成的Servlet代码 5.3 JSP基本语法 5.3.1 JSP表达式 5.3.2 在JSP中嵌入Java代码 5.3.3.JSP声明 5.3.4.JSP表达式语言(EL) 5.3.5 ...

    Android代码-YuanNews

    controller中在返回值的时候,注意添加注解:@ResponseBody !! 注意事项,jsp页面中的img标签添加获取项目名路径 ( request.getContextPath() )  原理图 架构-服务端 架构-客户端 主页-查询思路 推荐策略...

    java web开发技术大全

    5.2 JSP的运行原理 5.2.1 Tomcat如何处理JSP页 5.2.2 分析由JSP生成的Servlet代码 5.3 JSP基本语法 5.3.1 JSP表达式 5.3.2 在JSP中嵌入Java代码 5.3.3.JSP声明 5.3.4.JSP表达式语言(EL) ...

    Java Web编程宝典-十年典藏版.pdf.part2(共2个)

    2.2.2 理解JSP运行原理 2.3 使用JSP指令标识 2.3.1 页面指令page的使用 2.3.2 文件包含指令include的使用 2.3.3 引用标签库指令taglib的使用 2.4 使用JSP脚本 2.4.1 在JSP中应用代码片段 2.4.2 使用JSP表达式 2.4.3 ...

    基于J2EE框架的个人博客系统项目毕业设计论文(源码和论文)

    你在浏览器中访问这个应用的Jsp时,通常第一次会很慢,因为Tomcat要将Jsp转化为Servlet文件,然后编译。编译以后,访问将会很快。 Tomcat也具有传统的Web服务器的功能:处理Html页面。但是与Apache相比,它的处理...

    Struts原理、开发及项目实施

    &lt;br/&gt; 项目建立: 正式开发前,需要在Tocmat(我的tomcat装在c:\tomcat)中建立此项目。 比较快的一种建立方式为: 在C:\tomcat\webapps下新建目录test,再将C:\tomcat\webapps\struts-example下的...

    Java Web应用详解.张丽(带详细书签).pdf

    第5章 Web程序运行原理 5.1 Web程序架构 5.2 Web服务器汇总 5.3 Web程序流程 5.4 Web应用程序开发 第6章 Servlet及其应用 6.1 Servlet 简介 6.2 Servlet 应用实例 6.3 HTML表单在Servlet中的应用 6.4 HTML...

    从J2SE到J2EE知识点介绍

    3. 关于jsp在MyEclipse中打开的乱码问题 138 4. 关于html页面在eclipse中打开出现乱码情况 139 5. JSP页面通过URL传递中文参数的乱码问题 139 四、 Struts2 140 (一) 基于struts2的web应用的开发步骤 140 1. MVC设计...

    基于J2EE框架的个人博客系统项目毕业设计论...

    你在浏览器中访问这个应用的Jsp时,通常第一次会很慢,因为Tomcat要将Jsp转化为Servlet文件,然后编译。编译以后,访问将会很快。 Tomcat也具有传统的Web服务器的功能:处理Html页面。但是与Apache相比,它的处理...

    健身房管理信息系统设计.doc

    组件在分布式服务器的组件容器中运行,如Servl et组件在Servlet容器上运行,EJB组件在EJB容器上运行,容器间通过相关的协议进行通讯 ,实现组件的相互调用。遵从这个规范的开发者将得到行业的广泛支持,使企业级应用的 ...

    JAVA程序开发大全---上半部分

    本书内容丰富、技术全面、案例实用,而且所有的实例都以MyEclipse工程的形式组织,并按章节的顺序组织在附书光盘中,源代码工程都经过精心调试,可以直接导入MyEclipse中运行。 本书内容精练、重点突出、实例丰富,...

    java 面试题 总结

    异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的...

    java版中国象棋源码-YuanNews-master:元讯大师

    controller中在返回值的时候,注意添加注解:@ResponseBody !! 注意事项,jsp页面中的img标签添加获取项目名路径 ( request.getContextPath() )  ##原理图 架构-服务端 架构-客户端 主页-查询思路 推荐策略...

    java版中国象棋源码-dissertation_reference_1:dissertation_reference_1

    controller中在返回值的时候,注意添加注解:@ResponseBody !! 注意事项,jsp页面中的img标签添加获取项目名路径 ( request.getContextPath() )  ##原理图 架构-服务端 架构-客户端 主页-查询思路 推荐策略...

    Java Web程序设计教程

    10.1.3在hibernate中使用jta事务 210 10.1.4并发控制 211 10.2hibernate缓存 213 10.2.1缓存的工作原理 213 10.2.2应用一级缓存 214 10.2.3应用二级缓存 214 10.2.4应用第三方缓存 216 10.3项目实战——借还...

    超级有影响力霸气的Java面试题大全文档

     异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获...

    java面试题

    答:运行时异常时(JVM)java虚拟机在运行过程中发生的问题,比如:内存溢出等问题。这类异常没法要求程序员去一一捕获并抛出,一般异常是Java类库或程序员自己写的代码发生的错误,这类异常可以由我们去一一捕获并...

    Java面试宝典2020修订版V1.0.1.doc

    13、JSP和Servlet中的请求转发分别如何实现? 35 14、JSP乱码如何解决? 36 15、session 和 application的区别? 36 16、jsp有哪些内置对象?作用分别是什么? 36 17、Jsp有哪些动作?作用分别是什么? 37 18、JSP中动态...

Global site tag (gtag.js) - Google Analytics