一、Action的類型
A、使用普通的類
- 必須有public的execute且返回值為String的方法。
ActionType.java
package com; public class ActionType_1 { public String execute() { System.out.println("我是Action類型1"); return null; } }
B、實現Actin接口
- 實現com.opensymphony.xwork2.Action接口,並實現該接口中的execute()方法。
- 在實際開發中,action類很少直接實現Action接口,通常都是從com.opensymphony.xwork2.ActionSupport類繼承,ActionSupport實現了Action接口和其他一些可選的接口,提供了輸入驗證,錯誤信息存取,以及國際化的支持,選擇從ActionSupport繼承,可以簡化action的定義。
- Action接口中定義了一些常量和一個方法。
C、繼承ActionSupport類
- 這個類里面封裝了大量的方法,且實現了B中Action接口,
package com; import com.opensymphony.xwork2.ActionSupport; public class ActionType_3 extends ActionSupport { @Override public String execute() throws Exception { System.out.println("這是繼承ActionSupport的類"); return super.execute(); } }
二、調用Action中的方法
A、 使用method屬性
示例:
ActionMethod_1.java:
package method; import com.opensymphony.xwork2.ActionSupport; public class ActionMethod_1 extends ActionSupport { @Override public String execute() throws Exception { System.out.println("執行默認execute方法"); return super.execute(); } public String add() { System.out.println("執行add方法"); return NONE; } public String del() { System.out.println("執行del方法"); return NONE; } public String list() { System.out.println("執行list方法"); return NONE; } public String uptdate() { System.out.println("執行uptdate方法"); return NONE; } }
假設Actionmethod_1這個Action中有4個方法(除execute外),如果我們要用method屬性調用這些方法,則需要:
struts.xml
<package name="default" namespace="/" extends="struts-default"> <action name="method_1" class="method.ActionMethod_1" method="add"> </action> <action name="method_2" class="method.ActionMethod_1" method="del"> </action> <action name="method_3" class="method.ActionMethod_1" method="uptdate"> </action> <action name="method_4" class="method.ActionMethod_1" method="list"> </action> </package>
如配置,當地址欄URL=“工程名/method_1”時,執行method.ActionMethod_1類中的add方法; 當地址欄URL=“工程名/method_2”時,執行method.ActionMethod_1類中的adel方法,以此類推。
- 缺點:如果某個類有很多方法的時候,那么配置起來很麻煩,代碼非常多,一般適用於類方法特別少的情況下。
B、 使用動態方法調用
- 對以上示例優化:
ActionMethod_1.java:
package method;
import com.opensymphony.xwork2.ActionSupport;
public class ActionMethod_1 extends ActionSupport {
@Override
public String execute() throws Exception {
System.out.println("執行默認execute方法");
return super.execute();
}
public String add()
{
System.out.println("執行add方法2");
return NONE;
}
public String del()
{
System.out.println("執行del方法2");
return NONE;
}
public String list()
{
System.out.println("執行list方法2");
return NONE;
}
public String uptdate()
{
System.out.println("執行uptdate方法2");
return NONE;
}
}
struts.xml
<struts> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <constant name="struts.devMode" value="true" /> <package name="default" namespace="/" extends="struts-default"> <action name="method" class="method.ActionMethod_1"> </action> </package> </struts>
- 注意: 使用動態方法調用,struts.enable.DynamicMethodInvocation 這個常量必須是true ;
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <% String path=request.getContextPath(); %> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <a href="<%=path%>/method!add">執行add方法</a> <a href="<%=path%>/method!del">執行del方法</a> <a href="<%=path%>/method!uptdate">執行uptdate方法</a> <a href="<%=path%>/method!list">執行list方法</a> </body> </html>
解析: 當點擊a標簽時候,請求url中的!后跟的是方法名,<a href="<%=path%>/method!add">執行add方法</a> 即當點擊這個標簽時,執行action名為“method”中的add方法。其他的依次類推。 這種方法就避免了在struts.xml文件中配置過多,導致代碼臃腫。
注意的是:使用動態方法調用,struts.enable.DynamicMethodInvocation 這個常量必須是true ;
C、 使用通配符方法(推薦使用)
ActionMethod_1.java
package method; import com.opensymphony.xwork2.ActionSupport; public class ActionMethod_1 extends ActionSupport { @Override public String execute() throws Exception { System.out.println("執行默認execute方法"); return super.execute(); } public String add() { System.out.println("執行add方法3"); return NONE; } public String del() { System.out.println("執行del方法3"); return NONE; } public String list() { System.out.println("執行list方法3"); return NONE; } public String uptdate() { System.out.println("執行uptdate方法3"); return NONE; } }
idnex.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <% String path=request.getContextPath(); %> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <a href="<%=path%>/method_add">執行add方法</a> <a href="<%=path%>/method_del">執行del方法</a> <a href="<%=path%>/method_uptdate">執行uptdate方法</a> <a href="<%=path%>/method_list">執行list方法</a> </body> </html>
struts.xml
<struts> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <constant name="struts.devMode" value="true" /> <package name="default" namespace="/" extends="struts-default"> <action name="method_*" class="method.ActionMethod_1" method="{1}"> </action> </package> </struts>
- 解析:當點擊<a href="<%=path%>/method_add">執行add方法</a> 這個標簽的時候,請求url為"工程名/method_add",在命名空間為“/”的包下找到一個叫
“method_*”的Action,* 號表示任意字符(任意長度),即調用method.ActionMethod_1這個類,並調用method=“{1}” 這個方法,{1} 中的表示*表示的字符,在這個標簽中*代表add,所以就調用了ActionMethod_1類中的add方法。
注意: 如果有多個通配符,
<action name="method_*_*" class="method.ActionMethod_1" method="{1}"> 而標簽為<a href="<%=path%>/method_exam_add">執行add方法</a>,則調用的是第一個通配符匹配的字符即exam方法。
三、接收表單(用戶請求)的值
3.1 在struts中獲取servlet的原生對象
- 獲取servlet原生對象的方式如下:
A、 實現相應的接口,注入servlet對象
示例:
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <% String path=request.getContextPath(); %> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <a href="<%=path%>/servlet/obj">獲取並測試servlet原生對象</a> </body> </html>
struts.xml
<struts> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <constant name="struts.devMode" value="true" /> <package name="default" namespace="/servlet" extends="struts-default"> <action name="obj" class="com.ServletObject"></action> </package> </struts>
ServletObject.java
package com; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.struts2.interceptor.ServletRequestAware; import org.apache.struts2.interceptor.ServletResponseAware; import org.apache.struts2.util.ServletContextAware; import com.opensymphony.xwork2.ActionSupport; public class ServletObject extends ActionSupport implements ServletRequestAware,ServletResponseAware,ServletContextAware{ //定義servlet原生對象為成員變量,否則如果是局部變量生命周期太短。 private ServletContext servletContext; private HttpServletResponse response; private HttpServletRequest request; private PrintWriter out; private HttpSession session; /** * 設置ServletContext */ public void setServletContext(ServletContext servletContext) { this.servletContext=servletContext; } /** * 設置ServletResponse,得到response之后就可由response得到PrintWriter對象 */ public void setServletResponse(HttpServletResponse response) { this.response=response; if(response!=null) { try { this.out=response.getWriter(); } catch (IOException e) { e.printStackTrace(); } } } /** * 設置ServletRequest,得到request之后就可由request得到HttpSession */ public void setServletRequest(HttpServletRequest request) { this.request=request; if(request!=null) { this.session=request.getSession(); } } public String execute() { /** * 測試servlet原生對線是否真正獲取可以使用 */ System.out.println(this.request.getContextPath()); //獲取工程路徑 System.out.println(this.session.getId()); //獲取session的id System.out.println(this.servletContext.getRealPath("/index.jsp")); //獲取/index.jsp的真實路徑 this.out.print("我是PrintWriter類的對象out"); return NONE; } }
- 本例只獲取了5中servlet原生對象,但只實現了ServletRequestAware,ServletResponseAware,ServletContextAware三個接口,至於printWriter、httpsession對象,則分別由ServletResponseAware對象、ServletRequestAware對象來獲取即可。
- ServletContext.getRealPath()獲取的是真實路徑,即在硬盤上的路徑(如C:\Users\Administrator\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\struts_project_2\index.jsp),而request.getContextPath()獲得是工程路徑(如/struts_project_2)。
B、 使用struts提供的靜態類來獲取
package com; import java.io.PrintWriter; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class ServletObject extends ActionSupport { public String execute() { try{ HttpServletRequest request=ServletActionContext.getRequest(); HttpServletResponse response=ServletActionContext.getResponse(); ServletContext servletContext=ServletActionContext.getServletContext(); PrintWriter out=response.getWriter(); HttpSession session=request.getSession(); /** * 測試servlet原生對線是否真正獲取可以使用 */ System.out.println(request.getContextPath()); //獲取工程路徑 System.out.println(session.getId()); //獲取session的id System.out.println(servletContext.getRealPath("/index.jsp")); //獲取/index.jsp的真實路徑 out.print("我是PrintWriter類的對象out"); } catch(Exception e) { e.printStackTrace(); } return NONE; } }
-
ServletActionContext 這個靜態類提供了Servlet原生對象的創建等。
-
在Action中獲取servlet原生對象的總結:
一般來說用第一種方法來獲取,但是這種方法每個Action都要寫一大堆代碼很麻煩,所以這里可以把這些servlet原生對象封裝為一個抽象基類,其他Action要使用servlet原生對象的話就繼承這個抽象類並實現抽象execute方法即可。
示例:
BaseAction.java
package com; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.struts2.interceptor.ServletRequestAware; import org.apache.struts2.interceptor.ServletResponseAware; import org.apache.struts2.util.ServletContextAware; public abstract class BaseAction implements ServletRequestAware,ServletResponseAware,ServletContextAware { HttpServletRequest request; HttpServletResponse response; ServletContext servletContext; HttpSession session; PrintWriter out; public void setServletContext(ServletContext servletContext) { this.servletContext=servletContext; } public void setServletResponse(HttpServletResponse response) { this.response=response; if(response!=null) { try { this.out=response.getWriter(); } catch (IOException e) { e.printStackTrace(); } } } public void setServletRequest(HttpServletRequest request) { this.request=request; if(request!=null) { this.session=request.getSession(); } } abstract public String execute(); }
3.2 獲取請求參數中的值
A、 使用servlet原生對象request來獲取
A1. 從GET請求中獲取參數 :
-
get把數據放在網址中,例如:http://www.abc.com/index.php?a=1&b=2 其中?a=1&b=2就是get數據,並且連http://www.abc.com/index.php長度限制在1024個字。
示例:
index.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <% String path=request.getContextPath(); %> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <a href="<%=path%>/request/getpost!get?userId=001&userName=用戶名">用request原生對象來獲取GET請求中的參數</a> </body> </html>
- 解析:“<%=path%>/request/getpost!get?userId=001&userName=用戶名 ” 表示在“/request”這個命名空間中找到getpost這個對象,執行這個對象中的get方法,並
把參數userId=001和userName=用戶名作為參數傳過去。
struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.i18n.encoding" value="UTF-8"></constant> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <constant name="struts.devMode" value="true" /> <package name="request" namespace="/request" extends="struts-default" > <action name="getpost" class="com.ActionRequest"></action> </package> </struts>
ActionRequest.java
package com; import java.io.UnsupportedEncodingException; public class ActionRequest extends BaseAction{ @Override public String execute() { return null; } public String get() throws UnsupportedEncodingException { /** * 模擬GET請求 */ String userId=request.getParameter("userId"); String userName=request.getParameter("userName"); userName=new String(userName.getBytes("ISO-8859-1"),"UTF-8"); System.out.println("userId="+userId); System.out.println("userName="+userName); return null; } public String post() { /** * 模擬POST請求 */ //TODO return null; } }
- 解析: userName=new String(userName.getBytes("ISO-8859-1"),"UTF-8"); 如果沒有這行代碼,結果的userName值是亂碼,盡管我們在struts.xml里設置了<constant name="struts.i18n.encoding" value="UTF-8"></constant> 但是還是亂碼,就算再加個 request.setCharacterEncoding("utf-8");也是沒用的依舊是亂碼,可知
- struts.i18n.encoding=UTF-8和request.setCharacterEncoding("utf-8"); 只針對POST請求有作用,對GET是無效的。
- 對於GET請求亂碼問題,可以用 userName=new String(userName.getBytes("ISO-8859-1"),"UTF-8"); 這種方法來做,但是如果每個頁面都這樣做的話或者說需要轉的參數比較多的話就很麻煩,可以用過濾器來解決。
- 過濾器解決GETPOST參數亂碼示例見(四)Decorator設計模式解決GET/POST請求的亂碼問題
A2.POST請求:
-
post則是把數據放到http請求中,例如還是傳輸a=1&b=2,可是網址還是http://www.abc.com/index.php,比如表單的post提交,在網址上我們是看不到用戶輸入的數據的。
- 示例請見(四)Decorator設計模式解決GET/POST請求的亂碼問題
B、 使用屬性驅動來獲取
- 原則:控件的名稱等於Action中成員變量名,並且屬性都要有getset方法。
- 示例一:
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> 以屬性驅動來獲取表單值 <form action="request/shuxing!post_2" method="post" > 用戶名:<input type="text" name="userName" /> <br/> 密 碼:<input type="password" name="passWd"/><br/> 愛 好:<input type="checkbox" name="like" value="籃球"/>籃球 <input type="checkbox" name="like" value="足球"/>足球 <input type="submit" /> </form> </body> </html>
界面:
struts.xml
<struts> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <constant name="struts.devMode" value="true" /> <package name="default" namespace="/request" extends="struts-default"> <action name="shuxing" class="action.AttrrbuteDriver"></action> </package> </struts>
- AttrrbuteDriver.java
package action; import java.util.List; public class AttrrbuteDriver extends BaseAction{ /** * 以屬性驅動的方式來獲取表單中的值 * 前提是: 1. 控件名(即表單元素名)與Action中的成員變量名要一致 * 2. Action中的成員變量要有getset方法 */ private String userName; //獲取表單元素名為userName的值, private String passWd; //獲取表單元素名為passWd的值 private List<String> like; //也可以用String[]來獲取表單元素名為checkbox的值 public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassWd() { return passWd; } public void setPassWd(String passWd) { this.passWd = passWd; } public List<String> getLike() { return like; } public void setLike(List<String> like) { this.like = like; } @Override public String execute() { System.out.println("execute方法"); return null; } public String post_2(){ System.out.println(userName); System.out.println(passWd); for(String likes:like){ System.out.println(likes); } return null; } }
如果一個表單元素有很多的時候,那么Action中定義的成員變量就會很多,代碼會冗長,所以我們可以把其中一些成員變量封裝到JavaBean里,具體如下:
- 屬性驅動優化示例:
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h3>以屬性驅動來獲取表單值</h3> <form action="request/shuxing!post_2" method="post" > 用戶名:<input type="text" name="userName" /> <br/> 密 碼:<input type="password" name="passWd"/><br/> 愛 好:<input type="checkbox" name="like" value="籃球"/>籃球 <input type="checkbox" name="like" value="足球"/>足球 <h3>注冊狗的信息</h3> dogId:<input type="text" name="dog.dogId" /> <br/> dogName:<input type="text" name="dog.dogName" /> <br/> dogColor:<input type="text" name="dog.dogColor" /> <br/> <input type="submit" /> </form> </body> </html>
- 注意這里的 name="dog.dogId" 中的“dog.dogId”的寫法,dog為Action中成員變量的引用,dogId為javaBean中的成員變量名。
struts.xml
<struts> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <constant name="struts.devMode" value="true" /> <package name="default" namespace="/request" extends="struts-default"> <action name="shuxing" class="action.AttrrbuteDriver"></action> </package> </struts>
AttrrbuteDriver.java
package action; import java.util.List; import bean.DogBean; public class AttrrbuteDriver extends BaseAction{ /** * 以屬性驅動的方式來獲取表單中的值 * 前提是: 1. 控件名(即表單元素名)與Action中的成員變量名要一致 * 2. Action中的成員變量要有getset方法 */ private String userName; //獲取表單元素名為userName的值, private String passWd; //獲取表單元素名為passWd的值 private List<String> like; //也可以用String[]來獲取表單元素名為checkbox的值 private DogBean dog; //DogBean是JavaBean public DogBean getDog() { return dog; } public void setDog(DogBean dog) { this.dog = dog; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassWd() { return passWd; } public void setPassWd(String passWd) { this.passWd = passWd; } public List<String> getLike() { return like; } public void setLike(List<String> like) { this.like = like; } @Override public String execute() { System.out.println("execute方法"); return null; } public String post_2(){ System.out.println(userName); System.out.println(passWd); for(String likes:like){ System.out.println(likes); } System.out.println(dog.getDogName()); System.out.println(dog.getDogId()); System.out.println(dog.getDogColor()); return null; } }
- DogBean.java
package bean; public class DogBean { private String dogId; private String dogName; private String dogColor; public String getDogId() { return dogId; } public void setDogId(String dogId) { this.dogId = dogId; } public String getDogName() { return dogName; } public void setDogName(String dogName) { this.dogName = dogName; } public String getDogColor() { return dogColor; } public void setDogColor(String dogColor) { this.dogColor = dogColor; } }
結果:
解析: dogId:<input type="text" name="dog.dogId" /> 中的“dog.dogId”中的dog為Action類(本例中為AttrrbuteDriver類)的成員變量名即private DogBean dog; 而且dog成員變量也要有getset方法。“dog.dogId”中的dogId為JavaBean(本例中為DogBean)的成員變量dogId.
C、 使用模型驅動來獲取
- 定義一個模型來接受表單中的數據,前提是Action類實現ModelDriven<類型>,並重寫其中的getModel()方法,比如class Action_One ModelDriven<Dog>() 意思是這個Action接受Dog這個模型的數據。
- 每個Action類只能實現一個ModelDriven<類型> 模型,也就是只能接受一個模型的數據。
- 示例:
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h3>以模型驅動來獲取表單值</h3> <form action="request/shuxing!post_2" method="post" > 用戶名:<input type="text" name="userName" /> <br/> 密 碼:<input type="password" name="passWd"/><br/> 愛 好:<input type="checkbox" name="like" value="籃球"/>籃球 <input type="checkbox" name="like" value="足球"/>足球 <h3>注冊狗的信息</h3> dogId:<input type="text" name="dogId" /> <br/> dogName:<input type="text" name="dogName" /> <br/> dogColor:<input type="text" name="dogColor" /> <br/> <input type="submit" /> </form> </body> </html>
界面:
struts.xml和DogBean.java與前一個例子一樣,
package action; import java.util.List; import com.opensymphony.xwork2.ModelDriven; import bean.DogBean; public class AttrrbuteDriver extends BaseAction implements ModelDriven<DogBean>{ /** * 模型驅動方法來獲取表單元素值 * 1. 實現ModelDriven<類型>,並重寫其中的getModel()方法 * 2. 本例中AttrrbuteDriver接受Dog這個模型的數據,且實現一個接口,即這個類只能接受一個數據模型, * 如果再加implements ModelDriven<DogBean>,ModelDriven<UserBean> * 這是錯的,雖然平常來說語法是正確的。 */ private String userName; //獲取表單元素名為userName的值, private String passWd; //獲取表單元素名為passWd的值 private List<String> like; //也可以用String[]來獲取表單元素名為checkbooks的值 private DogBean dog; public DogBean getModel() { this.dog=new DogBean(); return dog; } public DogBean getDog() { return dog; } public void setDog(DogBean dog) { this.dog = dog; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassWd() { return passWd; } public void setPassWd(String passWd) { this.passWd = passWd; } public List<String> getLike() { return like; } public void setLike(List<String> like) { this.like = like; } @Override public String execute() { System.out.println("execute方法"); return null; } public String post_2(){ System.out.println(userName); System.out.println(passWd); for(String likes:like){ System.out.println(likes); } System.out.println(dog.getDogName()); System.out.println(dog.getDogId()); System.out.println(dog.getDogColor()); return null; } }
結果: