序
经过了两个星期不懈努力,今天终于完成了对strtus整体架构及核心标签库的介绍。从几乎不懂struts和Html标签,到可以给别人解决涉及struts的一些小问题,这与朋友的帮助和我的努力是分不开的,但我更希望它能给那些想要学的,正在学的和已经学过的人带来不同的益处。我知道我是个新手,但我会用百倍的努力继续在这个领域进行深入性的和扩展性的学习与研究。同时,就象我说的,我们会用实际行动证实我们为你提供的帮助。
这章适合做参考资料,他不仅包含了对struts的整体架构及主要组件的具体和清楚的介绍,而且对于很多人都关注的struts标签库也进行了细致的介绍,可以说它是你手头一个可以用来进行参考的资料。当你哪里不清楚,你完全可以到这里查询。为了你查询方便,我做了一个目录。
由于开源软件不断发展,所以这不可能是最后版本,我会不断进行内容的修改和新特性的添加。比如strus1.1的Nested Tag,但由于个人技术水平和时间等多方面原因,速度不会太快,这就需要大家的帮助,希望大家共同参加一些资料的整理。
最后,我真心的感谢jag,banq,steelg,holen,七老爷,还有混血儿,要不是他,我会更早完成这个资料的,不过他又一次锻炼了我的意志。
我已经尽力避免在文字或代码中出现错误,但是人无完人,疏漏总是难免的。假如你在阅读发现了其中的错误,比如文字的错误或错误的代码,我非常希望你将这些信息反馈给我,这样会帮助其他人解决碰到的问题,也会不断完善这套资料。我的邮件是: tyrones@cmmail.com <mailto:tyrones@cmmail.com> QQ:36983608
希望本资料能给你带来帮助!
目录
序…………………………………………………………………………………………………1
目录………………………………………………………………………………………………2
Struts框架
1.Struts压缩包内容.................................................... 3
2.Struts体系结构..........................................................4
3.Struts框架中的组件..................................................... 5
3.1 Struts配置文件................................................…...…5
3.2 ActionServlet类....................................................8
3.3 ActionMapping类......................................................10
3.4 Action类 ..........................................................10
3.5 ActionForm类 ......................................................11
3.6 ActionForward类 ...................................................12
3.7 错误处理 ...........................................................12
4.Struts标记库 ............................................................13
4.1 Bean标记.......................................................... 13
4.1.1 Bean复制标记 ...................................................14
4.1.2 定义脚本变量的标记 .............................................14
4.1.3 显示Bean属性.................................................. 15
4.1.4 消息标记和国际化 ...............................................15
4.2 逻辑标记 ...........................................................16
4.2.1 条件逻辑 .......................................................17
4.2.2 重复标记 .......................................................18
4.2.3 转发和重定向标记 ...............................................19
4.3 HTML标记 .........................................................20
4.3.1 显示表单元素和输入控件 .........................................20
4.3.2 显示错误信息的标记 .............................................24
4.3.3 其他HTML标记 ..................................................25
Struts框架
struts框架具有组件的模块化,灵活性和重用性的优点,同时简化了基于MVC的web应用程序的开发。
本章具体讨论struts架构。我们将看到struts是如何清楚地区分控制,事务逻辑和外观,从而简化了开发应用程序过程的。我们还将介绍struts提供的类如何使得开发工作更加简单,这些类包括:
控制程序流程的类
实现和执行程序事务逻辑的类
自定义的标 记库使得创建和验证HTML表单更加轻易
1.Struts压缩包内容
文件夹jakarta-struts-1.0.2包含两个目录,lib和webapps。在lib目录中有使用struts创建应用程序时所需的文件:
文件 描述
jdbc2_0-stdext.jar 包含JDBC2.0 Optional Package API类。假如我们要使用struts提供的数据资源,就需要将这个文件拷贝到WEB-INFlib下
Struts.jar 包含struts中所有的Java类。同样也需要拷贝到WEB-INFlib下
*.tld 标记库描述器文件,描述了多个struts标记库中的自定义标记。同样要拷贝到WEB-INFlib下
在webapps目录下有如下文件:
Web应用程序 描述
Struts-blank.war 一个简单的web应用程序
Struts-documentation.war 包含struts站点上所有struts文档
Struts-example.war Struts很多特性的示范
Struts-exercisetaglib.war 主要用于对自定义标签库进行增加而使用的测试页,但也可以示范如何使用struts标记
Struts-template.war 包含struts模板标记的介绍和范例
Struts-upload.war 一个简单的例子,示范如何使用struts框架上传文件
2.Struts体系结构
让我们从MVC角度观察struts框架中的组件
框架中三个部分:模型,视窗和控制器。
模型
在struts框架中,模型分为两个部分:
系统的内部状态
可以改变状态的操作(事务逻辑)
内部状态通常由一组ActinForm JavaBean表示。根据设计或应用程序复杂度的不同,这些Bean可以是自包含的并具有持续的状态,或只在需要时才获得数据(从某个数据库)。
大型应用程序通常在方法内部封装事务逻辑(操作),这些方法可以被拥有状态信息的bean调用。比如购物车bean,它拥有用户购买商品的信息,可能还有checkOut()方法用来检查用户的信用卡,并向仓库发定货信息。
小型程序中,操作可能会被内嵌在Action类,它是struts框架中控制器角色的一部分。当逻辑简单时这个方法很适合。
建议用户将事务逻辑(要做什么)与Action类所扮演的角色(决定做什么)分开。
视窗
由jsp建立,struts包含扩展自定义标签库,可以简化创建完全国际化用户界面的过程。
控制器
struts中,基本的控制器组件是ActionServlet类中的实例servelt,实际使用的servlet在配置文件中由一组映射(由ActionMapping类进行描述)进行定义。
3.Struts框架中的组件
(由于ROSE工具还未能下载,只能找来这幅图,它说明了一定问题,非凡是ActionErrors,但它并没有将ActionMapping,JSP和Tag Library包含进来,有时间作完替换)
框架中所使用的组件:
ActionServlet 控制器
ActionClass 包含事务逻辑
ActionForm 显示模块数据
ActionMapping 帮助控制器将请求映射到操作
ActionForward 用来指示操作转移的对象
ActionError 用来存储和回收错误
Struts标记库 可以减轻开发显示层次的工作
下面我们看看各安闲框架中所扮演的角色和责任。
3.1 Struts配置文件
这是将struts组件结合在一起的东东:struts-config.XML。默认值
WEB-INFstruts-config.xml。配置文件可以定义:
全局转发
ActionMapping类
ActionForm bean
JDBC数据源
配置全局转发
全局转发用来在JSP页之间创建逻辑名称映射。转发都可以通过对调用操作映射的实例来获得,例如:
actionMappingInstace.findForward(“logicalName”);
全局转发的例子:(所有的例子我没有进行解释,一是结合表可以理解,二是例子大部分来自系列四的示例,你应该在作完实验后,再来看一遍)
<global-forwards>
<forward name="bookCreated" path="/BookView.jsp"/>
</global-forwards>
属性 描述
Name 全局转发的名字
Path 与目标URL的相对路径
配置ActionMapping
ActionMapping对象帮助进行框架内部的流程控制,它们可将请求URI映射到Action类,并且将Action类与ActionForm bean相关联。ActionServlet在内部使用这些映射,并将控制转移到特定Action类的实例。所有Action类使用perform()方法实现特定应用程序代码,返回一个ActionForward对象,其中包括响应转发的目标资源名称。例如:
<action-mappings>
<action path="/createBook"
type="BookAction"
name="bookForm"
scope="request"
input="/CreateBook.jsp">
</action>
<forward name=”failure” path=”/CreateBook.jsp”/>
<forward name=”cancel” path=”/index.jsp”/>
</action-mappings>
属性 描述
Path Action类的相对路径
Name 与本操作关联的Action bean的名称
Type 连接到本映射的Action类的全称(可有包名)
Scope ActionForm bean的作用域(请求或会话)
Prefix 用来匹配请求参数与bean属性的前缀
Suffix 用来匹配请求参数与bean属性的后缀
attribute 作用域名称。
className ActionMapping对象的类的完全限定名默认的类是org.apache.struts.action.ActionMapping
input 输入表单的路径,指向bean发生输入错误必须返回的控制
unknown 设为true,操作将被作为所有没有定义的ActionMapping的URI的默认操作
validate 设置为true,则在调用Action对象上的perform()方法前,ActionServlet将调用ActionForm bean的validate()方法来进行输入检查
通过<forward>元素,可以定义资源的逻辑名称,该资源是Action类的响应要转发的目标。
属性 描述
Id ID
ClassName ActionForward类的完全限定名,默认是org.apache.struts.action.ActionForward
Name 操作类访问ActionForward时所用的逻辑名
Path 响应转发的目标资源的路径
redirect 若设置为true,则ActionServlet使用sendRedirect()方法来转发资源
配置ActionForm Bean
ActionServlet使用ActionForm来保存请求的参数,这些bean的属性名称与HTTP请求参数中的名称相对应,控制器将请求参数传递到ActionForm bean的实例,然后将这个实例传送到Action类。例子:
<form-beans>
<form-bean name="bookForm" type="BookForm"/>
</form-beans>
属性 描述
Id ID
className ActionForm bean的完全限定名,默认值是org.apache.struts.action.ActionFormBean
Name 表单bean在相关作用域的名称,这个属性用来将bean与ActionMapping进行关联
Type 类的完全限定名
配置JDBC数据源
用<data-sources>元素可以定义多个数据源。
属性 描述
Id ID
Key Action类使用这个名称来寻找连接
Type 实现JDBC接口的类的名称
下面属性需要<set-property>元素定义,在框架1.1版本中已不在使用,但你可用<data-source>元素。例子:
<data-sources>
<data-source id=”DS1”
key=”conPool”
type=”org.apache.struts.util.GenericDataSource”
<set-property id=”SP1”
autoCommit="true"
description="Example Data Source Configuration"
driverClass="org.test.mm.mysql.Driver"
maxCount="4"
minCount="2"
url="jdbc:mysql://localhost/test"
user="struts"
passWord="wrox" />
<data-source/>
</data-sources>
属性 描述
desciption 数据源的描述
autoCommit 数据源创建的连接所使用的默认自动更新数据库模式
driverClass 数据源所使用的类,用来显示JDBC驱动程序接口
loginTimeout 数据库登陆时间的限制,以秒为单位
maxCount 最多能建立的连接数目
minCount 要创建的最少连接数目
password 数据库访问的密码
readOnly 创建只读的连接
User 访问数据库的用户名
url JDBC的URL
通过指定要害字名称,Action类可以访问数据源,比如:
javax.sql.DataSource ds = servlet.findDataSource(“conPool”);
javax.sql.Connection con = ds.getConnection();
3.2 ActionServlet类
框架中的控制器组件是有org.apache.struts.action.ActionServlet类实现的,这个类是javax.servlet.http.HttpServlet类的扩展。
Struts controller基本功能是:
1. 截获用户的Http请求
2. 把这个请求映射到相应的Action类,假如这是此类收到的第一个请求,将初始化实例并
缓存。
3. 创建或发现一个ActionForm bean实例(看配置文件是否定义),然后将请求过程移植到
bean.
4. 调用Action实例的perform()方法并将ActioForm bean,Action Mapping对象,request
和response对象传给它。
如:public ActionForword perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
5.perform返回一个ActionForword对象,此对象连接到相应的jsp页面.
ActionServlet配置
我们需要在web.xml中声明ActionServlet,并且将它配置成启动时进行加载。以下为可以配置的初始化参数:
参数 默认值 描述
application null 应用程序的资源集合的类
bufferSize 4096 文件上传的缓冲区大小
config /WEB-INF/struts-config.xml 配置文件的位置和名称
content Text/html 默认的内容类型
debug 0 程序调试的级别
detail 0 程序调试细节的级别
factory null 消息资源工厂,用于国际化中解释消息资源
formBean org.apache.struts.action.ActionFormBean 封装ActionForm bean信息的类的名称
forward org.apache.struts.action.ActionForward 封装ActionForward对象信息的类的名称
locale true 为true,将在用户会话中存储一个本地对象
mapping org.apache.struts.action.ActionForward 封装ActionMapping信息的类的名称
maxFileSize 250M 上传文件的最大尺寸
multipartClass org.apache.struts.action.ActionForward 处理多部分请求的类的名称
noCache False HTTP标头是否要设置为禁止缓存
Null True 设置为true,对于无效的信息要害字将返回null
tempDir 作为一个servlet参数提供给程序的工作目录 处理下载文件是使用的临时工作目录
validate True 是否使用新格式的配置文件
validating True 是否对配置文件进行有效性分析
大多数情况下,标准的servlet就能够满足用户需要。
第一次收到特定请求的URI时,ActionServlet将适当的Action类进行实例化,然后ActionServlet在Action类实例中以servlet为变量名存储一个引用。当被实例化后,Action类会被暂存以备再用。
ActionServlet也提供一些方法,由Action类用来访问数据源和转发目标之类的资源。
ActionServlet方法
ActinServlet提供了一组能够被Action对象使用的方法。
Struts API的全部信息在struts-documentation.war中可以找到。动态的添加或删除,这些方法只影响应用程序当前的实例:
public void addFormBean(ActionFormBean formBean)
public void removeFormBean(ActionFormBean formBean)
public void addForward(ActionForward actionForward)
public void removeForward(ActionForward actionForward)
public void addMapping(ActionMapping actionMapping)
public void removeMapping(ActionMapping actionMapping)
根据名称查找对象:
public ActionFormBean findFormBean(String name)
public ActionForward findForward(String name)
public ActionMapping findMapping(String name)
用来处理数据源:
public void addDataSource(String key , DataSource ds)
public DataSource findDataSource(String key)
我们还可以:
使用destroy()方法结束ActionServlet
使用reload()方法从struts配置文件将信息重新加载。
3.3 ActionMapping类
将特定请求映射到特定Action的相关信息存储在ActionMapping中,ActionServelt将ActionMapping传送到Action类的perform()方法,Action将使用ActionMapping的findForward()方法,此方法返回一个指定名称的ActionForward,这样Action就完成了本地转发。若没有找到具体的ActionForward,就返回一个null.
public ActionForward findForward(String name)
可在映射中动态添加ActionForward:
public void addForward(ActionForward forward)
可返回与映射关联的表单bean:
public String getName()
可返回映射的属性域(会话或请求)
public String getScope()
3.4 Action类
Action类真正实现应用程序的事务逻辑,它们负责处理请求。在收到请求后,ActionServlet会:
为这个请求选择适当的Action
假如需要, 创建Action的一个实例
调用Action的perform()方法
假如ActionServlet不能找到有效的映射,它会调用默认的Action类(在配置文件中定义)。假如找到了ActionServlet将适当的ActionMapping类转发给Action,这个Action使用ActionMapping找到本地转发,然后获得并设置ActionMapping属性。根据servlet的环境和被覆盖的perform()方法的签名,ActionServlet也会传送ServletRequest对象或HttpServletRequest对象。
所有Action类都扩展org.apache.struts.action.Action类,并且覆盖类中定义的某一个perform()方法。有两个perform()方法:
处理非HTTP(一般的)请求:
public ActionForward perform(ActionMapping action,
AcionForm form,
ServletRequest request,
ServletResponse response)
throws IOException,ServletException
处理HTTP请求:
public ActionForward perform(ActionMapping action,
AcionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException,ServletException
Action类必须以“线程安全”的方式进行编程,因为控制器会令多个同时发生的请求共享同一个实例,相应的,在设计Action类时就需要注重以下几点:
不 能使用实例或静态变量存储特定请求的状态信息, 它们会在同 一个操作中共享跨越请求的全局资源
假如要访问的资源(如JavaBean和会话变量)在并行访问时需要进行保护, 那么访问就要进行同 步
Action类的方法
除了perform()方法外,还有以下方法:
可以获得或设置与请求相关联的区域:
public Locale getLocale(HttpServletRequest request)
public void setLocale(HttpServletRequest request,Locale locale)
为应用程序获得消息资源:
public MessageResources getResources()
检查用户是否点击表单上的“取消”键,假如是,将返回true:
public Boolean isCancelled(HttpServletRequest request)
当应用程序发生错误时,Action类能够使用下面方法存储错误信息:
public void saveErrors(HttpServletRequest request,ActionErrors errors)
ActionError实例被用来存储错误信息,这个方法在错误要害字下的请求属性列表中存储ActionError对象。通过使用在struts标记库中定义的自定义标记,JSP页能够显示这些错误信息,稍后我们就介绍。
3.5 ActionForm类
框架假设用户在应用程序中为每个表单都创建了一个ActionForm bean,对于每个在struts-config.xml文件中定义的bean,框架在调用Action类的perform()方法之前会进行以下操作:
在相关联的要害字下, 它检查用于适当类的bean实例的用户会话, 假如在会话中没有可用的bean, 它就会自动创建一个新的bean并添加到用户的会话中。
对于请求中每个与bean属性名 称对应的参数, Action调用相应的设置方法。
当Action perform()被调用时, 最新的ActionForm bean传送给它, 参数值就可以立即使用了。
ActionForm类扩展org.apache.struts.action.ActionForm类,程序开发人员创建的bean能够包含额外的属性,而且ActionServlet可能使用反射(答应从已加载的对象中回收信息)访问它。
ActionForm类提供了另一种处理错误的手段,提供两个方法:
Public ActionErrors validate(ActionMappin mapping,
ServletRequest request)
Public ActionErrors validate(ActionMappin mapping,
HttpServletRequest request)
你应该在自己的bean里覆盖validate()方法,并在配置文件里设置<action>元素的validate为true。在ActionServlet调用Action类前,它会调用validate(),假如返回的ActionErrors不是null,则ActinForm会根据错误要害字将ActionErrors存储在请求属性列表中。
假如返回的不是null,而且长度大于0,则根据错误要害字将实例存储在请求的属性列表中,然后ActionServlet将响应转发到配置文件<action>元素的input属性所指向的目标。
假如需要执行特定的数据有效性检查,最好在Action类中进行这个操作,而不是在ActionForm类中进行。
方法reset()可将bean的属性恢复到默认值:
public void reset(ActionMapping mapping,HttpServletRequest request)
public void reset(ActionMapping mapping,ServletRequest request)
典型的ActionFrom bean只有属性的设置与读取方法(getXXX),而没有实现事务逻辑的方法。只有简单的输入检查逻辑,使用的目的是为了存储用户在相关表单中输入的最新数据,以便可以将同一网页进行再生,同时提供一组错误信息,这样就可以让用户修改不正确的输入数据。而真正对数据有效性进行检查的是Action类或适当的事务逻辑bean。
3.6 ActionForward类
目的是控制器将Action类的处理结果转发至目的地。
Action类获得ActionForward实例的句柄,然后可用三种方法返回到ActionServlet,所以我们可以这样使用findForward():
ActionServlet根据名 称获取一个全局转发
ActionMapping实例被传送到perform()方法, 并根据名 称找到一个本地转发
另一种是调用下面的一个构造器来创建它们自己的一个实例:
public ActionForward()
public ActionForward(String path)
public ActionForward(String path,Boolean redirect)
3.7 错误处理
struts提供了两个类来处理错误:ActionErrors和ActionError,它们都扩展org.apache.struts.action。ActionErrors保存着ActionError对象的集合,其中每一个代表了独立的错误信息。每个ActionError都包含了要害字,能够映射到资源文件中存储的错误信息,而这个资源文件是在ActionServlet初始化参数中指定的。
ActionError类
ActionError类定义了一组重载的构造器来创建错误信息,第一个构造器方法使用一个字符串作为参数,例如:
ActionError error = new ActionError(“error.Invalid”);
实例error映射到应用程序资源文件中的一个错误消息:
error.invalid=<b>Invalid Number</b>
假如在JSP页使用<html:error>,用户就会看见加粗的Invalid Number。
另一种使用了java.text.MessageFormat类,可在消息中指定替换字符串,例如:
error.invalid=<b>Invalid Number{0}</b>
创建一个错误消息:
ActionError error = new ActionError(‘error.invalid’,new Double(-1));
JSP页显示:Invalild Number -1
还有获得特定消息的错误要害字:
public String getKey()
还有获得替换字符串数组:
public String[] getValues()
ActionError类
ActionError类从不独立进行错误处理,它们总是被存储在ActionErrors对象中。ActionErrors对象保存ActionError类的集合以及它们特定的属性值,我们可以使用自己定义的属性值,或是使用ActionErrors.GLOBAL_ERROR.
下面是典型Action类的perform()中错误处理情况:
MyForm form = (MyForm) form;
if (number == -1) {
ActionErrors errors = new ActionErrors();
ActionError error = new ActionError(“error.Invalid”,new Double(-1));
errors.add(ActionErrors.GLOBAL_ERROR,error);
saveErrors(req,errors);
String input = mapping.getInput();
Return new ActionForward(input);
}
ActionErrors有如下有用方法:
方法 描述
clear() 清除所有错误信息
empty() 假如ActionErrors对象是空的,它返回true
get() 返回错误信息。若无参数,所有信息将作为一个Iterator对象返回
properties() 返回包含属性名称的Iterator,这些属性至少有一个错误
size() 返回错误的数目(整型数)
Struts标记库
4.Struts标记库
JSP视窗组件所使用的 struts标记库由四类标记组成:
Bean标 记:用来在JSP页中治理bean
逻辑标 记:用来在JSP页中控制流程
HTML标 记:用来生成HTML标 记, 在表单中显示数据, 使用会话ID对URL进行编程
模板标 记:使用动态模板构造普通格式的页
4.1 Bean标记
这个标记库中包含用于定义新bean、访问bean及其属性的标记。Struts框架提供了多种自定义标记用来在JSP页中处理JavaBean。这些标记被封装在一个普通的标记库中,在文件struts-bean.tld中定义了它的标记库描述器。Bean标记库将标记定义在四个子类别中:
创建和复 制bean的标 记
脚本变量定义标 记
bean翻译标 记
消息国际化标 记
4.1.1 Bean复制标记
可定义新bean,可复制现有bean,还可从现有bean复制属性。
<bean:define>标记用来:
定义新字符串常数
将现有的bean复 制到新定义的bean对象
复 制现有bean的属性来创建新的bean
<bean:define>标记属性:
属性 描述
Id 新定义的bean脚本变量名称,必须设置
Type 定义引入脚本变量的类
Value 为id属性定义的脚本变量分配一个新的对象
Name 目标bean的名称。若value属性没有设置,这个属性就必须设置
property Name属性定义的bean的属性名称,用来定义新的bean
Scope 源bean的作用域。若没有设置,搜索范围是从页作用域到应用程序作用域
toScope 目标bean的作用域。若没有设置,默认值是页作用域
例如:定义一个bean:
<bean:define id=”test” value=”this is a test”/>
源bean在页作用域中被拷贝请求作用域中的另一个bean:
<bean:define id=”targetBean” name=”sourceBean”
scope=”page” toScope=”request”/>
4.1.2 定义脚本变量的标记
从多种资源中定义和生成脚本变量,这些资源包括cookie,请求参数,HTTP标头等等。属性如下:
属性 描述
Id 脚本变量和要定义的页作用域属性的名称
Name cookie/标头/参数的名称
multiple 假如这个属性设置了任意一个数值,所有匹配的cookie都会被积累并存储到一个Cookie[](一个数组)类型的bean里。若无设置,指定cookie的第一个值将作为Cookie类型的值
Value 假如没有匹配的cookie或数值,就返回这个属性指定的默认值
例如:
<bean:cookie id=”myCookie” name=”userName”/>
脚本变量名称是myCookie,用来创建这个属性的cookie的名称是userName。
<bean:header id=”myHeader” name=”Accept-Language”/>
脚本变量名称是myHeader,请求标头的名称是Accept-Language.
<bean:parameter id=”myParameter” name=”myParameter”>
脚本变量名称是myPatameter,它保存的请求参数的名称也是myParameter.
<bean:include>标记将对一个资源的响应进行检索,并引入一个脚本变量和字符串类型的页作用域属性。这个资源可以是一个页,一个ActionForward或一个外部URL。与<jsp:include>的不同是资源的响应被存储到一个页作用域的bean中,而不是写入到输出流。属性如下:
属性 描述
Id 脚本变量和要定义的页作用域属性的名称
Page 一个内部资源
forward 一个ActionForward
Href 要包含的资源的完整URL
例如:
<bean:include id=”myInclude” page=”MyJsp?x=1”/>
脚本变量的名称是myInclude,要检索的响应来自资源MyJsp?x=1。
<bean:resource>标记将检索web应用中的资源,并引入一个脚本变量和InputStream或字符串类型的页作用域属性。假如在检索资源时发生问题,就会产生一个请求时间异常。属性如下:
属性 描述
Id 脚本变量和要定义的页作用域属性的名称
Name 资源的相对路径
Input 假如这个属性不存在,资源的类型就是字符串
例如:
<bean:resource id=”myResource” name=”/WEB-INF/images/myResource.xml”/>
脚本变量的名称是myResource,要检索的资源的名称是myResource.xml。
4.1.3 显示Bean属性
标记库中定义了<bean:write>标记,用来将bean的属性输送到封装的JSP页写入器。这个标记与<jsp:getProperty>类似,属性如下:
属性 描述
Name 要进行属性显示的bean的名称
property 要显示的属性的名称。假如这个属性类有java.beans.PropertyEditor,getAsText()或toString 方法会被调用
Scope Bean的作用域,若没有设置,搜索范围是从页到应用程序作用域
Filter 假如设置true,属性中的所有非凡HTML字符都将被转化为相应的实体引用
Ignore 假如设置false,当发现属性时会产生一个请求时间异常,否则返回null
例如:
<bean:write name=”myBean” property=”myProperty” scope=”request”
filter=”true”/>
myBean的属性myProperty将会被显示,作用域为请求,假如发现任何HTML非凡字符都将被转化为相应的实体引用。
4.1.4 消息标记和国际化
strtus框架支持国际化和本地化。用户在他们的计算机中定义自己所在的区域,当web应用程序需要输出一条消息时,它将引用一个资源文件,在这个文件中所有的消息都使用了适当的语言。一个应用程序可能提供了很多资源文件,每个文件提供了用不同语言编写的消息。假如没有找到所选语言的资源文件,就将使用默认的资源文件。
struts框架对国际化的支持是使用<bean:message>标记,以及使用java.util数据包中定义的Locale和ResourceBundle类来实现Java2平台对这些任务的支持。Java.text.MessageFormat类定义的技术可以支持消息的格式。利用此功能,开发人员不需了解这些类的细节就可进行国际化和设置消息的格式。
用strtus实现国际化和本地化:
第一步要定义资源文件的名称,这个文件会包含用默认语言编写的在程序中会出现的所有消息。这些消息以“要害字-值”的形式存储,如下:
error.validation.location = The entered location is invalid
这个文件需要存储在类的路径下,而且它的路径要作为初始化参数传送给ActionServlet作为参数进行传递时,路径的格式要符合完整Java类的标准命名规范。比如,假如资源文件存储在WEB-INFclasses目录中,文件名是ApplicationResources.properties,那么需要传递的参数值是ApplicationResources。假如文件在WEB-INFclassescom est中,那么参数值就应该是com.test. ApplicationResources.
为了实现国际化,所有的资源文件必须都存储在基本资源文件所在的目录中。基本资源文件包含的是用默认地区语言-本地语言编写的消息。假如基本资源文件的名称是ApplicationResources.properties,那么用其他特定语言编写的资源文件的名称就应该是ApplicationResources_xx.properties(xx为ISO编码,如英语是en)。因此这些文件应包含相同的要害字,但要害字的值是用特定语言编写的。
ActionServlet的区域初始化参数必须与一个true值一起传送,这样ActionServlet就会在用户会话中的Action.LOCALE_KEY要害字下存储一个特定用户计算机的区域对象。现在可以运行一个国际化的web站点,它可以根据用户计算机上的设置的区域自动以相应的语言显示。
我们还可以使用特定的字符串来替换部分消息,就象用java.text.MessageFormat的方法一样:
error.invalid.number = The number {0} is valid
我们可以把字符串{0}替换成任何我们需要的数字。<bean:message>标签属性如下:
属性 描述
Key 资源文件中定义消息要害字
Locale 用户会话中存储的区域对象的属性名称。若没有设置,默认值是Action.LOCALE_KEY
Bundle 在应用程序上下文中,存储资源对象的属性的名称。假如没有设置这个属性,默认值是Action.MESSAGE_KEY
arg0 第一个替换参数值
arg1 第二个替换参数值
arg2 第三个替换参数值
arg3 第四个替换参数值
例如:资源文件中定义了一个消息:
info.myKey = The numbers entered are {0},{1},{2},{3}
我们可使用下面的消息标记:
<bean:message key=”info.myKey” arg0=”5” arg1=”6” arg2=”7” arg3=”8”/>
这个信息标记输出到JSP页会显示为:The numbers entered are 5,6,7,8
4.2 逻辑标记
逻辑库的标记能够用来处理外观逻辑而不需要使用scriptlet。Struts逻辑标签库包含的标记能够有条件地产生输出文本,在对象集合中循环从而重复地产生输出文本,以及应用程序流程控制。它也提供了一组在JSP页中处理流程控制的标记。这些标记封装在文件名为struts-logic.tld的标记包中。逻辑标记库定义的标记能够执行下列三个功能:
条件逻辑
重复
转发/重定向响应
4.2.1 条件逻辑
struts有三类条件逻辑。第一类可以比较下列实体与一个常数的大小:
cookie
请求参数
bean或bean的参数
请求标 头
以下列出了这一类标记:
标记 功能
<equal> 假如常数与被定义的实体相等,返回true
<notEqual> 假如常数与被定义的实体不相等,返回true
<greaterEqual> 假如常数大于等于被定义的实体,返回true
<lessEqual> 假如常数小于等于被定义的实体,返回true
<lessThan> 假如常数小于被定义的实体,返回true
<greaterThan> 假如常数大于被定义的实体,返回true
这一类的所有标记有相同的属性
属性 描述
Value 要进行比较的常数值
Cookie 要进行比较的HTTP cookie的名称
Header 要进行比较的HTTP请求标头的名称
parameter 要进行比较的HTTP请求参数的名称
Name 假如要进行比较的是bean或bean的属性,则这个属性代表bean的名称
property 要进行比较的bean属性的名称
Scope Bean的作用域,假如没有指定作用域,则它的搜索范围是从页到应用程序
例如:
<logic:equal parameter=”name” value=”SomeName”>
The entered name is SomeName
</logic:equal>
判定名为”name”的请求参数的值是否是”SomeName”。
<logic:greaterThan name=”bean” property=”prop” scope=”page” value=”7”>
The value of bean.Prop is greater than 7
</logic:greaterThan>
判定在页的作用域中是否有一个名为”bean”的bean,它有一个prop属性,这个属性的值是否大于7。假如这个属性能够转化为数值,就进行数值比较,否则就进行字符串比较。
第二类条件标记定义了两个标记:
<logic:present>
<logic:notPresent>
它们的功能是在计算标记体之前判定特定的项目是否存在。标记的属性和属性值决定了要进行检查的项目。
属性 描述
Cookie 由这个属性指定的cookie将被检查是否存在
Header 由这个属性指定的请求标头将被检查是否存在
parameter 由这个属性指定的请求参数将被检查是否存在
Name 假如没有设置property属性,那么有这个属性指定的bean将被检查是否存在。假如设置了,那么bean和bean属性都将被检查是否存在。
property 检查有name属性指定的bean中是否存在指定的属性
Scope 假如指定了bean的名称,这就是bean的作用域。假如没有指定作用域,搜索的范围从页到应用程序作用域。
Role 检查当前已经确认的用户是否属于非凡的角色
User 检查当前已经确认的用户是否有特定的名称
例如:
<logic:notPresent name=”bean” property=”prop” scope=”page”>
The bean property bean.prop is present
</logic:notPresent>
标记判定在页作用域中是否存在一个名为”bean”的bean,这个bean有一个prop属性。
第三类条件标记比较复杂,这些标记根据模板匹配的结果检查标记体的内容。换句话说,这些标记判定一个指定项目的值是否是一个特定常数的子字符串:
<logic:match>
<logic:notMatch>
这些标记答应JSP引擎在发现了匹配或是没有发现时计算标记主体。属性如下:
属性 描述
Cookie 要进行比较的HTTP cookie的名称
Header 要进行比较的的HTTP标头 的名称
parameter 要进行比较的的HTTP请求参数的名称
Name 若要对bean或bean的属性进行比较,这个属性是用户指定bean的名称
location 假如设置了这个属性的值,将会在这个指定的位置(索引值)进行匹配
scope 假如对bean进行比较,这个属性指定了bean的作用域。假如没有设置这个参数,搜索范围是从页到应用程序作用域
property 要进行比较的bean的属性名称
value 要进行比较的常数值
例如:
<logic:match parameter=”name” value=”xyz” location=”1”>
The parameter name is a sub-string of the string xyz from index 1
</logic:match>
标记检查名为”name”的请求参数是否是”xyz”的子字符串,但是子字符串必须从”xyz”的索引位置1开始(也就是说子字符串必须是”y”或”yz”)。
4.2.2 重复标记
在逻辑标记库中定义了<logic:iterate>标记,它能够根据特定集合中元素的数目对标记体的内容进行重复的检查。集合的类型可以是java.util.Iterator,java.util.Collection,java.util.Map或是一个数组。有三种方法可以定义这个集合:
使用运行时间表达式来返回一个属性集合的集合
将集合定义为bean, 并且使用name属性指 定存储属性的名 称。
使用name属性定义一个bean, 并且使用property属性定义一个返回集合的bean属性。
当前元素的集合会被定义为一个页作用域的bean。属性如下,所有这些属性都能使用运行时表达式。
属性 描述
collection 假如没有设置name属性,它就指定了要进行重复的集合
Id 页作用域bean和脚本变量的名称,它保存着集合中当前元素的句柄
indexed 页作用域JSP bean的名称,它包含着每次重复完成后集合的当前索引
Length 重复的最大次数
Name 作为集合的bean的名称,或是一个bean名称,它由property属性定义的属性,是个集合
Offset 重复开始位置的索引
property 作为集合的Bean属性的名称
Scope 假如指定了bean名称,这个属性设置bean的作用域。若没有设置,搜索范围从页到应用程序作用域
Type 为当前定义的页作用域bean的类型
例如:
<logic:iterate id=”currentInt”
collection=”<% =myList %>”
type=”java.lang.Integer”
offset=”1”
length=”2”>
<% =currentint %>
</logic:iterate>
代码将从列表中的第一个元素开始重复两个元素并且能够让当前元素作为页作用域和java.lang.Integer类型的脚本变量来使用。也就是说,假如myList包含元素1,2,3,4等,代码将会打印1和2。
4.2.3 转发和重定向标记
转发标记
<logic:forward>标记能够将响应转发给重定向到特定的全局ActionForward上。ActionForward的类型决定了是使用PageContext转发响应,还是使用sendRedirect将响应进行重定向。此标记只有一个”name”属性,用来指定全局ActionForward的名称,例如:
<logic:forward name=”myGlobalForward”/>
重定向标记
<logic:redirect>标记是一个能够执行HTTP重定向的强大工具。根据指定的不同属性,它能够通过不同的方式实现重定向。它还答应开发人员指定重定向URL的查询参数。属性如下:
属性 描述
Forward 映射了资源相对路径的ActionForward
Href 资源的完整URL
Page 资源的相对路径
Name Map类型的页名称,请求,会话或程序属性的名称,其中包含要附加重定向URL(假如没有设置 property属性)上的“名称-值”参数。或是具有Map类型属性的bean名称,其中包含相同的信息(没有设置property属性)
Property Map类型的bean属性的名称。Bean的名称由name属性指定。
Scope 假如指定了bean的名称,这个属性指定搜索bean的范围。假如没有设置,搜索范围从页到应用程序作用域
ParamID 定义特定查询参数的名称
ParamName 字符串类型的bean的名称,其中包含查询参数的值(假如没有设置paramProperty属性);或是一个bean的名称,它的属性(在paramProperty属性中指定)包含了查询参数值
paramProperty 字符串bean属性的名称,其中包含着查询参数的值
ParamScope ParamName定义的bean的搜索范围
使用这个标记时至少要指定forward,href或page中的一个属性,以便标明将响应重定向到哪个资源。
4.3 HTML标记
Struts HTML标记可以大致地分为以下几个功能:
显示表单元素和输入控件
显示错误信息
显示其他HTML元素
4.3.1 显示表单元素和输入控件
struts将HTML表单与为表单操作而定义的ActionForm bean紧密联系在一起。表单输入字段的名称与ActionForm bean里定义的属性名称是对应的。当第一次显示表单时,表单的输入字段是从ActionForm bean中移植过来的,当表单被提交时,请求参数将移植到ActionForm bean实例。
所有可以在<form>标记中使用的用来显示HTML输入控件的内嵌标记都使用下列属性来定义javascript事件处理器。
属性 描述
Onblur 字段失去了焦点
Onchange 字段失去了焦点并且数值被更改了
Onclick 字段被鼠标点击
Ondblclick 字段被鼠标双击
Onfocus 字段接收到输入焦点
Onkeydown 字段拥有焦点并且有键按下
onkeypress 字段拥有焦点并且有键按下并释放
Onkeyup 字段拥有焦点并且有键被释放
onmousedown 鼠标指针指向字段并且点击
onmousemove 鼠标指针指向字段并且在字段内移动
onmouseout 鼠标指针指向控件,但是指针在元素外围移动
onmouseover 鼠标指针没有指向字段,但是指针在元素内部移动
Onmouseup 鼠标指针指向字段,并且释放了鼠标按键
<form>元素中能够被定义的其他一般属性有:
属性 描述
Accesskey 定义访问输入字段的快捷键
Style 定义输入字段的样式
styleClass 定义输入字段的样式表类
Tabindex 输入字段的tab顺序
表单标记
<html:form>标记用来显示HTML标记,可以指定AcitonForm bean的名称和它的类名。假如没有设置这些属性,就需要有配置文件来指定ActionMapping以表明当前输入的是哪个JSP页,以及从映射中检索的bean名和类。假如在ActionMapping指定的作用域中没有找到指定的名称,就会创建并存储一个新的bean,否则将使用找到的bean。
<form>标记能够包含与各种HTML输入字段相对应的子标记。
<html:form>标记属性如下:
属性 描述
Action 与表单相关的操作。在配置中,这个操作也用来标识与表单相关的ActionForm bean
Enctype 表单HTTP方法的编码类型
Focus 表单中需要初始化焦点的字段
Method 表单使用的HTTP方法
Name 与表单相关的ActionForm bean的名称。假如没有设置这个属性,bean的名称将会从配置信息中获得
Onreset 表单复位时的JavaScript事件句柄
Onsubmit 表单提交时的JavaScript事件句柄
Scope 搜索ActionForm bean的范围。假如没有设置,将从配置文件中获取
Style 使用的格式
styleClass 这个元素的格式表类
Type ActionForm bean的完整名称。假如没有设置,将从配置文件获得
例如:
<html:form action=”validateEmploee.do” method=”post”>
</html:form>
与表单相关的操作路径是validateEmployee,而表单数据是通过POST传递的。对于这个表单来说,ActionForm bean的其他信息,如bean名称类型,作用域,都是从表单指定操作的ActionMapping中检索得到的:
<form-beans>
<form-bean name=”empForm” type=”com.example.EmployeeForm”/>
</form-beans>
<action-mappings>
<action path=”/validateEmployee”
type=”com.example.ValidateExampleAction”
name=”empForm”
scope=”request”
input=”/employeeInput.jsp”>
<forward name=”sUCcess” path=”/employeeOutput.jsp”>
</action>
</action-mapping>
假如配置文件中包含上述信息,并且请求URI的*.do被映射到ActionServlet,与表单相关的ActionForm bean的名称,类型和作用域分别是empForm,com.example.EmployeeForm和request.这些属性也可以使用<html:form>标记属性进行显示的定义。
以下标记必须嵌套在<html:form>标记里
按钮和取消标记
<html:button>标记显示一个按钮控件;<html:cancel>标记显示一个取消按钮。属性如下:
属性 描述
Property 定义在表单被提交时返回到服务器的请求参数的名称
Value 按钮上的标记
复位和提交标记
<html:reset>和<html:submit>标记分别能够显示HTML复位按钮和提交按钮。
文本和文本区标记
<html:text>和<html:textarea>标记分别为HTML文本框和文本区,属性如下:
属性 描述
Property 定义当表单被提交时送回到服务器的请求参数的名称,或用来确定文本元素当前值的bean的属性名称
Name 属性被查询的bean的名称,它决定了文本框和文本区的值。假如没有设置,将使用与这个内嵌表单相关的ActionForm的名称
<html:text>标记还有以下属性:
属性 描述
Maxlength 能够输入的最大字符数
Size 文本框的大小(字符数)
<html:textarea>标记特有的属性如下:
属性 描述
Rows 文本区的行数
Cols 文本区的列数
检查框和复选框标记
<html:checkbox>标记能够显示检查框控件。<html:multibox>标记能够显示HTML复选框控件,请求对象在传递检查框名称时使用的getParameterValues()调用将返回一个字符串数组。属性如下:
属性 描述
Name Bean的名称,其属性会被用来确定检查是否以选中的状态显示。假如没有设置,将使用与这个内嵌表单相关的ActionFrom bean的名称。
Property 检查框的名称,也是决定检查框是否以选中的状态显示的bean属性名称。在复选框的情况下,这个属性必须是一个数组。
Value 当检查框被选中时返回到服务器的请求参数的值
例如:
<html:checkbox property=”married” value=”Y”/>
一个名为married的检查框,在表单提交时会返回一个”Y”.
文件标记
<html:file>标记可以显示HTML文件控件。属性如下:
属性 描述
Name Bean的名称,它的属性将确定文件控件中显示的内容。假如没设置,将使用与内嵌表单相关的ActionForm bean的名称
property 这个属性定义了当表单被提交时送回到服务器的请求参数的名称,以及用来确定文件控件中显示内容的bean属性名称
Accept 服务器能够处理的内容类型集。它也将对客户浏览器对话框中的可选文件类型进行过滤
Value 按钮上的标记,这个按钮能够在本地文件系统中浏览文件
单选钮标记
<html:radio>标记用来显示HTML单选钮控件,属性如下:
属性 描述
Name Bean的名称,其属性会被用来确定单选钮是否以选中的状态显示。假如没有设置,将使用与这个内嵌表单相关的ActionFrom bean的名称。
property 当表单被提交时送回到服务器的请求参数的名称,以及用来确定单选钮是否以被选中状态进行显示的bean属性的名称
Value 当单选钮被选中时返回到服务器的值
隐藏标记
<html:hidden>标记能够显示HTML隐藏输入元素,属性如下:
属性 描述
Name Bean的名称,其属性会被用来确定隐藏元素的当前值。假如没有设置,将使用与这个内嵌表单相关的ActionFrom bean的名称。
property 定义了当表单被提交时送回到服务器的请求参数的名称,以及用来确定隐藏元素当前值的bean属性的名称
Value 用来初始化隐藏输入元素的值
密码标记
<html:password>标记能够显示HTML密码控件,属性如下:
属性 描述
maxlength 能够输入的最大字符数
Name Bean的名称,它的属性将用来确定密码元素的当前值。假如没有设置,将使用与这个内嵌表单相关的ActionFrom bean的名称。
property 定义了当表单被提交时送回到服务器的请求参数的名称,以及用来确定密码元素当前值的bean属性的名称
redisplay 在显示这个字段时,假如相应的bean属性已经被设置了数据,这个属性决定了是否显示密码的内容
Size 字段的大小
选择标记
<html:select>标记能够显示HTML选择控件,属性如下:
属性 描述
multiple 表明这个选择控件是否答应进行多选
Name Bean的名称,它的属性确定了哪个。假如没有设置,将使用与这个内嵌表单相关的ActionFrom bean的名称。
property 定义了当表单被提交时送回到服务器的请求参数的名称,以及用来确定哪个选项需要被选中的bean属性的名称
Size 能够同时显示的选项数目
Value 用来表明需要被选中的选项
选项标记(这个元素需要嵌套在<html:select>标记里)
<html:option>标记用来显示HTML选项元素集合,属性如下:
属性 描述
collection Bean集合的名称,这个集合存储在某个作用域的属性中。选项的数目与集合中元素的数目相同。Property属性能够定义选项值所使用的bean属性,而labelProperty属性定义选项标记所使用的bean的属性
labelName 用来指定存储于某个作用域的bean,这个bean是一个字符串的集合,能够定义<html:option>元素的标记(假如标志与值不相同)
labelProperty 与collection属性共同使用时,用来定义了存储于某个作用域的bean,这个bean将返回一个字符串集合,能够用来写入<html:option>元素的value属性
Name 假如这是唯一被指定的属性,它就定义了存储于某个作用域的bean,这个bean将返回一个字符串集合,能够用来写入<html:option>元素的value属性
property 这个属性在与collection属性共同使用时,定义了每个要显示选项值的独立bean的name属性。假如不是与collection属性共同使用,这个属性定义了由name属性指定的bean的属性名称(假如有name属性),或是定义了一个ActionForm bean,这个bean将返回一个集合来写入选项的值
我们看一下这个标记的一些例子:
<html:option collection=”optionCollection” property=”optionValue”
labelProperty=”optionLabel”/>
标记假设在某个作用域中有一个名为optionCollection的集合,它包含了一些具有optionValue属性的独立的bean,每个属性将作为一个选项的值。每个选项的标志由bean的optionLabel属性属性进行定义。
<html:option name=”optionValues” labelName=”optionLabels”/>
标记中optionValues代表一个存储在某个作用域中的bean,它是一个字符串集合,能够用来写入选项的值,而optionLabels代表一个存储在某个作用域中的bean,它也是一个字符串集合,能够用来写入选项的标志。
4.3.2 显示错误信息的标记
<html:errors>标记能够与ActionErrors结合在一起来显示错误信息。这个标记首先要从当前区域的资源文件中读取消息要害字errors.header,然后显示消息的文本。接下去它会在ActionErrors对象(通常作为请求参数而存储在Action.ERROR_KEY要害字下)中循环,读取单个ActionError对象的消息要害字,从当前区域的资源文件中读取并格式化相应的消息,并且显示它们。然后它读取与errors.footer要害字相对应的消息并且显示出来。
通过定义property属性能够过滤要显示的消息,这个属性的值应该与ActionErrors对象中存储ActionError对象的要害字对应。属性如下:
属性 描述
Bundle 表示应用程序作用域属性的名称,它包含着消息资源,其默认值Acion.MESSAGE_KEY
Locale 表示会话作用域属性的名称,它存储着用户当前登录的区域信息。其默认值是Action.ERROR_KEY
Name 表示请求属性的名称,它存储着ActionErrors对象。其默认值是Action.ERROR_KEY
property 这个属性指定了ActionErrors对象中存储每个独立ActionError对象的要害字,它可以过滤消息
例子:
<html:errors/>
显示集合中所有的错误。
<html:errors property=”missing.name”/>
显示存储在missing.name要害字的错误。
4.3.3 其他HTML标记
struts HTML标记还定义了下列标记来显示其他HTML元素:
<html:html> : 显示HTML元素
<html:img> : 显示图象标 记
<html:link> : 显示HTML链接或锚点
<html:rewrite> : 创建没有锚点标 记的URL
这些标记的具体内容请参照struts文档。
?! 索引?目?。动态模板是模块化WEB页布局设计的强大手段。Struts模板标记库定义了自定义标记来实现动态模板。
插入标记
<template:insert>标记能够在应用程序的JSP页中插入动态模板。这个标记只有一个template属性,用来定义模板JSP页。要插入到模板的页是有多个<template:put>标记来指定的,而这些标记被定义为<template:insert>标记的主体内容。
放置标记
<template:put>标记是<template:insert>标记内部使用的,用来指定插入到模板的资源。属性如下:
属性 描述
content 定义要插入的内容,比如一个JSP文件或一个HTML文件
direct 假如这个设置为true,由content属性指定的内容将直接显示在JSP上而不是作为包含文件
Name 要插入的内容的名称
Role 假如设置了这个属性,只有在当前合法用户具有特定角色时才能进行内容的插入。
获得标记
在模板JSP页中使用<template:get>标记能够检索由<template:put>标记插入到JSP页的资源。属性如下:
属性 描述
Name 由<template:put>标记插入的内容的名称
Role 假如设置了这个属性,只有在当前合法用户具有特定角色时才能进行内容的检索
使用模板标记
首先编写一个模板JSP页,它将被所有的web页使用:
<html>
<%@ taglib uri=”/template” prefix=”template” %>
<head>
<title></title>
</head>
<body>
<table width=”100%” height=”100%” >
<tr height=”10%”>
<td>
<template:get name=”header”/>
</td>
</tr>
<tr height=”80%”>
<td>
<template:get name=”content”/>
</td>
</tr>
<tr height=”10%”>
<td>
<template:get name=”footer”/>
</td>
</tr>
</table>
</body>
</html>
我们将这个文件命名为template.jsp。这个文件使用<template:get>标记来获得由JSP页使用<template:put>标记提供的内容,并且将内容在一个HTML表格中显示出来。这三个内容是标题,内容和页脚。典型的内容JSP会是这样:
<%@ taglib uri=”/template” prefix=”/template” %>
<template:insert template=”template.jsp”>
<template:put name=”header” content=”header.html”/>
<template:put name=”content” content=”employeeList.jsp”/>
<template:put name=”footer” content=”footer.html”/>
</template:insert>
这个应用程序JSP页使用<template:insert标记来定义模板,然后使用<template:put>标记将特定内容名称指定的资源放到模板JSP页中。假如我们有上百个布局相同的页,但忽然想改变这个模板,我们只需要改变template.jsp文件。
待续 <