struts2
Struts2访问Servlet的API
完全解耦和的方式实现Servlet的API的访问
获取ActionContext
ActionContext actionContex=ActionContext.getContext();
接受参数:
解耦和的方式通过ActionContext中的方法实现:
Map<String,Object> getParamters(); //Object是一个字符串类型的数组
Map<String,Object> getSession();
Map<String,Object> getApplication();
void setSession(Map<String,Object> session);
void setApplication(Map<String,Object> application);
//向request中存数据
actionContext.put(String name,Object object);
//向session中存数据
actionContext.getSession.put(String name,Object object);
//向application中存数据(ServletContext对象)
actionContext.getApplication().put(String name,Object object);
- post提交不用管中文action会管了,get提交需要设置
通过实现特定的接口来实现Servlet的API的访问
- 让action类去实现
ServletRequestAware
接口,然后在成员位置定义一个HttpServletRequest变量,下边重写一个setServletRequest方法,让成员的request等于方法中的,可以当作正常的request用。
public class RequestDemo2Action extends ActionSupport implements ServletRequestAware,ServletContextAware{
private HttpServletRequest request ;
private ServletContext application;
@Override
public String execute() throws Exception {
// 接收参数:需要使用request对象。
Map<String, String[]> parameterMap = request.getParameterMap();
for (String key : parameterMap.keySet()) {
String[] value = parameterMap.get(key);
System.out.println(key+" "+Arrays.toString(value));
}
// 向request域中存值:
request.setAttribute("reqName", "r郝天一");
// 向session域中存值:
request.getSession().setAttribute("sessName", "s郝思聪");
// 向application域中存值:
application.setAttribute("appName", "a郝冠希");
return SUCCESS;
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
@Override
public void setServletContext(ServletContext application) {
this.application = application;
}
}
- 如果想用ServletContext对象,则在实现一个ServletContextAwre接口,方式跟上边的一样。
通过ServletActionContext的静态方法实现Servlet的API的访问
struts核心包中的api
//获取request对象
HttpServletRequest request = ServletActionContext.getRequest();
Map(String,String[]) paramterMap=request.getParameterMap();
//获取ServletContext参数
ServletContext application=ServletActionContext.getServletContext();
Struts2的数据的封装
Struts2的多例
- 因为action是多例的,意思就是每次刷新页面都会重新执行action类
多例的话就可以使用成员变量,创建Service的时候,就可以放成全局。
属性驱动
Struts既有控制层,又有模型层。
提供属性的set方法完成数据的封装
- 在action类中,定义要接受的属性的成员变量,只提供set方法,即可获取属性值
- 这种方式应用的不多,因为还需要手动装到对象中。
在页面中提供表达式(OGNL)的方式完成数据封装(直接封装到实体对象中)
在页面中这样写
name
,前面的user必须跟action中成员方式的对象名一致。
在action类中的成员位置加一个实体类对象,并提供get跟set方法。
public class User2Action extends ActionSupport{
private User user;
// 需要提供get和set方法:
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String execute() throws Exception {
System.out.println(user);
return NONE;
}
}
- 注:
- 在第二种方法中,必须有get set方法
- 因为属性驱动是在拦截器中执行的,他需要把action中的对象实例化,所以要get到,如果不给提供get方法,则,每次封装的时候都会自动创建一个新的实例对象,这样会导致使用这个对象时只会有第一个封装进来的值
- 拦截器在strut-default.xml中
模型驱动
采用模型驱动的方式来实现(推荐):
- 页面即用普通页面。
- 让action来实现一个 ModelDriver/ 接口,里面必须手动构建对象。
T是要封装的那个实体的类型
- OGNL表达式的方式和模型驱动都有使用的。
模型驱动通常会使用的方式。有一个缺点,就是只能封装到一个对象中,如果想封装到多个对象,就需要用到OGNL
Struts2中复杂类型数据的封装
封装到List集合中
页面:
<h1>批量插入商品</h1>
<form action="${ pageContext.request.contextPath }/product1Action.action" method="post">
商品名称:<input type="text" name="list[0].name"><br/>
商品价格:<input type="text" name="list[0].price"><br/>
商品名称:<input type="text" name="list[1].name"><br/>
商品价格:<input type="text" name="list[1].price"><br/>
商品名称:<input type="text" name="list[2].name"><br/>
商品价格:<input type="text" name="list[2].price"><br/>
<input type="submit" value="批量导入">
</form>
Action:
/**
* Struts2复杂数据类型的封装:封装到List集合中
* @author jt
*
*/
public class Product1Action extends ActionSupport{
private List<Product> list;
public List<Product> getList() {
return list;
}
public void setList(List<Product> list) {
this.list = list;
}
@Override
public String execute() throws Exception {
for (Product product : list) {
System.out.println(product);
}
return NONE;
}
}
封装到Map集合
页面:
<h1>批量插入商品:封装到Map集合</h1>
<form action="${ pageContext.request.contextPath }/product2Action.action" method="post">
商品名称:<input type="text" name="map['one'].name"><br/>
商品价格:<input type="text" name="map['one'].price"><br/>
商品名称:<input type="text" name="map['two'].name"><br/>
商品价格:<input type="text" name="map['two'].price"><br/>
商品名称:<input type="text" name="map['three'].name"><br/>
商品价格:<input type="text" name="map['three'].price"><br/>
<input type="submit" value="批量导入">
</form>
Action:
/**
* Struts2的复杂数据的封装:Map集合的封装
* @author jt
*
*/
public class Product2Action extends ActionSupport{
private Map<String,Product> map;
public Map<String, Product> getMap() {
return map;
}
public void setMap(Map<String, Product> map) {
this.map = map;
}
@Override
public String execute() throws Exception {
for (String key : map.keySet()) {
Product product = map.get(key);
System.out.println(key+" "+product);
}
return NONE;
}
}
Struts中结果页面的配置
结果页面的分类:
- 全局结果页面
- 可以对所有的action都有效
- 局部结果页面
- 在 /< action /> 内部配置 /< result /> ,只会对当前的Action有效。
如果有全局页面跟局部页面同时存在的时候,首先要看局部页面。
全局结果页面的配置
<package>
<global-results>
<result name="success">地址。。。</result>
</global-results>
</package>
局部结果页面的配置
<package>
<action>
<result name="success">地址。。。</result>
</action>
</package>
Struts2结果页面类型的配置
- /< result /> 标签上还有一个属性:
- name :逻辑视图名称。
- type :页面跳转的类型
- dispather :默认值,转发,转发到jsp页面
- chain :转发到一个Action
- redirect :重定向。重定向到jsp
- redirectAction :重定向到一个Action,重定向的时候如果不是在一个命名空间中,可以自己加上属性,(在result下面加param标签)
- stream :文件下载的时候
struts2中内置数据类型的转换
会把传过来的特殊数据类型转换为实体中需要的类型,integer,
date
都能封装。 都是在拦截器执行的。当转换失败时,会到
Workflow
拦截器,然后查看是否有这个错误,如果有会运行一个input视图中有错误信息,跳转到input
的页面中。 例如Integer中添了一个字母。- 可以在配置文件中,设置一个input的跳转页面,当有错误时,会跳转到这个页面
- 这个页面中可以加一个标签,显示错误信息
<%@ taglib uri="/struts-tags" prefix="s" %>
//可以加两个标签,是哪个错误会显示哪个错误
<s:actionerror/>
<s:fielderror/>
注:
有的时候elipse会编译前一段时间的代码,修改之后不会及时编译最新的,可以把tomcat中的webapps项目中的class文件删除,然后再在elispe中,project/build all手动编译一下。
struts2中的带的log4j是2.2版本的,hibernate中是1.几版本的,所以不能把hibernate中的配置文件中copy过来直接用,可以在struts2提供的项目模板中找一个,2.2版本的配置文件是 .xml 的