Struts2访问Servlet的API
在struts2中,Action并没有直接和ServletAPI进行耦合,也就是说Struts2的Action
不能直接访问ServletAPI。
虽然解耦能带来很多好处,但是Action完全不访问Servlet API几乎不可能,在实现业务逻辑
的时候,经常要访问Servlet中的对象,如:session、request、application等
在Struts2中,访问ServletAPI的方式有三种:
第一种:通过ActionContext类访问
ActionContext是Action执行的上下文对象,在ActionContext中保存了Action执行所需要的所对象。
ActionContext类访问ServletAPI的几个常用的方法:
void put(String key, Object value) : 将key-value键值对放入ActionContext中,
模拟ServletAPI中的HttpServletRequest 的setAttribute()方法
Object get(String key) :通过参数key查找当前ActionContext中的值
Map<String,Object> getApplication() :返回一个Application级的Map对象
static ActionContext getContext() :获取当前线程的ActionContext对象
Map(String,Object) getParameters() :返回一个包含所有HttpServletRequest参数信息的Map对象
代码:
ActionContext context = ActionContext.getContext();
context.put("键","值");
context.getApplication.put("键","值");
//接收请求参数:
Map<String,Object> map = context.getParameters();
for(String key : map.keySet()){
Object value = map.get(key);
System.out.println(value);
}
通过以上方法的调用,分别在request、application中放入了键值对。并从页面中获得表单
传来的参数。
第二种:通过特定的接口访问
ActionContext类可以访问ServletAPI,但是无法直接获得ServletAPI实例,为了让Action中直接访问servletAPI,Struts2提供了一系列接口:
ServletRequestAware: 实现该接口的Action可以直接访问Web应用的HttpServletRequest实例
ServletResponseAware:
SessionAware:
ServletContextAware:
例如:
public class ActionDemo extends ActionSupport implements SetvletRequestAware{
HttpServletRequest request;
@Override
public void setServletRequest(HttpSetvletRequest request){
this.request = request;
}
@Override
public String execute() throws Exception{
reuqest.setAttribute("message","通过SetvletRequestAware接口实现访问ServletAPI");
return SUCCESS;
}
}
第三种:通过ServletActionContext访问
为了直接访问ServletAPI,Struts2框架提供了ServletActionContext类,该类提供了几个静态方法,如下:
1)static HttpServletRequest getRequest() : 返回web应用的HttpServletRequest对象
2)static HttpServletResponse getResponse() : 返回web应用的HttpServletResponse对象
3)static ServletContext getServletContext() : 返回web应用的ServletContext对象
4) static PageContext getPageContext() : 返回web应用的PageContext对象
代码:
public class ActionDemo extends ActionSupport{
@Override
public String execute() throws Exception{
//获得web应用的HttpServletRequest对象
HttpServletRequest request = ServletActionContext.getRequest();
return SUCCESS;
}
}
结果页面的配置
一、全局结果页面:是指同一个包(package)下配置的Action中返回相同字符串的值,都可以向这个页面来进行跳转
<global-results>
<result name="success">/success.jsp</result>
</global-results>
二、局部结果页面:是指在某个Action中返回的字符串的值,会向这个页面进行跳转
<action name="actionDemo" class="cn.scx.action.ActionDemo" ><result name="success">/demo.jsp</result>
</action>
Struts2数据封装
页面提交请求到Action---Action接收参数并对请求参数进行数据封装----封装到javaBean中---将javaBean传递给业务层
数据封装分为两大类:
第一类:属性驱动
也可以分为两类:一种只需要提供属性的set方法。另一种通过表达式方式(OGNL)直接封装到对象中在struts2中,可以直接在Action中定义各种java基本数据类型的字段,使这些字段与表单数据相对应,
并利用这些字段进行数据传递。
1)通过set方法
<form action="#" method="post"><input type="text" name="name"/>
<input type="text" name="age"/>
<input type="sumbit" name="提交"/>
</form>
public class ActionDemo extends ActionSupport{
//接收参数
private String name;
private String age;
public void setName(String name){
this.name =name;
}
public void setAge(String age){
this.age =age;
}
@Override
public String execute() throws Exception{
System.out.println(age);
return SUCCESS;
}
}
注:这种方式需要在Action中定义很多属性,并提供set方法。会使Action代码臃肿。
可以把属性和set方法提取出来,放进一个对象中,这个对象就是封装数据的,一般用javaBean来实现。
javaBean就是数据传递的载体。
2)页面提供表达式方式(OGNL)
<form action="#" method="post"><input type="text" name="user.name"/>
<input type="text" name="user.age"/>
<input type="sumbit" name="提交"/>
</form>
public class ActionDemo extends ActionSupport{
//接收参数
private User user;
//必须提供对象的get方法
public User getUser(){
return user;
}
public void setUser(User user){
this.user =user;
}
@Override
public String execute() throws Exception{
System.out.println(user);
return SUCCESS;
}
}
注:这种方式需要提供user的get方法,如果没有,struts2底层就没有办法得到user对象
那么在user中只会有一个属性被封装进去,而其他属性都是null。
第二类:模型驱动
通过实现ModelDriven接口来接收请求参数,Action必须实现这个接口,并重写getModel()方法,这个方法返回的就是Action所使用的数据模型对象。
模型驱动通过javaBean模型进行数据传递
代码:
<form action="#" method="post">
<input type="text" name="name"/>
<input type="text" name="age"/>
<input type="sumbit" name="提交"/>
</form>
public class ActionDemo extends ActionSupport implements ModelDriven<User>{
//手动构建对象
private User user = new User();
//必须提供对象的get方法
public User getModel(){
return user;
}
@Override
public String execute() throws Exception{
System.out.println(user);
return SUCCESS;
}
}
注:如果传递的数据为单个对象的属性时,优先使用这种方式。
封装集合类型的数据:
第一种:封装到List集合中:
<form action="#" method="post"><input type="text" name="list[0].name"/>
<input type="text" name="list[0].age"/>
<input type="text" name="list[1].name"/>
<input type="text" name="list[1].age"/>
<input type="sumbit" name="提交"/>
</form>
public class ActionDemo extends ActionSupport{
//接收参数
private List list<User>;
//必须提供对象的get方法
public List<User> getList(){
return list;
}
public void setList(List<User> listr){
this.list =list;
}
@Override
public String execute() throws Exception{
for(User user : list){
System.out.println(user);
}
return SUCCESS;
}
}
第二种:封装到Map集合中:
<form action="#" method="post"><input type="text" name="map["one"].name"/>
<input type="text" name="map["one"].age"/>
<input type="text" name="map["two"].name"/>
<input type="text" name="map["two"].age"/>
<input type="sumbit" name="提交"/>
</form>
public class ActionDemo extends ActionSupport{
//接收参数
private Map map<String,User>;
//必须提供对象的get方法
public Map<String,User> getMap(){
return map;
}
public void setMap(Map<String,User> map){
this.map =map;
}
@Override
public String execute() throws Exception{
for(String key : map.keySet()){
User user = map.get(key);
System.out.println(key + "----"+ user);
}
return SUCCESS;
}
}
Struts2的默认表达式语言 OGNL(对象图导航语言)
使用OGNL,可以通过某种表达式语法,存取Java对象的任意属性,调用Java对象的方法,同时能够自动实现必要的类型转换。
特点:
1)支持对象方法的调用:objName.methodName();
2)支持类静态方法调用和值的访问,格式为:
@[类全名]@[方法名 | 值名] @java.lang.String@format('foo %s', 'bar');
3)支持赋值操作和表达式串联
4)访问OGNL上下文 和 ActionContext
5)操作集合对象
OGNL结构:
1、表达式
带有语法含义的字符串,表达“要做什么操作”
2、根对象
可以理解为OBNL的操作对象,表达“对谁操作”
3、context对象
根对象所在的环境就是OGNL上下文环境,表达“在哪里进行操作”
上下文环境Context是一个Map类型的对象,
在表达式中访问Context中的对象,需要使用“#”号加上对象名称。
public void demo() throws OgnlException{
OgnlContext context = new OgnlContext();
Object obj = Ognl.getValue("'helloworld'.length()", context, context.getRoot());
System.out.println(obj); //结果为10
}
值栈(ValueStack):
ValueStack是Struts的一个接口,字面意义为值栈,OgnlValueStack是ValueStack的实现类,客户端发起一个请求struts2会创建一个Action实例,并且同时创建一个OgnlValueStack值栈实例,OgnlValueStack贯穿Action的生命周期。struts2将Action的请求参数
封装为对象存储在值栈中,并通过OGNL表达式读取值栈中对象的属性值。
值栈的内部结构:
1.Root栈(list)CompoundRoot:继承AraryList 实现压栈和出栈功能。存储Action实例和请求参数等
拥有先进后出,后进先出特点,最后压进栈的数据在栈顶,成为对象栈。
使用OgnlValueStack的findValue()方法可以在CompoundRoot中从栈顶向栈底查找对象的属性值
2.map(ognl上下文)栈
存储了一些引用,parameters、request、session、application等,上下文的Root为CompoundRoot
ActionContext 和 ValueStack 的关系
1.在创建ActionContext 的时候,创建ValueStack对象,将ValueStack对象给 ActionContext2.ActionContext中有ValueStack的引用,ValueStack中也有ActionContext的引用
3.ActionContext获取ServletAPI的时候,依赖的是值栈
获取值栈对象:
1.通过ActionContext对象获取值栈
ValueStack vs = ActionContext.getContext().getValueStack();
2.通过Request域获取值栈
ValueStack vs = ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
值栈的问题
1.什么是值栈 ValueStack ?
本质:数据的中转站,值栈ValueStack是struts2的一个接口规范,其作用就是存储Action在访问过程中的一些数据
一次访问对应一个Action对象,一个Action对象对应一个ActionContext对象,一个ActionContext对应一个
ValueStack对象,可以认为值栈对象的生命周期与Action同步
2.值栈的内部结构 ?
对象栈/Root栈 ---本质ListContext栈/map栈 ---本质Map
3.如何获得值栈对象 ?
1.通过ActionContext对象获取值栈ValueStack vs = ActionContext.getContext().getValueStack();
2.通过Request域获取值栈
ValueStack vs = ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
4.如何向值栈保存数据
值栈的内部结构:Root 和 Context1.向Root栈保存数据
/**
* 手动保存
*/
ValueStack vs = ActionContext.getContext().getValueStack(); //得到值栈对象
CompoundRoot root = vs.getRoot(); //得到Root栈
//使用List方法存储
root.add("a"); //这种方式存储到Root栈(List)的栈底
//使用原始方法向栈顶放置数据
root.add(0,"b");
//使用Root封装好的方法向栈顶存储数据---压栈
root.push("c");
root.peek();//取出栈顶数据
root.pop();//弹出栈顶数据
注:struts2自动向Root栈保存数据,保存的数据有 ---当前Action对象 ---当前Model对象(传递的参数)
2.向Context栈保存数据
ValueStack vs = ActionContext.getContext().getValueStack(); //得到值栈对象
Map<String,Object> context = ValueStack.getContext();
向map中存储数据。。。
注:struts2自动向Context栈保存数据保存的数据有
---request对象
---response对象
---servletContext对象
---request域数据
---application域数据
---session域数据
---paramters提交的参数
---attr所有域数据
5.如何取值栈的数据 ?
主要是jsp中如何取数据-------------->struts标签 + ognl表达式1.从Root栈中取 ---List
<s:property value="root栈中propertyName" />
2.从Context栈中取 ---Map
<s:property value="#context栈中的key" />