其他表示层技术
尽管外观可以用JSP或Struts的标签来实现但你仍然应该考虑融合其他技术来提高组件的重用减少维护工作量减少错误
特定应用标签
忽略
使用包含组合页面
将一个页面放在一个JSP文件中是一个普遍的设计方法但是许多应用需要将应用中的不同部分显示在一个页面中例如一个门户应用需要如下功能
访问门户的搜索引擎
访问门户的讨论区
用户感兴趣的话题
邮件等待指示器
将这些不同的功能交给不同的开发者开发要完成这个门户应用是比较容易的然后你就可以使用包含( include)来
将它们组合到一个页面中有三种不同的包含方式选择哪种取决于你希望整个输出在什么时候整合
<%@ include file=xxxxx %>
<jsp:include page=xxxxx flush=true />
bean:include
使用Tiles组合页面
Tiles是一个功能很强的模板库它可以将很多tile组合成最终的视图以下是设置向导
.创建layout/layoutjsp它包含标准外观
<html>
<body>
<tiles:insert attribute=body/>
</body>
</html>
.创建你的主页/indexjsp
<h>This is my homepage</h>
.创建文件/WEBINF/tilesdefsxml
<tilesdefinitions>
<definition
name=layout
path=/layout/layoutjsp>
<put name=body value=/>
</definition>
<definition name=homepage extends=layout>
<put
name=body
value=/indexjsp/>
</definition>
<tilesdefinitions>
.在文件strutsconfigxml中设置TilesPlugin
<plugin
className=orgapachestrutstilesTilesPlugin>
<setproperty
property=definitionsconfig
value=/WEBINF/tilesdefsxml/>
</plugin>
.在strutsconfigxml文件中设置一个Action指向你的主页
<action path=/index type=orgapachestrutsactionsForwardAction parameter=homepage/>
图片渲染组件
一些应用需要动态产生图片有两种方法符合如下需求
产生一个执行Servlet请求的超链接Servlet将使用图形库来产生图片
将JAVA Applet嵌入在HTML页面中来产生图片
文本输出
一些应用需要动态的产生文本(如XML)因为整个页面将通过PrinterWriter输出我们可以通过设置PrinterWriter的属性来做到
responsesetContentType(text/plain); // or text/xml
PrintWriter writer = responsegetWriter();
// use writer to render text
return(null);
Struts EL 标签库
Struts基本的标签都是依赖rtexprvalue(runtime scriptlet expression)来动态计算属性
的值例如要根据资源关键值打印来自属性文件中的信息
<bean:message key=<%= stringvar %>/> 这样写是假定stringvar是JSP中的
脚本变量如果使用Struts的EL标签库就会是如下形式
<beanel:message key=${stringvar}/>
创建控制(Controller)组件
概述
我们已经知道如何去构建Model和View组件现在我们将集中到Controller组件Struts包含了一个映射请求URI到Action类的Servlet因此你编写WEB应用时在Controller组件这方面要做的工作如下
.编写AtionForm作为Model和View的中介
.编写Action(继承orgapachestrutsactionAction)来处理请求
.为每一个逻辑请求在strutsconfigxml中编写一个ActionMapping
ActionServlet
对于熟悉MVC架构的人来讲ActionServlet就代表着C ? ControllerController的任务是
.处理用户请求
.根据用户请求来决定用户将要完成什么任务
.将Model的数据传到视图(View)
.选择合适的视图响应请求
Controller会将大部分工作放到Request Processor和Action 类中
请求处理器(Request Processor)
RequestProcessor对每个请求做核心处理的地方它要做的处理如下
processPath - 确定请求的路径以备后面的处理检索ActionMapping
processLocale ? 为请求选择一个locale
processContent - 设置默认的内容(Content)类型
processNoCache ? 设置响应头PragmaCacheControlExpires
processPreprocess - RequestProcessor让子类重载实现默认返回真(True)如果子类重载此方法并返回真则该请求将继续处理流程如果返回假则意味着你处理了该请求处理流程直接返回
processMapping - 确定请求所对应路径的ActionMapping
processRoles - 保证请求的用户具备特定的角色
processActionForm- 实例化ActioForm并且把它放在适当的作用域中
processPopulate - 用请求中的数据组装ActionForm
processValidate - 校验ActionForm中的数据
processForward - 如果映射是一个转向( Forward)指令就转向到特定的路径
processInclude - 如果映射是一个包含(Include)指令就将映射指定的路径的输出结果包含进来
processActionCreate - 实例化映射指定的Action
processActionPerform ? 执行Action的perform或excute方法
processForwardConfig - 最后RequetProcessor使用Action类返回的ActionForward来选择下一个资源大多数的AtionForward将会导航到显示页面输出响应
ActionForm类
一个ActionForm代表着一个与用户交互的HTML表单ActionForm中的属性来存储表单中的状态并且有gettersetter方法来访问他们ActionForm可以存储在session或request的作用域中(默认的是session)如果ActionForm放在session中记得要实现reset方法以备每次使用ActionForm时都会初始化Struts根据请求中的参数设置ActionForm的属性并且把经过校验后的ActionForm传到Action的execute方法
当你在编写ActionForm时必须坚持如下原则
.ActionForm本身没有任何特定的方法被实现仅仅用来表示它是整个框架中一个特定的角色ActinForm中只有gettersetter方法并没有任何商业逻辑
.AtionForm提供标准的校验机制如果你重载了ActionForm的validate方法并且在资源属性文件中提供了错误消息那么Struts就会自动校验表单中的数据当然你也可以忽略ActionForm中的校验在Action类中来实现校验
.为输入表单中的每一个输入定义属性输入域的名称和ActionForm中属性的名称必须符合JAVA规范例如一个输入域的名称username将会导致ActionForm中的setUsername被调用
.也可以为Form中的按钮或其他控件定义属性当提交表单时这将有利于你知道哪个控件被选中了
.把ActionForm当作HTTP和Action之间的防火墙ActionForm的方法可以校验所有必须的属性已经存在了并且包含合理的值如果校验失败请求将不会被Action类处理
.你可能会放一个Bean的实例在ActinForm中这样你就会用到嵌套属性引用例如你可能有一个customer在ActionForm中然后在页面中用customername来引用属性
DynaActionForm
维护一个具体的ActionForm是要耗费时间的特别是ActionForm越来越多并且都是校验一些简单的属性时你可能会感觉到一股挫折感
这个瓶颈通过DynaActionForm会有所减轻通过在Struts的配置文件中列出属性类型和默认值来替代以前的定义一个新类并且添加getter/setter方法例如在strutsconfigxml中添加一个UserForm
<formbean
name=UserForm
type=orgapachestrutsactionDynaActionForm>
<formproperty
name=givenName
type=javalangString
initial=John/>
<formproperty
name=familyName
type=javalangString
initial=Smith/>
</formbean>
DynaActionForm支持的数据类型
javalangBigDecimal
javalangBigInteger
boolean and javalangBoolean
byte and javalangByte
char and javalangCharacter
javalangClass
double and javalangDouble
float and javalangFloat
int and javalangInteger
long and javalangLong
short and javalangShort