【阅读】《Head First Servlets & JSP》第九章——强大的定制标记

来源:互联网 发布:淘宝上买iphone店铺 编辑:程序博客网 时间:2024/04/30 03:37

例子说明

如果你要打印出“<b></b>”这样一句文字应该怎么打印
尝试1:直接用
<span style="font-size:14px;">${requestScope.currentTip} <--文字是在request中一个名为currentTip的一个属性--></span>
尝试结果:什么都没有(实际上的打印出了一个加粗的null,所以什么都看不到)
这时我们就可以使用EL函数,注意要在JSP页面的最前面写上这句话
<span style="font-size:14px;"><%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %></span>
<span style="font-size:14px;">打印的代码是:${fn:escapeXml(requestScope.currentTip) }</span>
打印的代码是:<b></b> //这是显示结果
就仅仅只有这样吗?JSTL呢
看代码:
<span style="font-size:14px;"><c:out value="打印的代码是:${requestScope.currentTip }" escapeXml="true" /><span style="white-space:pre"></span><--escape的意思是“避开”--></span>
这样做的好处是
  1. 你可以方便的选择时候要将所有的XML都转换为web浏览器能呈现的形式
  2. 减少跨网站攻击或者跨网站脚本攻击,即Cross Site Script Execution(通常简写为XSS)是指攻击者利用网站程序对用户输入过滤不足,输入可以显示在页面上对其他用户造成影响的HTML代码,从而盗取用户资料、利用用户身份进行某种动作或者对访问者进行病毒侵害的一种攻击方式。
  3. 如果输出值为空就可以输出提前指定的值,通过其中的default属性其中
    <c:out value="${requestScope.currentTip }" escapeXml="true" default="This is null" />和<c:out value="${requestScope.currentTip }" escapeXml="true">This is null</c:out>效果是一样的
