1.为什么学习Struts框架
a.Struts框架好处
struts2是主流的开发技术,大多数公司在使用,struts把相关的servlet组件的各种操作都进行了相应的封装,这样就可以轻松地完成复杂的操作。Struts2是基于MVC模式开发的,MVC结构是一个优秀的设计思想,可以提高程序结构的灵活性,便于日后的维护和扩展。
--简化开发工作量,提高开发效率
--采用了优秀的设计思想(MVC)
b.Struts框架作用
struts充当控制器,接收请求,分发处理,
c.如何学习Struts框架
先重点掌握框架使用,原理性有余力可以多了解些。
注:我们目前使用的Struts版本为struts2 2.1.8。(2.1.6版本bug较多)
d.学校struts要掌握的重点:
valuestack
action
result
拦截器
标记库
2.MVC模式在JavaWeb中的应用
*a.什么是MVC
是一种软件架构的思想,将一个软件的组成部分划分成三种不同类型的 模块,分别是:
模型(用于封装业务逻辑,包括业务数据和业务处理逻辑,由JavaBean组件 (比如实体类,DAO,Service)实现),
视图(负责显示界面与用户交互,处理表示逻辑,一种是展示数据,另一种 是接受数据,由jsp组件实现),
控制器(用于控制流程,协调模型与视图,由Servlet、Filter组件(比如之 前的ActionServlet)实现)。
使用mvc的最主要的原因是为了实现模型的复用:即模型只需要开发 一次, 模型不关心处理的结果如何展现,模型将结果交给不同的视 图,由视图来展 现这些数据;另外,可以利用不同的视图来访问 同一个模型。
MVC:基于面向对象的一种常见的体系架构
Model:
封装数据以及对数据操作的方法(相当于饭店中做菜的材料(数据)和做菜的厨师(方法)
一个流程用一个方法
View:
封装的是用户界面,接收用户请求,负责输入和输出(和用户打交道)(相当于服务员)
Controller:
封装的是业务流程,控制业务流程(相当于饭店中的管理者)(如果程序比较简单,可以把Controller写在Model里面)
b.为什么使用MVC
企业程序更强调结构灵活,易于扩展和升级。所以广泛选用MVC模式开发。
*c.JavaWeb中如何实现MVC结构
JavaWeb技术主要有:Servlet,JSP,JavaBean,Filter,Listener等
V部分:JSP组件 (cart.jsp)
M部分:JavaBean组件(entity,dao)
C部分:Servlet,Filter组件 (ShoppingCartServlet)
*d.MVC处理流程
--首先浏览器发出请求
--请求进入C控制器
--C控制器调用M模型组件处理
--M模型组件处理后返回处理结果
-- C控制器调用V视图组件生成响应信息
*e.Struts框架的MVC实现
原有ShoppingCart程序,虽然符合MVC结构,但不适合大型项目开发,因为请求一多,ShoppingCartServlet会出现大量的if..else... ,可以进行以下方式的改造:
为ShoppingCartServlet配置一个XML文件,该文件定义不同请求和不同Action组件的对应关系,将原有if..else..分支处理用Action组件封装。
**f.Struts框架的处理流程
--浏览器发出struts请求
--请求进入struts控制器
--struts控制器解析xml配置文件(xml定义了请求和Action对应关系)
--控制器根据不同请求,调用不同的Action
--Action调用DAO处理请求,之后返回结果
--控制器根据结果调用视图组件为用户响应
struts总结
3.了解Struts历史
Struts框架分成Struts1和Struts2.Struts2和Struts1没有必然联系。Struts2是以WebWork框架核心(xwork)为基础构建起来
最早出现的Struts1是一个非常著名的框架,它实现了MVC模式。Struts1简单小巧,其中最成熟的版本是Struts1.2。之后出现了WebWork框架,其实现技术比Struts1先进,但影响力不如Struts1。在框架技术不断发展过程中,有人在WebWork核心XWork的基础上包装了Struts1(算是两种框架的整合),由此,结合了Struts1的影响力和WebWork的先进技术,Struts 2诞生了。所以说,Struts2不是Struts1的升级,它更像是WebWork的升级版本。
*4.Struts基本使用
a.引入struts2核心开发包(5个)
(1).struts2-core-2.1.8.1.jar
Struts2核心包,是Struts框架的“外衣。
(2).xwork-core-2.1.6.jar
Struts2核心包,是WebWork内核。
(3).ognl-2.7.3.jar
用来支持ognl表达式的,类似于EL表达式,功能比EL表达式强大的
多。
(4).freemarker-2.3.15.jar
freemarker是比jsp更简单好用,功能更加强大的表现层技术,用来 替代jsp的。在Struts2中提倡使用freemarker模板,但实际项目中使 用jsp也很多。
(5).commons-fileupload-1.2.1.jar
用于实现文件上传功能的jar包。
b.在web.xml中配置下struts控制器
c.根据请求编写Action,JSP
d.在struts.xml定义Action和请求对应关系
5.HelloWord入门实例
welcome.action-->Struts控制器-->struts.xml-->WelcomeAction
-->welcome.jsp
(Action请求可以是/welcome.action或者/welcome两种写法)
7、struts.xml基本配置
struts.xml放在src根目录下。
a)
根元素,可以包含多个
b)
元素主要用于将Action分组定义。name属性用于指定包名;extends一般指 定为struts-default。struts-default这个包在struts-default.xml中定义,其中 包含了struts2运行所需的必要组件。
添加namespace属性的主要作用是避免在大项目中出现的命名冲突问题。
注意:
http://localhost:8080/struts01/netctoss/welcome
extends="struts-default">
namespace属性默认为“/”(即从应用名后的第一个"/"开始到最后一个“/”结束)。
eg:对于http://localhost:8080/struts01/netctoss/cost/showList.action
其中的namespace属性值应为”/netctoss/cost”。
eg:
如果不加namespace="/netctoss"那么
http://localhost:8080/struts01/netctoss/list.action便不会得到正确的匹配
一个
和Action组件的对应关系。name属性指定请求名;class属性指定Action的包
名.类名
c)
一个
其中
(1).method属性可以省略,如果省略则默认调用Action中的execute()方法
(2.)如果不指定class属性,Struts会默认调用框架底层的ActionSupport
类处理(见下面:)。框架会默认为该
转发到对应
的
来时,struts不会调 用action(找不到)而是直接调用result中name属
性为success对应的页面。
注:name=”success”可以省略
struts总结
--------ActionSupport类:---------
public String execute(){
return “success”;
}
d)<result>
e:注意:
1.对于package、action、result,如果使用默认属性值,则可以省略属性名。
eg:
如果使用默认属性值:则可以写成:
对于重复使用的result可以写成全局的result
<global-results>
<result name="error">/WEB-INF/jsp/error.htmlresult>
<result name="login" type="redirectAction">showLoginresult>
global-results>
2.page包中的各组件的放置顺序:
具体见struts-2.1.7dtd
package (result-types——> interceptors——>default-interceptor-ref——>
default-action-ref——> default-class-ref——> global-results——>
global-exception-mappings——> action*)>
拦截器配置放在global-results之前
3.当项目业务处理较多时如果将所有的配置都写在struts.xml一个文件中将很不方便,所以可以将不同的处理模块分别写在不同的xml文件中,最后在struts.xml中加载和模块配置文件,过程如下:
struts.xml:
...........
拦截器、全局results....
struts-cost.xml:
........
struts-account.xml:
........
.............................
浏览器访问地址:
http://localhost:8080/应用名/namespace/action
http://localhost:8080/struts03_2/list/costList.action?page=4
以上的namespace默认为’’/’,本例为list
8、如何解决用户绕过ActionServlet,直接访问jsp文件的问题。
将所有jsp文件拷贝到WEB-INF目录下。因为WEB-INF目录中的内容不能直接访问,但能转发过来。
当然也可以用之前的session技术(太麻烦)。
对于struts中WebRoot文件夹下的.jsp页面仍可以直接输入地址访问。
9、Struts2提供的方便之处:
a.数据的自动的封装
根据页面组件的name属性,自动封装到Action中对应的name属性中。
在Jsp页面
在action中会自动给属性private String name 赋值。但是注意要有name对应的getter和setter方法。
b.数据的自动的传递
Action中的属性在jsp页面可以直接用EL表达式拿到
eg:
Action中属性private String name;
在jsp页面上可以直接${name}的到对应的值
按理说,EL表达式取数据的对象只有pageContext,request,session,application四类,不应该从Action对象中取name属性值,但struts框架重新包装了request,getAttribute()方法被改写(request的其他方法没被改写),如果从request对象中调用getAttribute()方法没获取到值(null),那么会自动从action中取,这样,struts中EL表达式就可以直接获取到Action属性中的值了。
上面介绍的采用了包装模式:(相当于手机加壳案例和线程池案例(其中的close方法特殊)。参考如下:
public class StrutsRequestWrapper extends HttpServletRequestWrapper{
//重写
public Object getAttribute(String key){
//寻找原request信息
Object obj = super.getAttribute(key);
if(obj == null){
//寻找valuestack信息
obj = valuestack.findValue(key);
//Ognl.getValue(key,context,root);
} struts总结
return obj;
}
}
${name} -->request.getAttribute("name")
-->Ognl.getValue("name",context,root)
10.项目示例(资费列表显示)
a.显示默认主页面
index.action-->struts控制器-->index.html
b.资费列表显示
feeList.action-->struts控制器
-->FeeListAction-->FeeDAO-->COST
-->fee_list.jsp
1)编写COST对应的Entity实体类
2)编写DAO,DBUtil
--引入oracle驱动包
3)编写Action
4)配置Action
5)编写JSP
--引入jstl.jar,standard.jar
11.OGNL技术的使用
1)什么是OGNL
OGNL是Object-Graphic Navigation Language(对象图导航语言)的缩写,
是一种功能强大的表达式语言(与EL表达式类似)。OGNL可以让我们用非常
简单的表达式访问对象层(访问对象的数据和方法),它用一个独立的lib形
式出现(封装于ognl.jar工具包中),方便我们使用或者构建自己的框架。
OGNL区别于EL表达式,OGNL可以在.java文件中通过getValue()方法访问对
象,而EL表达式不可以在.java文件中使用;EL表达式在.jsp文件中可以直接
输出数据,而OGNL不可以,OGNL在.jsp文件中只能当做struts标签中的属性
值,通过struts标签访问数据。
2)OGNL基本原理
OGNL工具主要由3部分构成,具体如下
a.OGNL引擎
负责解析ONGL表达式,定位数据
b.Root根存储区(Object类型)
负责存储要访问的目标对象(一个)。
c.Context变量存储区(Map类型)
负责存放多个要访问的目标对象。
*3)OGNL基本语法
a.访问Root区域对象基本语法
Ognl.getValue("OGNL表达式", "Map存储器内容","根存储器内容");
Ognl.getValue("OGNL表达式", "根存储器内容");
--访问简单数据:"属性" 例如"name"
int id = (Integer)Ognl.getValue("id", foo);
String name = (String)Ognl.getValue("name", foo);
--访问数组或List集合:"属性[0]"
例如"arr[1]"
String arrVal = (String)Ognl.getValue("arr[1]", foo);
String listVal = (String)Ognl.getValue("list[2]", foo);
--访问map集合元素:"属性['key']"或"属性.key"
例如"map.c"或"map[‘two’]"
注:”map[‘a’]”不可用(‘a’结果为整数)
String mapVal = (String)Ognl.getValue("map.b", foo);
String mapval2 = (String)Ognl.getValue("map['user.name']",foo);
--访问方法:"属性值.方法()",
例如"list.size()"
System.out.println(Ognl.getValue("map['two'].toUpperCase()", foo));
System.out.println(Ognl.getValue("list.size()", foo));
--访问构造方法:"new 包名.构造方法"
例如"new java.util.Date()"
Object obj =
Ognl.getValue("new org.tarena.entity.Foo('TOM')", foo);
--访问静态成员:"@包名.类名@成员"
例如"@java.lang.Math@PI"
Ognl.getValue("@java.lang.Math@abs(-1)", foo);
Ognl.getValue("@java.lang.Math@PI", foo);
--创建List对象:"{元素1,元素2}"
Object obj1 = Ognl.getValue("{'struts','hibernate','spring'}",foo);
--创建Map对象:
"#{key1:value1,key2:value2}"
Object obj2 = Ognl.getValue("#{1:'tom',2:'jack',3:'rose'}", foo);
public static void main(String[] args) throws Exception {
Foo foo = new Foo();
foo.setId(100);
foo.setName("张三");
foo.setArr(new String[] { "A", "B", "C" });
foo.setList(Arrays.asList("芙蓉", "凤姐", "春哥"));
Map
map.put("one", "Java");
map.put("two", "JavaWeb");
map.put("three", "Struts2");
map.put("user.name", "Scott");
foo.setMap(map);
//测试OGNL访问foo目标对象
//Ognl.getValue("OGNL表达式", "Map存储器内容","根存储器内容");
//Ognl.getValue(expression, root);
Map context = new HashMap();
//访问root基本的属性值
int id = (Integer)Ognl.getValue("id", foo);
System.out.println(id);
String name = (String)Ognl.getValue("name", foo);
System.out.println(name);
System.out.println(Ognl.getValue("user.name", foo));
//访问root数组和集合元素
String arrVal = (String)Ognl.getValue("arr[1]", foo);
System.out.println(arrVal);
String listVal = (String)Ognl.getValue("list[2]", foo);
System.out.println(listVal);
//访问root对象的map集合元素
String mapVal = (String)Ognl.getValue("map.b", foo);
System.out.println(mapVal);
String mapval2 = (String)Ognl.getValue("map['user.name']",foo);
System.out.println(mapval2);
//支持运算符
System.out.println(Ognl.getValue("id+1",foo));
//System.out.println((Integer)Ognl.getValue("id",foo)+1);
System.out.println(Ognl.getValue("\"姓名:\"+name", foo));
System.out.println(Ognl.getValue("id > 200",foo));
//方法调用
System.out.println(Ognl.getValue("map['two'].toUpperCase()", foo));
System.out.println(Ognl.getValue("list.size()", foo));
//构造方法的调用
Object obj = Ognl.getValue("new org.tarena.entity.Foo('TOM')", foo);
System.out.println(obj);
System.out.println(Ognl.getValue("name", obj));
//静态方法和常量的调用
System.out.println(Ognl.getValue("@java.lang.Math@abs(-1)", foo));
System.out.println(Ognl.getValue("@java.lang.Math@PI", foo));
//创建一个list集合
Object obj1 = Ognl.getValue("{'struts','hibernate','spring'}",foo);
System.out.println(obj1.getClass().getName());
//创建一个map集合
Object obj2 = Ognl.getValue("#{1:'tom',2:'jack',3:'rose'}", foo);
System.out.println(obj2.getClass().getName());
}
12、OGNL技术在Struts的使用
在Struts2中有一个ValueStack(本质就是存放数据的集合)数据对象,该对象存储了请求相关的所有数据信息。例如request,session,application,action等.
Struts2采用OGNL工具对ValueStack进行操作。
1)xwork对OGNL进行了部分改造
在xwork中将原来OGNL标准结构中的Root存储区改造成了一个栈结构
(CompoundRoot)以前只能存放一个对象,现在进行了扩容,可以存放
多个对象
当利用"属性"表达式访问时,优先去栈顶对象寻找,没有再去次栈顶寻找。
2)ValueStack结构(OgnlValueStack)
ValueStack就是一个容器(Map集合)(存放东西的不是Tomcat容器)
(参考valuestack.jpg)
3)Struts2标签的使用
在JSP中,利用Struts2标签显示数据,需要为标签指定OGNL表达式,标签利用表达式定位ValueStack中的数据,进行相应操作。
a) debug标签:显示valuestack状态
<s:debug>s:debug>
b) iterator标签:循环集合元素
value属性:指定ognl
var属性:指定循环变量,会被存放到ValueStack的context区域。
status属性:指定循环状态变量,会被存放到ValueStack的context区域.该
变量有count属性表示一共循环了多少个元素。
index属性表示当前循环元素的索引。
<s:iterator value="new int[totalPages]" status="i">
<s:if test="#i.count==page">
<a class="current_page"href="costList.action?page=${i.count }">
<s:property value="#i.count"/>
a>
s:if>
<s:else>
<a href="costList.action?page=${i.count }">
<s:property value="#i.count"/>
a>
s:else>
s:iterator>
c) if...else...标签:判断分支
test属性:指定ognl判断表达式
<s:if test="page < totalPages" >
<a href="costList?page=${page+1 }">下一页a>
s:if>
<s:else>
下一页
s:else>
d) property标签:显示数据
value属性:指定ognl表达式
<s:iterator value="costList" var="cost">
<tr><td><s:property value="#cost.id"/></td>
e) date标签:将date数据格式化输出
name属性:指定ognl表达式
format属性:指定日期模板
<td>
<s:date name="#cost.createTime" format="yyyy-MM-dd HH:mm:ss"/>
td>
13、Action组件的相关使用
1)Action组件的原理
--客户发出action请求给struts控制器
--前端控制器截获请求并根据配置信息调用对应的action
--struts控制器会创建valuestack对象
--struts控制器根据请求创建Action对象并将Action压入valuestack的root
栈顶(Action线性安全,不用考虑并发问题,struts会为每一个请求 创
建一个Action对象,区别于Servlet)
--struts控制器调用一系列拦截器做一些辅助性的工作(一般都是
valuestack的操作),如通过parmaeterInterceptor将表单中的数据赋值
给action中的对象;还有将请求相关request,session对象放入到
valuestack的context区域,同时将ValueStack对象存入到request中。
存储的key为”struts.valueStack”。(这样,当一次请求结束后,容器
会销毁request,request销毁了,其中的valuestack对象也就销毁了)
--控制器调用Action,执行业务方法处理(根据输入算输出并返回结果)
--控制器根据Action返回值调用result视图组件处理。
--请求处理完毕,销毁valuestack和Action对象。
一次请求,一个valuestack和action对象
2)Struts中写Action过程:
定输入、定输出、根据输入算输出、返回结果
*3)Action中如何使用session,request
(1).利用ActionContext和ServletActionContext工具类(不推荐)
a.ActionContext返回是Struts框架封装成Map之后的
request,session,application.
eg:
//将用户信息写入Session
ActionContext ac = ActionContext.getContext();
Map
session.put("user", adminCode);
Map
Map
b.ServletActionContext返回的是Servlet中使用的request, session,
application原有类型。
(使用建议:存值取值建议用Map结构API,如果有特殊需求再采用
Servlet原有类型(如获取客户端IP))
eg:
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = httpRequest.getSession();
HttpServletResponse response = ServletActionContext.getResponse();
ServletContext application = ServletActionContext.getServletContext()
ActionContext工具类中的方法getSession()如何将HttpSession对
象封装成Map对象的说明:
Map----impements--->AbstructMap---extends-->SessionMap(重
写了Map中的put和get方法)
----如何将原有HttpSession封装成Map------
public class SessionMap extends AbstractMap{
private HttpSession session;
public SessionMap(HttpSession session){
this.session = session;
}
public void put(Object key,Object val){
session.setAttribute(key,val);
}
public Object get(Object key){
session.getAttribute(key);
}
}
不推荐使用ActionContext访问Session的方式,因为这种方式的“侵入性”较强。ActionContext是Struts2的API, 如果使用其他框架代替目前的Struts2框架,而我们实际项目中的Action的数量非常庞大,每个类都修改的话,会非常麻烦。
(2).利用Aware接口方式注入(推荐)
将Action实现Aware接口,由框架底层将对象注入给Action中相应的变量
当action实例化时候,struts框架就会自动将session对象(在valuestack中)赋值给实现了SessionAware接口的类中的变量(就是注入)。
(即session,ruquest,response,application)
RequestAware 对应的是Map结构的Request
SessionAware 对应的是Map结构的Session
ApplicationAware 对应的是Map结构的Application
ServletRequestAware对应的HttpServletRequest
ServletResponseAware对应的HttpServeltResponse
ServletContextAware对应的ServletContext
eg:
public class LoginAction implements SessionAware{
protected Map
...............
public void setSession(Map
this.session = session;
}
public String execute(){
if(("admin".equals(adminCode)) && ("1234".equals(passWord))){
session.put("user", adminCode);
return "success";
}else{
return "error";
}
}
}
(3)、使用工具类(ActionContext、ServletActionContext)还是
Aware接口?
Action组件内部用Aware接口、Action组件之外(比如后面的拦截器)用ActionContext、ServletActionContext
4)Action属性注入
作用:在创建Action对象时指定属性值
在
Action对象时注入。可以将一些变化的参数值,利用该方法指定。例如
pageSize,管理员用户名,dir存储路径等。
在
属性值
eg:
public class ListAction{
private Stirng param1;
private String param2;
.....
public String getParam1(){
return param1;
}
..... struts总结
public setParam1(Stirng param1){
this.param1 = param1;
}
.......
}
struts.xml:
admin
1234
5)Action通配符配置
Action通配符可以将多个具有相同属性的Action整合为一个Action。
在
性中通过使用{1},{2}引用第一个*号,第二个*号所代表的字符串。
eg:
CostAction.java:
public class CostAction {
//属性定义--省略
public String add(){
System.out.println("资费添加操作");
return "success";
}
public String update(){
System.out.println("资费更新操作");
return "success";
}
}
struts.xml:
class="com.tarena.action.CostAction">
14、Result组件的相关使用
1)Result组件原理
a.Result组件的作用
Result组件负责生成响应视图内容。将ValueStack中的数据做不同形式
的输出。
Struts2框架提供了多种不同的Result组件类型,用于做不同形式响应。
例如json数据响应,流数据响应,jsp响应等。
b.Result组件相关配置
--Result声明定义
--Result使用定义
c.编写一个转发功能的Result组件
定义的类类必须实现Result接口(Result组件),并且将约定的execute方法实现在该方法中编写了生成响应输出的逻辑代码。
public class MyDispatcherResult implements Result{
private String location;
//setter和getter方法
................
//约定方法
public void execute(){
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response =ServletActionContext.getResponse();
RequestDispatcher rd = request.getRequestDispatcher(location);
rd.forward(request,response);
}
}
*2)掌握经常使用的Result组件
a. JSP视图
--dispatcher(默认):以转发方式调用JSP
--redirect:以重定向方式调用JSP
jsp页面
b.Action视图
--chain:以转发方式调用下一个Action
--redirectAction:以重定向方式调用下一个Action
c:
stream:以字节流方式响应,Action中的InputStream类型的属性以
字节流方式输出。
eg:由服务器端生成验证码图片并以流的方式发送给浏览器。
在struts.xml端的配置如下:
<action name="image" class="org.tarena.netctoss.action.ImageAction">
<result type="stream" name="success">
<param name="inputName">imageStreamparam>
result>
<result name="fail">/WEB-INF/jsp/login.jspresult>
action>
注:其中的<param name="inputName">imageStreamparam>区别于Action
属性注入,其作用为:给result对象指定参数值
d:
json:以json字符串响应,将Action中指定的属性拼成一个json字符串输
出。
注:
其中,a、b、c中的result组件在’struts-defaulg”包下,d中的result组件
在”json-default”,struts-core.jar中的默认包
相同命名空间调用:
请求名
跨命名空间调用
请求名
/
======资费删除流程=====
fee_delete.action-->FeeDeleteAction-->FeeDAO
-->FeeListAction-->fee_list.jsp
============练习=============
完成课上项目任务。
扩展任务:完成资费的添加,更新处理,查看,启用等。
16、json Result组件
主要负责将Action的属性以json字符串格式输出。
json Result的使用步骤:
a.引入struts2-json-plugin.jar
b.将
的范围比原struts-default包大,所以更改后仍可以使用以前包中的组件)
c.
//只返回Action中一个属性值
属性名
//返回Action中多个属性值
属性名1,属性名2,属性名3
//返回Action中所有属性值
因为使用name属性默认值,所以name=”success”可以省略。
17、Struts2表单标签
1.什么是标签
struts标签封装了界面显示逻辑,用于简化JSP。
jstl标签用来代替jsp页面中的java代码,struts标签不但可以代替jsp页面中的
java代码,还可以代替jsp页面中html标记
2.struts常用标签:
textfield,password,hidden,textarea
radio,checkboxlist,select
checkbox,form
a) textfield
以输入框方式显示属性值.
name属性指定ognl表达式,表示输入框中的值
<input type="text" class="readonly" name=”cost.id” value=${cost.id}
readonly />
相当于:
<s:textfield name="cost.id" cssClass="readonly" readonly="true">
s:textfield>
注:规定输入字段为只读(内容不可被更改)。在html中input标签readonly属性
直接写,在struts标签中要写成:readonly=”true”。类似的的还有disabled要写成
disabled=”true”
b) textarea
以文本域方式显示属性值.
name属性指定ognl表达式,表示文本域中的值
<textarea class="width300 height70">${cost.descr}textarea>
<s:textarea name="cost.descr" cssClass="width300 height70">s:textarea>
c)password:
以文本框方式显示密码
name属性指定ognl表达式,,表示输入框中的值
注:默认情况下,文本框内不会显示密码,如果要显示密码则需要设置showPassword属性。
密码:<s:password name="password" showPassword="true">s:password>
d) radio:
以一组单选框方式显示,并可以根据属性值决定哪个选项选中。
list属性指定集合ognl,用于生成若干radio选项。
name属性指定ognl,用于决定哪个raido选中。
<s:radio name="cost.costType" list="#{'1':'包月','2':'套餐','3':'计时'}">
</s:radio>
e)checkbox:
以单选框方式显示选中状态
name属性指定ognl表达式,name属性值为true时,单选框默认会被选中
eg:
婚姻状况:<s:checkbox name="marry"">s:checkbox>已婚
f)checkboxlist:
以复选框方式显示选中状态
name属性指定ognl表达式,用来决定哪些复选框默认被选中。
list属性为map
listKey属性为map集合中的key
listValue属性为map集合中的value,为在界面显示的内容
参考struts05_1中的form.jsp
eg1:
爱好:<s:checkboxlist name="chk" list="#session.favors" listKey="id"
listValue="name">s:checkboxlist>
eg2:
<s:checkboxlist name=”” list=”costList’” listKey="id"
listValue="name">s:checkboxlist>
g)select:
以下拉列表的方式显示数据:
name属性指定ognl表达式,用来决定哪个option默认被选中。
eg1:
list="#{‘0’:’暂停’,'1':'开通','2':'暂停','3':'删除'}">
相当于
<option value="2">全部option>
<option value="1">开通option>
<option value="0">暂停option>
<option value="-1">删除option>
>
eg2:
注:对于上面的struts标签中的name属性,不但可以指定ognl表达式获取相关的数据,还可以将action中的属性名设置为name的属性值,这样就可以实现表单数据的自动提交。
h)form:
theme属性:表示主题,可选项有xhtml和simple;如果不写,默认为xhtml 。
theme属性如果为默认值(xhtml),那么在使用struts表单标
签时候会自动添加样式(自动添加tr、tr,让显示更美观),
这样就会破坏当前页面的布局和样式。
如果在用struts表单标签时,没有用struts中的form标签而是
使用html中的form标签,那么在使用struts表单标签时候也
会自动添加样式
.............
通用属性(所有标记都具备的属性):
label
labelpostion
required
tooltip
tooltipIconPath
cssClass(html中的class)
cssStyle(html中的style)
name
value
18、拦截器组件
2)什么是拦截器:
一般利用拦截器封装一些通用性处理功能,便于重复利用。例如请求参
数给action属性赋值、日志记录、权限检查、文件上传、事务处理等。拦截
器通过配置方式调用,因此使用方法比较灵活,便于维护或扩展。
Struts2框架提供了大量的拦截器组件,如果不能满足开发者需要,可以
进行自定义。
eg:
<interceptor name="params"
class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
其中ParametersInterceptor类用于在创建Action对象时将表单中的参数
赋值给Action中的相关属性。
具体见:
ReferencedLibraries/struts2-core-2.1.8.jar/struts-default.xml
/
2)拦截器完整工作流程:
上图中的FilterDispatcher为前端控制器
a.客户发送一个Action请求,请求交给控制器
b.控制器创建一个ValueStack、Action对象,并将Action压入ValueStack栈顶
c.控制器调用ActionInvocation组件执行请求处理
d.ActionInvocation组件调用请求相关的拦截器组件--前部分处理.
e.然后再调用Action组件业务方法
f.然后再调用Result组件处理方法
g.最后执行拦截器组件--后部分处理.
h.将响应信息输出,为客户端响应
3)拦截器作用
拦截器可以在Action和Result组件调用之前执行,也可以在Action和Result
组件之后执行。
4)自定义拦截器
a.编写拦截器组件实现类(两种方法):
1.编写拦截器组件实现类实现Interceptor接口的interceptor方法。
public class MyInterceptor implements Interceptor{
public String intercept (ActionInvocation in){
//拦截器的前期处理逻辑
in.invoke();//执行Action和Result
//in.invokeActionOnly();//仅执行Action
//拦截器的后期处理逻辑
}
}
eg:
public class CheckLoginInterceptor implements Interceptor{
public void destroy() {
// TODO Auto-generated method stub
}
public void init() {
// TODO Auto-generated method stub
}
public String intercept(ActionInvocation in) throws Exception {
System.out.println("(前期处理)自定义拦截器被调用。。。");
ActionContext ac = ActionContext.getContext();
//ActionContext ac = in.getInvocationContext();
Map
//登录检查
if(session.get("user") == null){
//为登录
return "login";//进入登录页面
}
in.invoke();//执行Action、DAO和Result--->jsp
System.out.println("(后期处理)自定义拦截器被调用。。。");
return null;//invoke()方法执行之后,后面的返回值都无效(即不会返回),因为执行in.invoke(),也即执行Action和Result调用Jsp后,返回的值没有任何意义。
}
}
2.所有拦截器组件实现类也可以通过继承AbstractInterceptor类并实现
inteceptor方法。
eg:
public class Interceptor2 extends AbstractInterceptor {
public String intercept(ActionInvocation in) throws Exception {
System.out.println("(前期处理)自定义拦截器被调用。。。");
// ActionContext ac = ActionContext.getContext();
ActionContext ac = in.getInvocationContext();
Map
// 登录检查
if (session.get("user") == null) {
// 未登录
return "login";// 进入登录页面
}
in.invoke();// 执行Action和Result
System.out.println("(后期处理)自定义拦截器被调用。。。");
return null;//invoke()方法执行之后,后面的返回值都无效(即不会返回),写着只是好看一点
}
}
注意:当执行了invoke()方法后,invoke()方法后面的返回值无效(即不会返回),写着只是好看一点。如果没有执行invoke(),返回值有效。控制器会根据该返回值调用一个Result生成响应信息
b.注册拦截器(将拦截器注册给struts2框架)
(1).方法一:
eg:
<interceptors>
<interceptor name="checklogin"
class="org.tarena.netctoss.interceptor.CheckLoginInterceptor2"/>
interceptors>
<action name="costDelete" class=”org.tarena.netctos.CostDeleteAction”>
<interceptor-ref name="checklogin"/>
<interceptor-ref name="defaultStack"/>//调用默认拦截器栈中的拦截器
<result name=”cuccess”>/WEB-INF/jsp/cost/cost_delete.jspresult>
action>
struts总结
(1).方法二
创建拦截器栈(<interceptor-stack name="loginStack">),将多个拦截器放在拦截器栈中,这样就可以在需要的地方直接引入拦截器栈就行了(<interceptor-ref name="loginStack"/>)
eg:
<interceptors>
<interceptor name="checklogin"
class="org.tarena.netctoss.interceptor.CheckLoginInterceptor2"/>
<interceptor-stack name="loginStack">
<interceptor-ref name="checklogin"/>
<interceptor-ref name="defaultStack"/>
interceptor-stack>
interceptors>
<action name="costDelete" class=”org.tarena.netctos.CostDeleteAction”>
<interceptor-ref name="loginStack"/>
<result name=”cuccess”>/WEB-INF/jsp/cost/cost_delete.jspresult>
action>
方法二中的定义拦截器的方法实际上是先定义一个checklogin拦截器,然后定义一个拦截器栈(用于存放多个拦截器),把定义的checklogin拦截器和struts默认的拦截器放在拦截器栈里面。在使用拦截器时候,直接引入拦截器栈就可以了(相当于引入了checklogin拦截器和struts默认拦截器)。
c.使用拦截器组件
(1).为所有Action指定默认使用配置,这样,拦截器便对该包中的所有Action
起拦截作用
--(2).为某一个Action指定使用配置
eg:
<action name="showAddCost">
<interceptor-ref name="loginStack"/>
<interceptor-ref name="defaultStack"/>
<result>/WEB-INF/jsp/cost/cost_add.jspresult>
action>
注意:如果为某个Action指定了拦截器配置,不会再调用指定的默认拦截器.所以一般会加上<interceptor-ref name="defaultStack"/>。
5)fileUpload内置拦截器的使用
a)fileUpload拦截器功能
用于实现文件上传功能。
fileUpload拦截器处理流程:
客户端发送上传文件请求
首先,struts控制器收到请求后调用fileUpload拦截器,fileUpload拦截器调用commons-file-upload.jar上传组件对请求提交
的表单信息进行解析。
然后将解析后的文件保存到服务器临时目录下,并将临时目录下的文件
对象赋值给Action的File属性。
执行Action,在Actin业务中,需要做文件复制,将临时文件转移到目标
目录中。
当Action和Result调用完毕后,清除临时目录下的文件,因此在Actin业务中,需要做文件复制,将临时文件转移到目标目录中。
b)上传示例
注意事项:
--需要引入commons-io.jar)
--form表单method必须为post;enctype必须为multipart/form-data
--Action组件按下面规则接收表单信息
Action属性如下:
private File xxx;// 临时目录下的文件
private String xxxFileName;// 源文件名
private String xxxContentType;// 源文件类型
---struts默认允许上传的文件所占最大内存为2097152字节(不同计算机可
能略有不同)。如果要更改默认设置,可以参考如下“更改struts中的默
认设置”
更改struts中的默认设置(即修改如下配置文件):
ReferencedLibraries/struts2-core-2.1.8.jar/org-apache.struts2/default.properties
18、更改strts中的默认配置:
1.更改对客服端发送过来的参数进行解码的方式:
2.更该允许客户端上传的最大文件大小值:
(默认大小为:2097152字节,约2M)
19、全局异常处理:
<global-results>
<result name="error">/WEB-INF/jsp/error.htmlresult>
global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="error">
exception-mapping>
global-exception-mappings>
20、用户输入不存在请求资源路径(及action不存在)处理:
<default-action-ref name="defaultAction"/>
<action name="defaultAction">
<result type="redirectAction">
<param name="namespace">/param>
<param name="actionName">toLoginparam>
result>
action>
<action name="toLogin">
<result>/WEB-INF/jsp/login.jspresult>
action>
通过此配置后,用户输入非法请求资源路径时便不会出现“404”错误提示了,而是友好地跳转到登录页面。
======NETCTOSS项目========
1)项目描述(一期工程)
实现电信计费系统的账号管理,业务管理,资费管理,管理员和角色管理的功能。
2)项目技术架构
主要采用Struts2,JDBC,Ajax,jQuery技术。
采用MVC结构分层思想开发。
表现层(V):JSP,Ajax,jQuery
控制层(C):Struts2控制器Filter+Action
业务层(M):JavaBean,Bean组件
数据访问层(M):DAO+JDBC
3)项目工程结构
a.开发包引入
--Struts2开发包(5个核心+1个json响应包)
--Oracle驱动包
b.src源码
org.tarena.netctoss.action
org.tarena.netctoss.action.fee
org.tarena.netctoss.action.account
org.tarena.netctoss.service
org.tarena.netctoss.dao
org.tarena.netctoss.pojo
org.tarena.netctoss.util
org.tarena.netctoss.test
c.配置文件
web.xml : 配置struts2控制器
struts.xml:struts2框架主配置
--struts-fee.xml : 资费模块配置
--struts-account.xml:账号模块配置
d.WebRoot
WebRoot/WEB-INFO/jsp/fee/资费页面
WebRoot/styles/样式文件
WebRoot/js/脚本文件
WebRoot/images/页面图片
=========记录检索=========
search.action-->SearchAction-->DAO
1.项目评审
1)自我简介,项目需求描述,功能演示
2)典型功能实现讲解
2.共通问题处理
1)表单校验处理(参考“jQuery表单校验插件”目录的资料)
可以利用jQuery编写校验函数,
也可以基于现有的jQuery扩展插件来实现
例如validate和formvalidate等插件都可以
2)Struts2全局异常处理
当异常抛出Action的业务方法时,可以利用全局异常处理方式解决(在struts.xml追加配置)。
3)将页眉导航部分提取成一个head.jsp,
通过include方式引入各个页面。
4)设置一个默认响应Action。
遇到不能识别的Action请求,或找不到请求对应的Action时,调用该默认Action做响应
1, 当Action设置了某个属性后,Struts将这些属性封装一个叫做Struts.valueStack的属性里。获取valueStack对象: ValueStack vs = (ValueStack) request.getAttribute("struts.valueStack");
调用ValueStack 的vs.findValue("books")方法(books为Action中的属性);
2, struts2的Action类是一个普通的POJO类(通常包含一个无参的execute方法)从而很 好的重用代码。
4,struts2通常直接使用Action来封装HTTP请求参数,所以Action中要定义与请求参数对应的属性,并且为该属性提供相应的 getter和setter方法。
5,即使Action需要处理的请求name和pass两个HTTP请求参数,Action类也可以不包含name和pass属性,因为系统是通过对应的 getter和setter方法来处理请求参数。而不是通过属性来处理请求参数的。所以Action类是否包含name和pass属性不重要, 重要的是需要setter和getter方法。
6,Action类的属性,不仅可以封装请求参数,还可以用于封装处理结果,通过Struts2标签来输出对应的属性值。如
7,ActionContext类。Struts2的Action并未直接与任何Servlet api耦合,从而更加方便测试该Action(可以通过脱离web容器测试Action)。但是对于Web应用的控制器来说,不访问Servlet api 几乎是不能的。例如跟踪HTTP session状态等。访问的Servlet Api 就 是HttpServeltRequest、HttpSession、ServletContext,这三个类分别jsp内置对象中的request、session、application。Web应用中提供了一个ActionContext类,Struts2的Action可以通过该类来访问Servlet api。
该类的ActionContext提供getContext方法得到ActionContext实例,
该类的方法:
①Object get(Object key),该方法类似于HttpServletRequest的getAttribute(String name)方法;
②Map getApplication(),返回Map对象,该对象模拟了应用的ServletContext的实例
③static ActionContext getContext(),静态方法,获得系统提供的ActionContext实例。
④Map getParameters()获取所有的请求参数,类似于调用HttpServletRequest对象的getParammeterMap方法。
⑤Map getSession()该Map对象模拟了HttpSession实例。
⑥void setApplication(Map application)直接传入一个Map实例,将该Map实例的key-value对转换成application的属性名、属性值。类似的还有setSession(Map session)
⑦put(Object key, Object value)直接为HttpServletRequest设置属性。相当于request.setAttribute(key,value).可通过EL表达式输出。
8,ServletActionContext类(是ActionContext类的子类)。 虽然Struts2提供了ActionContext来访问Servlet Api,但是这种访问毕竟不能直接获得Servlet Api实例,为了Action中 直接访问Servlet api,Struts2提供了如下的接口:ServletContextAware、ServletRequestAware、ServletResponseAware 。如果Action实现这些接口,能分别直接访问用户请求的ServletContext、HttpServletRequest、HttpServletResponse实例。
并且,为了直接访问Servlet api。Struts2提供了一个ServletAction类。通过ServletActionContext类可以更加方便的地直接访问Servlet api。这类的主要方法(全是static):
①getActionContext(HttpServletRequest req)得到当前的ActionContext实例。
②getActionMapping()得到ActionMapping实例(得到 action mapping为context)。
③getRequest()得到HttpServletRequest实例(Gets the HTTP servlet request object)。
④getResponse()得到HttpServletResponse实例(Gets the HTTP servlet response object.)
⑤getServletContext()得到ServletAction实例(Gets the servlet context.)
⑥getValueStack(HttpServletRequest req)得到ValueStack实例。
⑦setRequest(HttpServletRequest request)(Sets the HTTP servlet request object)相应的有setResponse(HttpServletResponse response)、setServletContext(ServletContext servletContext)。
9,虽然可以在Action类获取HttpServletResponse,但如果希望通过HttpServletResponse来生成服务器响应是不可能的,因为Action只是控制器(它并不直接对浏览器生成任何相应)。即如果在Action中写如下代码:response.getWriter().println("hello world");
是没有意义的。
10,对于使用Struts2框架的应用而言,尽量不要让超级链接链接到某个视图资源,
因为这种方式增加了额外的风险,推荐将所有请求都发给Struts2框架,让该框架来处理用户的请求,
即使是简单的超级链接。
11,逻辑视图名是指:Action返回的字符串;物理视图是指:页面的实际名称。
Struts2通过配置逻辑视图名和物理视图之间的映射关系,一旦系统收到Action返回的某个逻辑视图,系统就会把相应的物理视图呈现给用户。
12,默认值:如果配置
13,归纳起来,Struts2内建支持结果类型如下(14):
②chart结果类型:用于整合JFreeChart的结果类型。
③dispatch结果类型:用于jsp整合的结果类型。
④freemarker结果类型:FreeaMarker整合的结果类型。
⑤httpheader结果类型:用于控制Http行为的结果类型。
⑥jasper结果类型:用于JasperReports整合的结果类型。
⑦jsf结果类型:用于整合JSF整合的结果类型。
⑧redirect结果类型:用于直接跳转到其他的URI的结果类型。
⑨redirectAction结果类型:用于直接跳转到其他的Action的结果类型。
⑩stream结果类型:用于向浏览器返回一个InputStream(一般用于文件下载)。
⑾tiles结果类型:用于与Tiles整合的结果类型。
⑿velocity结果类型:用于与Velocity整合的结果类型。
⒀xslt结果类型:用于与XML/XSLT整合的结果类型。
⒁plainText结果类型:用于显示某个页面的原始代码的结果类型。
14,【redirect】结果类型。
这种结果类型与dispatch结果类型相对,dispatch结果类型是将请求Forward(转发)
到指定的jsp资源。而redirect结果类型,则意味着将请求Redirect(重定向)
到指定的视图资源。
dispatch结果类型与redirect结果类型的差别就是转发和重定向的差别:
重定向会丢失所有的请求参数和请求属性---当然也会丢失Action的处理结果。
使用redirect结果类型的效果是:系统将调用HttpServletResponse的sendRedirect(String)方法来重定向指定的视图资源,这种重定向的效果就是重新产生一个请求。所以所有的请求参数、请求属性、Action实例和Action中封装的属性全部丢失。
15,【redirectAction】结果类型.
使用redirectAction结果类型时,系统将重新生成一个新的请求,
只是该请求的URI不是一个具体的试图资源,而是一个Action。因此前一个Action处理结果
,请求参数,请求参数都会丢失。
16,除了可以通过通配符来配置Action(result),还可以使用OGNL表达式,这种
用法允许让请求参数来决定结果。如:
对于上面的表达式语法,要求对应的Action实例里应该包含currentSkill属性,且currentSkill属性必须包含name属性--否则,${currentSkill.name}表达式为null。
17,模型驱动:
对于Struts1的ActionForm对象而言。它的唯一作用就是封装请求参数,当Struts1拦截到用户的请求后,Struts1负责将请求参数封装成ActionForm对象。
如果Struts2的开发者怀念这种开发方式,则可以使用Struts2提供的模型驱动模式,
这种模式也通过专门的JavaBean来封装请求参数。
相比于Struts1的Action类,Struts2的Action承担了太多的责任,既用于封装来回请求的参数,也保护了控制逻辑---这种模式实在不太清晰。出于清晰的考虑,应该采用单独的Model实例来封装请求参数和处理结果,这就是所谓的模型驱动。
作用:Struts2的模型对象可以封装更多的信息,它不仅可以封装用户的请求参数,而且还可以封装Action的处理结果。用单独的JavaBean实例来贯穿MVC流程。
使用模型驱动时,Action必须实现ModelDriven接口,且必须实现getModel方法,
该方法用于把Action和与之相对应的Model实例关联起来。
简单的说,模型驱动使用单独的VO(值对象)来封装请求参数和处理结果。
18,【属性驱动】:
使用属性(Property)作为贯穿MVC流程的信息携带者,当然属性无法独立存在,他必须依附于一个对象,这个对象就是Action实例,
简单的说,属性驱动使用Action实例来封装请求参数和处理结果。
19,Struts2的【处理异常机制】:
在execute方法中手动捕捉异常,当捕捉到特定的异常时,返回特定的视图--但是
这种方式很是繁琐,需要在execute中书写大量的catch块,最大的缺点
还在于异常与代码耦合,一旦需要改变异常处理方式,必须修改代码!
Struts2提供了一种声明式的异常处理方式。
在输出错误信息的jsp页面,有两种输出方式:
①通过struts2标签输出异常对象的message属性。
②通过struts2标签输出堆栈信息。
注意:全局异常映射的result属性通常不要使用局部结果,局部异常映射的result属性可以使用全局结果,也可以不使用。
20,对于WEB应用而言,所有的请求参数都是字符串类型的。
21,【类型转换器】:
struts2的类型转换器实际上是基于OGNL实现的,在OGNL项目中有一个TypeConverter接口,因其实现的方法过于麻烦,所以OGNL项目还提供了一个该接口的实现类:DefaultTypeConverter,通过继承该类来实现自己的转换器。
实现自定义的类型转换需要重写DefaultTypeConverter类的convertValue方法。
22,上面的类型转换器都是基于OGNL的DefaultTypeConverter类实现的,基于
该类实现类型转换器的时候时,将字符串转化成符合类型要通过convertValue方法实现
因此我们必须先通过toType参数来判断转换的方向,然后分别实现不同的转换逻辑。
为了简化类型转换的实现,struts2提供了一个StrutsTypeConverter抽象类(基于struts2的类转换器)
这个抽象类是DefaultTypeConverter类的子类.
23,对于以上的类型转换,我们一直只处理字符串数组的第一个元素---我们都假设请求参数是单个值。实际上,必须考虑请求参数是字符数组的情形, 假设用户信息的请求参数,名称都是user。那么这两个请求参数必须通过getParameterValues方法来获取参数。此时user请求参数必须是数组类型,或者List类型(实际上,List和数组是完全相通的)。
24,因为struts2内建的OGNL表达式的支持,那么可以用另一种方式将请求参数转换成复合类型,如(JSP页面中):
,这样就不需要转换器了。
通过这种方式也可以把字符串转换成复合类型。但需要注意以下几点:
①因为struts2是需要直接创建一个复合类(User类)的实例,因此系统必须为该复合类构建一个无参的构造方法。
②如果希望使用user.name请求参数的形式为Action实例的user属性和pass属性赋值,则必须为user属性对应的复合类型提供setName方法,因为struts2是通过该方法类为属性赋值的。当然Action类还应该包含setUser方法。
25,表单元素enctype属性指定的是表单数据的编码方式。属性有如下3个值:
①application/x-www-form-urlencoded:这是默认的编码方式。它只处理表单中的value属性值,采用这种编码方式会将表单域的值处理成URL编码方式。
②multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定的文件内容也封装到请求参数里。
③text/plain:这种编码方式当表单的action的属性为mailto:URL的形式时比较方便,这种方式主要适用于直接通过表单发送邮件的方式。
26,通过Action在jsp页面输出提示信息,我们可以
①在Action中添加一个属性(通过setXx方法设置属性值),然后通过struts2的标签(
②通过ActionContext类来处理,如:ActionContext.getContext.put(key,value);然后通过EL表达式进行输出。
27,在Form表单中action属性的值要得到【上下文路径】:
①<%=request.getContextPath()%>
②还可以通过EL表达式得到 :${pageContext.request.contextPath}
28,得到【ValueStack】的对象有哪几种方法:
①ServletActionContext类中的方法:static getValueStack(HttpServletRequest req)【Gets the current value stack for this request】;
②ActionContext类中的方法:getValueStack()【Gets the OGNL value stack.】;
③ValueStack vs = (ValueStack) request.getAttribute("struts.valueStack");
(request.getAttribute()返回一Object类型)
29,【拦截器】。在默认的情况下,如果我们为某个Action定义了拦截器,则这个拦截器会拦截Action的所有方法。可能在有些情况下,我们无需拦截器所有的方法,只需要拦截某些方法,此时就需要struts2拦截器的方法过滤特性。
30,struts2的【校验】,可以继承ActionSupport类重写validate方法,利用ActionSupport的addFieldError方法把错误信息通过key保存起来,在jsp页面通过struts2标签的fielderror属性输出错误信息。注意:struts2的校验在配置action的时候需要提供输入页面(就是
如果要对action中指定的方法进行校验,把validate方法名改为:validateXxx,其中Xxx是需要校验的指定方法名。
31,输入校验的流程:
①类型转换器把请求参数进行类型转换,并把转换后的值赋给action中的属性。
②如果在执行类型转换的过程中出现异常,系统会将异常信息保存到ActionContext中,conversionError拦截器将异常信息 添加到fieldErrors中。不管类型转换是否失败都会转入第三步。
③系统通过反射技术调用action中的validateXxx方法。
④再调用validate方法。
⑤如果fieldErrors中存在错误信息,系统自动将请求转发至input视图。如果没有错误信息将执行action中的方法。
注意:如果validate方法里没有问题,却返回input页面,可能是类型转换有问题。所以返回input视图有两种原因(类型转换有问题或校验出错).
32,基于xml配置方式对action内所有的方法进行校验,xml文件的命名规则是:ActionClassName-validation.xml
如果只需要对action内指定的方法进行校验,则xml文件的命名规则为:ActionClassName-ActionName-validation.xml。其 中ActionName(action的逻辑名称)。它的配置一般用通配符(有助于实验)。
①基于xml配置方式的校验,如果ActionClassName-validation.xml、ActionClassName-ActionName-validation.xml同时存在则把两个文件汇总,在进行校验。如果两个xml文件的校验规则起了冲突则执行后面的xml文件。
②如果action继承了另一个action则先找到父action校验文件,在找到子action校验文件,再把4(每个action都有指定方法名或非指定方法名)个文件汇总。
33,【国际化】。国际化按范围分为:全局、action、package的范围的资源文件。Properties文件命名的规则为:xxx_language_country.properties(xxx为用户定义的名字,第二部分为语言类别。)
Ⅰ定义好了国际化文件后,需要在struts.xml文件配置
Ⅱ也可以通过action类继承ActionSupport类,再调用个getText方法的资源文件的key(getText("key")).然后可以通过EL表达式在jsp页面输出。
Ⅲ也可以通过struts2的表单标签的key属性。如
输出带有占位符的国际化信息:
①
②通过ActionSupport类的getText(String key,String[] str)或者getText(String key,List list)
34,包范围的国际化资源文件,
在大型的应用程序中,整个应用有大量的内容需要国际化,如果我们把国际化的内容放置在全局资源属性文件中,显然会导致资源文件变得过于庞大、臃肿,不便于维护,这个时候我们需要针对不同的模块,使用包范围来组织国际化文件。
在java的包下创建名为:package_language_country.properties的资源文件,package为固定写法,language_country是对应的语言类别。处于该包及子包都可以访问该资源文件。当在包范围找不到对应的资源文件,然后会在全局范围内查找。
35,Action范围的资源文件。在Action所在的路径创建名为:ActionClassName_language_country.properties
如果同时存在全局、package、Action范围的国际化资源文件,系统搜索的顺序是:Action-->package-->全局范围。
36,以上三种配置有的是基于配置的国际化资源文件。我们也可以通过无配置的方式进行直接访问某个资源文件。
通过struts2标签,如:
其中xxx是全局范围文件的名称的前缀。
如果直接想访问包范围的国际化资源文件
其中package是固定写法。
37,OGNL表达式(Object Graphic Navigation Language对象图导航语言),当struts2接受一个请求时,会迅速创建ActionContext、ValueStack、action,然后把action存放在ValueStack,所以OGNL表达式可以迅速访问action实例的属性。
OGNL表达式一般要配合Struts2标签使用。
在struts2中,EL表达式只能访问OgnlValueStack的root里的属性。即action的属性(因为action的属性放在OgnlValueStack的root属性里)。利用OGNL表达式创建List/Map对象,
38,防止表单重复提交,首先要有struts的token标签。再使用系统的拦截器。