servlet规范 2.2 翻译

黄鹤 2008-07-26 12:49:35
引子:

看Spring Security的时候,看到其比较多地使用了Servlet Listener、filter之类的东西。Filter做过,listener却从来没有。

于是想从网上找一份servlet规范仔细看看,查来查去,没有合适的中文翻译版(v2.3有一份网友翻译的,不过看了一下,不大合我的口味)。于是,准备自己翻译一下,一来翻译的过程中看得会更仔细,二来,有感于接触过的技术人员基础知识大多很不扎实,翻译一下也许对大家有点帮助吧。

从sun网站合jsr网站上,目前好找到的是v2.2, v2.3, v2.4这三份。v2.5看起来还没有final。先从v2.2看起吧,一个个看下来,了解这几个版本的发展过程,应当也会有所收获。



规范文档容易找到,相应实现的源代码还没下到。了解从哪里下servlet API参考实现源代码请帮忙说一下。

翻译有不合适的地方,也请多提意见
http://blog.csdn.net/oldcrane/category/434848.aspx



前言
本文内容为Java Servlet规范v2.2。
可以从下面网址下载到响应的Java Servlet API的Javadoc文档(v2.2)及其参考实现:
http://java.sun.com/products/servlet/index.html
上面提供的参考实现提供了一个规范实现的参考标准。如果规范、API和参考实现三者存在不一致的情况,则Servlet规范2.2 > Java Servlet API Reference 2.2 > 参考实现。
0.1. 谁应当阅读本规范
本文档的目标读者为:
 遵循规范提供Servlet引擎的Web服务器或应用服务器提供商
 Web应用开发工具提供商
 需要了解servlet运行机制,以编写复杂的servlet应用的开发人员
说明:
本规范不是关于servlet的用户手册。
0.2. API参考
Java Servlet API Reference v2.2 提供了组成Servlet API的所有接口、类、例外(Exception)、方法的说明。本文档中对各函数的参数签名做了简要说明。请参考API参考文档了解详细说明。
0.3. 其他的Java规范
在本规范中,将多处参考如下Java API规范:
 Java2 Platform Enterprise Edition v1.2(J2EE)
 JavaServer Pages v1.1(JSP)
 JavaNaming and Direcotry Interface(JNDI)
上述规范可以从J2EE网站上找到:
http://java.sun.com/j2ee
0.4. 其他重要的参考资料
在Servlet API和Servlet应用的开发实现中,还参考和遵循了如下互联网规范:
 RFC 1945 Hypertext Transfer Protocol (HTTP/1.0)
 RFC 2045 MIME Part One: Format of Internet message Bodies
 RFC 2046 MIME Part Two: Media Types
 RFC 2047 MIME Part Three: Message Header Extensions for non-ASCII text
 RFC 2048 MIME Part Four: Registration Procedures
 RFC 2049 MIME Part Five: Conformance Criteria and Examples
 RFC 2109 HTTP State Management Mechanism
 RFC 2145 Use and Interpretation of HTTP Version Numbers
 RFC 2324 Hypertext Coffee Pot Control Protocol (HTCPCP/1.0)
 RFC 2616 Hypertext Transfer Protocol (HTTP/1.1)
 RFC 2617 HTTP Authentication: Basic and Digest Authentication
