MVC的处理流程
1. 浏览器向Servlet(Control)发送请求。
2. Control仅仅是一个调度器。接受到请求后,调用Model的方法来处理用户的请求
3. 处理结束后, Servlet会将结果数据放入“指定银行”中。
转发到指定试图页面(JSP),在试图页面上取出结果数据,并以合适的格式显示出来。
request.setAttribute(”aaa” , list) Request.getAttribute(“aaa”)
在上面的流程中,有如下的操作时每次都要做的,而且是通用的:
1. 通过request.getParameter来得到请求参数。
2. 将请求参数进行类型转换。
3. 对请求参数进行输入校验。
4. 文件上传
……
框架: 当我们做了N个项目时,你会发现这些项目中。总有些代码在多个项目中时重复的,而且具有通用性质。
于是就考虑把N个项目中通用的,重复性的代码“抽取”出来做成自己的库。
——这就是框架。
为什么选择开源框架?
1. 开源框架经过很多的市场检验,稳定性,性能都有较好的保障。
2. 开源框架本身都出自于经验丰富的开发团队,因此质量也有较好保证。
MVC框架:
Struts 2
Spring MVC
JSF(Sun推荐的官方MVC规范,有Renference Implemention,MyFace)
/****************************
*.jar — N个*.class
*.war — 一个web应用包
*.ear — 一个企业应用包,包含N个jar和N个war
****************************/
Struts 2的历史:
2001,Struts 1 (全世界第一个MVC框架)
↓
Apache
↓
开源的其他的MVC框架。WebWork (XWork + Web前端) , OpenSymphony(OS)
↓
2007,WebWork 更名为Struts 2 / shale
↓
2011,OpenSymphony关闭了。
Struts 2 解压之后,得到4个文件夹
apps : 包括5个Web应用包。
Struts2-blank.war — Struts 2的空应用。
Struts2-rest-showcase.war — Strust 2关于REST技术的小例子。
Struts2-showcase.war — Struts 2 技术的所有小例子。
docs : API文档 相关的Guide。
lib : Struts 2自己的JAR包,以及它编译和运行所需要第三方的JAR包。
src : Struts 2的源码。
---------------------------------------------安装Struts 2-------------------------------------------------
Struts 2.3.1.2
(1)拷jar包;apps下的Struts2-blank.war
(2)修改web.xml文件。加载Struts 2的核心Filter。
让Filter过滤所有的用户请求。
(3)在classes目录下增加一个Struts 2的配置文件:struts.xml。
(开发时把struts.xml放在目录下即可)
Struts 2的开发步骤
(1)先定义一个能转发请求的页面。也可是超链接,也可以是表单。
(2)开发Action类。
Struts 2对Action并没有过多的要求,只要求:
A。推荐实现Action接口,或继承ActionSuppor。
ActionSuppor本身实现Action接口。
B。为每个请求参数都提供Field,并为之提供相应的Setter和Getter方法。
C。该Action应该有无参数的构造器
(3)配置Action类
<Action…/>元素有如下常用的属性:
- name:指定该Action处理哪一些请求。
- class:指定Action对应的处理类。
- method:指定使用Action的哪一个方法来处理用户请求。默认值为execute
并为之处理返回的字符串,指定相应的物理试图。
/************************
POJO (Plain Old Java Object)-尽量使用POJO编程
尽量使用特定框架、特定规范相关的API。
************************/
当用了Struts 2之后。
(1)浏览器发送请求:abc.action。.action后缀可以保留。也可以省略。
(2)浏览器发送的请求被StrutsPrepareAndExecuteFilter拦截。
--因为在web.xml中指定StrutsPrepareAndExecuteFilter来过滤所有的请求。
(3)StrutsPrepareAndExecuteFilter会去创建Action的实例。
假如我们请求abc.action。StrutsPrepareAndExecuteFilter会去搜索struts.xml文件
中name为abc的Action配置,根据class属性“使用反射”来创建Action实例。
(4)调用
Map<String,String> paramMap = request.getParameterMap(); //获取所有的请求参数名。
for(String paramName :paramMap.keySet())
{
//得到请求参数对应的Setter方法.
Action类.getMethod("set"+paramName的首字母大写);
String paramValue = paramMap.get(paramName);
//以Action实例为调用者,调用Setter方法,把请求参数值作为参数值传入。
setter.invoke(actionInst , paramValue);
}
(5)再次通过反射来调用method属性所指定的方法。
返回一个字符串。
(6)根据struts.xml文件中的<result.../>元素中的name以及物理试图资源,
跳转到实际的视图资源。
如何action中访问Servlet API
总有些时候,需要访问Servler API
比如我们需要把数据存入Session、Application。
更甚至于我们要添加Cookie:response.addCookie();
Struts 2提供两种方式访问Servlet API:
伪访问:借助于ActionContext
ActionContext,提供getSession --模拟访问Http Session
getApplication --模拟访问Application
真访问:(比如要添加Cookie)。借助于ServletActionContext。
ServletActionContext提供如下的静态方法:
static PageContext getPageContext()
static HttpServletRequest getRequest()
static HttpServletResponse getResponse()
static ServletContext getServletContext()
常量配置
Struts 2常量,也叫Struts 2属性。
--控制整个Struts 2的应用特性。
一个常量名,指定一个常量值。
配置方式有3种:
- 在web.xml中:每个要4行。
<!-- 通过Filter配置初始化参数,就可以配置Struts 2的常量 -->
<init-param>
<param-name>常量名</param-name>
<param-value>常量值</param-value>
</init-param>
- 在struts.xml文件配置。
<constant name="常量名" value="常量值"/>
- 额外增加一个struts.properties配置文件
常量名=常量值 --每行配置一个常量。
Struts 2支持的常量:
struts.i18n.encoding -- 文件字符编码。
struts.multipart.saveDir -- 设置文件上传到临时目录
struts.multipart.maxSize -- 设置每次请求上传的文件总大小。
struts.anction.extension -- 设置action默认的后缀。该常量的值为action。
struts.serve.static.borwserCache -- 控制浏览器是否缓存静态内容。
struts.devMode -- 设置struts开发模式。
struts.i18n.reload -- 是否为每次请求都重新加载资源。
struts.configuration.xml.reload -- 是否每次struts.xml修改之后,应用自动加载。
struts.custom.i18n.resources -- 加载国际化资源文件。
/*****************************
Action接口与ActionSuppor
Action接口中定义了5个字符串常量,和一个exuecute抽象方法。
include 其他配置文件
企业开发 -- 模块化开发
- 开发阶段 : 每个人都要维护自己的配置文件。
- 销售阶段 : 软件做成模块化:
A - B模块:免费的;
C - E模块:20W;
C - E; F - G: 50W.
struts.xml'配置包:
每个package元素定义了一个包配置。定义package元素时可以指定如下几个属性:
- name:这是一个必填属性,该属性指定该包的名字,改名字是该包被其他包引用的Key
- extends:该属性是一个可选属性,该属性指定该包继承其他包。继承其他包,可以继承其他包中的Action定义、拦截器定义等。
- namespace:该属性是一个可选属性,该属性定义该包的命名空间。
- abstract:该属性是一个可选属性,它指定该包是否是一个抽象包,抽象包Action定义。
struts 2开发步骤:
(1)编写一个能发送请求的页面:表单或是超级链接.
(2)编写一个Action类:
1.推荐实现Action接口或是继承ActionSupport。
2.为每个请求参数,包括需要传到下一个页面显示的数据提供Field。
并提供Setter和Getter方法。
3.要有无参数构造器。
(3)在struts.xml文件配置Action。
struts.xml配置:
1.常量配置
2.包配置和命名空间配置。
这种设计主要是为了企业应用的模块化开发。把多个配置文件以include的方式包含进来。
3.处理结果的配置。
Action中处理用户请求的方法:① 该方法不能有形参声明
② 返回值是String
传统的MVC:
(1)Servlet(控制器)调用Model处理完用户请求之后
(2)requst.getRequestDispatcher("/abc.jsp").forward(request,response);
这种方式下,坏处:
1. 跳转代码,已经写死,跳转到某一物理视图。(硬编码与物理视图耦合)
2. 在未来的日子里,软件可能要跳转到其他页面(甚至不再使用JSP视图),如果是硬编码耦合,必然需要手动修改代码。
Struts 2的做法:
(1)Action调用Model处理完用户请求之后。
(2)只是返回一个String类型的逻辑视图名。
(3)然后在struts.xml文件通过<result.../>元素定义了“逻辑视图名”于物理视图之间的对应关系。这样就把原来的硬编码耦合,提取到XML中进行管理。
逻辑视图名与物理视图的关系,是通过<result.../>元素来管理。
<result name="" type="">
<param> </param>
<param> </param>
...
</result>
支持如下属性:
- name:指定逻辑视图名。默认是success。
- type:指定你使用的物理视图类型。默认值就是dispatcher。
如果有如下result配置:
<result name="逻辑视图名"type="视图类型">
<param name="location">物理视图的位置</param>
<!--是否解析OGNL表达式的值-->
<param name="arse">true</param>
</result>
就可以简化为如下写法:
<result name="逻辑视图名"type="视图类型">物理视图的位置</result>
在struts-default.xml文件中的struts-default抽象包中:
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
<result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
<result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
<result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
<result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
<result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>
<result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
<result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>
<result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
<result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />
/************************
forward与redirect的区别?
forward :依然是一次请求,地址栏URL没有变化。请求参数和请求属性都不会丢失。
redirect:重新发送一次新的请求,(就跟直接在地址栏输入新URL,并回车的效果是一样的)
地址栏URL会改变。请求参数和请求属性会全部丢失。
************************/
常见的结果类型:
chain - Action处理完用户请求之后,转发到下一个Action继续处理。形成“链”式处理。
redirect - 直接“重定向”到新的URL
会生成一次新的请求,原有的请求参数,请求属性都会丢失。
与默认的dispatcher“转发”对应的。
dispatcher - 默认值。
转发到JSP页面。
plainText - 直接显示视图页面的源代码。
一般不会太大的用处。只要用于显示源代码。
steam - 直接生成“二进制”流作为响应。
全局result与局部result:
result元素放在Action,就是局部result。
result元素放在global-results,就是全局result。
尽量少用全局result--只有在多个Action都具有某一通用性质的result时,才考虑使用全局result。
/****************************
Struts的配置文件,包括:
struts-default.xml ----struts2的核心包使用该配置文件。
struts-plugin.xml ----struts2的插件包使用该配置文件。
struts.xml ----strust2应用使用该配置文件。
struts-abc.xml ----这种其他的配置文件,必须用include才会加载。
****************************/
动态结果:
在定义的物理视图资源时,可以直接使用OGNL表达式。所以在这个物理视图资源可以动态的改变。
动态方法调用(DMI Dyna Methdo Invocation):
用处不是特别大!大致了解就行了。
功能:可以提交请求时,直接提交给Action的指定方法。
就是在页面指定请求地址为:action名字!方法名
--表明将请求提交给指定的Action的指定方法进行处理。
如: JSP页面的Form
<form action=”LoginRegistAction!regist.action”>
.....
</form>
Struts.xml
<action name=”login” class=”advance.LoginRegistAction” method=”login”>
<result.../>
</action>
为什么少用动态方法调用:
- 动态方法调用的安全性不高。
- 其实完全可以通过在Action元素中指定method属性来代替动态方法调用的功能。
===========================Struts 2的国际化===============================
程序国际化:
程序可以根据机器所在的国家、语言环境,自动显示当前国家、语言的内容。
国际化的本质:查找、替换。
国际化的步骤:
(1)为不同国家、语言环境提供相应的资源包。
如果你的国际化语言资源包中有非西欧字符,要使用nativeascii命令处理该文件。
(2)在程序中输出国际化信息的key。
Struts 2的国际化:
1.支持模块化加载。
2.Strust 2支持自动加载国际化资源。
1.JSP页面的国际化:
A。需要手动加载国际化消息。
使用<s:i18n name="">
B。在页面上使用<s:text .../>根据key来输出国际化消息。
如果是表单标签,直接使用key来指定国际化消息。
2.Action的国际化:
A。自动加载国际化消息。
让国际化消息的baseName与Action的类名相同,并且放在同一个目录下。
B。在Action类中调用getText()方法来加载国际化消息。
3.包范围的国际化:
A。自动加载国际化消息。
让国际化消息的baseName为package(不是与包名相同),并且放在该包的目录下。
--可以让该包下的所有Action共享同一个国际化资源文件。
B。在Action类中调用getText()方法来加载国际化消息。
4.全局国际化资源文件。
A。通过一个常量:struts.custom.i18n.resources来加载国际化资源文件。
B。全局国际化资源文件,既可被Action访问,也可以被JSP页面访问。
全局国际化资源文件的方式尽量少用!这样不利于项目后期的升级和维护。
/****************************************************
Action接口与ActionSupport实现类:
ActionSupport实现类实现了Action接口。
而且增加了输入校验支持、国际化支持等功能。
*****************************************************/
struts 2默认根据浏览器的语言环境设置来选择自己的语言、国家的环境。
struts 2还提供了机制,让用户来选择自己的语言、国家的环境。
A。根据request_locale来确定的。
struts 2的异常处理:
传统的Web编程的异常模式:
try{
//业务代码
}
//异常1
catch(XxxException ex){
forward("/a.jsp");
}
//异常2
catch(YyyException ex){
forward("/b.jsp");
}
//异常3
catch(ZzzException ex){
forward("/c.jsp");
}
对于Action的处理方法而言,处理结果可能出现如下的情况:
1.正常执行结束,会返回一个String类型的逻辑视图。
对于String类型的逻辑视图,使用
使用<result name="逻辑视图名">物理视图资源</result>
2.遇到异常,返回一个异常对象。
<exception-mapping exception="异常类" result="逻辑视图名"/>
Struts 2的异常配置的本质:
为不同的异常类,“起一个”逻辑视图名。
Struts 2设计的处理方法完全不需要处理任何异常,他可以声明抛出任意的异常。
如果希望在错误页面上,显示异常提示:
<s:property value="exception.getMessage()"/>
Java领域的MVC框架
- Struts 2主要实现了控制器。(StrutsPrepareAndExecuteFilter+Action)
- 提供了大量的标签库,可以简化View的开发。
==============================OGNL表达式=======================================
OGNL(Object Graph Navigation Language)
回顾JSP 2 EL - 做数据访问的工具,并不是编程语言。
所以它必然很简单。
EL 开始就提供了11个内置对象。P142
pageContext
pageScope
requestScope
sessionScope
applicationScope
param
paramValues
header
headerValues
cookie
initParam
${requestScope.abc.xyz.def} 当请求参数多个值时:XxxValue。 "."相当于的。
OGNL
既然要访问数据,必须要有个东西装数据,
OGNL的装数据的东西叫“Stack Context (OGNL Context)”,
--可以理解它相当于一个Map。
1.它里面的每一个对象,都应该有个名字,根据名字来访问。
#对象名
假如OGNL Context中 有3个对象:foo、bar、test
#bar.abc - 访问bar对象的getAbc()返回值。
#test.xyz.abc.def - 访问test对象的getXyz().getAbc().getDef()
2.OGNL Context中有个根(root)对象。如果我们要访问(root)对象的属性,可以省略对象名
假如OGNL Context中有3个对象:foo、bar、test,但bar是根对象。
abc.xyz.def - 访问bar.getAbc().getXyz().getDef()。
3.OGNL可以直接创建List对象:{ele1,ele2,ele3,ele4......}
4.OGNL可以直接创建List对象:#{key1:value1,key2:value2,key3:value3,key4:value4......}
5.OGNL还可以直接获取“自集合”
person.cats.{? #this.age > 2} --获取person所养的cat中age大于两岁的cat。
person.cats.{^ #this.age > 2} --获取person所养的cat中age大于两岁的第一个cat。
person.cats.{$ #this.age > 2} --获取person所养的cat中age大于两岁的最后一个cat。
6.OGNL还支持直接调用静态方法:
(struts.ognl.allowStaticMethodAccess常量设为true)
类名@静态Field
类名@静态方法(参数值)
Struts 2控制标签:
if/elseif/else - 判断语句
iterator - 迭代集合
append/merge - 把两个或以上的集合合并成一个集合
generator - 按耨中规则把字符串分割成一个新的集合。
subset - 截取子集合。
Struts 2数据标签:
set - 定义一个变量。可以将变量放入指定的scope中。
property - 输出指定表达式的值,如果指定了value属性,就输出value属性对应的值。
如果没有指定value的值,就输出ValueStack栈顶的值。
bean - 创建一个Bean对象。var指定对象的名(Stack Context中)。name指定实现类。
debug - 帮忙调试。可以开发者观察ValueStack以及Stack Context中的数据。
i18n - 为指定页面加载国际化资源文件,name指定国际化资源包的baseName。。
text - 输出表达式的值。也通过name指定国际化消息的key。
action - 可以直接在页面上调用指定的Action
可以直接把Action的处理结果包含在本页面上。
name和namespace确定调用哪一个Aciotn。
var:指定将被调用Action放在Stack Context(官方式胡扯的。)
executeResult:指定被调Action的处理结果完全包含当前页面中。
ignoreContextParams:控制当前页面请求参数,是否传入被调的Action。
功能是比较有用的 - 假如我们进入一个添加用户的页面:
用户名:□□□□□□
密码: □□□□□□
性别: 下拉菜单 <s:action var="genders" name="listGender"/>
学历: 下拉菜单 - 来自系统数据库中的数据。
籍贯: 下拉菜单 <s:action var="jiguans" name="listJiguans"/>
dete - 对日期进行格式化输出。
name:指定要格式化输出的日期。
format:指定格式字符串。
include - 用于包含指定的JSP页面。
param - 用于设置参数。
push - 把表达式的值,放入ValueStack的栈顶。
当我们的对象所在对象图“很深”时,
可以将该对象“推入”ValueStack栈顶。
UI标签:
主题与模板
当我们在页面上使用的s:textfield标签,他生成两列布局,并提供了label标签。
--因为struts 2为所有的标签都提供了一个模板。
每个标签所表现的效果 -- 有它对应的模板所决定的。
如果为所有的标签都提供了模板,这一系列的模板组成了主题。
Struts 2默认提供了3个主题:
simple :没有额外的附加行为的主题。
只生成最核心的Html元素。(比如两列布局,Label全部没有)
xhtml :默认主题。
1.两列布局。
2.生成label。
3.输出错误提示。
4.客户端校验支持。
css_xhtml :就是在xhtml增加一些样式。
如果有需要,我们也可以针对自己的羡慕开发自定义主题。
如何设置主题?
1. 为我们的标签设置theme属性。子标签默认使用父标签所设置的主题。
2. 通过page\request\session\application范围内的theme来设置主题。
3. 也可直接常量struts.ui.theme来设置主题
这些UI都可以指定CSSClass、CSSStyle来指定CSS样式。
还可以指定大量的onXxx属性,用于绑定JavaScript函数。
表单标签:
checkbox - 生成单个复选框。
head - 引入一些辅助的css样式单和js脚本。
file - 生成一个文件上传域。
form - 生成一个表单域。
hidden - 生成一个隐藏域。
label
password - 生成一个密码框。
reset - 生成重置按钮。
submit - 生成提交按钮。
textarea - 生成一个多行文本域
textfield - 生成一个单行文本框
可以与action合用。
checkboxlist - 生成多个复选框。
radio - 生成多个单选框。
select - 生成下拉菜单。
optgroup - 生成下拉菜单子菜单。
combobox - 生成一个文本框与列表框的组合(不能用中划线"-")
updownselect - 生成菜单,可下移。
optiontranferselect - 生成菜单,两个updownselect的组合。
doubleselect - 两个列表框,而且有级联效果(form中的action必须有值)。
token - 防止刷新
默认情况下,如果没有进行防止刷新控制,每次刷新都会添加一条相同的记录。
(1)需要在表单添加<s:token/>
(2)在相应的配置文件中增加一个拦截器<interceptor-ref name="token"/>
以及默认的拦截器 <interceptor-ref name="defaultStack"/>如果拦截器检测到用户刷新,
会返回一个invalid.token的逻辑逻辑视图名
(3)给invalid.token的逻辑逻辑视图名指定一个物理视图。
非表单标签:
actionerror/actionmessage - 它们体现的struts 2的信息机制。
当我们需要把action中的一段文本,传入下个页面时,
就可以借助Struts 2的信息机制。
1)Action中可以通过addActionError()或addActionMessage()来添加消息。
2)接下来皆可以在下一个页面上使用<s:actionerror/>或<s:actionmessage/>输出消息。
fielderror - 输出类型转换失败、输入校验失败后的错误提示。
文件上传:
传统的文件上传:
(1)需要将form的enctype设置为multipart/form-data。此处会将整个表单
以二进制流的形式上传。
(2)接下来就无法用request.getParameter()来获取请求参数。
(3)需要提供一个文件上传组件(SmartUpload、Common-FileUpload)
(4)Servlet通过文件上传组件来获取请求参数,获取上传的文件。
得到上传文件后,以IO流的方式把文件写入磁盘。
Servlet 3.0以后:
只要增加@MuitiparConfig来修饰Servlet。
接下来就可以用request.getParameter()来获取普通请求参数。
用request.getPart()获取上传文件。
得到上传文件后,以IO流的方式把文件写入磁盘。
Struts 2的更简单:
<1> 每个文件上传域,需要在Action中提供3个Field进行封装。
1.与文件上传域的name同名的,类型为File的field。
2.名为 文件上传域的name + FileName,类型为String的field。
3.名为 文件上传域的name + ContentType,类型为String的field。
<2> 使用IO流控制将文件写入服务器的物理磁盘。
文件的过滤:
A。只允许上传指定类型的文件。
B。只允许上传指定大小的文件。
文件过滤的方式有两种:
1)在Action通过代码进行控制。
File类型的File可以获取上传文件的大小。(long)
String类型xxxContentType可以获取上传文件的类型。
通过判断上传文件的大小、类型,即可对上传文件进行过滤。
2)使用fileUpload拦截器进行过滤。
只要进行简单配置即可。
1.启用fileUpload的拦截器。当文件过滤失败时,Struts 2会返回input逻辑视图名。
2.需要为input逻辑视图名配置一个物理视图。
需要配置:
allowedTypes:该参数指定允许上传文件类型,多个文件类型之间以英文逗号","隔开。
maximumSize: 该参数指定允许上传文件大小,单位是字节。
3.更改错误提示:
要通过如下两个国际化消息的key:
struts.messages.error.content.type.not.allowed=您上传的文件类型只能是图片文件!请重新选择!
struts.messages.error.content.type.too.large=您上传的文件太大,请重新选择!
文件下载:
可能有人疑问:直接把文件放在Web应用的根路径下,即可实现下载。
但实际上可能存在如下问题:
1.当文件名有中文字符时,就无法下载了。
2.直接放在Web应用的根路径下,将导致所有人可以自由下载该资源,毫无安全性可言。
为了解决上面两个问题,此时就需要通过Struts 2的文件下载进行控制。
实现文件下载的Action,关键只有一条:
要提供一个返回值为InputStream的getter方法。
--该方法代表文件下载的入口,它就是要让客户下载的文件的输入流。
借助于Struts 2的文件下载之后,
--所有的文件下载都需要经过Struts 2的Action处理。
因此Action就可以对是否允许用户下载进行控制。
Struts 2 的一个常见的错误:
在迭代的时候,var命名别名是要注意避免冲突。
Struts 2类型转换:
1.struts 2内置了强大的基于OGNL的转换机制。
2.struts 2允许开发者开发自定义类型的转换器。
3.如果转换失败。struts 2的conversionError会自动起作用,跳转到input的逻辑视图名。。
input逻辑视图名 -- 代表上传文件的类型不允许,大小超过指定规定。类型转换失败。输入校验失败。
Struts 2内置的转换器:
boolean和Boolean:完成字符串和布尔值之间的转换。
char和Character:完成字符串和字符之间的转换。
int和Integer:完成字符串和整型值之间的转换。
long和Long:完成字符串和长整型值之间的转换。
float和Float:完成字符串和单精度浮点型值之间的转换。
double和Double:完成字符串和双精度浮点型值之间的转换。
Date:完成字符串和日期类型之间的转换,日期格式使用用户请求所在的Locale的SHORT格式。
数组:在默认情况下,数组元素是字符串,如果用户提供了自定义类型转换器,也可以是其他复合类型的数组。
集合:在默认情况下,假定集合元素类型为String,并创建一个新的ArrayList封装所有的字符串。
================================================================================================
其中Date转换器很容易失败 -- 原因是因为Struts 2要求日期格式必须符合用户请求所在的Locale的SHORT格式。
自定义类型转换
在某些时候,出于一些非常极端的场景,程序需要完成如下的转换:
String → 自定义的复合类
这种转换是特定业务要求的,因此只能由自定义转换实现
(1) 为了实现自定义转换器,需要实现一个TypeConverter接口。但实际上,为了简化开发,推荐继承StrutsTypeConverter基类
TypeConnverter(接口)
↑
DefaultTypeConverter
↑
StrutsTypeConverter
但实际上,为了简化开发,推荐继承StrutsTypeConverter基类
继承实现StrutsTypeConverter基类时,需要实现如下的两个抽象方法:
- Object convertFromString(Map context, String[] values, Class toClass)
把字符串字符类型的请求参数请求,转换为实际所需的类型。
- String convertToString(Map context,Object o)
把实际类型的对象,转换成字符串字符类型
关键是实现第一个方法。
(2)注册类型转换器。
局部类型转换:在Action所在的包下,增加Action类名-conversion.properties文件,该文件包含如下内容:
属性 = 转换器类名。
对Action类名 的 指定属性 使用指定转换器,进行转换。
全局类型转换:在src目录下,增加xwork-conversion.properties,该文件包含如下内容:
类型 = 转换器类名。
对所有Action 的 指定类型 的 使用指定转换器,进行转换。
默认的defaulsStack中已经包含了conversionError拦截器。
当类型转换失败时,conversionError拦截器跳转到input逻辑视图。
默认的错误提示是:Invalid field value for field {0}.
如果需要使用自定义的错误提示信息:
A.全局方式:增加一个全局的国际化资源文件。
在该文件中增加key为:xwork.default.invalid.fieldvalue的国际化消息即可。
在struts.xml或是jsp页面中配置国际化。
B.局部方式:专门为指定的Action的、指定属性指定转换失败的错误提示。
因此这种方式的错误提示更有针对性,更具体。
为指定的Action增加一个Action范围的国际化资源文件。
在该文件中增加key为:invalid.fieldvalue.(Action中自定义转换的属性名)的国际化消息即可。
==============Struts 2 输入校验===============
类型转换和输入校验是“牢牢”结合的。
String类型请求参数
↓
类型转换(可能失败)→conversionError拦截器跳转到input逻辑视图。
↓
输入校验 (可能与我们业务要求不符合)
只有通过了① 类型转换、② 输入校验后的数据,才能去调用Action。
Struts 2 输入校验十分简单
客户端校验:防止用户的误输入,从而降低服务器的负担。
服务器校验:它是整个应用最后的安全防线。
Struts 2的输入校验,完全是模块化进行的。
需要校验哪个Action,
1.让Action继承ActionSupport基类。
2.为该Action增加校验规则文件。--Struts 2会自动加载该校验规则文件。
3.校验规则文件的文件名应该是Action类名-validation.xml。每个校验器就对应一条校验规则。
4.当校验失败是,会跳转到input的Result,因此需要配置一个名为input的result元素。
Struts 2内置了大量的校验器
常用的:
required validator - 必填
date validator - 判断必须在指定日期范围内的。
double validator - 判断必须在指定double范围内的。
int validator - 判断必须在指定int范围内的。
expression validator - 表达式校验器。要求必须满足某一表达式。
regex validator - 正则表达式校验器。要求必须满足某一正则表达式。
email validator - email校验器
url validator - url校验器
(均可用regex validator替代)
stringlength validator - 字符串长度必须在指定日期范围内的。
错误提示消息的国际化:
错误提示信息,有两种方式指定:
A。<message>提示信息</message> -- 错误提示信息不会国际化。
B。<message key="消息key"> -- 错误提示信息会国际化。
客户端校验:
1.表单标签应该用struts 2的s:form来定义表单。
2.为s:form标签增加validate="true"属性。
使用客户端校验:有一点需要注意:
如果依然使用Action范围的国际化资源文件来生成错误提示,表单页面将无法加载国际化资源文件。
此时就必须使用全局变量的国际化资源。
(有些校验器规则,在客户端校验不支持。如:fieldexpression)
校验器有两种配置风格:
1.字段优先的配置风格。(优先使用)
2.校验器优先的配置风格。
--通过为校验器指定fieldName参数,来确定该校验器要校验哪个字段。
校验规则文件的搜索顺序:
假如:
BaseAction (BaseAction-validation.xml)
↑
UserAction (UserAction-validation.xml)
↑
RegistAction (RegistAction-validation.xml)
那么RegistAction的校验文件为:BaseAction-validation.xml
UserAction-validation.xml
RegistAction-validation.xml
一共是3份校验规则文件的校验总和。
===========================拦截器=============================
Struts 2内置了大量的拦截器,来完成系统的绝大部分通用功能。
配置了这些基本的拦截器之后,
Struts 2又为我们定义了大量的为特定功能组合的拦截器栈。
考虑到大部分开发者技术叫差,struts 2又定义了一个默认的拦截器栈(defaultStack/completeStack)
-- 它不一定是性能最好的,但他是最通用的,最通用的。
拦截器配置中,涉及好如下元素:
(1)
<interceptor name="拦截器名字" class="拦截器类">
<param name="excludeMethods"/> -- 用于为拦截器参数指定默认值。
</interceptor>
-- 配置一个拦截器。
(2)
<interceptor-stack name="拦截器栈的名">
<interceptor-ref name="已有的拦截器"/>
<interceptor-ref name="已有的拦截器"/>
<interceptor-ref name="已有的拦截器"/>
<interceptor-ref name="已有的拦截器">
<param name="excludeMethods"/> -- 用于为拦截器参数指定参数值。
</interceptor-ref>
...
</interceptor-stack>
-- 配置一个拦截器栈。
从功能上来看,拦截器栈相当于是大的拦截器。
(3)<default-interceptor-ref name="已有的拦截器或拦截器栈"/>
一旦为某一个包指定了默认的拦截器,如果该包中的Action没有显式指定拦截器,则默认的
拦截器将会起作用。
如果我们为该包中的Action显式应用了某个拦截器,则默认的拦截器将不会器作用。如果该
Action需要使用该默认拦截器,则必须手动配置该拦截器的引用。
开发自定义拦截器:
拦截器一般用于一些具有通用性质的、而且横跨多个Action的相同的逻辑。
(1)开发拦截器实现类,拦截器实现类需要Interceptor接口。
实现给接口就需要实现它的3个方法。
如果需要为拦截器实现类配置参数,就需要在拦截器中定义一个与参数同名的field
并为之提供setter和getter方法。
(2)使用<interceptor.../>元素定义拦截器。
还要用<interceptor-ref.../>使用拦截器。
当然,可以把我们开发的拦截器添加到默认的拦截器中。
输入校验
完全自定义的输入校验
假设有如下需求,系统要求用户名不能与系统中已有的用户名重名。
这种校验要求,它具有一定的业务相关的并不是通用的校验。
struts 2允许开发者通过重写validete()进行校验。
-- 只有当我们要进行校验,是特定业务要求的,才考虑该方法。
推荐采用的校验方式:
(1)优先考虑使用-validetion.xml校验规则文件来进行输入校验。
(2)只用对于一些特定业务相关的校验规则,考虑重写validetei()方法来进行校验。
Ajax:
在后台以“异步”方式发送请求,并以服务器响应局部更新页面。
Struts 2的Ajax支持:
无需Dojo的支持
(1)通过stream类型的ersult实现:
1.客户端浏览器通过JavaScript向服务器发送Ajax请求。
2.
.A 开发一个Action,
让该Action返回一个InputSream作为响应。
.B 配置该Action,指定stream结果类型。
该结果类型向客户端生成文本响应 -- 这就是Ajax响应。
3.在浏览器中动态加载、并显示服务器相应。
(2)通过JSON插件来实现。
JSON是一种轻量级的数据交换格式。
{} - 对象。
[] - 数组。
(1)添加JOSN插件。复制一个插件JAR包即可。
它提供了json-default的包,该包继承了struts-default。
而且在该包中提供一个json类型的Result。
(2)使用JSON插件之后,关于配置Action时可以指定一个类型为json的result。
json类型的Result会把整个Action实例转换JSON字符串后 直接所谓服务器响应
需要注意,让我们包要继承json-default包。