Head First Servlets & JSP 学习笔记 第九章 —— 使用JSTL

时间:2021-11-23 21:04:12

JSTL1.1 不是JSP2.0规范的一部分!你能访问Servlet和JSP API 不意味着你能访问JSTL!

使用JSTL之前,需要将两个文件("jstl.jar" 和 "standard.jar")放在自己Web应用的WEB-INF/lib目录中。

将Html标记以纯文本显示出来,而不是解释标记渲染页面:<c:out />

1 <c:out value='${pageContent.rawHTML}' escapeXml='false' />   //escapeXml=false,所有的Html标记都会得到计算,而不是作为文本显示
2 <c:out value='${pageContent.currentTip}' escapeXml='true' />  //escapeXml=true,则所有的Html标记都是以纯文本显示出来,escapeXml默认值为true

使用<c:out />标记来输出所有的用户串,可以避免跨网站攻击或跨网站脚本攻击

给<c:out />标记提供一个默认值:

1 <b>Hello  <c:out value='${user}' default='guest' />.</b>  //当value计算结果为null时,就会输出默认值。这是<c:out />标记的优势,因为EL和JSP表达式当计算结果为null时,只能打印一个空格

实现循环:<c:forEach />

1 <table>
2     <c:forEach var="movie" items="${movieList}"> //将movieList集合中的每一个元素依次赋给变量movie,然后打印到表格中
3         <tr>
4             <td>${movie}</td>
5         </tr>
6     </c:forEach>
7 </table>

可选参数varStatus

 1 <table>
 2     <c:forEach var="movie" items="${movieList}" varStatus="movieLoopCount" >
 3         <tr>
 4             <td>Count: ${movieLoopCount.count}</td>     //varStatus参数的count属性,打印计数器的当前值
 5         <tr>
 6         <tr>
 7             <td>${movie}</td>
 8         </tr>
 9     </c:forEach>
10 </table>

<c:forEack />标记还可以进行嵌套:

servlet代码:

1 String[] movies1 = {"Matrix Revolutions", "Kill Bill", "Boondock Saints"};
2 String[] movies2 = {"Amelie", "Return of the King", "Mean Girls"};
3 java.util.List movieList = new java.util.List ArrayList();
4 movieList.add(movies1);
5 movieList.add(movies2);
6 
7 request.setAttribute("movieList", movieList);

JSP:

1 <table>
2     <c:forEach var="listElement" items="${movieList}"> //外部循环,将movieList数组列表中的元素(一共2个元素)赋给listElement
3         <c:forEach var="movie" items="${listElement}"> //内部循环,依次获取外部循环的元素listElement,将listElement中的元素赋给movie,打印到表格中
4             <tr>
5                 <td>${movie}</td>
6             </tr>
7         </c:forEach>
8     </c:forEach>
9 </table>

使用<c:if />完成条件包含:

同一个页面,注册用户和非注册用户看到的内容不一样。注册用户能添加评论。

1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
2 
3 <c:if test="${userType eq 'member'}">
4     <jsp:include page="inputComments.jsp"/>
5 </c:if>

如果一个if不行,需要else,可以用<c:choose/>标记

 1 <c:choose>
 2     <c:when test="${userPref == 'performance'}">
 3         Now you can stop even if you <em>do</em> drive insanely fast.
 4     </c:when>
 5     
 6     <c:when test="${userPref == 'safety'}">
 7         Our brakes will never lock up, no matter how bad a driver you are.
 8     </c:when>
 9     
10     <c:when test="${userPref == 'maintenance'}">
11         Lost your tech job? No problem--you won't have to service these brakes for at least three years.
12     </c:when>
13     
14     <c:otherwise>
15         Our brakes are the best.
16     </c:otherwise>
17 </c:choose>

<c:set />

<jsp:setProperty>标记只能做一件事情,就是设置bean的性质。

<c:set/>标记可以做得更多。<c:set/>有两个版本:var版本和target版本。两个版本又都有两种形式:有体和没体。

var版本:

1 <c:set var="userLevel" scope="session" value="Cowboy"/>
2 
3 <c:set var="Fido" value="${person.dog}"/>
4 
5 <c:set var="userLevel" scope="session">   //有体
6     Sheriff, Bartendar, Cowgirl
7 </c:set>

target版本:

1 <c:set target="${PetMap}" property="dogName" value="Clover" />
2 
3 <c:set target="${person}" property="name">   //有体
4     ${foo.name}
5 </c:set>

使用<c:remove/>标记删除一个变量

 1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 2 <html><body>
 3 
 4 <c:set var="userStatus" scope="request" value="Brilliant" />
 5 
 6 userStatus: ${userStatus} <br>
 7 
 8 <c:remove var="userStatus" scope="request" /> //scope是可选的,但是如果没有指定scope,就会从所有作用域中删除userStatus属性
 9 
10 userStatus is now: ${userStatus}
11 
12 </body></html>

使用<c:import/>标记包含内容:

之前已经知道了两种:<%@ include file="xx.jsp" %>include指令  <jsp:include page="xx.jsp" />include动作

现在再学一招:<c:import />JSTL标记

1 <c:import url="http://www.wickedlysmart.com/skyler/horse.html" />  //动态:在请求时,将URL属性指定的内容增加到当前页面。它与<jsp:include/>相似,但是更强大、更灵活。

