## Struts2访问Servlet

1 概述:在Struts2中,Action并没有直接和Servlet API耦合,Action不能直接访问Servlet API。

  尽管Action和Servlet的API的解耦会带来很多好处,但在实现业务逻辑时,还是要经常访问到Servlet中的对象。

2 ActionContext类:

(1)概述:Struts2提供ActionContext类来访问Servlet API。ActionContext类是Action执行的上下文对象,保存了

   Action执行所需的所有对象,如parameters,request,session,application。

(2)ActionContext的生命周期和获取方式

<1>生命周期

每次接收请求到Action就会创建一个相应的ActionContext对象,请求处理完自动销毁ActionContext

<2>获取方式

ActionContext创建好后会和当前线程绑定,若要获取ActionContext对象只需从ThreadLocal中获取即可。

(3)ActionContext访问Servlet API的常用方法:

<1>void put(String key,Object value)

      功能描述:将key-value放进ActionContext中,模拟Servlet API中的HttpServletRequest中的setAttribute()方法。

<2>Oject get(String key) 功能描述:通过参数key获取ActionContext中的value值

示例(获取request域):

Map<String,Object> requestScope = (Map<String, Object>) ActionContext.getContext().get("request");

<3>Map<String ,Object> getApplication() 功能描述: 返回一个Application级的Map对象

示例:

Map<String, Object> applicationScope = ActionContext.getContext().getApplication();

applicationScope.put("name","applicationTom");

<4>static   ActionContext   getContext() 功能描述:获取当前线程的ActionContext对象

示例:

ActionContext.getContext().put("name","requestTom");

<5>Map<String,Object> getParameters() 功能描述:返回一个包含所有HttpServletRequest信息的Map对象

<6>Map<String,Object> getSession() 功能描述:返回一个HttpSession级的Map对象

示例:

Map<String, Object> sessionScope = ActionContext.getContext().getSession();

sessionScope.put("name","sessionTom");

<7>void  setApplication(Map<String,Object>) 功能描述:设置Application上下文

<8>void  setSession(Map<String,Object>) 功能描述:设置Session

3  获取原生ServletAPI问题

获取原生的Servlet API方式一:

可使用stuts2提供的ServletActionContext类

代码示例:

//获取原生的request域

HttpServletRequest request = ServletActionContext.getRequest();

//获取原生的session

HttpSession session = request.getSession();

//获取原生的response域

HttpServletResponse response = ServletActionContext.getResponse();

//获取原生的ServletContext

ServletContext servletContext = ServletActionContext.getServletContext();

//获取原生的PageContext

PageContext pageContext=ServletActionContext.getPageContext();

获取原生的Servlet API方式二:

通过实现接口来获取 原生的 ServletAPI

代码示例:

public class Demo6Action extends ActionSupport implements ServletRequestAware,ServletResponseAware,ServletContextAware{

private HttpServletRequest request;

private HttpServletResponse response;

private ServletContext context;

public String execute()throws Exception{

System.out.println(request);

return SUCCESS;

}

//获取原生 request

@Override

public void setServletRequest(HttpServletRequest request) {

this.request=request;

}

//获取原生的 response

@Override

public void setServletResponse(HttpServletResponse response) {

this.response=response;

}

//获取原生的 ServletContext

@Override

public void setServletContext(ServletContext context) {

this.context=context;

}

}

5  获取原生的request域问题。

HttpServletRequest request = ServletActionContext.getRequest();

分析:

struts2不推荐使用原生的request域,若想达到原生的request域的效果,可直接把数据存到ActionContext容器中,

因为ActionContext的生命周期和原生的request一模一样。

值得一提的是:把值放到ActionContext中,但取的方法却是和原生的Request域一样,

使用 request.getParameter("name"),原因是在struts2的核心过滤器中StrutsPrepareAndExecuteFilter

已经把request域对象进行包装处理过了: request = prepare.wrapRequest(request);

## 结果页面配置

1 概述:在struts.xml使用<result>标签配置Result逻辑视图和物理视图之间的映射,<result>元素存在name,type常见属性,

但这两种属性都不是必选的。

name属性:指定逻辑视图名称,默认值为success.

type属性:指定返回视图资源的类型,默认值为dispatcher(请求转发),还包括的为redirect(重定向) ,

chain(转发到另一个Action,少用),redirectAction(重定向到另一个Action,常用)

2 结果页面配置

概述:在struts2的结果配置中,有两种方式,全局结果页面配置和局部结果页面配置。

(1)全局结果页面配置

全局结果页面是指在同一个包下配置Action中返回相同的字符串的值,都可以跳转到该页面。

示例:

<global-results>

<result name="success">/success.jsp</result>

</global-results>

(2)局部结果页面配置

局部结果页面是只针对某个Action,根据该字符串的值进行页面跳转。

示例:

<action name="Demo1Action"

class="cn.iesult.Demo1Action" method="execute">

<result name="success" type="dispatcher">/hello.jsp</result>

</action>

(3)结果页面配置扩展了解

一个结果类型resultType接口com.opensymphony.xwork2.Result的实现。

struts2把内置的<result-type>都放在 struts2-core-2.3.24.jar/struts-default.xml文件中

## Struts2的数据封装

1 概述:在实际开发中,Action会接收  页面提交的请求参数,并将数据封装到一个javaBean中,传递到业务层。

          struts2封装数据的方式有两种:属性驱动(属性set方法) 和 模型驱动(表达式方式)。

2 属性驱动

(1)概述:直接在Action中定义各种Java基本数据类型的字段,使这些字段与表单数据相对应,并利用这些字段进行数据传递。

以前我们使用Serlvet只能在方法内获取参数的原因是:

