<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解析转换(如:将<转换成<,>转换成>等)
// 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>