Struts 2的OGNL表达式
Struts 2支持以下几种表达式语言:
OGNL(Object-Graph Navigation Language),可以方便地操作对象属性的开源表达式语言;
JSTL(JSP Standard Tag Library),JSP 2.0集成的标准的表达式语言;
Groovy,基于Java平台的动态语言,它具有时下比较流行的动态语言(如Python、Ruby和Smarttalk等)的一些起特性;
Velocity,严格来说不是表达式语言,它是一种基于Java的模板匹配引擎,具说其性能要比JSP好。
Struts 2默认的表达式语言是OGNL,原因是它相对其它表达式语言具有下面几大优势:
支持对象方法调用,如xxx.doSomeSpecial();
支持类静态的方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如:@java.lang.String@format('foo %s', 'bar')或@tutorial.MyConstant@APP_NAME;
支持赋值操作和表达式串联,如price=100, discount=0.8, calculatePrice(),这个表达式会返回80;
访问OGNL上下文(OGNL context)和ActionContext;
操作集合对象。
“#”主要有三种用途:
访问OGNL上下文和Action上下文,#相当于ActionContext.getContext();下表有几个ActionContext中有用的属性: 名称 作用 例子
parameters 包含当前HTTP请求参数的Map #parameters.id[0]作用相当于request.getParameter("id")
request 包含当前HttpServletRequest的属性(attribute)的Map #request.userName相当于request.getAttribute("userName")
session 包含当前HttpSession的属性(attribute)的Map #session.userName相当于session.getAttribute("userName")
application 包含当前应用的ServletContext的属性(attribute)的Map #application.userName相当于application.getAttribute("userName")
attr 用于按request > session > application顺序访问其属性(attribute) #attr.userName相当于按顺序在以上三个范围(scope)内读取userName属性,直到找到为止
用于过滤和投影(projecting)集合,如books.{?#this.price<100};
构造Map,如#{'foo1':'bar1', 'foo2':'bar2'}。
%”符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。例如在Ognl.jsp中加入以下代码:
<hr />
<h3>%的用途</h3>
<p><s:url value="#foobar['foo1']" /></p>
<p><s:url value="%{#foobar['foo1']}" /></p>
清单6 演示%用途的代码片段
刷新页面,结果如下所示:
清单7 示例运行结果2
“$”有两个主要的用途
用于在国际化资源文件中,引用OGNL表达式,例子请参考《在Struts 2.0中国际化(i18n)您的应用程序》
在Struts 2配置文件中,引用OGNL表达式,如
<action name="AddPhoto" class="addPhoto">
<interceptor-ref name="fileUploadStack" />
<result type="redirect">ListPhotos.action?albumId=${albumId}</result>
</action>
清单8 演示$用途的代码片段
Struct总结:
1. Action
a) namespace(掌握)
b) path(掌握)
c) DMI(掌握)
d) wildcard(掌握)
e) 接收参数(掌握前两种)
f) 访问request等(掌握Map IOC方式)
g) 简单数据验证(掌握addFieldError和<s:fieldError)
1. Result
a) 结果类型(掌握四种,重点两种)
b) 全局结果(掌握)
c) 动态结果(了解)
1. OGNL表达式(精通)
a) # % $
2. Struts标签
a) 掌握常用的
3. 声明式异常处理(了解)
4. I18N(了解)
5. CRUD的过程(最重要是设计与规划)(精通)
6. Interceptor的原理(掌握)
7. 类型转换(掌握默认,了解自定义)
Struct 1 Action
每次请求时,都只会用原先那个Action类生成的实例
Struct 2 Action
每次请求时,都会重新生成Action类的实例
实际上主流的开发有两个方向:
1. 轻量级、开源框架:以Spring+Hibernate为基础的。
2. Sun公司提供的Java EE规范:以EJB 3+JPA为基础的。
Struts 2和Xwork[X1]
Struts 2是由WebWork发展而来的,WebWork是以XWork为基础的。
所以Struts 2也是以XWork为基础的。
安装struts 2
(1) 拷JAR包[X2] 。
(2) 修改web.xml文件,增加Struts2支持。 DEMO
需要在web.xml文件中增加一个核心Filter。以前是FilterDispatcher,
现在改为使用StrutsPrepareAndExecuteFilter。
但实际上,2.1.6中依然不能使用StrutsPrepareAndExecuteFilter,因为它在处理中文问题时有乱码。
(3) 在WEB-INF/classes目录增加一个struts.xml文件,它负责管理Struts 2的配置。
struts.xml是开发过程中一个非常重要的配置文件。
1. 注册(插入一条记录) 2.登录(查看指定记录是否存在) 3. 查看/修改用户。(查询全部记录)
与传统MVC开发的差别:
1. 传统的MVC开发,每次用户请求,通常会定义一个Servlet进行处理。
用了Struts 2之后,定义一个Action进行处理。
2. 传统的MVC开发,Servlet开发完成之后,需要在web.xml文件中配置Servlet
用了Struts 2之后,需要在struts.xml文件中配置Action
Struts2提高了系统的安全机制,默认不会列出web应用的文件列表。所以如果我们
希望访问哪个页面,必须直接输入此页面的此文件名。如果直接输入http://localhost:8888/Struts2Dermo将看到错误页面。(默认)
struts2-core-2.1.8.1.jar
xwork-core-2.1.6.jar
freemarker-2.3.15.jar
ognl-2.7.3.jar
commons-fileupload-1.2.1.jar
commons-logging-1.0.4.jar
Struts 2的Action的要求:
1. 实现Action接口,或者继承ActionSupport基类[X1]
2. 为所有的请求参数定义Field,并提供getter和setter方法。
以后就可通过该Field来获取请求参数,无需搞request.getParameter[X2] !!!!
3. 定义一个处理用户请求的方法。该方法的签名是:
public String xxx() execute
{
}
用了Struts 2之后[X3] ,
在Action类中,无需通过getParameter来获取请求参数。
也不需要调用request.setAttribute将需要显示的数据传到JSP页面。
<!-- 配置列出Web应用根路径下所有文件的Action -->
<action name="">
<result>.</result>
</action[X4] >
因为ActionSupport类完全符合一个Action实现类,所以我们可以直接使用ActionSupport作为业务控制器。实际上,如果我们配置Action没有指定class属性(即没有用户提供的Action类),系统会自动使用ActionSupport类作为Actiont处理类
如果需要以post方式提交请求,则定义包含表单数据的JSP页面。如果仅仅是以get方式发送请求,则无须经过这一步
配置action就是让struct2的哪个Actin处理哪个请求,也就是完成用户请求和Action之间的对应关系
虽然action的命名空间非常灵活,但如果name用带.或-的值,则可能引发其他异常
原则:约定优于配置
常量配置:
它就是一些简单的key-value对!
通常就是一个常量名、一个常量值。
为struts 2配置常量有3种方式:
↗ 在web.xml文件中为PrepareAndExecuteFilter指定初始化参数。
每个<init-param.../>元素配置一个常量。
↗ 增加一个struts.properties文件(放在WEB-INF/classes)。
struts.i18n.encoding=UTF-8 指定默认编码集
struts.action.extension= 扩展名 默认是action
structs.i18n.reload = 是否每次HTTP请求到达时,系统自动加载资源文件
structs.configuratin.xml.reload 当XML文件改变后,系统是否自动重新加载此文件。
structs. i18n.resources 所需要的国际第资源文件,如果有多个资源文件则用,分开
struts.devMode=true 是否使用开发模式。如果为true则可以在应用出错时显示更多、更友好的出错提示。
通常开发阶段设为true,开发阶段设为false
↗ 在struts.xml文件中使用<constant.../>元素进行配置。
<constant name="struts.i18n.encoding" value="GBK"/>
<constant name="struts.action.extension" value="html"/>
包含其他配置文件:
默认情况下,Struct2会自动加载类加载路径下的structs.xml default.xml stuts-plugin.xml三类文件[X1]
<include file=”struts-part1.xml > DEMO
包,抽象包不能用action (包和命名空间)(“” 默认命名空间可以处理任何命名空间的请求)
Struct2 还可以显示指定根命名空间,通过设置某个包的namespace=”/”来指定根命名空间。
如果请求为/barspace/bar.action,系统首先查找/barspace空间下的bar.action请求,如果在此命名空间里找不到,则到默认的命名空间里找,都找不到的就出错。
如果请求为/login.action ,系统会在根命名空间下(“/”)查找名为login的Action,找到了就处理此请求,否则到默认的命名空间里找,都长不到的就出错。
命名空间只有一个级别。如果请求的URL是/bookservice/search/get.action,系统将先在/bookservice/search的命名空间下查找名为get的Action,没有的就到默认的空间找,而不会到//bookservice的命名空间下查找。。。。
Struts 2不允许为单独的Action配置命名空间,只能为一个package整体配置命名空间。
Struts 2的核心JAR包里包含了一个struts-default.xml文件,
该文件中定义了一个名为struts-default的抽象包。
设置默认的Action
为了让Struct2的Action可以接管用户请求,我们可以配置 name=”*” 的Action,
除此之外,Struct2还支持配置默认Action ,当用户请求找不到对应的Action时,系统默认的Action即将处理用户请求
<default-action-ref name=”simpleCddfsdf”>
<action name="simpleCddfsdf" class="lee.simpleCddfsdf" >
<result ... />
</action>
实现Action:
Struct2 2 的Action优势:
低侵入式设计。代码的保值性很好;
与Servlet API分离,便于测试
通常,structs2框架按如下顺序加载Struct2常量:
Structs-default.xml (保存在struts2-core-2.1.2文件中)
Structs-plugin.xml (保存在struts2-Xxxx-2.1.2等struct2插件JAR文件中)
Structs.xml
Structs.properties (stucts2默认的配置文件)
Web.xml
Action访问Servlet API[X1] :
两种方式:
1 借助ActionContext实现伪访问 DEMO jsp
2 借助ServletActionContext实现真实访问
借助ServletContextAware:实现此接口可以直接访问ServletContext实例 DEMO
借助ServletRequestAware:直接访问HttpRequest实例
借助ServletResponseAware[X2] :
DMI 动态方法调用: ! 好像用处不大 跟method差不多 在浏览器URL里可以用..!..
使用动态方法调用前必须设置 struts.enable.DynamicMethodInvocation = true
指定Method属性及使用通配符:
如果省略了method属性,则默认采用execute方法处理请求
<action name="*Action" class="lee.LoginRegistAction" method="{1}">
<action name="*-*" class="action.{1}" method="{2}">
<!—通用的Action -->
<action name=”*”> <result>/{1}.jsp</result> </action>
<action name=””>
<result>.</result>
</action>
<!—浏览器 列出当前目录-->
配置处理结果:
Action的处理方法的签名必须为如下格式:
public String xxx()
{
}
配置结果有两种方式[X3] :
局部结果:将<result.../>元素作为<action.../>元素的子元素定义。
全局结果:将<result.../>元素作为<global-results..../>元素的子元素定义。
<gloabl-results>
<result name="success">/WEB-INF/jsp/{1}Succ.jsp</result>
</gloabl-results>
配置结果的完整语法为:
<result name="Action处理方法所返回的字符串" type="视图类型">
<!-- location参数指定视图资源的位置 -->
<param name="locatioin">/视图资源的位置</param>
<param .../>
</result>
-name属性指定Action处理方法所返回的字符串,该属性的默认值是"success"
-type指定将要使用的视图资源的类型,该属性的默认值是"dispatcher"
如果配置<result.../>时,只需要一个<param.../>子元素,
而且该<param.../>元素所配置的参数名为location,那么可以简写为如下形式:
<result name="Action处理方法所返回的字符串" type="视图类型">/视图资源的位置</result>
Struts 2支持的结果类型:
chain :使用两个Action作为链来处理。一个用户请求,需要先后经过两个或更多的Action处理。
就要用到这种chain处理结果。
dispatcher:默认的处理结果。(转发)
freemarker
httpheader
redirect:重定向另一个URL。 Jsp (重定向[X4] )
redirectAction 重定向另一个Action。
对于redirect和redirectAction两种类型,都是重新生成一个请求,区别是前者通常用于生成一个对具体资源的请求,而后者通常是用于生成对另一个Action的请求。
stream:做文件下载的。
velocity
xslt
plainText :使用普通文本作为视图。 (主要用于显示实际视图资源的源代码[X5] )
Web应用中通常访问的API是:HttpServletRequest 、HttpSession 、ServletContext(代表application对象)
既可以彻底与Servlet Api分离,从而允许此Action脱离Web容器运行,也就可以脱离Web容器来测试Action,又允许用简单的方式操作各范围内属性
虽然在Actin类里直接获得了response对象,但也不要尝试直接在action中生成响应
Result默认的name属性名是sussecc,可以省略的
局部结果只对当前<action.../>配置起作用。
全局结果则对所有的<action.../>配置都起作用。
当局部结果和全局结果冲突时,局部结果生效!!!!
<result name="success" type="redirect">
<param name="location">foo.jsp</param>
<param name="parse">false</param>
</result>
<!—parse 是否允许在location参数中使用表达式
-->
<action name="displayJspRawContent" >
<result type="plaintext">
<param name="location">/myJspFile.jsp</param>
<param name="charSet">UTF-8</param>
</result>
</action>
<!-- charSet 指定输出页面时所用的字符集-->
动态结果: *
“零配置” the Convention Plugin is bundled with Struts since 2.1 and replaces the Codebehind Plugin and Zero Config plugins. It provides the following features: (代替了零配置插件)
------------------------------------
用Annotation来代替了XML配置。
Rails框架,“CoC” Convention Over Configuration
使用XML配置的优势是:
管理信息从Java源代码中分离出来。因此降低了耦合,从提高了可扩展性。
使用XML配置的劣势是:
a. 重写编写XML工作量大,开发效率低。
b. XML文件越来越多,维护XML文档也变得很难。
Rails说:有一个约定。
Convention Over Configuration 约定优于配置。
Struts 2的工具插件:
struts2-config-browser-plugin-2.1.8.1.jar
configBrowser插件的用法:
1. 将插件的JAR包复制到Web应用WEB-INF/lib下。
2. 访问主机名:端口/项目名/config-browser/index
这个插件的作用是帮助你调试的。
Convention插件。 (约定插件,不叫零配置)
<constant name="struts.convention.result.path" value="/WEB-INF/jsp/"/> //XML文件
@ResultPath("/WEB-INF/jsps") //放在Actin类前面
DEMO
<!-- 系统自动搜索的Action类的后缀 -->
<constant name="struts.convention.action.suffix" value="Action"/>
<!-- 系统自动搜索的Action类所在的子包 -->
<constant name="struts.convention.action.packages" value="actions"/>
<!-- 指定是否自动搜索所有匹配的action -->
<constant name="struts.convention.action.mapAllMatches" value="true"/>
1. Action类必须满足一定的规则。
2. Action类通常应该放在actions子包下。
这样Convention插件会自动搜索所有匹配的Action,并将其进行“配置”
将Action的类名的后缀去掉,并将原来的“camerl”写法,改为中划线写法,
作为<action.../>的name
Struts 2异常处理: DEMO 网站DEMO
在struts-defult.xml里已经配置了开启异常映射功能
<interceptors> <interceptor name=”exception” class=” ”
局部异常映射:<exception-mappting>作为<action>子元素配置[X1]
<action><exception-mappting exception=”java.sql.SQLException” result=”sql” /><action>
全局异常映射:<exception-mappting>作为<global-exception-mapping>子元素配置
<global-exception-mapping><exception-mappting exception=”java.sql.SQLException” result=”sql” /><global-exception-mapping>
输出异常信息: (可直接放在JSP页面中) 要先导入标签库<%@ taglib prefix=”s” uri=”/struts-tags” %>
<s:property value=”exception”> 输出异常对象本身
<s:property value=”exceptionStack”> 输出异常堆栈信息
<s:property value=”exception.message”>
<s:property value=”exceptionStack”> 使用Structs2标签输出异常跟踪栈信息
Struts2国际化:
Sruts.custom.i18n.resource = messageResource 使用native2ascii工具[X2]
访问国际化信息: messageResouce.properties _zh_CN.properties _en_US.properties
JSP页面,<s:text name=”” /> name指定了国际化资源文件中的key DEMO
Action类,使用ActionSupport类的getText 方法 name属性 name指定了国际化资源文件中的key
在此表单元素的Label里输出国际化信息,可以为此表单标签指定一个key属性,此key指定了国际化资源文件中的key <s:textfield name="username" key="user"/>
输出带占位符的国际化消息: DEMO
JSP页面,<s:text ../>标签中 使用多个<s:param ../> 依此类推的
Action类,getText 来自于ActionSuport
加载资源文件的方式:
1. 全局资源 需要显式加载 利用这个常量Sruts.custom.i18n.resource
2. 包范围的国际化资源(资源文件放在此包;命名PackageName_language_country.properties)
3. Action范围内国际化资源(资源文件与Action类放在一起;命名ActionName_language_country.properties)
4. 页面范围(局部)国际化资源 (临时[X3] ) <s:i18n >作为父标签,通过这个标签显式加载 DEMO
全局异常映射的result属性值通常不要使用局部结果,局部映射的result属性值既可以使用全局结果集,也可以使用局部结果集
native2ascii 源资源文件 目的资源文件
页面上使用<s:text>标签来输出国际化消息,
当此标签在资源文件找不到对应的key,它将直接输出默认消息,如果默认消息也没有,它将输出key
Struts标签库:
OGNL表达式
Stack Context中有两个对象,foo和bar,其中foo是根。
#foo.abc -输出foo.getAbc()
#bar.abc -输出bar.getAbc()
OGNL规定,如果省略对象,那么默认就是访问根的属性。
abc - 输出foo.getAbc()
如果Stack Context有2个根:foo,bar(根之间有顺序)
#foo.abc -输出foo.getAbc()
#bar.abc -输出bar.getAbc()
abc - 优先输出foo.getAbc(),如果foo对象没有getAbc(),尝试输出bar.getAbc()
Struts 2的OGNL求值是基于Stack Context
在Struts 2中,Stack Context的第一个根对象是Value Stack,Value Stack里又包含大量对象。
如果需要访问ValueStack里的属性,只需通过以下方式即可:
${bar}
Struts还提供了一些命名对象,这些命名对象与根对象无关,它们只是存在于StackContext中。所以访问这些对象时需要使用#前缀来指明:
Parameters #Parameters["foo"] 或 #Parameters.foo
Request #request["ddd"] 或 #request.ddd
Session
Application
Attr 此对象将依次搜索如下对象:PageContext HttpServlet HttpSession ServletyContext中的属性
Debuger调试标签 <s:debug />
OGNL中的集合操作
创建List集合 {e2 , e2 , ...}
创建Map类型集合 #{key1:value1 , key2:value2 , ....}
取得子集时有如下3个操作符:
? 取出所有符合选择逻辑的元素 person.relatives.{ ? #this.gender == ‘male’ }
^ 取出符合选择逻辑的第一个元素
$ 取出符合选择逻辑的最后一个元素
对于集合类型,OGNL表达式可以使用in和not in两个元素符号。其中,in表达式用来判断某个元素是否在指定的集合对象中;not in判断某个元素是否不在指定的集合对象中,
%”符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。例如在Ognl.jsp中加入以下代码:
<hr />
<h3>%的用途</h3>
<p><s:url value="#foobar['foo1']" /></p>
<p><s:url value="%{#foobar['foo1']}" /></p>
清单6 演示%用途的代码片段
刷新页面,结果如下所示:
清单7 示例运行结果2
“$”有两个主要的用途
用于在国际化资源文件中,引用OGNL表达式,例子请参考《在Struts 2.0中国际化(i18n)您的应用程序》
在Struts 2配置文件中,引用OGNL表达式,如
<action name="AddPhoto" class="addPhoto">
<interceptor-ref name="fileUploadStack" />
<result type="redirect">ListPhotos.action?albumId=${albumId}</result>
</action>
清单8 演示$用途的代码片段
控制标签[X1]
If elseif else append generator iterator merge sort subset
Append元素与merge元素拼合的方式不同:
Append:a.1 a.2 a.3 b.1 b.2 b.3 c.1 c.2
Merge: a.1 b.1 c.1 a.2 b.2 c.2 a.3 b.3 c.3
getCount() 返回当前迭代了几个元素
getIndex() 当前迭代元素的索引
isEvent() 当前的索引是否是偶数
isOdd () 当前的索引是否是奇数 <..test=”#st.odd”>
isFirst()
isLast()
数据标签 DEMO
Action 在JSP页面直接调用Action
Bean 创建一个javabean实例[X1]
Date 格式化输出一个日期(nice指定是否输出其时差)
Debug
I18n 指定国际化资源文件的basename
Include 用于在JSP页面中包含其他的JSP或servlet资源
Param 设置一个参数,通常是用做bean标签、url标签的子标签
Push 将某个值放入ValueStack的栈顶
Set 设置一个新变量,并可以将新变量放入指定的范围:applicatin,session
Text 输出国际化消息
url 生成一个url地址
property 输出某个值,包括输出ValueStack、Stack Context、Action Context中的值
在bean标签的标签体内时,bean标签创建的javaBean实例位于ValueStack的顶端;但一旦此bean标签结束了,则bean标签创建的javaBean实例被移出ValueStack,将无法再次访问此javaBean实例。除非指定了var属性,则还可以通过Stack Context来访问此实例
UI标签
都是基于主题和模板的[X1]
不用尝试自己加载模板,开发者只要指定主题就够了,主题会负责去加载模板[X2]
需要掌握的知识点:
1. 为struts2标签指定theme的方式(7种)
2. Struts2常用的主题及其特性 simple(不会有额外的布局功能) css_xhtml xhtml(默认的,非常方便,两列布局,输出检验错误提示,出处客户端校验提示)
主题是模板的组织形式,模板被包装在主题里面,;
设置主题的方法:
1. 通过设定特定UI标签上的theme属性来指定主题;
2. 设定特定UI标签外围的Form标签的theme属性
3. 取得Page会话范围的内以theme为名称的属性来确定主题;
4. 取得Request会话范围的内以theme为名称的属性来确定主题;
5. 取得Session会话范围的内以theme为名称的属性来确定主题;
6. 取得application会话范围的内以theme为名称的属性来确定主题;
7. 通过设置名为struts.ui.theme的常量(默认值是xhtml)来确定默认主题,此常量可以在struts.properties文件或者struts.xml文件确定
Struts可以选择自己的模板技术,通过修改struts.ui.templateSuffix常量的值就可以改变struts2默认的模板技术。
Ftl:(缺省) 基于Freemaker的模板技术;
Vm:基于Velocity的模板技术;
Jsp:基于JSP的模板技术
<action name=””>
<result>.</result>
</action>
<!—浏览器 列出当前目录-->
表单标签:
分两类:form标签本身;单个表单元素的标签
Form标签的行为不同于表单元素标签。Struts2的表单元素标签都包含了非常多的属性,但有很多属性
完全是通用的。
所有表单标签处理类都继承了UIBean类,UIBean包含了一些通用属性,这些通用属性分为了3类:
模板相关属性
Javascript相关属性
通用属性
Checkboklist
combolist
doubleselect doubleselect02 [W1] 级联
Doubleseelct必须放在form标签中使用,且必须为此form标签指定action属性。此外还应该在struts.xml文件中增加如下:
<!---将所有jsp映射成可通过Action来访问-->
<action name="*">
<result> /{1}.jsp</result>
</aciton>
Head标签
optiontransferselect
Select
radio
optgroup
token [W1]
updownselect
生成一个隐藏域,生成的参数是随机的。
防止重复提交:
1.进入表单页面时,系统会生成一个随机字符串,并将其放入session,并放入页面中的一个隐藏域
2.提交请求时,系统会将sessin中的随机参数与隐藏域的随机参数进行对比,如果相同,即判断为有效请求,系统要清空session中的..
3.如果刷新,隐藏域对应的请求参数没变,但session中随机字符串已经没了,此时隐藏域的与session的不pi配,判断为无效请求。
非表单标签:
Actionerror actionmessgae component fielderror
内建类型转换器:
boolean和Boolean:完成字符串与布尔值之间的转换
char和Character
int和Integer
long和Long
float和Float
double和Double
Date:完成字符串与日期类型之间的转换日期格式使用用户请求所在Locale的SHORT格式
数组:在默认情况下,数组元素是字符串,如果用户提供了自定义类型转换器,也可以是其他复合类型的数组。[W1]
集合:在默认情况下,假定集合元素类型为String,并创建一个新的ArrayList封闭所有的字符串
基于OGNL的类型转换:
DEMO 上课实例(子表单)DEMO
指定集合对象的类型 DEMO
ActinName-converesion.properties文件放到Action所在的目录下
通过局部类型转换文件指定如下 key-value对
Element_users=lee.user (List类型的做法[W2] )
自定义类型转换: DEMO
1) 实现TypeConverter接口,意味着要完成类型转换的全部工作
2) 实现TypeConverter接口比较复杂,可继承DefultTypeConver [W3]
3) 更简单的是继承StrutsTypeConverter 上课实例DEMO UserVoConverter.java
重写convertFromString( string到自定义类型 疯狂JAVA实例DEMO
重写convertToString( 自定义类型到string
注册类型转换器:
全局:在类加载路径下指定xwork-conversion.properties DEMO
自定义类型=转换器类
局部:指定对特定的Action的特定的属性使用指定的转换器 DEMO
局部类型的转换的文件放到Action相同的路径下,文件名为AcitonName-conversion.properties
Action属性名=转换器类
#指定user属性需要使用lee.UserConverter类来完成类型转换
user=lee.UserConverter
使用JDK1.5的注释来注册类型转换器。
全局类型转换器是根据目标类来起作用的--只有你的Aciton类里有指定类型的属性,
那么自定义类型转换器就会起作用。
局部类型转换器是根据指定Action的指定属性来起作用的,--此类型转换器只对特定Acitn类的特定属性起作用
[W4]
类型转换中的错误处理: DEMO [W5]
转换失败时,系统会跳到input Result ,因此需要配置name="input"的result;
struts全局使用key为Xwork.default.invalid.fieldvalue的消息作为提示信息。
Xwork.default.invalid.fieldvalue={0}字段类型转换失败
需要对特定字段指定特别的提示信息,通过学习Action的局部资源文件来实现,
invalid.fieldvalue.<propName>=<tipMsg>
在页面上显示错误提示:
1.使用xhtml主题的struts 2标签
2.使用<s:fieldError />来输出
错误提示的国际化
全局 在全局的国际化文件里添加key为Xwork.default.invalid.fieldvalue={0}字段类型转换失败
局部 在局部的国际化文件里添加key为invalid.fieldvalue.<propName>=<tipMsg>
处理集合类型的错误处理:
DEMO
输入检验: DEMO
服务端检验:防止非法数据进入程序,导致程序异常、底层数据库异常。服务器端校验是保证程序有效运行及数据完整的手段
1.编写校验规则文件
a) 校验规则文件与Aciton的类文件放在同一路径
b) 校验规则文件名 就是 Aciton的类名-validatin.xml
2.页面上使用 表单标签,会输出验证错误 。或使用<s:fielderror />也可以输出
3.错误提示国际化输出 <s:message key=/>
[W6] [W7]
对于数组的类型转换将按照数组元素的类型来单独转换每个元素,但对于其他的类型转换,如果转转换无法完成,系统将出现类型转换
如果是Map类型的,则需要同时指定Map类型的key类型和value类型:
Key_<MapPropName>=<keyType>
Element_<MapPropName>=<valueType>
可以认为DefultTypeConver是通过HttpServletRequest的getParameterVaues(name)方法来获取请求参数值的。因此它获取请求参数总是字符串数组,如果请求参数只包含一个单个值,则此请求参数的值是一个长度为1的字符串数组
struts2的ActionSupport基类负责收集类型转换错误、输入检验错误,并将它们封闭成FieldError对象,添加到ActionContext中。
struts2提供了一个名为conversionError的拦载器,这个拦载器被注册在默认的拦载器栈中。此拦载器负责将对应错误封闭成表单域错误(FieldError)
由于JS脚本本身的限制,并不是所有的服务器端校验都可以转换成客户端校验
客户端校验两值得注意:
struts2的<s:form ../>元素的theme 属性,不要将此属性指定为simple;
不要在校验规则文件的错误提示信息中使用key来指定国际化提示。如下:
客户端检验:拒绝误操作输入提交到服务器处理,降低服务器负担,异常 DEMO
1.应该用<s:form ../>生成表单
2.为<s:form ../>增加validate="true"
3.[W1] 如果希望国际化,应该把错误信息放到全局国际化资源中。并用${getText("key")}的方式来加载国际化消息
如果希望类型转换还有输入检验可以正常工作,记住你的Action应该继承ActinSupport
转换失败时,系统会跳到input Result ,因此需要配置name="input"的result;
国际化提示信息:
DEMO
字段优先风格 (字段校验器配置风格)
<field name="被校验的字段">
<field-validator type="检验器名">
<param name="filedName">需要被检验的字段</param>
<message key= >
检验器优先风格 (非字段校验器配置风格) DEMO
<validator type="校验器名">
<param name="filedName">需要被检验的字段</param>
<message key= >
短路校验器(默认是非短路的)
在<field-validator>或<validator> 增加属性short-circuit="true" DEMO
校验文件的搜索规则:
Struts2允许通过为校验规则文件名增加Aciton别名来指定具体需要校验的处理逻辑
DEMO
假设系统有两个Action: BaseActin和RegistAction,搜索规则文件顺序如下:
BaseAction-validation.xml
BaseAction-别名-validation.xml
RegistAction-validation.xml
RegistAction-别名-validation
不管有没有规则文件,也不管是否找到,系统都会按顺序一直找下去的
校验顺序和短路:
校验器的执行顺序规则:
所有非字段风格的校验器优先于字段风格的校验器
所有非字段风格的校验顺中,排在前面的会先执行
所有字段风格的校验器中,排在前面的会先执行
校验器短路的原则:
所有非字段校验器是最先执行的,如果某个非字段校验顺校验失败了,是此字段上所有字段校验器都都不会获得校验机会
非字段校验器的校验失败,不会阻止其他非字段校验的执行
如果一个字段校验器校验失败后,则此字段下且排在此校验失败的校验器之后的其他字段校验器不会获得校验的机会
字段校验器永远不会阻止非字段校验器的执行
开发自己的校验器:
新建一个validator.xml 放到classes中,
<validators>
<validator name= class= ><validator>
</validators>
如果struts2系统在WEB-INF/CLASS路径下找到一个validator.xml,则不会再加载指纹默认的default.xml文件,所以要把default.xml文件中原有的校验器复制到自己建立的validator.xml文件中去
输入校验的手动校验:
1. 在Action类里重写validate()方法(DEMO)或 validate处理方法()方法。
比如你的处理方法名为abc。
那么你应该重写validateAbc()方法。 (DEMO)
只要系统调用Action里的处理方法来处理用户请求,validate()方法都会被执行。
只有当系统调用Action里abc方法来处理用户请求时,validateAbc()方法才会被执行。
2. 实现这些方法很简单:
程序先判断某个字段是否满足要求,
如果字段不满足要求,调用addFieldError()向Action关联的容器中添加fielderror消息。
ActionSupport提供了addFieldError()、addActionError、addActionMessage()
向Action所关联的3个容器添加消息,下面3个标签就用于遍历、并输出对应容器中消息。
<s:fielderror/> :输出类型转换失败、输入校验失败的错误提示。
<s:actionerror/>
<s:actionmesssage/>
内建校验器:
<param name="trim">true</param> //指定载断被校验属性值前后的空白
Struts2中有一个小小的问题,当需要使用客户端校验时,如果在校验规则文件RegistAction-validation.xml的<message>元素中指定了key属性,系统将无法从全局国际化资源文件中加载此key对应的国际化信息。可以用$getText("fff")}
struts2 文件上传: DEMO (这个有点问题) 课堂实例DEMO
1. 页面上的表单必须增加enctype="multipart/form-data" [W1]
表单的enctype属性指定的是表单数据的编码方式:
applicaiton/x-www-form-urlencoded:默认的编码方式,它只处理表单域里的value属性值,采用这种编码方式的表单会将表单域的值处理成URL编码方式;
multipart/form-data:以二进制的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数里;
tet/pain:当表单的action属性为mailto:URL的形式时比较方便,适用于直接通过表单发送邮件方式。
一旦设置了enctype="multipart/form-data" ,服务器端就不能通过request.getParameter()方法来取得参数
2. 选择文件上传的底层支持。
默认使用Common-FileUpload。 [W1]
在struts.properties配置文件中
#指定使用COS文件上传解析器
#struts.multipart.parser=cos
#指定使用Pell的文件上传解析器
#struts.multipart.parser=pell
#默认使用Jakarta的Common-FileUpload的文件上传解析器(不用指定的)
#struts.multipart.parser=jakarta
需要说明的是:无论你使用何种文件上传支持,你上层的编码几乎不需要改变。
因为Struts2 已经为你做了很好的封装。
3. 实现Action
一个文件上传域,在Action里对应3个field。比如name为abc的文件上传域,需要
File abc;
String abcFileName;
String abcContentType;
至于文件上传,就是将File类型参数中数据写入本地磁盘。
ActionSupport提供了addFieldError()、addActionError、addActionMessage()
向Action所关联的3个容器添加消息,下面3个标签就用于遍历、并输出对应容器中消息。
<s:fielderror/> :输出类型转换失败、输入校验失败的错误提示。
<s:actionerror/>
<s:actionmesssage/>
同时上传多个文件?而且我不确定有多少个文件,怎么办?
1。 页面上的文件上传域可通过JS来动态地增加。、
2。 Action里用数组来代表多个文件。
文件过滤(只允许上传指定大小的文件、只允许上传指定类型的文件)
1. 用代码过滤 手动 DEMO
通过File类型的属性来进行文件大小过滤。
也通过xxxContentType属性进行文件类型过滤。
2. 用拦截器过滤。 拦截器 DEMO
使用fileUplod拦截器,使用该拦截器时指定如下两个参数:
allowTypes:指定所有允许上传的文件类型。
maximumsize:指定允许上传的文件大小。
如果你要上传的文件超过了指定大小,或者不是允许的文件类型。
系统会跳转到input视图。
fileUpload拦截器必须配置在defaultStack拦截器栈之前。
3. 当上传的文件大小超出、或文件类型不允许时,
系统会将错误提示添加成fielderror。
所以可通过<s:fielderror/>或Struts 2的theme="xhtml"的表单标签来输出错误提示。
国际化错误提示:
上传文件太大的提示信息的key是:"struts.messages.error.file.too.large"
不允许上传的文件的key 为:struts.messages.error.content.type.not.allowed
未错误 struts.messages.error.Uploading
struts2 文件下载: DEMO
根据MVC规范,应用请求并不能直接向指定资源发送。
1.如果文件名是中文,就出问题
2.如果应用程序需要在用户下载之前做进一步检查,比如我们要检查用户权限,有权限的人才可以下载,没有权限的人就不能下载
更好的做法:为了保护某些资源,我们考虑将一些受保护的资源放入/WEB-INF/路径下,那么/WEB-INF/是被保护的,用户不能直接访问WEB-INF下的任何资源。
Struts2为文件下载提供了stream的结果类型
实现下载的Action:
下载的Action应该提供一个getter方法,此getter方法的返回值类型是InputStream
拦截器:interceptors
拦截器,一个处理类用于完成一个特定的、小粒度的功能
拦截器栈,将多个小粒度的拦截器组合成一个完成较大功能的、较大粒度的“拦截器”
Struts2配置了一个默认的拦截器,它会引用系统的defaultStack.
对于绝大部分开发者,直接在应用中l默认的拦截器就足够了
自定义,使用拦截器 DEMO [W1]
拦截方法的拦截器 DEMO
拦截器的权限控制 DEMO
HTTP1.1 相比HTTP1.0最大的区别在于:
HTTP1。1支持持久连接,在一个TCP连接上可以传送多个HTTP请求和响应、减少了建立和关闭连接的消耗和延迟。
HTTP1。1还允许客户端不用等待上一次结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次返回响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少整个下载过程所需要的时间
小软件httplook
Intercept(ActinInvocation invocation)方法是用户需要实现的拦截动作。就像Action的execute方法一样,intercept方法会返回一个随行人员中作为逻辑视力。如果此方法直接返回不念旧恶随行人员中,系统将会跳转到此逻辑视图对应的实际视图资源,不会调用被拦截的Action。此方法的AvtionInvocation参数包括了被拦截的Action引用,可以通过调用此参数的invoke方法,将控制权转给下一个拦截器,或者转给Action的ececute方法