一个web应用只能有一个Servlet,意味着该Servlet的成员变量都是唯一的。

但是因为Servelet是线程不安全的,当它的成员变量同时被几个请求访问时,就会出现被覆盖的情况。

所以我们使用Servlet接收参数只能在方法内用局部变量接收,不能像Action这样使用成员变量接收。

所以我们这里可以使用成员变量接收参数--也表明我们的Action是线程安全的

每次请求Action时都会创建新的Action实例对象。

(2)方式一:在Action内定义属性,通过提供属性set方法来完成。

示例:

<form action="${pageContext.request.contextPath }/Demo8Action" method="POST">

用户名:<input type="text" name="name"/><br>

年龄:<input type="text" name="age"/><br>

生日:<input type="text" name="birthday"/><br>

<input type="submit" value="提交" />

</form>

public class Demo8Action extends ActionSupport{

//接收姓名参数

private String name;

public void setName(String name) {this.name = name;}

//接收年龄参数--自动类型转,只能转换8大基本数据类型以及对应的包装类

private Integer age;

public void setBirthday(Date birthday) {this.birthday = birthday;}

//接收日期参数--struts2支持特定类型字符串(yy-MM-dd)转换为Date

private Date birthday;

public void setAge(Integer age) {this.age = age;}

public String execute()throws Exception{

System.out.println("参数name为:"+name+",参数age为:"+age+",birthday:"+birthday);

return SUCCESS;

}

public Demo8Action() {

super();

System.out.println("创建了一个新的Action对象");

}

}

缺点:数据过于多时,会使Action非常臃肿。

(3)方式二:把属性数据和对应的getter/setter方法抽取到一个javaBean类,Action直接使用javaBean即可。

此方式除了提供属性的set方法还要有get方法,get方法用于获取javaBean类中的属性。

  同理,Action类中的javaBean对象也需要提供get/set方法。

示例:(注意此处jsp页面的name属性值与第一种方式的不同)

<form action="${pageContext.request.contextPath }/Demo10Action" method="POST">

用户名:<input type="text" name="user.username"/><br>

年龄:<input type="text" name="user.age"/><br>

生日:<input type="text" name="user.birthday"/><br>

<input type="submit" value="提交" />

</form>

public class User {

private String Username;

private Long age;

private Date birthday;

public String getUsername() {return Username; }

//提供getter/setter方法

public void setUsername(String username) {Username = username;}

public Long getAge() {return age;}

public void setAge(Long age) {this.age = age;}

public Date getBirthday() {return birthday;}

public void setBirthday(Date birthday) {this.birthday = birthday;}

@Override

public String toString() {

return "User [Username=" + Username + ", age=" + age + ", birthday=" + birthday + "]";

}

}

public class Demo9Action extends ActionSupport{

private User user;

//提供javaBean类的getter/setter方法

public User getUser() {return user;}

public void setUser(User user) {this.user = user;}

public String execute()throws Exception{

System.out.println(user);

return SUCCESS;

}

public Demo9Action() {

super();

System.out.println("创建了一个新的Action对象");

}

对比方式一的不同之处:

(1)方式二jsp页面的name属性格式为:user.name,user.age,user.birthday。

方式一的没有user前缀

(2)方式二的封装对象极其属性必须要提供getter/setter方法

方法一:只需提供属性的setter方法

3 模型驱动

(1)概述:

· 通过实现ModelDriven<>接口,复写getModel()方法直接获取Action数据模型对象(javaBean类型),

   与属性驱动方式二都使用到javaBean对象,与之不同的是,

& 它不需提供javaBean对象的getter/setter方法。

& 它的jsp页面name属性没有user对象前缀。

开发我们优先使用模型驱动,若有多个数据模型对象则是用属性驱动的方式二获取数据。

(2)示例:

<form action="${pageContext.request.contextPath }/Demo10Action" method="POST">

用户名:<input type="text" name="username"/><br>

年龄:<input type="text" name="age"/><br>

生日:<input type="text" name="birthday"/><br>

<input type="submit" value="提交" />

</form>

public class Demo10Action extends ActionSupport implements ModelDriven<User>{

//复写接口ModelDriven<User>的方法

@Override

public User getModel() {

return user;

}

private User user=new User();

public String execute()throws Exception{

System.out.println(user+"10----");

return SUCCESS;

}

public Demo10Action() {

super();

System.out.println("创建了一个新的Action对象");

}

}

4 struts2对集合对象的数据模型封装

(1)概述:在开发中,我们需要批量插入用户或其他对象。Action中可能会接受多个其他的Action封装的对象,

         这时候我们需将表单数据封装到集合中。我们一般使用的集合为List或Map

(2)表单数据封装到List集合中示例:

<form action="${pageContext.request.contextPath }/Demo11Action" method="POST">

list:<input type="text" name="list"/><br>

list:<input type="text" name="list[1]"/><br>

list:<input type="text" name="list[3]"/><br>

<input type="submit" value="提交" />

</form>

public class Demo11Action extends ActionSupport{

private List<String>list;

public List<String> getList() {return list;}

public void setList(List<String> list) {this.list = list;}

public String execute()throws Exception{

System.out.println("list:"+list);

return SUCCESS;

}

}

   (3)表单数据封装到Map集合中示例:

<form action="${pageContext.request.contextPath }/Demo11Action" method="POST">

map:<input type="text" name="map['key1']"/><br/>

map:<input type="text" name="map['key2']"/>

<input type="submit" value="提交" />

</form>

public class Demo11Action extends ActionSupport{

private Map<String,String>map;

public Map<String, String> getMap() {return map;}

public void setMap(Map<String, String> map) {this.map = map;}

public String execute()throws Exception{

System.out.println(map);

return SUCCESS;

}

}