解读<c:out>源码

<c:out>标签是用来在页面中输出属性值,在使用<c:out>时,一般都会在JSP页面中做如下声明:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

在此标签的c.tld文件中,关于out标签定义如下(取部分有用信息):

 

对core标签库的描述:

  <description>JSTL 1.1 core library</description>
  <display-name>JSTL core</display-name>
  <tlib-version>1.1</tlib-version>
  <short-name>c</short-name>
  <uri>http://java.sun.com/jsp/jstl/core</uri>

 

对out标签的描述如下:

<tag>
    <name>out</name>
    <tag-class>org.apache.taglibs.standard.tag.rt.core.OutTag</tag-class>//标签的处理类
    <body-content>JSP</body-content>
    <attribute>
        <name>value</name>               //属性对应的名称,与上面class类所提供的setter应一致
        <required>true</required>        //表示此属性是否必须提供
        <rtexprvalue>true</rtexprvalue> //表示此属性值可以在运行时确定(如EL表达式,jspscript等)
    </attribute>
    <attribute>
        <name>default</name>
        <required>false</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
    <attribute>
        <name>escapeXml</name>
        <required>false</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
  </tag>

 

org.apache.taglibs.standard.tag.rt.core.OutTag的源码如下:

package org.apache.taglibs.standard.tag.rt.core;

import org.apache.taglibs.standard.tag.common.core.OutSupport;

public class OutTag extends OutSupport {       
    // for tag attribute
    public void setValue(Object value) {   //如果在页面标签中的给出了value属性的值(对象),则此方法被调用
        this.value = value; //value属性已在父类中定义,使用页面上value对象来填充
    }
      
    // for tag attribute
    public void setDefault(String def) {  //同理
        this.def = def;    //def属生也在父类中定义,使用页面上default的值来填充
    }
        
    // for tag attribute
    public void setEscapeXml(boolean escapeXml) {  //同理
        this.escapeXml = escapeXml; //同上,使用页面上escapeXml值来填充
    }
}

 OutTag类继承了OutSupport类,OutSupport类的源码如下:

package org.apache.taglibs.standard.tag.common.core;

import java.io.IOException;
import java.io.Reader;

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

public class OutSupport extends BodyTagSupport {

    protected Object value;                     // tag attribute
    protected String def;	            // tag attribute
    protected boolean escapeXml;          // tag attribute
    private boolean needBody;                // non-space body needed?

    public OutSupport() {
        super();
        init();
    }

    // resets local state
    private void init() {
        value = def = null;
        escapeXml = true;
        needBody = false;
    }

    // Releases any resources we may have (or inherit)
    public void release() {
        super.release();
        init();
    }

     //标签开始时执行此方法
      public int doStartTag() throws JspException {

      needBody = false;	// reset state related to 'default'
      this.bodyContent = null;
      
      try {
	// print value if available; otherwise, try 'default'
	if (value != null) {  //如果value对象不为null
                    out(pageContext, escapeXml, value); //输出value对象所表示的值
	    return SKIP_BODY; //跳过标签体内容
	} else {
	    // if we don't have a 'default' attribute, just go to the body
	    if (def == null) { //如果value为空,且def为空(即没有提供default值)
		needBody = true; //表示需要标签体
		return EVAL_BODY_BUFFERED;//执行标签体
	    }

	    // if we do have 'default', print it
	    if (def != null) { //表示提供了default的值
               	                out(pageContext, escapeXml, def);  //在页面中输出def所表示的值
	    }
	    return SKIP_BODY; //跳过标签体内容
	}
      } catch (IOException ex) {
	throw new JspException(ex.toString(), ex);
      }
    }
     //结束标签时执行此方法	
      public int doEndTag() throws JspException {
      try {
	if (!needBody)
	    return EVAL_PAGE;

	// trim and print out the body
	if (bodyContent != null && bodyContent.getString() != null)
            out(pageContext, escapeXml, bodyContent.getString().trim());
	return EVAL_PAGE;
      } catch (IOException ex) {
	throw new JspException(ex.toString(), ex);
      }
    }


    public static void out(PageContext pageContext,
                           boolean escapeXml,
                           Object obj) throws IOException {
        JspWriter w = pageContext.getOut();//获取向页面输出信息的对象
	if (!escapeXml) { //escapeXml为false,表示不需要对输出信息进行xml解析转换
            // write chars as is
            if (obj instanceof Reader) { //如果当前输出对象是Reader流,需要将流中的信息保存到字符数组中
           Reader reader = (Reader)obj; 
                char[] buf = new char[4096];
                int count;
                while ((count=reader.read(buf, 0, 4096)) != -1) {
                    w.write(buf, 0, count); //输出
                }
            } else {
                w.write(obj.toString()); //如果不是流,则转换成字符串输出
            }
        } else {  //escapeXml为true,表示需要对输出信息进行xml解析转换(如:将<转换成&lt,>转换成&gt等)
            // escape XML chars
            if (obj instanceof Reader) {
                Reader reader = (Reader)obj;
                char[] buf = new char[4096];
                int count;
                while ((count = reader.read(buf, 0, 4096)) != -1) {
                    writeEscapedXml(buf, count, w); //解析
                }
            } else {
                String text = obj.toString();
                writeEscapedXml(text.toCharArray(), text.length(), w); //解析
             }
        }
    }
   //解析字符数组中的xml特殊字符(<,>,",',&)
    private static void writeEscapedXml(char[] buffer, int length, JspWriter w) throws IOException{
        int start = 0; //用来标记当前所遇到特殊字符的下个位置

        for (int i = 0; i < length; i++) {
            char c = buffer[i];
            if (c <= Util.HIGHEST_SPECIAL) { //特殊字符中ASCII码值最高是HIGHEST_SPECIAL=Ox3e,是>的ASCII值
                char[] escaped = Util.specialCharactersRepresentation[c]; //判断是否为特殊字符	
                if (escaped != null) {//信息不为空,则是特殊字符
                    // add unescaped portion
                              if (start < i) { //输出在特殊之前之前所有字符
                        w.write(buffer,start,i-start);
                             }
                    // add escaped xml
                    w.write(escaped); //输出特殊字符所对应的转换码
                    start = i + 1; //确认下次信息输出起始位置
                }
            }
        }
        // add rest of unescaped portion
        if (start < length) {
            w.write(buffer,start,length-start);
        }
    }
}

     示例:

<% 
	//非Reader对象
	String str = "Hello String";
	request.setAttribute("str",str);
	//Reader对象
	Reader reader = new CharArrayReader("Hello Reader".toCharArray());
	request.setAttribute("reader",reader);
%>
<c:out value="${requestScope.str}"/> //Hello String
<c:out value="${requestScope.reader}" /> //Hello Reader

<c:out value="${requestScope.str}" default="defalut value"/> //Hello String
<c:out value="${null}" default="default value"/> //default value
<c:out value="${null}" >default body content value</c:out> //default body content value 

<c:out value="<b>Hello</b>"/> //<b>Hello</b>
<c:out value="<b>Hello</b>" escapeXml="true"/> //<b>Hello</b>
<c:out value="<b>Hello</b>" escapeXml="false"/> //黑体的Hello
<c:out value="${null}" escapeXml="true" default="<b>Hello</b>"/> //<b>Hello</b>
<c:out value="${null}" escapeXml="false" default="<b>Hello</b>"/> //黑体的Hello
<c:out value="${null}" escapeXml="false"><b>Hello</b></c:out>//黑体的Hello
<c:out value="${null}" escapeXml="true"><b>Hello</b></c:out>//<b>Hello</b>

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值