上述RFC文档可以下面的网站上找到:
http://www.rfc-editor.org/
W3c协会(http://www.w3.org)是HTTP相关信息的权威发布机构
在本规范中,部署描述符使用了XML(Extensible Markup Language)。在如下网站可以找到关于XML的更多信息:
http://java.sum.com
http://www.xml.org
0.5. 提供反馈
Java社区的成功有赖于您的积极参与。我们欢迎您就本规范提出任何方面的反馈意见,请将您的意见email到:servletapi-feedback@eng.sun.com
由于会收到大量的反馈信息,我们的工程师无法对邮件一一进行回复。但我们将安排一个专门小组,对所有的反馈信息进行认真地阅读、评估和存档。
0.6. 鸣谢
感谢Anselm Baird-Smith, Elias Bayeh, Vince Bonfanti, Larry Cable, Robert Clark, Daniel Coward, Satish Dharmaraj, Jim Driscoll, Shel Finkelstein, Mark Hapner, Jason Hunter, Rod McChesney, Stefano Mazzocchi, Craig McClanahan, Adam Messinger, Ron Monzillo, Vivek Nagar, Kevin Osborn, Bob Pasker, Eduardo Pelegri-Lopart, Harish Prabandham, Bill Shannon, Jon S. Stevens, James Todd, Spike Washburn, and Alan Williamson为本规范的改进和发展作出了巨大贡献。感谢Connie Weiss, Jeff Jackson和Mala Chandra支持和推动servlet的发展提供了非凡的管理和帮助。
本规范是一项持续的、广泛的努力的成果,包含了来自Sun及其合作伙伴的大量贡献,尤其是如下这些公司和小组,对Servlet规范的发展作出了巨大的贡献:Apache Developer Community, Art Technology Group, BEA Weblogic, Clear Ink, IBM, Gefion Software, Live Software, Netscape Communications, New Atlanta Communications和Oracle。
规范的检查和修订过程同样是非常有价值的。我们的合作伙伴和公众提供了很多反馈意见来帮助我们定义和改进规范。再次,谨对所有提供反馈的人和机构致意诚挚的感谢。


1. 概述
1.1. 什么是Servlet
Servlet是受容器管理的web组件,它能动态地生成内容。Servlet是一段小程序,被编译成平台无关、架构中立的的字节码之后,可以被Web服务器器动态地加载和运行。Servlet通过容器实现的请求-相应(request-response)方式与Web浏览器进行交互,这种请求-相应模式是基于超文本传输协议(HTTP)的。
1.2. 什么是Servlet容器
Servlet容器和Web服务器或者应用服务器一起提供网络服务,能解析MIME编码的请求,能生成MIME编码格式的相应。容器还负责容纳servlet,并对其生命周期进行管理。
Servlet容器可以内置在Web服务器中,也可以通过web服务器的扩展API作为附加组件安装。Servlet容器同样可以作为具体Web服务功能的应用服务器的内置模块或者附加组件。
所有的Servlet容器必须支持HTTP协议,并可以支持其他基于请求-相应模式的协议,例如HTTPS。Servlet容器至少需要支持HTTP 1.0版本,并强烈建议同时支持HTTP 1.1版本。
Servlet容易可以对servlet的运行环境设置安全限制。在J2SE1.2或者J2EE 1.2环境下,这些限制条件应当使用Java2平台所提供的授权框架来实现。例如,high end application servers 会限制某些操作,例如创建Thread对象,来保证容器的其他组件不会收到负面影响。

1.3. 一个例子
客户端程序,如Web浏览器,使用HTTP请求来访问Web服务器。请求首先被Web服务器处理,并被转交给Servlet容器。Servlet根据内部配置决定调用哪一个servlet,并在调用时将代表request和response的对象传递给它。Servlet容器可以与Web服务器运行在同一个进程中,同一个主机的不同进程中,或者运行在不同的主机中。
Servlet通过request对象知道谁是远程对象,哪些HTML表单参数作为request的一部分被发送,以及其他相关的数据。Servlet可以执行程序设定的各种逻辑,生成发还给客户端的数据,并通过response对象将这些数据发还给客户端。
一旦servlet完成对request的处理,servlet容器需要保证response内容被正确刷新,并将控制返还给Web服务器。

1.4. Servlet和其他技术的比较
从功能性的角度,Servlet介于CGI程序和私有服务器扩展(例如Netscape服务器API-NSAPI,Apache模块)之间。
相对于其他的服务器扩展机制,Servlet具备如下优点:
 由于使用了不同的进程模型,其速度远远超过CGI脚本
 使用标准API,这些API得到大量Web服务器的支持
 拥有Java编程预言的所有有点,包括易于开发,平台无关性
 可以使用Java平台所提供的大量API
1.5. Servlet和J2EE的关系
Servlet API是Java 2 平台企业版 1.2版本所需要的API。J2EE规范描述了对servlet和servlet容易的附加要求。Servlet应当被部署到容器中,而容器和servlet则都运行在J2EE环境中。
1.6. 可分布的Servlet容器
在这个版本的规范中,增加了一个特性:将一个Web应用标记为可分布。这个标记允许servlet容器提供商将一个Web应用的servlet部署在多个Java虚拟机中,而这些虚拟机可以运行在同一台主机上,也可以运行在不同的主机上。一个被标记为可分布的应用必须遵循一些限制条件,使得支持分布式应用的容器能实现集群、失效转移等特性。
高性能的环境支持可扩展性、集群、失效转移(J2EE兼容)。所有需要在高性能的环境下运行的Web应用,应当设计实现成为可发布的Web应用,这使得应用可以最大程度地利用服务器所提供的特性。如果一个不可分布的应用部署在这样一个服务器上,则不能充分利用服务器提供的特性。

1.7. 自2.1版本之后的变动
自2.1版正式发布之后,对本规范的主要变动如下:
 Web应用的概念的介绍
 web application archive files的介绍
 Response buffering(响应缓存)的介绍
 可分布servlet的介绍
 增加通过名称获取RequestDispatcher的功能
 增加通过相对路径获取RequestDispatcher的功能
 改进国际化
 对于分布式servlet引擎语义的一些澄清
对API做了如下变动:
 ServletConfig接口添加了getServletName方法,用于获取在系统中表示本servlet的名称
 ServletContext接口添加getInitParameter,getInitParameterNames这两个方法,使初始化参数能在应用层面被设置,并被改应用的所有servlet所共享
 ServletRequest接口添加getLocale方法,帮助决定客户端当前在哪个locale
 ServletRequest接口添加isSecure方法,用于标识request是否通过安全的方式进行传输,例如使用HTTPS协议
 修改了UnavailableException类的构造函数。因为现有的构造器方面参数签名容易被开发人员混淆。修改之后的构造器使用了更简单的参数签名。
 HttpServletRequest接口添加getHeaders方法,用于获取在request中,所有用某个名称标识的头信息
 HttpServletRequest添加isUserInRole、getUserPrinciple两个方法,使servlet可以使用基于抽象角色的认证
 HttpServletResponse接口添加addHeader、addIntHeader、addDateHeader三个方法,允许使用同一个名字,创建多个头信息
 HttpSession接口添加getAttribute、getAttributeNames、setAttribute、removeAttribute四个方法,以改进API的命名规范,相应地,getValue,、getValueNames,、setValue、removeValue这四个方法被废弃。
此外,还增加了大量概念的说明和澄清。
...全文
585 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
地狱咆哮者 2010-09-26
  • 打赏
  • 举报
回复
学习中
ynjxxk 2009-03-13
  • 打赏
  • 举报
回复
一直在用,但是对内部规范不太了解,呵呵!正想补补,谢谢!
黄鹤 2008-07-26
  • 打赏
  • 举报
回复

2. 术语
在本规范中,将大量使用这些术语。
2.1. 基本术语
2.1.1. 统一资源定位符
统一资源定位符(URL)是一段简洁的字符串,用以标识在网络上的某个资源。当通过URL访问资源时,可能对该资源进行不同的操作处理。URL是通用资源标识(URI)的一种形式,通常使用如下格式:
<protocol>//<servername>/<resource>
基于本规范的目的,我们主要关心基于HTTP协议的URL,其格式如下所示:
http[s]://<servername>[:port]/<url-path>[?<query-string>]
样例:
http://java.sun.com/products/servlet/index.html
https://javashop.sun.com/purchase
在基于HTTP的URL中,斜杠’/’是保留字符,用于划分URL的url-path部分分层结构的路径。服务器负责决定分层结构的含义。url-path和某个文件系统路径的分层结构之后,不要求存在对应关系。
2.1.2. Servlet定义
一个servlet的定义是将一个唯一的名称与一个全限定格式的类名进行关联,该类必须实现Servlet接口。Servlet定义中还可以设定一组初始化参数。
2.1.3. Servlet映射
一个servlet映射是在一个serlvet容器中,将一个servlet定义与一个URL路径格式进行关联。所有符合指定格式的请求都将被关联的servlet处理。
2.1.4. Web应用
Web应用是一个集合,它包括servlet,JSP页面,HTML文档,一级其他web资源,包括图片文件、压缩档案等。一个Web应用可以被打包成一个存档文件,或者放在一个开放的目录结构中。
所有兼容的servlet容器都必须能接受Web应用,并能将Web应用的内容部署到运行环境中。这意味着容器应当既可以通过Web应用存档文件运行一个应用,也可以将web应用的内容移动到容器指定的特定位置,而后运行。

2.1.5. Web Application Archive(Web应用存档)
Web应用存档是一个单独的文件,它包含了web应用的所有组件。这个存档文件可使用标准的JAR工具来创建,可以对Web应用的部分或所有组件进行签名。
Web应用存档文件使用.war后缀名。使用这个新的后缀而不使用.jar的原因是:jar文件用于包含一组class文件,并可以通过存放在classpath下,或通过GUI双击来启动一个应用程序。而Web应用存档文件的内容不适用于这样的情况,故此应当使用一个新的后缀名。


2.2. 角色
基于servlet的应用的开发、部署、运行过程往往由不同的人员负责,这些人员需要进行不同的活动,并承担不同的职责。实际情况下,一个小组可能会承担多个角色的职责,也可能每个角色都由一个单独的小组负责。
2.2.1. 应用开发员
应用开发人员是Web应用的生产者,其生产成果是一批servlet classes,jsp页面,html页面,及其相关的类库和其他文件(如图片文件,压缩存档文件等)。应用开发人员一般是应用领域专家,需要了解servlet环境及其编程相关的知识,例如并发访问等,并据此开发web应用。
2.2.2. 应用装配员
应用装配员的职责是将开发员交付的成果组装为一个可部署单元。其工作的输入是开发院所提供的java classes,JSP页面,HTML页面,以及web应用所许需的类库和其他文件。其工作的输出则是Web应用存档文件,或者是保存了Web应用的一个目录结构
2.2.3. 部署员
部署人员的职责是将一个或多个,web应用存档文件或者web应用目录,部署到指定的运营环境下。运营环境往往包括指定的servlet容器和web服务器。部署人员必须解决开发人员所声明的所有外部依赖需求。部署人员通常使用servlet容器提供的工具来完成这些工作。
部署人员是某个运营环境的专家。例如,部署人员需要负责将开发人员定义的安全角色映射成为运营环境下已经存在的用户组或者帐号。
2.2.4. 系统管理员
系统管理员负责对servlet容器和web服务器进行配置和管理。系统管理员同时需要监视web应用的运行是否健康。
本规范没有定义系统管理员的具体工作内容contracts for system management and administrator. 系统管理员通常使用容器提供商和主机制造商所提供的运行监控和管理工具来进行他们的工作。
2.2.5. Servlet容器提供商
Servlet容器提供商负责提供运行环境-servlet容器,并可能同时提供web服务器。其中一般包含一个web应用,作为部署web应用的工具。
Servlet容器提供商主要在HTTP层面商进行编程。本规范没有定义web服务器和servlet容器之间的接口,因此servlet容器提供商可以根据自己的需求决定两者的边界及其实现。
2.3. 安全术语
2.3.1. Principal(参与者)
一个principal是指可能被身份认证协议认证所的对象实体。一个principal由principal名称来标识,并使用认证数据进行认证。Principal名称、认证数据的内容和格式,取决于所选择的身份认证协议。
2.3.2. Security Policy Domain(安全策略域)
Security policy domain是一个scope,其中,安全服务管理员定义了安全策略,并对其中的活动强制应用了这些安全策略。Security policy domain又经常被成为realm(领域)。
2.3.3. Security Technology Domain(安全技术域)
Security technology domain是一个scope,其中,相同的安全机制,例如Kerboros,被用于执行安全策略。在一个security technology domain中,可以同时存在多个security policy domain.
2.3.4. 角色(Role)
在一个应用中,角色作为一个抽象概念被开发人员定义,而部署人员则需要在一个security policy domain中将它们映射成为具体的用用户或者用户组。



3. Servlet接口
Servlet接口是Servlet API的核心抽象,所有的servlet都需要实现这个接口。可以直接实现servlet接口,而更常见的方式则是通过扩展/继承一个实现了servlet接口的类来实现这一点。在API中提供两个实现了servlet接口的类:GenericServlet和HttpServlet。大部分情况下,开发人员通过继承HttpServlet来实现自己的servlet。
3.1. 处理请求的方法(Request Handling Methods)
Servlet接口定义了一个名为service的方法来处理客户端的请求。每当servlet容器将request路由到一个servlet实例时,这个方法都会被调用。多个request线程可以同时调用并执行同一个service方法。
3.1.1. HTTP专用的请求处理方法(HTTP Specific Request Handling Methods)
HttpServlet抽象子类添加了几个附加的方法,service方法会根据request自动调用这些附加的方法。这些方法是:
 doGet方法,用于处理HTTP GET请求
 doPost方法,用于处理HTTP POST请求
 doPut方法,用于处理HTTP PUT请求
 doDelete方法,用于处理HTTP DELETE请求
 doHead方法,用于处理HTTP HEAD请求
 doOptions方法,用于处理HTTP OPTIONS请求
 doTrace方法,用于处理HTTP TRACE请求
在开发基于HTTP的servlet的时候,开发人员一般只涉及doGet和doPost方法。其他的方法可视为高级方法,为熟悉HTTP编程的程序员准备。
Servlet开发人员可以通过实现doPut和doDelete方法来支持HTTP/1.1客户端。HttpServlet的doHead方法会执行doGet方法,但是只返回doGet方法生产的头信息给客户端。doOptions方法自动检测servlet支持哪些HTTP方法,并将此信息发送给客户端。doTrace方法则将返回一个response,其中包含了trace 请求中的所有头信息。
由于HTTP/1.0没有定义PUT, DELETE, OPTIONS 和TRACE方法,因此,只支持HTTP/1.0的容器,只会使用servlet的doGet, doHead和doPost。
3.1.2. 有条件GET的支持(Conditional GET Support)
HttpServlet接口定义了getLastModified方法用于支持有条件get操作。有条件get操作是指客户端通过HTTP GET方法请求一个资源的时候,在头信息里设置只有当被请求的资源在指定时间之后被修改过,才返回响应的body部分。
Servlets that implement the doGet method and that provide content that does not necessarily change from request to request should implement this method to aid in efficient utilization of network resources.
3.2. 实例数量
缺省情况下,在容器中,每个servlet定义(servlet definition)只有一个实例。
在servlet实现了SingleThreadModel接口的情况下,容器将创建多个实例,这样容器能够处理高负载请求,并同时保证request排队访问单个servlet实例。
对于一个标记为可分布的应用,对于容器所使用的每一个虚拟机,都将创建为一个servlet定义的创建一个实例。如果servlet实现了SingleThreadModel方法,则对容器使用的每个虚拟机,都可以创建多个实例。
3.2.1. 关于单线程模式(SingleThreadModel)的说明
SingleThreadModel接口用于保证在同一时刻,只有一个线程,访问一个servlet实例的service方法。需要重点说明的是,上述保证只限于对servlet实例的访问。对于能被多个servlet实例访问的对象,例如HttpSession的实例对象,还是能够被多个servlet实例同时访问的,不管servlet是否实现SingleThreadModel接口。
3.3. Servlet生命周期
Servlet生命周期管理包括:如何被载入(load),如何实例化,如何初始化,如何处理客户端情况,以及如何被销毁。这个生命周期,在API中,通过Servlet接口(javax.servlet.Servlet)的init,service和destroy方法得以体现。所有的servlet都必须实现这些接口。可以直接实现servlet接口,也可以通过继承GenericServlet或HttpServlet抽象类来实现。
3.3.1. 载入和实例化
Servlet容器负责servlet的载入和实例化。这项工作可以在servlet引擎启动的时候进行,也可以延迟到当容器检测到需要servlet来处理某个请求的时候进行。
首先,servlet容器得能找到servlet对应的class文件。容器可以根据需要选择使用java类装载器(class loader)从本地文件系统、远程文件系统或者网络服务中加载这个类。
在这个类被加载之后,容器就创建该类的一个实例。
需要重点说明的是,在servlet容器中,一个servlet类可能会有多个实例。例如,多个servlet定义使用同一个类,但定义了不同的初始化参数。另外,如果servlet实现了SingleThreadModel接口,容器会创建一个实例池。
3.3.2. 初始化
在servlet对象载入和实例化之后,容器必须在servlet处理客户端请求之前对它进行初始化。在初始化过程中,servlet可以读取持久化的配置数据,初始化昂贵(costly)的资源,例如jdbc数据库连接,并执行其他一次性的操作。容器通过调用Servlet接口的init来初始化servlet,对于每个servlet定义,容器将创建一个唯一的、实现了ServletConfig接口的对象,并将其作为参数传递给init方法。通过这个配置信息对象,servlet可以name-value的方式获取初始化参数。这个配置信息对象还包含了一个实现了ServletContext接口的对象,描述了servlet的运行环境信息。关于ServletContext接口的详细信息请看第4章。
3.3.2.1. 初始化过程出错
在初始化过程中,servlet实例可以通过抛出UnavailableException或者ServletException异常来声明初始化失败。这种情况下,容器必须释放servlet实例,不能将其作为一个活动的服务。由于初始化没有成功,此时destroy方法不会被调用。
在初始化失败的servlet实例被释放之后,容器可以在任何时候实例化并初始化新的servlet。唯一的例外是在servlet初始化过程中抛出的UnavailableException中定义了最短失效时间,在这段时间内,不能创建新的实例。
3.3.2.2. Tool Considerations
用工具加载并分析(introspect)一个web应用的时候,它可以加载并分析(introspect)web应用的成员类,这会触发静态初始化方法的执行。出于这个特性的考虑,在Servlet接口的init方法被调用之前,开发人员不能认为servlet已经在活动在容器的运行环境内。例如,当servlet的静态初始化方法被调用的时候,不应当去创建到数据库或者EJB容器的连接
3.3.3. 请求处理
Servlet被正确初始化之后,容器就能用它来处理请求。请求被封装在ServletRequest类型的对象中,响应信息被封装在ServletResponse类型的对象中,这两个对象以参数的形式传给Servlet接口的service方法。处理HTTP请求时,容器必须通过实现HttpServletRequest和HttpServletResponse接口来提供请求和响应对象。
需要说明的是,servlet实例被创建成为服务之后,可能在整个生命周期不需要响应任何请求。
3.3.3.1. 多线程问题
在处理客户端情况过程中,容器有可能并发访问servlet的service方法,以处理来自客户端的并发访问。开发人员必须注意这一点,保证servlet在并发情况下正确运行。
开发人员可以通过让servlet实现SingleThreadModel接口来避免这种缺省行为。通过实现这个接口可以保证同一时刻只允许一个请求线程调用service方法。Servlet容器可以多种方式实现这个要求,可以让访问一个servlet的请求排队,也可以提供servlet实例池。如果servlet属于可分布应用,容器可以在应用所分布的每个虚拟机中保持一个servlet实例池。
如果service方法使用了synchronized修饰符(或者是HttpServlet的doGet、doPost等通过service方法分发调用的方法),servlet容器将保证对该方法的排队访问,并且不能为其创建实例池。我们强烈建议不要同步service方法和HttpServlet的doGet、doPost这些服务方法。
3.3.3.2. 处理请求过程中的异常
在处理请求过程中,servlet可以抛出ServletException或者UnavailableException异常。ServletException表明处理情况过程中发生了某种错误,容器需要采取适当的方式来清理请求。UnavailableException异常则表示servlet临时性或者永久性不能响应请求。
如果servlet抛出了声明为永久性失效的UnavailableException,servlet容器必须移除这个servlet服务,调用其destroy方法,并释放servlet实例。
如果是临时性失效,在指定的最短失效期内,容器不能把请求路由到这个servlet。容器必须向被拒绝的请求返回SERVICE_UNAVAILABLE(503)响应,并在用Retry-After后信息标明何时再次生效。容器也可以选择不区分临时性失效和永久性失效,将所有UnavailableException当作永久性失效,然后移除servlet服务。
3.3.3.3. 线程安全
请求和响应对象是不保证线程安全的。这意味着它们只应当在请求处理线程范围内被使用。请求对象和响应对象的引用不应当被传递给在其他线程中失效的对象,否则会产生无法预料的结果。
3.3.4. 服务终止
Servlet容器不需要在任何时刻都保持servlet处于被加载的状态。Servlet实例的活动时间可以只有几毫秒,可以和引擎的生命周期一样长(几天,几个月,或者几年),也可以介于两者之间。
当servlet容器检测到应当将一个servlet服务移除的时候(例如容器需要保留内存,或者容器被停止),必须允许servlet释放资源,并保存持久化状态。容器通过调用Servlet接口的destroy方法实现这一点。
在servlet容器调用destroy方法之前,必须先确保所有在servlet方法中运行的线程或者停止,或者超出服务器定义的运行限制时间。
Servlet实例的destroy方法一旦被调用,容器就不能再将请求路由到这个servlet实例。如果容器需要重新提供这个服务,必须使用新的servlet实例。
Destroy方法完成执行后,容器必须释放servlet实例,以便进行垃圾回收。

未完待续
1:外文原文 Struts——an open-source MVC implementation This article introduces Struts, a Model-View-Controller implementation that uses servlets and JavaServer Pages (JSP) technology. Struts can help you control change in your Web project and promote specialization. Even if you never implement a system with Struts, you may get some ideas for your future servlets and JSP page implementation. Introduction Kids in grade school put HTML pages on the Internet. However, there is a monumental difference between a grade school page and a professionally developed Web site. The page designer (or HTML developer) must understand colors, the customer, product flow, page layout, browser compatibility, image creation, JavaScript, and more. Putting a great looking site together takes a lot of work, and most Java developers are more interested in creating a great looking object interface than a user interface. JavaServer Pages (JSP) technology provides the glue between the page designer and the Java developer. If you have worked on a large-scale Web application, you understand the term change. Model-View-Controller (MVC) is a design pattern put together to help control change. MVC decouples interface from business logic and data. Struts is an MVC implementation that uses Servlets 2.2 and JSP 1.1 tags, from the J2EE specifications, as part of the implementation. You may never implement a system with Struts, but looking at Struts may give you some ideas on your future Servlets and JSP implementations. Model-View-Controller (MVC) JSP tags solved only part of our problem. We still have issues with validation, flow control, and updating the state of the application. This is where MVC comes to the rescue. MVC helps resolve some of the issues with the single module approach by dividing the problem into three categories: • Model The model contains the core of the application's functionality. The model encapsulates the state of the application. Sometimes the only functionality it contains is state. It knows nothing about the view or controller. • View The view provides the presentation of the model. It is the look of the application. The view can access the model getters, but it has no knowledge of the setters. In addition, it knows nothing about the controller. The view should be notified when changes to the model occur. • Controller The controller reacts to the user input. It creates and sets the model. MVC Model 2 The Web brought some unique challenges to software developers, most notably the stateless connection between the client and the server. This stateless behavior made it difficult for the model to notify the view of changes. On the Web, the browser has to re-query the server to discover modification to the state of the application. Another noticeable change is that the view uses different technology for implementation than the model or controller. Of course, we could use Java (or PERL, C/C++ or what ever) code to generate HTML. There are several disadvantages to that approach: • Java programmers should develop services, not HTML. • Changes to layout would require changes to code. • Customers of the service should be able to create pages to meet their specific needs. • The page designer isn't able to have direct involvement in page development. • HTML embedded into code is ugly. For the Web, the classical form of MVC needed to change. Figure 4 displays the Web adaptation of MVC, also commonly known as MVC Model 2 or MVC 2. The ActionServlet class Do you remember the days of function mappings? You would map some input event to a pointer to a function. If you where slick, you would place the configuration information into a file and load the file at run time. Function pointer arrays were the good old days of structured programming in C. Life is better now that we have Java technology, XML, J2EE, and all that. The Struts Controller is a servlet that maps events (an event generally being an HTTP post) to classes. And guess what -- the Controller uses a configuration file so you don_t have to hard-code the values. Life changes, but stays the same. ActionServlet is the Command part of the MVC implementation and is the core of the Framework. ActionServlet (Command) creates and uses Action, an ActionForm, and ActionForward. As mentioned earlier, the struts-config.xml file configures the Command. During the creation of the Web project, Action and ActionForm are extended to solve the specific problem space. The file struts-config.xml instructs ActionServlet on how to use the extended classes. There are several advantages to this approach: • The entire logical flow of the application is in a hierarchical text file. This makes it easier to view and understand, especially with large applications. • The page designer does not have to wade through Java code to understand the flow of the application. • The Java developer does not need to recompile code when making flow changes. Command functionality can be added by extending ActionServlet. The ActionForm class ActionForm maintains the session state for the Web application. ActionForm is an abstract class that is sub-classed for each input form model. When I say input form model, I am saying ActionForm represents a general concept of data that is set or updated by a HTML form. For instance, you may have a UserActionForm that is set by an HTML Form. The Struts framework will: • Check to see if a UserActionForm exists; if not, it will create an instance of the class. • Struts will set the state of the UserActionForm using corresponding fields from the HttpServletRequest. No more dreadful request.getParameter() calls. For instance, the Struts framework will take fname from request stream and call UserActionForm.setFname(). • The Struts framework updates the state of the UserActionForm before passing it to the business wrapper UserAction. • Before passing it to the Action class, Struts will also conduct form state validation by calling the validation() method on UserActionForm. Note: This is not always wise to do. There might be ways of using UserActionForm in other pages or business objects, where the validation might be different. Validation of the state might be better in the UserAction class. • The UserActionForm can be maintained at a session level. Notes: • The struts-config.xml file controls which HTML form request maps to which ActionForm. • Multiple requests can be mapped UserActionForm. • UserActionForm can be mapped over multiple pages for things such as wizards. The Action class The Action class is a wrapper around the business logic. The purpose of Action class is to translate the HttpServletRequest to the business logic. To use Action, subclass and overwrite the process() method. The ActionServlet (Command) passes the parameterized classes to ActionForm using the perform() method. Again, no more dreadful request.getParameter() calls. By the time the event gets here, the input form data (or HTML form data) has already been translated out of the request stream and into an ActionForm class. Struts, an MVC 2 implementation Struts is a set of cooperating classes, servlets, and JSP tags that make up a reusable MVC 2 design. This definition implies that Struts is a framework, rather than a library, but Struts also contains an extensive tag library and utility classes that work independently of the framework. Figure 5 displays an overview of Struts. Struts overview • Client browser An HTTP request from the client browser creates an event. The Web container will respond with an HTTP response. • Controller The Controller receives the request from the browser, and makes the decision where to send the request. With Struts, the Controller is a command design pattern implemented as a servlet. The struts-config.xml file configures the Controller. • Business logic The business logic updates the state of the model and helps control the flow of the application. With Struts this is done with an Action class as a thin wrapper to the actual business logic. • Model state The model represents the state of the application. The business objects update the application state. ActionForm bean represents the Model state at a session or request level, and not at a persistent level. The JSP file reads information from the ActionForm bean using JSP tags. • View The view is simply a JSP file. There is no flow logic, no business logic, and no model information -- just tags. Tags are one of the things that make Struts unique compared to other frameworks like Velocity. Note: "Think thin" when extending the Action class. The Action class should control the flow and not the logic of the application. By placing the business logic in a separate package or EJB, we allow flexibility and reuse. Another way of thinking about Action class is as the Adapter design pattern. The purpose of the Action is to "Convert the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn_t otherwise because of incompatibility interface" (from Design Patterns - Elements of Reusable OO Software by Gof). The client in this instance is the ActionServlet that knows nothing about our specific business class interface. Therefore, Struts provides a business interface it does understand, Action. By extending the Action, we make our business interface compatible with Struts business interface. (An interesting observation is that Action is a class and not an interface. Action started as an interface and changed into a class over time. Nothing's perfect.) The Error classes The UML diagram also included ActionError and ActionErrors. ActionError encapsulates an individual error message. ActionErrors is a container of ActionError classes that the View can access using tags. ActionErrors is Struts way of keeping up with a list of errors. The ActionMapping class An incoming event is normally in the form of an HTTP request, which the servlet Container turns into an HttpServletRequest. The Controller looks at the incoming event and dispatches the request to an Action class. The struts-config.xml determines what Action class the Controller calls. The struts-config.xml configuration information is translated into a set of ActionMapping, which are put into container of ActionMappings. (If you have not noticed it, classes that end with s are containers) The ActionMapping contains the knowledge of how a specific event maps to specific Actions. The ActionServlet (Command) passes the ActionMapping to the Action class via the perform() method. This allows Action to access the information to control flow. ActionMappings ActionMappings is a collection of ActionMapping objects. Struts pros • Use of JSP tag mechanism The tag feature promotes reusable code and abstracts Java code from the JSP file. This feature allows nice integration into JSP-based development tools that allow authoring with tags. • Tag library Why re-invent the wheel, or a tag library? If you cannot find something you need in the library, contribute. In addition, Struts provides a starting point if you are learning JSP tag technology. • Open source You have all the advantages of open source, such as being able to see the code and having everyone else using the library reviewing the code. Many eyes make for great code review. • Sample MVC implementation Struts offers some insight if you want to create your own MVC implementation. • Manage the problem space Divide and conquer is a nice way of solving the problem and making the problem manageable. Of course, the sword cuts both ways. The problem is more complex and needs more management. Struts cons • Youth Struts development is still in preliminary form. They are working toward releasing a version 1.0, but as with any 1.0 version, it does not provide all the bells and whistles. • Change The framework is undergoing a rapid amount of change. A great deal of change has occurred between Struts 0.5 and 1.0. You may want to download the most current Struts nightly distributions, to avoid deprecated methods. In the last 6 months, I have seen the Struts library grow from 90K to over 270K. I had to modify my examples several times because of changes in Struts, and I am not going to guarantee my examples will work with the version of Struts you download. • Correct level of abstraction Does Struts provide the correct level of abstraction? What is the proper level of abstraction for the page designer? That is the $64K question. Should we allow a page designer access to Java code in page development? Some frameworks like Velocity say no, and provide yet another language to learn for Web development. There is some validity to limiting Java code access in UI development. Most importantly, give a page designer a little bit of Java, and he will use a lot of Java. I saw this happen all the time in Microsoft ASP development. In ASP development, you were supposed to create COM objects and then write a little ASP script to glue it all together. Instead, the ASP developers would go crazy with ASP script. I would hear "Why wait for a COM developer to create it when I can program it directly with VBScript?" Struts helps limit the amount of Java code required in a JSP file via tag libraries. One such library is the Logic Tag, which manages conditional generation of output, but this does not prevent the UI developer from going nuts with Java code. Whatever type of framework you decide to use, you should understand the environment in which you are deploying and maintaining the framework. Of course, this task is easier said than done. • Limited scope Struts is a Web-based MVC solution that is meant be implemented with HTML, JSP files, and servlets. • J2EE application support Struts requires a servlet container that supports JSP 1.1 and Servlet 2.2 specifications. This alone will not solve all your install issues, unless you are using Tomcat 3.2. I have had a great deal of problems installing the library with Netscape iPlanet 6.0, which is supposedly the first J2EE-compliant application server. I recommend visiting the Struts User Mailing List archive (see Resources) when you run into problems. • Complexity Separating the problem into parts introduces complexity. There is no question that some education will have to go on to understand Struts. With the constant changes occurring, this can be frustrating at times. Welcome to the Web. • Where is... I could point out other issues, for instance, where are the client side validations, adaptable workflow, and dynamic strategy pattern for the controller? However, at this point, it is too easy to be a critic, and some of the issues are insignificant, or are reasonable for a 1.0 release. The way the Struts team goes at it, Struts might have these features by the time you read this article, or soon after. Future of Struts Things change rapidly in this new age of software development. In less than 5 years, I have seen things go from cgi/perl, to ISAPI/NSAPI, to ASP with VB, and now Java and J2EE. Sun is working hard to adapt changes to the JSP/servlet architecture, just as they have in the past with the Java language and API. You can obtain drafts of the new JSP 1.2 and Servlet 2.3 specifications from the Sun Web site. Additionally, a standard tag library for JSP files is appearing. 2:外文资料翻译译文 Struts——MVC 的一种开放源码实现 本文介绍 Struts,它是使用 servlet 和 JavaServer Pages 技术的一种 Model-View-Controller 实现。Struts 可帮助您控制 Web 项目中的变化并提高专业化水平。尽管您可能永远不会用 Struts 实现一个系统,但您可以将其中的一些思想用于您以后的 servlet 和 JSP 网页的实现中。 简介 小学生也可以在因特网上发布 HTML 网页。但是,小学生的网页和专业开发的网站有质的区别。网页设计人员(或者 HTML 开发人员)必须理解颜色、用户、生产流程、网页布局、浏览器兼容性、图像创建和 JavaScript 等等。设计漂亮的网站需要做大量的工作,大多数 Java 开发人员更注重创建优美的对象接口,而不是用户界面。JavaServer Pages (JSP) 技术为网页设计人员和 Java 开发人员提供了一种联系钮带。 如果您开发过大型 Web 应用程序,您就理解 变化 这个词的含义。“模型-视图-控制器”(MVC) 就是用来帮助您控制变化的一种设计模式。MVC 减弱了业务逻辑接口和数据接口之间的耦合。Struts 是一种 MVC 实现,它将 Servlet 2.2 和 JSP 1.1 标记(属于 J2EE 规范)用作实现的一部分。尽管您可能永远不会用 Struts 实现一个系统,但了解一下 Struts 或许使您能将其中的一些思想用于您以后的 Servlet 的 JSP 实现中。 模型-视图-控制器 (MVC) JSP 标记只解决了部分问题。我们还得处理验证、流程控制和更新应用程序的状态等问题。这正是 MVC 发挥作用的地方。MVC 通过将问题分为三个类别来帮助解决单一模块方法所遇到的某些问题: • Model(模型) 模型包含应用程序的核心功能。模型封装了应用程序的状态。有时它包含的唯一功能就是状态。它对视图或控制器一无所知。 • View(视图) 视图提供模型的表示。它是应用程序的 外观。视图可以访问模型的读方法,但不能访问写方法。此外,它对控制器一无所知。当更改模型时,视图应得到通知。 • Controller(控制器) 控制器对用户的输入作出反应。它创建并设置模型。 MVC Model 2 Web 向软件开发人员提出了一些特有的挑战,最明显的就是客户机和服务器的无状态连接。这种无状态行为使得模型很难将更改通知视图。在 Web 上,为了发现对应用程序状态的修改,浏览器必须重新查询服务器。 另一个重大变化是实现视图所用的技术与实现模型或控制器的技术不同。当然,我们可以使用 Java(或者 PERL、C/C++ 或别的语言)代码生成 HTML。这种方法有几个缺点: • Java 程序员应该开发服务,而不是 HTML。 • 更改布局时需要更改代码。 • 服务的用户应该能够创建网页来满足它们的特定需要。 • 网页设计人员不能直接参与网页开发。 • 嵌在代码中的 HTML 很难看。 对于 Web,需要修改标准的 MVC 形式。图 4 显示了 MVC 的 Web 改写版,通常也称为 MVC Model 2 或 MVC 2。 Struts,MVC 2 的一种实现 Struts 是一组相互协作的类、servlet 和 JSP 标记,它们组成一个可重用的 MVC 2 设计。这个定义表示 Struts 是一个框架,而不是一个库,但 Struts 也包含了丰富的标记库和独立于该框架工作的实用程序类。图 5 显示了 Struts 的一个概览。 Struts 概览 • Client browser(客户浏览器) 来自客户浏览器的每个 HTTP 请求创建一个事件。Web 容器将用一个 HTTP 响应作出响应。 • Controller(控制器) 控制器接收来自浏览器的请求,并决定将这个请求发往何处。就 Struts 而言,控制器是以 servlet 实现的一个命令设计模式。 struts-config.xml 文件配置控制器。 • 业务逻辑 业务逻辑更新模型的状态,并帮助控制应用程序的流程。就 Struts 而言,这是通过作为实际业务逻辑“瘦”包装的 Action 类完成的。 • Model(模型)的状态 模型表示应用程序的状态。业务对象更新应用程序的状态。ActionForm bean 在会话级或请求级表示模型的状态,而不是在持久级。JSP 文件使用 JSP 标记读取来自 ActionForm bean 的信息。 • View(视图) 视图就是一个 JSP 文件。其中没有流程逻辑,没有业务逻辑,也没有模型信息 -- 只有标记。标记是使 Struts 有别于其他框架(如 Velocity)的因素之一。 详细分析 Struts 图 6 显示的是 org.apache.struts.action 包的一个最简 UML 图。图 6 显示了 ActionServlet (Controller)、 ActionForm (Form State) 和 Action (Model Wrapper) 之间的最简关系。 ActionServlet 类 您还记得函数映射的日子吗?在那时,您会将某些输入事件映射到一个函数指针上。如果您对此比较熟悉,您会将配置信息放入一个文件,并在运行时加载这个文件。函数指针数组曾经是用 C 语言进行结构化编程的很好方法。 现在好多了,我们有了 Java 技术、XML、J2EE,等等。Struts 的控制器是将事件(事件通常是 HTTP post)映射到类的一个 servlet。正如您所料 -- 控制器使用配置文件以使您不必对这些值进行硬编码。时代变了,但方法依旧。 ActionServlet 是该 MVC 实现的 Command 部分,它是这一框架的核心。 ActionServlet (Command) 创建并使用 Action 、 ActionForm 和 ActionForward 。如前所述, struts-config.xml 文件配置该 Command。在创建 Web 项目时,您将扩展 Action 和 ActionForm 来解决特定的问题。文件 struts-config.xml 指示 ActionServlet 如何使用这些扩展的类。这种方法有几个优点: • 应用程序的整个逻辑流程都存储在一个分层的文本文件中。这使得人们更容易查看和理解它,尤其是对于大型应用程序而言。 • 网页设计人员不必费力地阅读 Java 代码来理解应用程序的流程。 • Java 开发人员也不必在更改流程以后重新编译代码。 可以通过扩展 ActionServlet 来添加 Command 功能。 ActionForm 类 ActionForm 维护 Web 应用程序的会话状态。 ActionForm 是一个抽象类,必须为每个输入表单模型创建该类的子类。当我说 输入表单模型 时,是指 ActionForm 表示的是由 HTML 表单设置或更新的一般意义上的数据。例如,您可能有一个由 HTML 表单设置的 UserActionForm 。Struts 框架将执行以下操作: • 检查 UserActionForm 是否存在;如果不存在,它将创建该类的一个实例。 • Struts 将使用 HttpServletRequest 中相应的域设置 UserActionForm 的状态。没有太多讨厌的 request.getParameter() 调用。例如,Struts 框架将从请求流中提取 fname ,并调用 UserActionForm.setFname() 。 • Struts 框架在将 UserActionForm 传递给业务包装 UserAction 之前将更新它的状态。 • 在将它传递给 Action 类之前,Struts 还会对 UserActionForm 调用 validation() 方法进行表单状态验证。 注: 这并不总是明智之举。别的网页或业务可能使用 UserActionForm ,在这些地方,验证可能有所不同。在 UserAction 类中进行状态验证可能更好。 • 可在会话级维护 UserActionForm 。 注: • struts-config.xml 文件控制 HTML 表单请求与 ActionForm 之间的映射关系。 • 可将多个请求映射到 UserActionForm 。 • UserActionForm 可跨多页进行映射,以执行诸如向导之类的操作。 Action 类 Action 类是业务逻辑的一个包装。 Action 类的用途是将 HttpServletRequest 转换为业务逻辑。要使用 Action ,请创建它的子类并覆盖 process() 方法。 ActionServlet (Command) 使用 perform() 方法将参数化的类传递给 ActionForm 。仍然没有太多讨厌的 request.getParameter() 调用。当事件进展到这一步时,输入表单数据(或 HTML 表单数据)已被从请求流中提取出来并转移到 ActionForm 类中。 注:扩展 Action 类时请注意简洁。 Action 类应该控制应用程序的流程,而不应该控制应用程序的逻辑。通过将业务逻辑放在单独的包或 EJB 中,我们就可以提供更大的灵活性和可重用性。 考虑 Action 类的另一种方式是 Adapter 设计模式。 Action 的用途是“将类的接口转换为客户机所需的另一个接口。Adapter 使类能够协同工作,如果没有 Adapter,则这些类会因为不兼容的接口而无法协同工作。”(摘自 Gof 所著的 Design Patterns - Elements of Reusable OO Software )。本例中的客户机是 ActionServlet ,它对我们的具体业务类接口一无所知。因此,Struts 提供了它能够理解的一个业务接口,即 Action 。通过扩展 Action ,我们使得我们的业务接口与 Struts 业务接口保持兼容。(一个有趣的发现是, Action 是类而不是接口)。 Action 开始为一个接口,后来却变成了一个类。真是金无足赤。) ActionMapping 类 输入事件通常是在 HTTP 请求表单中发生的,servlet 容器将 HTTP 请求转换为 HttpServletRequest 。控制器查看输入事件并将请求分派给某个 Action 类。 struts-config.xml 确定 Controller 调用哪个 Action 类。 struts-config.xml 配置信息被转换为一组 ActionMapping ,而后者又被放入 ActionMappings 容器中。(您可能尚未注意到这一点,以 s结尾的类就是容器) ActionMapping 包含有关特定事件如何映射到特定 Action 的信息。 ActionServlet (Command) 通过 perform() 方法将 ActionMapping 传递给 Action 类。这样就使 Action 可访问用于控制流程的信息。 ActionMappings ActionMappings 是 ActionMapping 对象的一个集合。 Struts 的优点 • JSP 标记机制的使用 标记特性从 JSP 文件获得可重用代码和抽象 Java 代码。这个特性能很好地集成到基于 JSP 的开发工具中,这些工具允许用标记编写代码。 • 标记库 为什么要另发明一种轮子,或标记库呢?如果您在库中找不到您所要的标记,那就自己定义吧。此外,如果您正在学习 JSP 标记技术,则 Struts 为您提供了一个起点。 • 开放源码 您可以获得开放源码的全部优点,比如可以查看代码并让使用库的每个人检查代码。许多人都可以进行很好的代码检查。 • MVC 实现样例 如果您希望创建您自己的 MVC 实现,则 Struts 可增加您的见识。 • 管理问题空间 分治是解决问题并使问题可管理的极好方法。当然,这是一把双刃剑。问题越来越复杂,并且需要越来越多的管理。 Struts 的缺点 • 仍处于发展初期 Struts 开发仍处于初级阶段。他们正在向着发行版本 1.0 而努力,但与任何 1.0 版本一样,它不可能尽善尽美。 • 仍在变化中 这个框架仍在快速变化。Struts 1.0 与 Struts 0.5 相比变化极大。为了避免使用不赞成使用的方法,您可能隔一天就需要下载最新的 Struts。在过去的 6 个月中,我目睹 Struts 库从 90K 增大到 270K 以上。由于 Struts 中的变化,我不得不数次修改我的示例,但我不保证我的示例能与您下载的 Struts 协同工作。 • 正确的抽象级别 Struts 是否提供了正确的抽象级别?对于网页设计人员而言,什么是正确的抽象级别呢?这是一个用 $64K 的文字才能解释清楚的问题。在开发网页的过程中,我们是否应该让网页设计人员访问 Java 代码?某些框架(如 Velocity)说不应该,但它提供了另一种 Web 开发语言让我们学习。在 UI 开发中限制访问 Java 有一定的合理性。最重要的是,如果让网页设计人员使用一点 Java,他将使用大量的 Java。在 Microsoft ASP 的开发中,我总是看到这样的情况。在 ASP 开发中,您应该创建 COM 对象,然后编写少量的 ASP 脚本将这些 COM 对象联系起来。但是,ASP 开发人员会疯狂地使用 ASP 脚本。我会听到这样的话,“既然我可以用 VBScript 直接编写 COM 对象,为什么还要等 COM 开发人员来创建它呢?”通过使用标记库,Struts 有助于限制 JSP 文件中所需的 Java 代码的数量。Logic Tag 就是这样的一种库,它对有条件地生成输出进行管理,但这并不能阻止 UI 开发人员对 Java 代码的狂热。无论您决定使用哪种类型的框架,您都应该了解您要在其中部署和维护该框架的环境。当然,这项任务真是说起来容易做起来难。 • 有限的适用范围 Struts 是一种基于 Web 的 MVC 解决方案,所以必须用 HTML、JSP 文件和 servlet 来实现它。 • J2EE 应用程序支持 Struts 需要支持 JSP 1.1 和 Servlet 2.2 规范servlet 容器。仅凭这一点远不能解决您的全部安装问题,除非使用 Tomcat 3.2。我用 Netscape iPlanet 6.0 安装这个库时遇到一大堆问题,按理说它是第一种符合 J2EE 的应用程序服务器。我建议您在遇到问题时访问 Struts 用户邮件列表的归档资料。 • 复杂性 在将问题分为几个部分的同时也引入了复杂性。毫无疑问,要理解 Struts 必须接受一定的培训。随着变化的不断加入,这有时会令人很沮丧。欢迎访问本网站。 Struts 的前景 在这个软件开发的新时代,一切都变得很快。在不到 5 年的时间内,我已经目睹了从 cgi/perl 到 ISAPI/NSAPI、再到使用 VB 的 ASP、一直到现在的 Java 和 J2EE 的变迁。Sun 正在尽力将新的变化反映到 JSP/servlet 体系结构中,正如他们对 Java 语言和 API 所作的更改一样。您可以从 Sun 的网站获得新的 JSP 1.2 和 Servlet 2.3 规范的草案。此外,一个标准 JSP 标记库即将出现。 3:外文出处 [1]Malcolm Davis. Struts——an open-source MVC implementation [2]IBM System Journal,2006

81,114

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