第一節(jié):Struts2訪問Servlet的API
考慮這么一種情況:如果表單中有參數(shù)因悲,通過Action如何進行接收又或者需要向頁面保存一些數(shù)據(jù)晃琳,又該如何操作呢?我們可以通過學習Struts2訪問Servlet的API來實現(xiàn)這樣的功能人灼。
在Struts2中投放,Action并沒有直接和Servlet API進行耦合灸芳,也就是說在Struts2的Action中不能直接訪問Servlet API拜姿。雖然Struts2中的Action訪問Servlet API麻煩一些蕊肥,但是這卻是Struts2中Action的重要改良之一晴埂,方便Action進行單元測試。
盡管Action和Servlet API解耦會帶來很多好處,然而在Action中完全不訪問Servlet API幾乎是不可能的琅锻,在實現(xiàn)業(yè)務邏輯時向胡,經(jīng)常要訪問Servlet中的對象僵芹,如 session拇派、request和application等。在Struts2中疮方,訪問Servlet API有3種方法骡显,具體如下:
1.1 通過ActionContext類訪問
Struts2框架提供了ActionContext類來訪問Servlet API惫谤,ActionContext是Action執(zhí)行的上下文對象,在ActionContext中保存了Action執(zhí)行所需要的所有對象博助,包括parameters富岳、request窖式、session动壤、application等琼懊。下面列舉ActionContext類訪問Servlet API的幾個常用方法:
具體使用哼丈,請參照如下案例:
- 訪問頁面的代碼
<%--
Created by IntelliJ IDEA.
User: F
Date: 2019/4/5
Time: 19:38
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>ActionContext訪問Servlet API 實例</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/RequestAction_login.action">
用戶名:<input type="text" name="name"/></br>
密碼:<input type="password" name="password"/></br>
<input type="submit" value="提交"/>
</form>
</body>
</html>
- Action的處理邏輯
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.dispatcher.HttpParameters;
import org.apache.struts2.dispatcher.Parameter;
public class RequestActionDemo extends ActionSupport {
public String login() throws Exception{
//接收表單的參數(shù)
//使用actionContext來獲取參數(shù)
ActionContext context = ActionContext.getContext();
//接收參數(shù)
HttpParameters parameters = context.getParameters();
Parameter name = parameters.get("name");
String nameValue = name.getValue();
Parameter password = parameters.get("password");
String passwordValue = password.getValue();
System.out.println(nameValue +"=====" + passwordValue);
//設置參數(shù)
context.put("requestName","張三");
context.getSession().put("sessionName","李四");
context.getApplication().put("applicationName","王五");
return SUCCESS;
}
- struts2.xml中對Action的配置,使用通配符來實現(xiàn)方法的調(diào)用饶米。
<!--通過ActionContext訪問Servlet API-->
<action name="RequestAction_*" class="com.seapp.struts2.action.RequestActionDemo" method="{1}">
<result name="success">/demo01.jsp</result>
</action>
- 通過jsp界面對Action傳入?yún)?shù)的獲取
<%--獲取action中傳遞過來的參數(shù)--%>
${requestName}</br>
${sessionName}</br>
${applicationName}</br>
1.2 通過特定接口訪問:
Struts2框架提供了ActionContext類來訪問Servlet API檬输,雖然這種方法可以訪問Servlet API丧慈,但是無法直接獲得Servlet API實例逃默。為了在Action中直接訪問Servlet API队秩,Struts2還提供了一系列接口馍资,具體如下:
- ServletRequestAware:實現(xiàn)該接口的Action可以直接訪問Web應用的HttpServletRequest實例。
- ServletResponseAware:實現(xiàn)該接口的Action可以直接訪問Web應用的HttpServletResponse實例使兔。
- SessionAware:實現(xiàn)該接口的Action可以直接訪問Web應用的HttpSession實例藤韵。
- ServletContextAware:實現(xiàn)該接口的Action可以之間訪問Web應用的ServletContext實例泽艘。
下面以ServleRequestAware為例匹涮,講解如何在Action中訪問HttpServletRequest實例: - 定義Action繼承ActionSupport實現(xiàn)ServleRequestAware接口:
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.interceptor.ServletRequestAware;
import javax.servlet.http.HttpServletRequest;
public class RequestActionDemo02 extends ActionSupport implements ServletRequestAware {
HttpServletRequest httpServletRequest;
@Override
public void setServletRequest(HttpServletRequest httpServletRequest) {
this.httpServletRequest = httpServletRequest;
}
public String login() throws Exception {
String username = httpServletRequest.getParameter("name");
String password = httpServletRequest.getParameter("password");
System.out.println(username + "======" + password);
httpServletRequest.setAttribute("message","通過ServletRequestAware接口來訪問Servlet API");
return SUCCESS;
}
}
需要注意的是然低,上述類必須實現(xiàn)setServletRequest()方法和execute()方法雳攘,
通過setServletRequest()方法,可以得到HttpServletRequest的實例刚照。這是在調(diào)用execute()方法或其他自定義的方法之前就調(diào)用了的涩咖。
- 修改struts.xml配置文件繁莹,添加上述Action的訪問配置咨演。
<!--通過ServleRequestAware訪問Servlet API-->
<action name="RequestAction02_*" class="com.seapp.struts2.action.RequestActionDemo02" method="{1}">
<result name="success">/demo01.jsp</result>
</action>
- 修改提交界面的url地址薄风,并在成功返回界面獲取Action中返回的數(shù)據(jù)
<%--獲取HttpServletRequest返回的數(shù)據(jù)--%>
${requestScope.message}
-
結(jié)果界面如下:
1.3 通過ServletActionContext訪問
為了直接訪問Servlet API遭赂,Struts2框架還提供了ServletActionContext類撇他,該類包含了幾個常用的靜態(tài)方法困肩,具體如下:
- static HttpServletRequest getRequest():獲取web應用的HttpServletRequest對象。
- static HttpServletResponse getResponse():獲取Web應用的HttpServletResponse對象勇劣。
- static ServletContext getServletContext():獲取Web應用的ServletContext對象。
- static PageContext getPageContext():獲取Web應用的PageContext對象潭枣。
接下來比默,實現(xiàn)如何通過ServeltActionContext來訪問Servlet API: - 實現(xiàn)Action測試類。具體代碼如下:
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Map;
public class RequestActionDemo03 extends ActionSupport {
public String login() throws Exception{
//1.通過ServletActionContext對象獲取request對象
HttpServletRequest request = ServletActionContext.getRequest();
//2.通過request對象來獲取參數(shù)
Map<String, String[]> parameterMap = request.getParameterMap();
for (String key:parameterMap.keySet()) {
String[] value = parameterMap.get(key);
System.out.println(Arrays.toString(value));
}
String name = request.getParameter("name");
String password = request.getParameter("password");
System.out.println(name + "=====" + password);
//3.設置參數(shù)
request.setAttribute("requestName","張三");//向request域中存值
request.getSession().setAttribute("sessionName","李四");//向session域中存值
ServletActionContext.getServletContext()
.setAttribute("applicationName","王五");//向application域中存值
return SUCCESS;
}
}
- 配置struts.xml
<!--通過ServleActionContext訪問Servlet API-->
<action name="RequestAction03_*" class="com.seapp.struts2.action.RequestActionDemo03" method="{1}">
<result name="success">/demo01.jsp</result>
</action>
- 成功返回界面的代碼及內(nèi)容展示
<%--獲取action中傳遞過來的參數(shù)(通過ServletActionContext傳入)--%>
${requestName}</br>
${sessionName}</br>
${applicationName}</br>
第二節(jié):結(jié)果頁面的配置
在struts.xml文件中盆犁,Result的配置非常簡單命咐,使用<result>元素來配置Result邏輯視圖與物理視圖之間的映射,<result>元素可以有name和type屬性蚣抗,但這兩種屬性都不是必選的。
- name屬性:指定邏輯視圖的名稱翰铡,默認值是success;
- type屬性:指定返回的視圖資源的類型钝域,不同的類型代表不同的結(jié)果輸出,默認值是dispatcher;
struts.xml文件中的<result>元素配置代碼如下所示:
<action name="RequestAction03_*" class="com.seapp.struts2.action.RequestActionDemo03" method="{1}">
<result name="success" type="dispatcher">/demo01.jsp</result>
</action>
注意:name屬性的值可以是jsp頁面锭魔,也可以是一個Action的name值例证。
在結(jié)果界面的配置中,Struts2有兩種配置的方式迷捧,一種稱為全局結(jié)果頁面织咧,一種稱為局部結(jié)構(gòu)頁面。全局結(jié)果是指在這個包下的所有返回相同字符串的值漠秋,都可以向這個頁面進行跳轉(zhuǎn)笙蒙。局部結(jié)果是指在某個Action中返回的字符串的值,會向這個頁面跳轉(zhuǎn)庆锦。
2.1 全局結(jié)果頁面:
全局結(jié)果頁面是指在同一個包下面配置的Action中返回相同的字符串的值捅位,都可以跳轉(zhuǎn)到該頁面,需要通過<global-result>進行配置:
<!--配置全局的結(jié)果頁面返回數(shù)據(jù)-->
<global-results>
<result name="success" type="dispatcher">/demo01.jsp</result>
</global-results>
2.2 局部結(jié)果頁面:
局部結(jié)果頁面是指在某個Action中根據(jù)該字符串的值進行頁面的跳轉(zhuǎn)搂抒。只對這個Action有效艇搀。
<action name="RequestAction03_*" class="com.seapp.struts2.action.RequestActionDemo03" method="{1}">
<result name="success" type="dispatcher">/demo01.jsp</result>
</action>
在Struts2中,當框架調(diào)用Action對請求進行處理后求晶,就要向用戶呈現(xiàn)一個結(jié)果視圖焰雕。在Struts2中,預定義了多種ResultType芳杏,其實就是定義了多種展示結(jié)果的技術矩屁。
一個結(jié)果類型就是實現(xiàn)了com.opensymphony.xwork.Result接口的類辟宗,Struts2把內(nèi)置的<result-type>都放在struts-default包中,struts-default就是配置包的父包档插。每個<result-type>元素都是一種視圖技術或者跳轉(zhuǎn)方向的封裝慢蜓,其中name屬性指出在<result>元素中如何引用這種視圖技術或跳轉(zhuǎn)方式,對應著<result>元素的type屬性郭膛。Struts2中預定義的ResultType如表所示:
其中紅色的幾個值比較常用晨抡,需要重點記憶。
第三節(jié):Struts2中數(shù)據(jù)的封裝
在很多實際開發(fā)的場景中:頁面提交請求參數(shù)到Action,在Action中接收參數(shù)并且對請求參數(shù)進行數(shù)據(jù)封裝则剃。封裝到一個JavaBean中耘柱,然后將JavaBean傳遞給業(yè)務層。在Struts2中將數(shù)據(jù)的封裝分成兩大類棍现,一類被稱為屬性驅(qū)動调煎,一類被稱為模型驅(qū)動。
3.1 屬性驅(qū)動(提供屬性的set方法)
屬性驅(qū)動又可以細分為兩種己肮,一種只需要提供屬性的set方法即可士袄。另一種可以通過表達式方法直接封裝到對象中。
- 定義jsp頁面谎僻,建立表單提交數(shù)據(jù)與需要封裝的數(shù)據(jù)對應
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>struts2中的數(shù)據(jù)封裝</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/RequestAction04_submit" method="post">
姓名:<input type="text" name="name"/><br/>
年齡:<input type="text" name="age"/><br/>
生日:<input type="date" name="birthday"/><br/>
工資:<input type="text" name="salary"/><br/>
<input type="submit" value="提交" />
</form>
</body>
</html>
- 定義Action實現(xiàn)需要封裝數(shù)據(jù)的set方法
public class RequestActionDemo04 extends ActionSupport {
private String name;
private int age;
private Date birthday;
private Double salary;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public String submit() throws Exception{
System.out.println(name);
System.out.println(age);
System.out.println(birthday);
System.out.println(salary);
return NONE;
}
- 在struts.xml中對Action進行配置娄柳;
<action name="RequestAction04_*" class="com.seapp.struts2.action.RequestActionDemo04" method="{1}">
</action>
以上這種方式需要通過在Action中定義屬性,并且提供屬性的set方法來完成艘绍。這種方式只需要提供set方法即可赤拒。但若需要傳入的數(shù)據(jù)很多的話,那么Action的屬性也會變得很多诱鞠。再加上屬性有對應的getter/setter方法挎挖,Action類的代碼會變的很膨大。在Action里編寫業(yè)務代碼時航夺,會使得Acction非常臃腫蕉朵。那么如何解決這個問題呢?具體如下:
把屬性和相應的getter/setter方法從Action里提取出來阳掐,單獨作為一個值對象墓造,這個對象就是用來封裝這些數(shù)據(jù)的,在相應的Action里直接使用這個對象锚烦,而且可以在多個Action里使用。采用這種方式帝雇,一般以JavaBean來實現(xiàn)涮俄,所封裝的屬性和表單的屬性一一對應,JavaBean將成為數(shù)據(jù)傳遞的載體尸闸。
3.2 屬性驅(qū)動(頁面提供表達式方式):
- 編寫jsp彻亲,在表單中添加對應的表達式(OGNL)
<h2>通過頁面表達式實現(xiàn)數(shù)據(jù)的封裝</h2>
<form action="${pageContext.request.contextPath}/RequestAction05_submit" method="post">
姓名:<input type="text" name="user.name"/><br/>
年齡:<input type="text" name="user.age"/><br/>
生日:<input type="date" name="user.birthday"/><br/>
工資:<input type="text" name="user.salary"/><br/>
<input type="submit" value="提交" />
</form>
- Action的代碼實現(xiàn):
public class RequestActionDemo05 extends ActionSupport {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String submit() throws Exception{
System.out.println(user);
return NONE;
}
}
- 實現(xiàn)User的JavaBean對象
package com.seapp.struts2.domain;
import java.util.Date;
public class User {
private String name;
private int age;
private Date birthday;
private Double salary;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", birthday=" + birthday +
", salary=" + salary +
'}';
}
}
注意:以上這種方式在Action中需要提供User對象的get方法孕锄,如果沒有get方法,在Struts2的底層就沒有辦法獲得該對象苞尝,那么在User中只會有一個屬性被封裝進去畸肆,而其他的屬性都是null;
3.3 模型驅(qū)動:
在Struts2中模型驅(qū)動(ModelDriven)通過實現(xiàn)ModelDriven接口來接收請求參數(shù),并且要重新getModel()方法宙址,這個方法返回的就是Action所使用的數(shù)據(jù)模型對象轴脐。
模型驅(qū)動方式通過JavaBean模型進行數(shù)據(jù)傳遞。只要是普通的JavaBean就可以充當模型部分抡砂。采用這種方式大咱,JavaBean所封裝的屬性與表單的屬性一一對應,JavaBean將成為數(shù)據(jù)傳遞的載體注益。
- 編寫jsp頁面進行數(shù)據(jù)傳遞
<h2>通過驅(qū)動模型的方法實現(xiàn)數(shù)據(jù)的封裝</h2>
<form action="${pageContext.request.contextPath}/RequestAction06_submit" method="post">
姓名:<input type="text" name="name"/><br/>
年齡:<input type="text" name="age"/><br/>
生日:<input type="date" name="birthday"/><br/>
工資:<input type="text" name="salary"/><br/>
<input type="submit" value="提交" />
</form>
- 新建Action并實現(xiàn)ModelDriVen碴巾,通過數(shù)據(jù)模型來獲取傳遞過來的數(shù)據(jù)
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.seapp.struts2.domain.User;
public class RequestActionDemo06 extends ActionSupport implements ModelDriven<User> {
private User user = new User();
@Override
public User getModel() {
return user;
}
public String submit() throws Exception{
System.out.println(user);
return NONE;
}
}
大部分我們會優(yōu)先使用模型驅(qū)動的方式,因為Struts2內(nèi)部有很多結(jié)果是圍繞模型驅(qū)動設計的丑搔。但如果頁面向多個對象中封裝厦瓢,那么就需要使用屬性驅(qū)動的方式二了。
第四節(jié):Struts2中封裝集合類型的數(shù)據(jù)
4.1 Struts2中List集合數(shù)據(jù)的封裝啤月。
- jsp中頁面編寫煮仇,提供list集合中的提交測試數(shù)據(jù)
<h2>實現(xiàn)List集合數(shù)據(jù)的封裝</h2>
<form action="${pageContext.request.contextPath}/RequestAction07_submit" method="post">
姓名:<input type="text" name="list[0].name"/><br/>
年齡:<input type="text" name="list[0].age"/><br/>
生日:<input type="date" name="list[0].birthday"/><br/>
工資:<input type="text" name="list[0].salary"/><br/>
姓名:<input type="text" name="list[1].name"/><br/>
年齡:<input type="text" name="list[1].age"/><br/>
生日:<input type="date" name="list[1].birthday"/><br/>
工資:<input type="text" name="list[1].salary"/><br/>
<input type="submit" value="提交" />
</form>
- Action中對該list設置getter/setter方法,獲取數(shù)據(jù)并打印
public class RequestActionDemo07 extends ActionSupport {
private List<User> list;
public List<User> getList() {
return list;
}
public void setList(List<User> list) {
this.list = list;
}
public String submit() throws Exception{
for(int i =0;i<list.size();i++){
System.out.println(list.get(i));
}
return NONE;
}
}
4.2 Struts2中Map集合數(shù)據(jù)的封裝:
- 編寫jsp ,提供封裝Map所需要的測試數(shù)據(jù)
<h2>實現(xiàn)Map集合數(shù)據(jù)的封裝</h2>
<form action="${pageContext.request.contextPath}/RequestAction08_submit" method="post">
姓名:<input type="text" name="map['one'].name"/><br/>
年齡:<input type="text" name="map['one'].age"/><br/>
生日:<input type="date" name="map['one'].birthday"/><br/>
工資:<input type="text" name="map['one'].salary"/><br/>
姓名:<input type="text" name="map['two'].name"/><br/>
年齡:<input type="text" name="map['two'].age"/><br/>
生日:<input type="date" name="map['two'].birthday"/><br/>
工資:<input type="text" name="map['two'].salary"/><br/>
<input type="submit" value="提交" />
</form>
- 新建Action顽冶,實現(xiàn)對Map集合數(shù)據(jù)的封裝以及打印
public class RequestActionDemo08 extends ActionSupport {
private Map<String,User> map;
public Map<String, User> getMap() {
return map;
}
public void setMap(Map<String, User> map) {
this.map = map;
}
public String submit() throws Exception{
for (String key:map.keySet()) {
System.out.println(key + "======"+map.get(key));
}
return NONE;
}
}