## 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;
}
}