JSTL
SimpleTag接口中的方法
void doTag() JspTag getParent() void setJspBody(JspFragment jspBody):把标签体通过该方法传递进来,我们可以在doTag方法中拿到jspBody对象即拿到了标签体,然后可以对标签体做想做的事 void setJspContext(JspContext pc) void setParent(JspTag parent)
JspContext是pageContext的父类,执行顺序:JSP引擎首先通过uri和viewIP标签名去找tld文件,在tld中通过viewIP找到ViewIPTag类,该类中,首先调用setJspContext方法把页面的pageContext传递进来,再调用setParent把父标签传递进来(没有则不传),然后再调用setJspBody方法,把代表标签体的jspFragment对象传递进去,至此完成了标签的初始化工作。然后开始执行标签,即调用doTag方法。下面我们使用简单标签扩展上面的功能。
1)控制JSP页面某一部分内容是否执行
//控制标签体是否执行 public class SimpleTagDemo1 extends SimpleTagSupport { //用简单标签使用这个方法完成所有业务逻辑 @Override public void doTag() throws JspException, IOException { //得到代表标签体的JspFragment JspFragment jf = this.getJspBody(); // PageContext pageContext = (PageContext)this.getJspContext(); //获得pageContext // jf.invoke(pageContext.getOut()); //将输出流放到invoke方法中,写给浏览器 jf.invoke(null);//null默认写给浏览器。不调用该方法即不运行标签体 } }
在simple.tld文件中配置如下(与上面的基本一样的):
<?xml version="1.0" encoding="UTF-8" ?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0"> <description>A tag library exercising SimpleTag handlers.</description> <tlib-version>1.0</tlib-version> <short-name>SimpleTagLibrary</short-name> <uri>/simpleitcast</uri> <tag> <name>demo1</name> <tag-class>web.simpletag.SimpleTagDemo1</tag-class> <body-content>scriptless</body-content> </tag> </taglib>
2)控制整个JSP页面是否执行
public class SimpleTagDemo4 extends SimpleTagSupport { @Override public void doTag() throws JspException, IOException { throw new SkipPageException();//抛出个SkipPageException异常即不会执行下面的JSP页面,否则会执行 } }
3)控制JSP页面内容重复执行
//控制标签体执行10次 public class SimpleTagDemo extends SimpleTagSupport { @Override public void doTag() throws JspException, IOException { JspFragment jf = this.getJspBody(); for(int i = 0; i < 10; i++) { jf.invoke(null); } } }
4)修改JSP页面内容输出
//将标签体内容改成大写 public class SimpleTagDemo3 extends SimpleTagSupport { @Override public void doTag() throws JspException, IOException { JspFragment jf = this.getJspBody(); StringWriter sw = new StringWriter(); jf.invoke(sw);//不要invoke到浏览器,先invoke到自己的流里,然后修改修改再输出 String content = sw.getBuffer().toString();//获得标签体的String内容 content = content.toUpperCase(); PageContext pageContext = (PageContext)this.getJspContext(); pageContext.getOut().write(content);//再将流输出给浏览器 } }
带属性的标签
自定义标签可以定义一个或多个属性,这样在JSP页面中应用自定义标签时就可以设置这些属性的值,通过这些属性为标签处理器传递参数信息,从而提供标签的灵活性和复用性。想要让一个自定义标签具有属性,通常需要完成两个任务即可:
1)在标签处理器中编写每个属性对应的setter方法
2)在tld文件中描述标签的属性
为自定义标签定义属性时,每个属性都必须按照javaBean的属性命名方式,在标签处理器中定义属性名对应的setter方法,用来接收JSP页面调用自定义标签时传递进来的属性值。例如属性url,在标签处理器类中就要定义相应的setUrl(String url)方法。在标签处理器中定义相应的set方法后,JSP引擎在解析执行开始标签前,也就是调用doStartTag方法前,会调用set属性方法,为标签设置属性。我们看下面的例子:
//通过属性控制标签体的执行次数 public class SimpleTagDemo5 extends SimpleTagSupport { public int count; //<itcast:demo5 count="6" public void setCount(int count) {//自动将属性传进来 this.count = count; } @Override public void doTag() throws JspException, IOException { for(int i = 0; i < count; i++){ this.getJspBody().invoke(null); } } }
tld文件中配置如下:
<tag>
<name>demo5</name>
<tag-class>web.simpletag.SimpleTagDemo5</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>count</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue> <!-- true的话jsp中该属性只可以为表达式,false只能为静态值 -->
<type>java.lang.Integer</type> <!-- 指明参数的类型 -->
</attribute>
</tag>
在JSP页面中就可以使用标签
<itcast:demo5 count="4">
xxxx
</itcast>
xxxx被输出4次
案例
自定义JSTL标签开发一个防盗链的标签:如果客户端直接访问http://localhost:8080/example/test.jsp,会被阻止,先跳转到主页index.jsp,再访问1.jsp
public class RefererTag extends SimpleTagSupport { private String site; private String page; public void setSite(String site) { this.site = site; } public void setPage(String page) { this.page = page; } @Override public void doTag() throws JspException, IOException { //看来访者是从哪个页面来的 PageContext pageContext = (PageContext)this.getJspContext(); HttpServletRequest request = (HttpServletRequest)pageContext.getRequest(); String referer = request.getHeader("referer");//得到是从哪个页面来的 //判断是否从自己的主页过来的 if(referer == null || !referer.startsWith(site)) { HttpServletResponse response = (HttpServletResponse)pageContext.getResponse(); String webroot = request.getContextPath(); //example if(page.startsWith(webroot)) response.sendRedirect(page); else response.sendRedirect(webroot + page); //重定向后,控制保护的页面不要执行 throw new SkipPageException(); } } }
看一下index.jsp页面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> This is my JSP page. <br> <a href="${pageContext.request.contextPath }/test.jsp">内容</a> <!--掉转到1.jsp--> </body> </html>
再看一下test.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib uri="/simpleitcast" prefix="it"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <it:referer site="http://localhost:8080/" page="/index.jsp"/> <html> <head> <title>防盗链</title> </head> <body> 这是内容 </body> </html>
1)<c:out>
<c:out>标签用于输出一段文本内容到pageContext对象当前保存的"out"对象中,即:将内容输出给浏览器。该标签有三个属性可选,value属性指定要输出的内容;escapeXml指定是否将<、>、&、`等特殊字符进行html编码转换后再进行输出,默认为true;default属性指定如果value属性的值为null时所输出的默认值。该标签主要用于escapeXml属性和default属性
2)<c:set>
<c:set>标签用于把某一个对象存在指定的域范围内,或者设置web域中的java.util.Map类型的属性对象或javaBean类型的属性对象的属性。有如下属性:
value:用于指定属性的值;
scope:用于指定属性所在的web域;
var:用于指定要设置的web域属性的名称;
target:用于指定要设置属性的对象,这个对象必须是javaBean对象或者java.util.Map对象;
property:用于指定当前为对象设置的属性名称。
<!-- c:set标签 :向web域中存数据,向map或Bean中存数据--> <c:set var="data" value="xxx" scope="page"/> ${pageScope.data } <% Map map = new HashMap(); request.setAttribute("map", map); %> <c:set property="data" value="yyy" target="${map }" /> ${map.data } <c:set property="name" value="eson_15" target="${person }"/> ${person.name }
<c:remove>
<c:remove>标签用于删除各种web域中的属性:
<c:remove var="varName" [scope="{page|request|session|application}"]/>
<c:if>
<c:if>标签可以判断是否执行标签体
<c:if test="${user==null}" var="result" scope="page"> xxx </c:if>
<c:choose>
标签用于构造条件判断语句
<c:choose>
<c:when test="${count == 0}">
对不起,没有符合您要求的记录
</c:when>
<c:otherwise>
符合您要求的记录共有${count}条
</c:otherwise>
</c:choose>
<c:forEach>
<c:forEach>标签用于对一个集合对象中的元素进行循环迭代操作,或者按指定的次数重复迭代执行标签体中的内容。它有如下属性:
var属性:指定当前迭代到的元素保存到page域中的属性名称;
items属性:将要迭代的集合对象;
begin属性:如果指定items属性,就从集合中的第begin个元素开始迭代,begin的索引值从0开始编号;如果没有指定items属性,就从begin指定的值开始迭代,直到end值结束。
step属性:指定迭代的步长。
<!-- c:forEach标签 --> <c:forEach var="num" begin="1" end="10" step="1"> ${num } <!-- 输出1-10 --> </c:forEach> <br> <% List list = Arrays.asList("1","2"); request.setAttribute("list", list); %> <c:forEach var="index" begin="0" end="${fn.length(list) }"> ${list[index] } </c:forEach> <c:forEach var="index" items="${list}"> ${index} </c:forEach>
<c:param>标签
在JSP页面进行url的相关操作时,经常用在url地址后面附加一些参数。<c:param>标签可以嵌套在<c:import>、<c:url>或<c:redirect>标签内,为这些标签所使用的url地址附加参数。<c:param>标签在为一个url地址附加参数时,将自动对参数值进行url编码,例如,如果传递的参数为“中国”,则将其转换为"%d6%d0%b9%fa"后再附加到url地址后面,这也就是使用<c:param>标签的最大好处。如:<c:param name="name" value="value"/>
<c:url>标签用于在JSP页面中构造一个url地址,其主要目的是实现url重写。url重写就是将会话标识号以参数形式附加在url地址后面。它有如下属性:
value属性:指定要构造的url;
var属性:指定将构造出的url结果保存到web域中的属性名称
scope属性:指定将构造出的url结果保存到那个web域中
<!-- c:url标签(重点) -->
<a href="<c:url value="/servlet/servletDemo1"/>">点点</a>
<c:url value="/servlet/servletDemo2" var="servletdemo2"><!-- 如果没有var,则会把地址直接打给浏览器 -->
<c:param name="name" value="中国"/> <!-- 中国两个字已经被url编码了 -->
<c:param name="password" value="我是一个"></c:param>
</c:url>
<a href="${servletdemo2}">点点</a>
<c:redirect>标签用于实现请求重定向
url属性:指定要转发或重定向到的目标资源的url地址;
context:当要使用相对路径重定向到同一个服务器下的其他web应用程序中的资源时,context属性指定其他web应用程序的名称
参考:
https://blog.csdn.net/eson_15/article/details/51264254
浙公网安备 33010602011771号