使用<%@ include file="xx.jsp">或者<jsp:include page="xx.jsp" />只能包含当前Web应用之内的页面。但是<c:import />还可以把容器之外的内容包含进来。

还有<c:param/>标记:

 1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 2 <html><body>
 3 
 4 <c:import url="Header.jsp">
 5     <c:param name="subTitle" value="We take the sting out of SOAP." />
 6 </c:import>
 7 
 8 <br>
 9 
10 <em>Welcome to our Web Services Support Group.</em><br><br>
11 Contact us at : ${initParam.mainEmail}
12 </body></html>

<c:url/>标记可以满足所有超链接需求:

客户禁用cookie后,容器会自动地完成URL重写。但是如果使用Servlet,还必须对URL编码:

 1 //Servlet的URL重写
 2 public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{
 3     response.setContentType("text/html; charset=utf-8");
 4     PrintWriter out = request.getWriter();
 5     HttpSession session = request.getSession();
 6     
 7     out.println("<html><body>");
 8     out.println("<a href=\"" + response.encodeURL("/BeerTest.do") + "\">click</a>"); //在Java中写Html真的是很麻烦
 9     out.println("</body></html>");
10 }

那如果使用<c:url/>标记呢:

1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
2 <html><body>
3 
4 This is a hyperlink with URL rewriting enabled.
5 
6 <a href="<c:url value='/inputComments.jsp'/>"Click here</a>
7 
8 </body></html>

<c:url />标记所做的只是URL重写,URL通常都需要编码:

1 <c:url value="/inputComments.jsp" var="inputURL">
2     <c:param name="firstName" value="${first}" /> //现在<c:param>标记负责对URL进行编码工作
3     <c:param name="lastName" value="${last}" />
4 </c:url>    

建立自己的错误页面:(errorPage)

让发生的错误对用户更加友好!而不是显示一堆跟踪错误(自己都不想看)

1 <%@ page isErrorPage="true" %>      //向容器做出确认,这个是正式的错误页面
2 <html><body>
3 <strong>Bummer.</strong>
4 <img src="images/bummerGuy.jpg" />
5 </body></html>
1 <%@ page errorPage="errorPage.jsp" %>  //告诉容器,出问题了就把请求转发到errorPage.jsp
2 <html><body>
3 About to be bad...
4 <% int x = 10 / 0; %>
5 </body></html>

那么问题来了,要给一个一个的JSP加上<%@ page errorPage="errorPage.jsp" %>也是很麻烦的!

可以使用<error-page>DD标记,为整个Web应用配置错误页面:(<%@ page errorPage="errorPage.jsp" %>优先级高于DD中的<error-page>标记)

在DD(web.xml)中,可以根据<exception-type>或HTTP状态码<error-code>声明错误页面。

 1 <error-page>
 2     <exception-type>java.lang.Throwable</exception-type>  //普通的错误
 3     <location>/errorPage.jsp</location>
 4 </error-page>
 5 
 6 <error-page>
 7     <exception-type>java.lang.ArithmeticException</exception-type>  //更加明确的错误
 8     <location>/arithmeticError.jsp</location>
 9 </error-page>
10 
11 <error-page>
12     <error-code>404</error-code>  //404错误
13     <location>/notFoundError.jsp</location>    //<location>必须以/开头,无论<exception-type>还是<error-code>
14 </error-page>

错误页面得到一个额外的对象:exception:

错误页面实际上就是处理异常的JSP,所以容器为这个页面提供了一个额外的exception对象。exception隐式对象只对错误页面可用(有明确定义的page指令:<%@ page isErrorPage="true" %>)

1 <%@ page isErrorPage="true" %>
2 <html><body>
3 <strong>Bummer.</strong><br>
4 
5 You caused a ${pageContext.exception} on the server.<br>    //这样会得到更加明确的错误类型,因为调用了exception隐式对象
6 
7 <img src="images/bummerGuy.jpg" />
8 </body></html>

<c:catch />标记 —— 就像try/catch.......

<c:catch />标记,把有风险的标记或表达式包起来。因为倘若不这样,就会抛出异常,默认的错误处理机制就会插手!

 1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 2 <%@ page errorPage="errorPage.jsp" %> //这是一个正式指定了错误页面,可以使用exception隐式对象
 3 <html><body>
 4 
 5 About to do a risky thing: <br />
 6 
 7 <c:catch>
 8     <% int x = 10 / 0; %>  //一个可预见的错误
 9 </c:catch>
10 
11 If you see this, we survived.  //因为使用了<c:catch>标记,遇到异常立即跳过,所以我们得救了 12 
13 </body></html>

理解TLD:(Tag Library Descriptor,TLD,标记库描述文件)

标记库描述文件TLD,描述了两个主要内容:定制标记和EL函数。

1.TLD,标记库描述文件可以放到WEB-INF的任何子目录中去!

2.在部署描述文件(DD,web.xml)中使用<taglib>元素定义TLD(标记库描述文件)

1 <taglib>
2     <taglib-uri>myTags</taglib-uri>
3     <taglib-location>/WEB-INF/myTags.tld</taglib-location>
4 </taglib>