在这一小节中,将修改在第三章中曾经给出的
Struts
框架示例,以
Struts
框架和
JSTL
的协同工作来实现。
对于第三章的示例,要将
JSTL
整合进去,需要做以下几步工作。
(
1
)下载
JSTL
并配置。
(
1
)修改原先的
web.xml
使其作为
Servlet2.4
的实现。
(
3
)修改
JSP
显示页面,整合
JSTL
和
Struts
标签库一起工作。
9.9.1
下载
JSTL
并配置
可以从
http://java.sun.com/products/jsp/jstl
网址中下载
JSTL1.1
的最新版本。要使用这些标签库需要做
3
个步骤的工作。
(
1
)将下载的
jstl.jar
放置到
Web
应用的
WEB-INF
的
lib
目录下。
(
2
)将下载的
TLD
文件放置到
Web
应用的
WEB-INF
目录下。
(
3
)在需要使用的
JSP
页面中声明该标签库。
9.9.2
修改
web.xml
使其作为
Servlet2.4
的实现
在第三章的示例中所给出的
web.xml
是
Servlet2.3
规范的,因此无法很好的支持
JSTL1.1
,要修改为符合
Servlet2.4
规范的代码。使
web.xml
成为
Servlet2.4
规范是十分容易的,需要修改的是其头部
DTD
声明。
在
Servlet2.3
之前,校验和规范
web.xml
都是使用
DTD
,因此其头部声明如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
…
</web-app>
而到了
Servlet2.4
规范,首此使用了
xmlns
来声明
web.xml
,因此其头部声明为:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
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-app_2_4.xsd
">
…
</web-app>
所以,为了支持
Servlet2.4
规范,应该将第三章示例的
web.xml
改成如例
9.6
的样子。
例
9.6
:修改后的
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
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-app_2_4.xsd">
<filter>
<filter-name>Set Character Encoding</filter-name>
<filter-class>struts.sample.cap1.sample3.util.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>setSolution.jsp</welcome-file>
</welcome-file-list>
<taglib>
<taglib-uri>/WEB-INF/struts-template.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-template.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-template.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-template.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-tiles.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-tiles.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-nested.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-nested.tld</taglib-location>
</taglib>
</web-app>
修改的地方不多,仅仅是头部的声明。其他地方完全不必改动,这样的
web.xml
已经支持了
Servlet2.4
规范了。
9.9.3 JSP
部分:
<logic:notEmpty>
和
<c:if>
标签
对于
JSP
显示页面的修改是整合的核心部分,在第三章示例的
showAttackSolution.jsp
中出现了这样的语句:
<logic:notEmpty name="allAttackSolution">
...
</logic:notEmpty>
将类型为
ArrayList
的变量“
allAttackSolution
”从作用范围中取出,利用
<logic:notEmpty>
标签判断该
ArrayList
是否为空。
根据之前讨论的“所有判断标签被
EL
表达式和
<c:if>
标签替换”,可以利用
<c:if>
标签和
EL
表达式来修改该段
JSP
代码。
修改后的结果如下:
<c:if test="${(requestScope.allAttackSolution != null)
&& fn:length(requestScope.allAttackSolution) != 0}">
...
</c:if>
<logic:notEmpty>
标签其本身具有多种功能:
q
一是判断是否为
null
。
q
二是当它为
String
类型的变量时,判断字符串长度是否为
0
。
q
三是当它为集合类型的变量时,利用集合类的
isEmpty
方法可以判断是否是一个空的集合。
本示例既然要在替换后与替换前的工作一致,就应该对集合做两个判断:
q
一是该集合不为
null
。
q
二是该集合中的对象数量不为
0
。
“
!=null
”的
EL
表达式实现了集合实例不为
null
的判断;
fn:length()
函数实现了集合内对象数量不为
0
的判断,两个判断用“
&&
”连接起来就实现了
<logic:notEmpty>
标签对于集合判断的工作。
在这里应该利用“
<logic:notEmpty>
标签”,还是利用“
EL
表达式和
<c:if>
标签”呢?
<logic:notEmpty>
标签相对来说可读性更强些,
EL
表达式作为判断条件则可读性稍差些。然而,这些仅是就本示例的改动而言的,其他情况下,利用
EL
表达式和
<c:if>
标签还是有其优势的。
9.9.4 JSP
部分:
<logic:iterate>
和
<c:forEach>
标签
在第三章示例的
showAttackSolution.jsp
中出现了这样的使用:
<logic:iterate name="allAttackSolution"
id="attackSolution"
type="struts.sample.cap1.sample3.entity.AttackSolution">
<tr>
<td style="word-break: break-all;">
<bean:write property="attack_event_code" name="attackSolution" />
</td>
<td style="word-break: break-all;">
<bean:write property="attack_mean" name="attackSolution" />
</td>
<td style="word-break: break-all;">
<bean:write property="attack_action" name="attackSolution" />
</td>
<td style="word-break: break-all;">
<input type="button"
onclick="del('<%=attackSolution.getAttack_event_code()%>');"
value="<bean:message key="message.delete"/>">
</td>
</tr>
</logic:iterate>
由于在
Action
中将显示的内容作为
ArrayList
类型的实例保存在
request
中,因此这段
JSP
页面标签的工作是:
(
1
)利用
<logic:iterate>
标签对保存在
ArrayList
实例中的所有对象进行循环取得。
(
2
)
ArrayList
类型实例中的对象为
struts.sample.cap1.sample3.entity.AttackSolution
类型,
AttackSolution Java
类中的变量属性都有
get
、
set
方法,因此可以被认为是一个标准的
JavaBean
。利用
<bean:write>
标签将
AttackSolution
实例的变量属性读取出来,并显示。
根据之前讨论的“
<logic:iterate>
标签被
<c:forEach>
标签和
EL
表达式替换”,可以利用
<c:forEach>
标签和
EL
表达式来修改该段
JSP
代码。修改的方式有两种:
q
完全使用
<c:forEach>
标签和
EL
表达式来替换全部。
q
仅使用
EL
表达式来替换
<bean:write>
标签。
1. <c:forEach>
标签和
EL
表达式
<c:forEach>
标签和
EL
表达式:
<c:forEach items="${requestScope.allAttackSolution}"
var="attackSolution">
<tr>
<td style="word-break: break-all;" >
${attackSolution.attack_event_code}
</td>
<td style="word-break: break-all;" >
${attackSolution.attack_mean}
</td>
<td style="word-break: break-all;" >
${attackSolution.attack_action}
</td>
<td style="word-break: break-all;" >
<input type="button"
onclick="del('${attackSolution.attack_event_code}');"
value="<bean:message key="message.delete"/>">
</td>
</tr>
</c:forEach>
这种修改方式将屏弃
Struts
框架的
<logic:iterate>
标签,而以
<c:forEach>
标签来作为循环迭代的工作。它的最大优点是无需关注集合中的对象类型,只要保证该对象是一个标准的
JavaBean
就可以了。
2.
使用
EL
表达式来替换
<bean:write>
标签
<logic:iterate name="allAttackSolution"
id="attackSolution"
type="struts.sample.cap1.sample3.entity.AttackSolution">
<tr>
<td style="word-break: break-all;" >
${attackSolution.attack_event_code}
</td>
<td style="word-break: break-all;" >
${attackSolution.attack_mean}
</td>
<td style="word-break: break-all;" >
${attackSolution.attack_action}
</td>
<td style="word-break: break-all;" >
<input type="button"
onclick="del('${attackSolution.attack_event_code}');"
value="<bean:message key="message.delete"/>">
</td>
</tr>
</logic:iterate>
这种方式对原来的代码没有做多大的改动,依然会使用
<logic:iterate>
标签来作为循环标签。不过对于原来使用
<bean:write>
标签做显示功能的地方,摒弃了
<bean:write>
标签而直接使用
EL
表达式。灵活的
EL
表达式对页面显示逻辑有很大帮助,这种方式比较适合熟悉
<logic:iterate>
标签的程序设计者。
下面看一个完整的修改后
JSP
页面的代码,注释掉的是被替换之前的代码,读者可以比较一下两种实现方法。请见例
9.7
。
例
9.7
:修改后
showAttackSolution.jsp
。
<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<html>
<head>
<!--
略过
JavaScript
部分
-->
...
</head>
<body>
<em><bean:message key="message.attacksolutionDB"/></em><p>
<table>
<html:errors/>
</table>
<bean:message key="message.attackcode"/>:
<input name="attack_event_codeC" value="" type="text">
<bean:message key="message.attackdesc"/>:
<TEXTAREA style="height:100" name=attack_meanC></TEXTAREA>
<bean:message key="message.attacksolution"/>:
<TEXTAREA style="height:100" name=attack_actionC></TEXTAREA>
<p/>
<html:form action="AddAttackSolutionAction.do">
<html:hidden property="attack_event_code"/>
<html:hidden property="attack_mean"/>
<html:hidden property="attack_action"/>
<input type="button" onclick="add();" value="<bean:message key="message.add"/>">
<input type="button"
onclick="search();"
value="<bean:message key="message.search"/>">
</html:form>
<table border=1 cellspacing=1 cellpadding=2>
<tr>
<td style="background-color: #808080;font-size: 12pt;color: #ffffff;font-weight:
bold;line-height: 15pt;border: 1px solid #808080;">
<bean:message key="message.attackcode"/>
</td>
<td style="background-color: #808080;font-size: 12pt;color: #ffffff;font-weight:
bold;line-height: 15pt;border: 1px solid #808080;">
<bean:message key="message.attackdesc"/>
</td>
<td style="background-color: #808080;font-size: 12pt;color: #ffffff;font-weight:
bold;line-height: 15pt;border: 1px solid #808080;">
<bean:message key="message.attacksolution"/>
</td>
<td style="background-color: #808080;font-size: 12pt;color: #ffffff;font-weight:
bold;line-height: 15pt;border: 1px solid #808080;">
<bean:message key="message.delete"/>
</td>
</tr>
<!--
没有替换前的代码
-->
<!--
<logic:notEmpty name="allAttackSolution">
<logic:iterate name="allAttackSolution"
id="attackSolution"
type="struts.sample.cap1.sample3.entity.AttackSolution">
<tr>
<td style="word-break: break-all;" >
<bean:write property="attack_event_code"
name="attackSolution"/>
</td>
<td style="word-break: break-all;" >
<bean:write property="attack_mean" name="attackSolution"/>
</td>
<td style="word-break: break-all;" >
<bean:write property="attack_action" name="attackSolution"/>
</td>
<td style="word-break: break-all;" >
<input type="button"
onclick="del('
<bean:write
property="attack_event_code"
name="attackSolution"/>');"
value="<bean:message key="message.delete"/>">
</td>
</tr>
</logic:iterate>
</logic:notEmpty>
-->
<!--
仅替换
<bean:write>
标签的代码
-->
<!--
<logic:notEmpty name="allAttackSolution">
<logic:iterate name="allAttackSolution"
id="attackSolution"
type="struts.sample.cap1.sample3.entity.AttackSolution">
<tr>
<td style="word-break: break-all;" >
${attackSolution.attack_event_code}
</td>
<td style="word-break: break-all;" >
${attackSolution.attack_mean}
</td>
<td style="word-break: break-all;" >
${attackSolution.attack_action}
</td>
<td style="word-break: break-all;" >
<input type="button"
onclick="del('${attackSolution.attack_event_code}');"
value="<bean:message key="message.delete"/>">
</td>
</tr>
</logic:iterate>
</logic:notEmpty>
-->
<!--
替换后的实现代码
-->
<c:if test="${(requestScope.allAttackSolution != null)
&& fn:length(requestScope.allAttackSolution) != 0}">
<c:forEach items="${requestScope.allAttackSolution}" var="attackSolution">
<tr>
<td style="word-break: break-all;" >
${attackSolution.attack_event_code}
</td>
<td style="word-break: break-all;" >
${attackSolution.attack_mean}
</td>
<td style="word-break: break-all;" >
${attackSolution.attack_action}
</td>
<td style="word-break: break-all;" >
<input type="button"
onclick="del('${attackSolution.attack_event_code}');"
value="<bean:message key="message.delete"/>">
</td>
</tr>
</c:forEach>
</c:if>
</table>
</body>
</html>
可以看到,在这个被修改的
JSP
页面代码中,利用了
Struts
框架提供的标签来实现提交部分的工作以及国际化资源配置文件读取显示的工作,也利用
JSTL
的标签库和
EL
表达式来实现页面逻辑部分的工作。
在
JSP
页面使用
JSTL
是一种规范,也是一件令人兴奋的事情,因为它使
JSP
部分的程序设计变得更加有效合理。