这里附带一个HTML特殊字符的实体码表
字符字符实体码<&lt>&gt&&amp`&#039``&#034(好奇试了一下&#038,发现是“&”,马上又好奇试了一下这个<%="&#038"=="&amp"%>输出的false,嘻嘻,你懂我的意思吗)

不用脚本就能实现循环

<c:forEach>

这是例子<body><%String[] strs = {"java", "C++", "C"};pageContext.setAttribute("strs", strs);%><c:forEach var="str" items="${strs }" >${str }<br></c:forEach></body>
如果你要添加一个计数器可以这样
<body><%String[] strs = {"java", "C++", "C"};pageContext.setAttribute("strs", strs);%><c:forEach var="str" items="${strs }" varStatus="Number" >${Number.count} ${str }<br></c:forEach></body>
当然,可以用嵌套循环
<body><c:forEach var="student" items="${requestScope.students }"><!-- 要一个变量,变量的内容是requestScope中的students属性 --><c:forEach var="num" items="${student.num }"><!-- 再要一个变量,它的内容是刚刚要的student属性中的num属性,这个属性是一个数组 -->${num }</c:forEach></c:forEach></body>

<c:if>完成条件包含

(书上就是叫“完成条件包含”,虽然我不知道为什么~)
不同的访问对应不同的页面,就像这样
用登录用户访问
用游客访问
这样就可以给访问者不同的访问内容,这样的功能可以通过<c:if>来实现
小例子:
<body><%request.setAttribute("name", "xiaoxiao");%><c:if test="${name eq 'xiaoxiao' }"><span style="white-space:pre"></span><--我把eq改成==也可以--><jsp:include page="show.jsp"/></c:if></body>
怎么样,厉害吧~不过<c:if>有一个缺点,就是不能做成if...else那样这个时候<c:choose>跑过来说:“我能做到”

<c:choose>

小例子:
<body><%request.setAttribute("favour", "Swift");%><c:choose><c:when test="${favour == 'Java' }">我猜你喜欢Java</c:when><c:when test="${favour == 'Swift' }">OCOCOCOCOCOC</c:when><c:otherwise>这个是所有when都不正确的时候执行的</c:otherwise></c:choose></body>

<c:set>

用它可以设置bean、Map等的性质,这一天<jsp:setProerty>可做不到
Demo:
<body>
<!-- 这个是var那种的演示 --><c:set var="user" scope="session" value="username"/><!-- 这样我们就创建好了一个变量,这个变量的内容是"username" --><!-- 还有另一种样式可以达到同样的效果 --><c:set var="user1" scope="session">${1+2 }</c:set><!-- 这个变量的内容是3,也就是计算出结果之后在赋值,这一点值得注意 --></body>
这里还有介绍了一种删除这个变量的方法,不过我觉得没什么必要,因为有<c:remove>(等会要讲)
那就是把变量的值设成null,我说的是null,你在value那里弄成""是没有用的,我是用EL做出一个空的
把值设成null,变量就会被删除
set还有一种形式,可以方便的对Map中的东西进行修改(Demo那个不是)
Demo:
<body><%ArrayList<Student> students = new ArrayList<Student>();Student student1, student2;student1 = new Student();student1.setName("A");student2 = new Student();student2.setName("B");students.add(student1);students.add(student2);session.setAttribute("students", students);%><c:set target="${students[1] }" property="name" value="C"/><!-- 意思是得到students中的第二个student,并把他的name属性设置成C -->${students[1].name }</body>
我在这一段的时候遇到了一个问题,就是用target那种的时候怎么给他设置范围,万一要是page和sessionScope中有两个同名的不就麻烦了
于是我就在set中加了scope,可是会有这个错误:Illegal scope attribute without var in "c:set" tag
然后我就问了一下别人,说target和scope不要再一起,如果要指定范围的话可以在target那里的EL中设置好
说到作用域,如果你没有指定,那么默认就是page,就只是page,不会再去找其他什么地方的了

<c:remove>

这个挺简单的,就是如果你要删那个变量只需这样:
<c:remove var="students" scope="session"/>

<c:import>

我现在学了三个包含内容的方法了
  1. include指令(静态):<%@ include file="filename.html"%>
  2. <jsp:include>标准动作(动态):<jsp:include page="name.html">
  3. <c:import>JSTL标记(动态):<c:import url="http://www.csdn.net"/>
最后那个功能更为强大,前两种不能超出当前容器范围外,而<c:import>可以

定制包含的内容

当我们要包含一个网页,这个网页所显示的内容需要根据包含他的网页的不同而显示不同的内容,这个时候我们应该怎么办呢?
Demo
<body><jsp:include page="show.jsp"><jsp:param value="Hello World!" name="out"/></jsp:include><!-- 意思是包含show.jsp页面,并把名为"out"的变量传入show.jsp中 --></body>
show.jsp
<body><strong>${param.out }</strong></body>
这样我就可以在Demo页面通过修改param的参数来改变show.jsp中显示的内容
上面那个是使用JSP的动作,我们还可以使用JSTL
Demo by JSTL
<c:import url="show.jsp"><c:param name="out" value="hehe"/></c:import>
JSTL的和动作的那个很像

<c:url>(这一点我没有看懂)

如果客户不支持cookie,那么我应该怎么让URL重写呢?
<c:url>就可以做到
<a href="<c:url value="/jstl"/>">TEST</a>

如果URL需要编码怎么办(让你的网站更安全)

如果在HTTP请求中包含了不安全的字符,那么。。。它就不安全了
这里用URL不可以有空格的例子来说明
错误Demo
<c:set var="last" value="Hidden Cursor"/><c:set var="first" value="Crouching Pixels"/><c:url value="/inputComments.jsp?first=${first }&last=${last }" var="inputURL" />The URL using params is:${inputURL }<br><!-- 这个inputComments.jsp好神奇。。。可以弄出我的项目名 --><!-- 这样输出的是不正确的,因为它包含了空格 -->
正确Demo
<body><c:set var="last" value="Hidden Cursor"/><c:set var="first" value="Crouching Pixels"/><c:url value="/inputComments.jsp" var="inputURL"><c:param name="firstName" value="${first }"/><c:param name="lastName" value="${last }"/></c:url>The URL using params is:${inputURL }<br></body>

错误界面

可能产生错误的页面
<%@ page errorPage="error.jsp"%> 
error.jsp页面
<%@ page isErrorPage="true" %>  
这样如果那个可能产生错误的页面真的产生了错误,他就会跳转到error.jsp这个页面去了
可如果要让多个页面出现错误的时候都跳转的一个页面,岂不是要在每个页面都要写errorPage了?
不用这么麻烦的,可以在DD中配置错误页面
<error-page>  <exception-type>java.lang.Throwable</exception-type>  <location>/error.jsp</location>  </error-page>
这样如果在可能出现错误的也页面也写了errorPage,那么errorPage优先于DD中的配置

<c:catch>

顾名思义,这个和Java中的try/catch的功能类似,不同的是没有<c:try>这种标签,看Demo:
<c:catch var="myException"><%int i = 10/0; //除零错误%><!-- 在出现错误的地方一直到catch的结束那一部分的代码都不会执行 --><!-- 也就是说出错就会直接跳转到catch最后那里 --><!-- 不过最后的那一点catch之外的代码还是会执行的,你可以试试 -->你看我不到</c:catch>出现错误:${myException.message }<!-- 这个可以把错误的内容显示出来 --></body>

0 0