目錄
l 使用Domain Model (實體模型) 接收參數 - 11 -
l Struts ValueStack(值棧) Debug 15
建立一個Struts2 工程
Ø 1在MyEclipse中新建web工程
Ø 2在struts-2.2.1.1-all\struts-2.2.1.1解壓struts2-blank.war( 最基礎的示例程序 )
Ø 3進入struts-2.2.1.1\apps\struts2-blank\WEB-INF\classes下把struts.xml拷到web工程的src下面,因爲工程編譯完它默認就把src下的文件放到class文件下面。
、
Ø 4.拷類庫,在這個項目的lib文件下面拷
把jar放入lib後看不見jar文件,是因爲MyEclipse默認視圖是package Explorer,如果要看硬盤上對應的視圖,應該打開windows-Show View-other-navigatior
4.配置web.xml,參考struts自帶的web.xml,把filter的配置拷過來
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
第一個示例程序Hello Struts
<struts>
<constant name="struts.devMode" value="true" />
<package name="default" namespace="/" extends="struts-default">
<action name="hello">
<result>/hello.jsp</result>
</action>
</package>
</struts>
http://localhost:8080/strust2_0100_Introduction/
http://localhost:8080/strust2_0100_Introduction/hello 或者
http://localhost:8080/strust2_0100_Introduction/hello.action
跳轉到hello.jsp,第一個示例程序成功!
Struts2讀源碼
配置文件中的
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
一看就應該知道它是對應一個類,在jar文件中找到對應的源碼編譯完的class文件,
查看源碼: jar文件點右鍵---àproperties--àJava Source AttachmentàExternal Folder
(外部文件)
àstruts-2.2.1.1-all/struts-2.2.1.1/src/core/src/main/java
點擊class文件可以查看源碼了,假如想看它的doc文檔,同樣的方法
jar文件點右鍵---àproperties--àJavadoc Location-à導入doc就可以在源碼中右鍵或者F1觀察對應的文檔了。
敲尖括號不提示的問題
Struts.xml文件頭定義了
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
配置:windows---preferences---catalog---。。。xml—xml Catalog—Add
Add入本地定義當前xml的dtd文件:找到struts2-core-2.2.1.1.jar解壓開找到struts-2.1.7.dtd
完成,驗證代碼提示成功!
Struts2的運行機制
當你在客戶端敲http://localhost:8080/strust2_0100_Introduction/hello
首先找到:strust2_0100_Introduction這個web application,找到後去執行這個web application下的web.xml
Tomcat接收到請求之後,會發現這個web.xml下面,配了一個filter,而這個filter過濾所有的url地址,所以當我們在地址欄敲http://localhost:8080/strust2_0100_Introduction/hello後,會被StrutsPrepareAndExecuteFilter接收到
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
StrutsPrepareAndExecuteFilter接收到後url情求後,它首先看namespace
Struts.xml
<package name="default" namespace="/" extends="struts-default">
<action name="hello" >
<result>/hello.jsp</result>
</action>
</package>
查到“/”後面的hello,它就會去package下面查是否有name屬性叫“hello”的action,有的話,找裏面對應的result是誰--àhello.jsp
Struts的好處就是:我可以把“請求”和“視圖展現”分開,而不是寫死。分開的好處就是:如果要換成其他視圖,配一下就好了,所以更加靈活。Struts核心的本質就是解決了:把你的請求和最後的結果分開。
Struts的namespace
示例工程Struts2_0200_Namespace
Struts.xml
<struts>
<constant name="struts.devMode" value="true" />
<package name="front" extends="struts-default" namespace="/front">
<action name="index">
<result>/Namespace.jsp</result>
</action>
</package>
<package name="main" extends="struts-default" namespace="">
<action name="index">
<result>/Namespace.jsp</result>
</action>
</package>
</struts>
所以namespace爲空意味着:只要找到一個index.action,沒有找到精確的對應的namespace,全部都交給namespace爲空的這個package去處理,所以這個package囊括了其他所有package處理不了的action。
Struts自定義具體視圖的返回
示例工程Struts2_0300_Action
修改jsp模板字符編碼:windows-preferences- JSP 修改編碼爲UTF-8即可
IndexAction1.java
public class IndexAction1 {
public String execute() {
return "success";
}
}
IndexAction2.java
public class IndexAction2 implements Action {
public String execute() {
return "success";
}
}
真正企業開發只用這第三種!另外兩種忘記!
IndexAction3.java
public class IndexAction3 extends ActionSupport {
public String execute() {
return "success";
}
}
<struts>
<constant name="struts.devMode" value="true" />
<package name="front" extends="struts-default" namespace="/">
<action name="index" class="com.bjsxt.struts2.front.action.IndexAction1">
<result name="success">/ActionIntroduction.jsp</result>
</action>
</package>
</struts>
具體視圖的返回可以由用戶自己定義的Action來決定
具體的手段是根據返回的字符串找到對應的配置項,來決定視圖的內容
具體Action的實現可以是一個普通的java類,裏面有public String execute方法即可
或者實現Action接口
不過最常用的是從ActionSupport繼承,好處在於可以直接使用Struts2封裝好的方法
如果不配置class屬性,默認執行xwork框架的ActionSupport這個action,這個action就有execute這個方法,return success。
Struts路徑問題
示例工程:Struts2_0400_Path
struts2中的路徑問題是根據action的路徑而不是jsp路徑來確定,所以儘量不要使用相對路徑。
雖然可以用redirect方式解決,但redirect方式並非必要。
解決辦法非常簡單,統一使用絕對路徑。
(在jsp中用request.getContextRoot方式來拿到webapp的路徑)
或者使用myeclipse經常用的,指定basePath
先點擊鏈接http://localhost:8080/Struts2_0400_Path/path/path.action 跳轉到path.jsp 頁面
在path.jsp頁面上有鏈接<a href="index.jsp">index.jsp</a>雖然在webRoot上面index.jsp和
path.jsp同級,但是點擊index.jsp卻跳到http://localhost:8080/Struts2_0400_Path/path/index.jsp
如果改成<a href="/index.jsp">index.jsp</a>跳到http://localhost:8080/index.jsp
因爲JSP中“/”代表整個站點的根路徑而不是應用的根路徑。
解決方案是:永遠使用絕對路徑。
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%>
<base href="<%=basePath%>" />
request.getContextPath()會拿到webapplication的名稱:Struts2_0400_Path
request.getScheme()拿到“http”字符串
request.getServerName()拿到“localhost”
request.getServerPort()拿到“8080”
動態方法調用
<body>
Action執行的時候並不一定要執行execute方法
可以在配置文件中配置Action的時候用method=來指定執行哪個方法
也可以在url地址中動態指定(動態方法調用DMI)(推薦)
<a href="<%=context %>/user/userAdd">添加用戶</a>
<a href="<%=context %>/user/user!add">添加用戶</a>
前者會產生太多的action,所以不推薦使用
</body>
<struts>
<constant name="struts.devMode" value="true" />
<package name="user" extends="struts-default" namespace="/user">
<action name="userAdd" class="com.bjsxt.struts2.user.action.UserAction" method="add">
<result>/user_add_success.jsp</result>
</action>
<action name="user" class="com.bjsxt.struts2.user.action.UserAction">
<result>/user_add_success.jsp</result>
</action>
</package>
</struts>
Action接收參數的方式
Action有三種接收參數的方式
1. 屬性接收參數
2. 用DomainModel(實體模型)接收參數
3. 用ModelDriven接收參數( 不常用 )
Struts2_0700_ActionAttrParamInput
Index.jsp
<head>
<base href="<%=basePath %>"/> </head>
使用action屬性接收參數<a href="user/user!add?name=a&age=8">添加用戶</a>
</body>
</html>
鏈接的意思是:執行user下面的user.action下面的add方法
怎麼接受參數的呢?第一種方式.在自己的action下面定義兩個屬性,寫好get,set方法,當new 完action的時候,會自動把這兩個屬性從參數裏面拿過來,幫你設置好。
參數跟我們的成員變量一一對應,這時候它就會自動把我們的參數傳遞到我們成員變量裏。這時候當我們調用add()方法時,它直接可以用了。
UserAction.java
public class UserAction extends ActionSupport {
private String name;
private int age;
public String add() {
System.out.println("name=" + name);
System.out.println("age=" + age);
return SUCCESS;
}
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;
}
}
Struts.xml
<struts>
<package name="user" extends="struts-default" namespace="/user">
<action name="user" class="com.bjsxt.struts2.user.action.UserAction">
<result>/user_add_success.jsp</result>
</action>
</package>
</struts>
使用Domain Model (實體模型) 接收參數
Struts2_0800_DomainModelParamInput
<html>
<body> 使用Domain Model接收參數
<a href="user/user!add?user.name=a&user.age=8">添加用戶</a>
</body>
</html>
public class UserAction extends ActionSupport {
private User user;
//private UserDTO userDTO;
public String add() {
System.out.println("name=" + user.getName());
System.out.println("age=" + user.getAge());
return SUCCESS;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
public class User {
private String name;
private int age;
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;
}
一般來說,我們輸入參數不一定剛好跟我們的域模型一致,比如說:用戶有name跟password兩個屬性,但是你輸入進來的應該還有個密碼確認passwordconfiguration
這時候我們要麼使用屬性接收,要麼用DTO,或者VO
根據Struts文檔的規定:只要在Struts.xml中配置這段話就可以解決中文亂碼問題
<constant name="struts.i18n.encoding" value="GBK" />
但是2..1.6版本中這是一個Bug,沒法解決中文亂碼問題
解決辦法是:一:升級到2.1.7之後的版本;二是:使用spring的filter,在web.xml中配置過濾
三:在web.xml中配置2.0版本的filter
<filter>
<filter-name>struts2</filter-name> <!--<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>-->
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
</filter>
Struts2文檔的位置:
struts-2.1.8.1-all\struts-2.1.8.1\docs\docs
要知道Strust.xml中有哪些常量可以配置,可以進文檔裏面查看
例子:
struts.i18n.encoding=UTF-8 //表示默認字符集是UTF-8
struts.action.extension=action,, //後綴名可以是“action”,或者是“”空也行。
Struts.xml中:配
<include file=”login.xml”/>
相當於把文件login.xm內容l複製過來
Struts簡單數據驗證
示例程序:Struts2_1100_SimpleDataValiation
UserAction.java
public class UserAction extends ActionSupport {
private String name;
public String add() {
if(name == null || !name.equals("admin")) {
this.addFieldError("name", "name is error");
this.addFieldError("name", "name is too long");
return ERROR;
}
return SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Struts.xml
<struts>
<constant name="struts.devMode" value="true" />
<package name="user" extends="struts-default" namespace="/user">
<action name="user" class="com.bjsxt.struts2.user.action.UserAction">
<result>/user_add_success.jsp</result>
<result name="error">/user_add_error.jsp</result>
</action>
</package>
</struts>
登陸不成功的時候,該怎麼樣向前臺傳遞信息呢? 這時候其實是個麻煩事,因爲我們的userAction實際上是沒有跟我們的Request, response屬性綁在一起的;userAction訪問不到我們的Request, response,ServletContext,這些都沒有,在Struts2裏面是採用另外一種機制。
This.addFieldError(“name”,”name is error”);
添加對於屬性校驗的錯誤信息的,錯誤信息的名字一般也是我們的屬性名字叫做name,那麼這個屬性出錯,後面是這個錯誤的具體信息:name is error!
user_add_error.jsp
<body>
User Add Error!
<s:fielderror fieldName="name" theme="simple"/>
<br />
<s:property value="errors.name[0]"/>
<s:debug></s:debug>
</body>
這裏調用addFieldError()之後在前面如何把它拿出來?
在這裏我們用到struts2的標籤
<s:fielderror fieldname=”name” theme=”simple”>
調用標籤庫的時候,必須這麼寫:
<%@taglib uri=”/struts-tags” prefix=”s”%>
Struts的標籤定義是位於
如果我們去看源碼的話會看到它把我們的錯誤信息封裝成:
<url class=”errorMassage”>
<li><span>name is error!</span></li>
</url>
指定成CSS修飾,這樣就給我們帶來不便,這是Struts2設計不太好的地方。所以Struts2展現的標籤在企業開發中應用得不多,因爲它都是強制要求你必須按照它的命名規則來去定義它的各種各樣的展現。
那我們應該怎麼樣把我們的字符串拿出來?引出下一個標籤,這個標籤以後會很常用:
<s:debug></s:debug>
當你寫了這個標籤之後在頁面就會默認顯示這個標籤 [Debug]
點開[Debug]
Struts ValueStack(值棧) Debug
Value Stack Contents
Object |
Property Name |
Property Value |
com.bjsxt.struts2.user.action.UserAction |
texts |
null |
actionErrors |
[] |
|
errors |
{name=[name is error, name is too long]} |
|
fieldErrors |
{name=[name is error, name is too long]} |
|
errorMessages |
[] |
|
name |
a |
|
locale |
zh_CN |
|
actionMessages |
[] |
|
com.opensymphony.xwork2.DefaultTextProvider |
texts |
null |
首先:Struts2會把Action裏面的屬性挨着排給你放進Value Stack 來
專門有這個標籤很常用s:property
<s:property value="errors.name[0]"/>
<s:property value="errors"/>
取到errors實際上是一個map:{name=[name is error, name is too long]}
那麼我想取到map裏面某一個key的內容:
<s:property value="errors.name"/>
[name is error, name is too long]
而這時候實際上value是一個數組,所以我要想去數組的第一項
<s:property value="errors.name[0]"/>
name is error
Struts2_訪問Web元素
後臺的Action跟我們前臺的頁面來通訊的時候,由於它拿不到request,session,servletContext比如當我們有人登陸了,我們要在session中設一個值,表示它登陸了,但是如果你Action訪問不到session,你如何把相關的數據設到session裏面,response不用訪問它,因爲我們的結果是通過result返回的。
<body>
取得Map類型request,session,application,真實類型 HttpServletRequest, HttpSession, ServletContext的引用:
<li>前三者:依賴於容器</li>
<li>前三者:IOC</li> (只用這種)
<li>後三者:依賴於容器</li>
<li>後三者:IOC</li>
<form name="f" action="" method="post">
用戶名:<input type="text" name="name"/>
密碼:<input type="text" name="password"/>
<input type="button" value="submit1" οnclick="javascript:document.f.action='login/login1';document.f.submit();" />
<input type="button" value="submit2" οnclick="javascript:document.f.action='login/login2';document.f.submit();" />
<input type="button" value="submit3" οnclick="javascript:document.f.action='login/login3';document.f.submit();" />
<input type="button" value="submit4" οnclick="javascript:document.f.action='login/login4';document.f.submit();" />
</form>
</body>
Strust.xml
<struts>
<constant name="struts.devMode" value="true" />
<package name="login" extends="struts-default" namespace="/login">
<action name="login*" class="com.bjsxt.struts2.user.action.LoginAction{1}">
<result>/user_login_success.jsp</result>
</action>
</package>
</struts>
第一種方式:(忘記)
取值的方法:可以在構造方法LoginAction1裏面取值,也可以在execute方法取值。
就是說:下面三行“取值”代碼可以寫在任意兩個方法裏面!
request = (Map)ActionContext.getContext().get("request");
session = ActionContext.getContext().getSession();
application = ActionContext.getContext().getApplication();
public class LoginAction1 extends ActionSupport {
private Map request;
private Map session;
private Map application;
public LoginAction1() {
//取值
request = (Map)ActionContext.getContext().get("request");
session = ActionContext.getContext().getSession();
application = ActionContext.getContext().getApplication();
}
public String execute() {
request.put("r1", "r1");//這裏就不能用setAttribute()了,因爲這裏是Map類型的。用put
session.put("s1", "s1");
application.put("a1", "a1");
return SUCCESS;
}
}
request = (Map)ActionContext.getContext().get("request");
ActionContext.getContext()
Context直接翻譯過來是:”上下文”,在西方人寫的程序特別多,但是中國人很少用,因爲不理解它是什麼東西;Context就是當前執行的環境,就比如同學們在這裏學習,實際上是有一個Context,代表了你周圍的情況,機器的情況,空調的情況,等等,它會把周圍環境幫你封轉到Context這個對象裏面,當你想訪問這些東西的時候,通過Context去取。
原來學習過得ServletContext代表的就是servlet的運行環境,原來我們寫程序就用ServletContext拿到各種各樣的配置,ActionContext也就是Action周邊運行的情況,Action運行的時候,首先接收到請求接收到request,response等等後面再接着調你的處理過程,Action處理的過程中,比如說那些配置怎麼配的,執行環境怎麼樣等等都要通過ActionContext來拿。
原先我們在頁面中都是通過HttpResquest,HttpResponse拿到我們的值,現在我們通過
request = (Map)ActionContext.getContext().get("request");
session = ActionContext.getContext().getSession();
application = ActionContext.getContext().getApplication();
拿到我們的request,response,application。
User_login_success.jsp
<body>
User Login Success!u
<s:property value="#request.r1"/> | <%=request.getAttribute("r1") %>
<s:property value="#session.s1"/> | <%=session.getAttribute("s1") %>
<s:property value="#application.a1"/> | <%=application.getAttribute("a1") %>
<s:property value="#attr.a1"/>
<s:property value="#attr.s1"/>
<s:property value="#attr.r1"/>
<s:debug></s:debug>
</body>
我們的後臺放了request,session,application但是這三個東西都是map,但是它反饋到前臺之後居然用request,session,application可以拿到,所以struts2一定幫我們在Map和HttpRequest之間建立某種聯繫,對於我們自己設定的map類型的request這裏面的屬性在處理的過程中會全都複製到Http對象裏邊去。
第一種訪問request裏面的值:<%=request.getAttribute("r1") //原始的方式
第二種訪問request裏面的值:<s:property value="#request.r1"/>
第二種是用標籤的方式取值,查看debug模式,
Stack Context
These items are available using the #key notation
。。。略
These items are available using the #key notation :下面的items是供你使用的,只要你用#key訪問它,所以你用#request 就可以訪問到request了
上面的Value Stack是可以直接拿的
ActionContext要拿的話加#就能拿。
第二種方式(這種方式是最常用的,其他的都可以忘記)
其實request我們也很少去拿它,因爲我們Action的成員變量默認會起到request的作用,它自己會放到valueStack裏面, valueStack本身就是放到request裏面,所以根本不用去拿request.
import org.apache.struts2.interceptor.ApplicationAware;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;
public class LoginAction2 extends ActionSupport implements RequestAware,SessionAware, ApplicationAware {
//第二種方式區別於第一種方式的不同點是:第一種方式還要在構造函數中進行“取值”,第二種方式直接就能用了!!這個就是IOC(控制反轉)的設計思想,依賴注入DI
private Map<String, Object> request;
private Map<String, Object> session;
private Map<String, Object> application;
public String execute() {
request.put("r1", "r1");
session.put("s1", "s1");
application.put("a1", "a1");
return SUCCESS;
}
public void setRequest(Map<String, Object> request) {
this.request = request;
}
public void setSession(Map<String, Object> session) {
this.session = session;
}
public void setApplication(Map<String, Object> application) {
this.application = application;
}
}
1. 實現一個Action最常用的方式,從ActionSupport繼承
2. DMI動態方法調用
3. 通配符*{1}{2}
4. 接收參數的方法(一般用屬性或者DomainModel來接收)
5. 簡單參數驗證addFieldError 一般不使用Struts2的UI標籤
6. 訪問Web元素
1) Map類型
1. IOC
2. 以來Struts2
2) 原始類型(忘記)
7. 包含文件配置
8. 默認action處理
Struts2_結果類型
<struts>
<constant name="struts.devMode" value="true" />
<package name="resultTypes" namespace="/r" extends="struts-default">
<action name="r1">
<result type="dispatcher">/r1.jsp</result>
</action>
<action name="r2">
<result type="redirect">/r2.jsp</result>
</action>
<action name="r3">
<result type="chain">r1</result>
</action>
<action name="r4">
<result type="redirectAction">r2</result>
</action>
</package>
</struts>
Result類型
1. dispatcher
2. redirect
3. chain
5. freemarker
6. httpheader
7. stream
8. velocity
9. xslt
10. plaintext
11. tiles
前面四個要掌握,只要用前兩個。
ResultType是chain的時候,跳轉到一個Action那邊去處理,如果Action是在另外一個包p1該怎麼辦呢?
查Struts2文檔的路勁---guides----resultTypes-----chain---
例子:
<package name="public" extends="struts-default">
<!-- Chain creatAccount to login, using the default parameter -->
<action name="createAccount" class="...">
<result type="chain">login</result>
</action>
<action name="login" class="...">
<!-- Chain to another namespace -->
<result type="chain">
<param name="actionName">dashboard</param>
<param name="namespace">/secure</param>
</result>
</action>
</package>
<param name="namespace">:指定要跳到的namespace
<param name="actionName">指定要跳到的Action
OGNL是Object-Graph Navigation Language(對象圖導航語言)的縮寫,它是一種功能強大的表達式語言(Expression Language,簡稱爲EL),通過它簡單一致的表達式語法,可以存取對象的任意屬性,調用對象的方法,遍歷整個對象的結構圖,實現字段類型轉化等功能。它使用相同的表達式去存取對象的屬性。
第一個例子
Index.jsp
<body>
訪問屬性
<a href="<%=contextPath %>/ognl.action?username=u&password=p">ognl</a>
</body>
Ognl.xml
<struts>
<package name="ognl" extends="struts-default">
<action name="ognl" class="com.bjsxt.struts2.ognl.OgnlAction">
<result>/ognl.jsp</result>
</action>
</package>
</struts>
OgnlAction.java
public class OgnlAction extends ActionSupport {
private String password;
private String username;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getPassword() {
return password;
}
public String getUsername() {
return username;
}
public void setPassword(String password) {
this.password = password;
}
public void setUsername(String username) {
this.username = username;
}
}
User.java
public class User {
private int age = 8;
public User() {
}
public User(int age) {
super();
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override//重寫toString
public String toString() {
return "user" + age;
}
}
此時的url:http://localhost:8080/ognl_0100/ognl.action?username=u&password=p 值棧中的內容
<body>
<ol>
<li>訪問值棧中的:username = <s:property value="username"/> </li>
<li>訪問值棧中的:password=<s:property value="password"/></li>
</ol>
<s:debug></s:debug>
</body>
Struts ValueStack Debug
Value Stack Contents
Object |
Property Name |
Property Value |
com.bjsxt.struts2.ognl.OgnlAction |
password |
p |
locale |
zh_CN |
|
user |
null |
|
errorMessages |
[] |
|
errors |
{} |
|
actionErrors |
[] |
|
username |
u |
|
texts |
null |
|
fieldErrors |
{} |
|
actionMessages |
[] |
|
com.opensymphony.xwork2.DefaultTextProvider |
texts |
null |
http://localhost:8080/ognl_0100/ognl.action?username=u&password=p&user.age=9就出來了。
在OGNL表達式的裏面傳參的時候必須把user.xxx 傳進去,Struts才能幫我們構造user方法
只有user.xxx 傳,纔會構造
1).能不能不在url中傳user.xxx直接在Action中直接new 出來,能不能取到user的值呢?
Private User user=new User(10);
//原來初始值等於8
結論:也是可以的,因爲我們new出Action,Action又new出User,當然就不爲null了
2).把User()空的構造方法去掉,能不能取到user的值呢?
http://localhost:8080/ognl_0100/ognl.action?username=u&password=p&user.age=9
把User爲空的構造方法去掉之後,它就沒有默認爲空的構造方法,別人要幫你初始化這個User的時候它確定不了應該調用哪個構造方法,所以取不到值。
java.lang.InstantiationException: com.bjsxt.struts2.ognl.User
實例化User出錯,所以一般我們的Domain Model(領域模型)永遠都要提供一個默認參數爲空的方法;
結論:如果我的Domain Model,也就是User對象我自己沒有new,也就是Action裏面自己沒有new,想讓Struts2幫你new的時候必須要給domainModel傳值,在它幫你new的過程中你的damainModel必須有一個默認爲空的構造方法,否則它不知道new出哪一個。
OGNL_2
在原來的OgnlAction.java中增加Cat屬性和get set 方法
Cat.java
public class Cat {
private Dog friend;
public Dog getFriend() {
return friend;
}
public void setFriend(Dog friend) {
this.friend = friend;
}
public String miaomiao() {
return "miaomiao";
}
}
Dog.java
public class Dog {
private String name;
public Dog() { }
public Dog(String name) {
super();
this.name = name;
}
Get,set方法……..
public String toString() {
return "dog: " + name;
}
}
爲什麼叫做OGNL對象圖導航語言?比如說我們訪問OgnlAction.java裏面通過“user.age”
那麼這時候如果我們想訪問ognlAction裏面的cat的dog該怎麼寫? Cat.friend.name
OGNL
1. user.xxx只有傳,纔會構造,想初始化domain Model,可以自己new也可以傳值,但這時候必須有默認爲空的構造方法。
OGNL訪問
http://localhost:8080/ognl_0100/ognl.action?username=u&password=p&cat.friend.name=judi
值棧中的內容
<body>
<li>訪問值棧中對象的普通屬性(get set方法):
<s:property value="cat.friend.name"/></li>
<li>訪問值棧中對象的普通方法:
<s:property value="password.length()"/></li>
<s:property value="cat.miaomiao()" /></li>
<li>訪問值棧中action的普通方法:<s:property value="m()" /></li>
</body>
OGNL訪問靜態方法/屬性:
訪問靜態方法/屬性的語法:前面@+類名,後面@+方法名/前面@+類名,後面@+屬性名
先寫類S.java
public class S {
public static String STR="STATIC STRING ";
public static String s(){
return "Hello";
}
}
<body>
訪問靜態方法:<s:property value="@com.bjsxt.struts2.ognl.S@s()"/>
</body>
要在struts.xml中增加配置:
<constant name="struts.ognl.allowStaticMethodAccess" value="true">
</constant>
在Struts2中常量的值在:
struts2-core-2.1.8.1.jar-->org.apache.struts2-->default.properties中查:
<body>訪問普通類的構造方法:
<s:property value="new com.bjsxt.struts2.ognl.User(8)"/>
</body>
OGNL訪問集合
在OgnlAction.java中添加:
private List<User> users = new ArrayList<User>();
private Map<String, Dog> dogMap = new HashMap<String, Dog>();
private Set<Dog> dogs = new HashSet<Dog>();
get方法。。。set方法。。。。(略)
public OgnlAction() {
users.add(new User(1));
users.add(new User(2));
users.add(new User(3));
dogs.add(new Dog("dog1"));
dogs.add(new Dog("dog2"));
dogs.add(new Dog("dog3"));
dogMap.put("dog100", new Dog("dog100"));
dogMap.put("dog101", new Dog("dog101"));
dogMap.put("dog102", new Dog("dog102"));
}
11.訪問List:<s:property value="users"/>
12.訪問List中某個元素:<s:property value="users[1]"/>
13.訪問List中元素某個屬性的集合:<s:property value="users.{age}"/>
14.訪問List中元素某個屬性的集合中的特定值:<s:property value="users.{age}[0]"/> | 第二種訪問方式<s:property value="users[0].age"/>
15.訪問Set:<s:property value="dogs"/>
16.訪問Set中某個元素:<s:property value="dogs[1]"/>
17.訪問Map:<s:property value="dogMap"/>
18.訪問Map中某個元素:
第一種寫法:<s:property value="dogMap.dog101"/> |
第二種寫法:<s:property value="dogMap['dog101']"/>|
第三種寫法:<s:property value="dogMap[\"dog101\"]"/>
19.訪問Map中所有的key:<s:property value="dogMap.keys"/>
20.訪問Map中所有的value:<s:property value="dogMap.values"/>
21.訪問容器的大小:
<s:property value="dogMap.size()"/> | <s:property value="users.size"/>
Struts投影
投影,英文叫做projection,其實就是過濾器的意思,把符合條件的給過濾出來
<body>
投影(過濾):<s:property value="users.{?#this.age==1}.{age}"/>
投影:<s:property value="users.{^#this.age>1}.{age}"/>
投影:<s:property value="users.{$#this.age>1}.{age}"/>
投影:<s:property value="users.{$#this.age>1}.{age} == null"/>
</body>
執行結果:
如果去掉.{age} <s:property value="users.{?#this.age==1}"/>
執行結果:
如果想取出集合中的第一個元素。
<s:property value="users.{?#this.age==1}[0]"/>
執行結果:
<s:property value="users.{^#this.age>1}.{age}"/>
“^”(小尖號)代表開頭,指的是:大於一的集合那些元素裏頭開頭的第一個,它的age值的集合
<s:property value="users.{$#this.age>1}.{age}"/>
“$”[dolar]代表結尾,指的是: 大於一的集合那些元素裏頭結尾的那個,它的age值的集合
<s:property value="users.{$#this.age>1}.{age} == null"/>
用來判斷集合裏面有沒有元素。
用中括號訪問元素
[]:<s:property value="[1]"/>
執行結果:
查看Debug這個ValueStack只有兩個Object,我們剛剛訪問的這個Action永遠在棧頂,所以如果要訪問Action對象,完全可以這樣寫:
[]:<s:property value="[0]"/>
中括號訪問的OGNL這個棧裏面從上往下數的第幾個元素;
在OGNL裏面[0]代表的是ognl的stack從上往下從第0個位置開始往下一直到棧底的集合
如果要訪問ognl裏面的某一個成員變量比如說username,這時候如果裏面有兩個Action的話,第一個Action沒有,它會按順序往下找第二個Action,什麼情況下會有兩個Action在裏面呢?
<action name="ognl" class="com.bjsxt.struts2.ognl.OgnlAction">
<result>/ognl.jsp</result>
</action>
<action name="test" class="com.bjsxt.struts2.ognl.TestAction">
<result type="chain">ognl</result>
</action>
在url訪問: http://localhost:8080/Struts2_1900_OGNL/test.Action
說明了:首先棧裏面被壓入了test.action,其次被壓入了ognl.action所以證明了如果用了服務器端跳轉,它會把用到的action挨着排往裏面壓。
Struts標籤
Struts標籤分爲
1.通用標籤 (重要)
2.控制標籤 (重要)
3.UI標籤 (重要)
4.AJAX標籤 (不重要)
5.$,#,%區別
標籤多動手就會用了,如果程序設計得比較好很多標籤都很少用,所以只講重要的常見的。
1.通用標籤
A) property
B) set
C)
D)
E)
2.控制標籤
A)
B)
3.UI標籤
5.$,#,%區別
-----------------------------------------------------------------------------------------------------------------
http://localhost:8080/Struts2_2000_StrutsTags/tags.action?username=u&password=p
Struts.xml
<action name="tags" class="com.bjsxt.struts2.tags.TagsAction">
<result>/tags.jsp</result>
</action>
public class TagsAction extends ActionSupport {
private String password;
private String username;
public TagsAction() {
}
public String execute() {
this.addFieldError("fielderror.test", "wrong!");
return SUCCESS;
}
Get,set方法。。。。
}
Property
<body>
<s:property value="username"/>
property取值爲字符串 <s:property value="'username'"/>
property設定默認值 <s:property value="admin" default="管理員"/>
property設定HTML<s:property value="'<hr/>'" escape="false"/>
</body>
Value的屬性值究竟是OGNL還是普通字符串,得去API查parameters!
Set
set設定adminName值(如果不設scope屬性,默認爲request和ActionContext)
<s:set var="adminName" value="username"/>
set從request取值<s:property value="#request.adminName"/>
set 從ActionContext取值<s:property value="#adminName" />
set 設定var,範圍爲ActionContext:
<s:set var="adminPassword" value="password" scope="session"/>
set 使用#取值<s:property value="#adminPassword"/>
set 從相應範圍取值<s:property value="#session.adminPassword"/>
request裏面也能取到adminName的值,但是在debug標籤下的request沒有找到adminName變量,原因是:它還沒來得及把這個值放到request裏面debug已經形成了,
所以判定它有沒有應該取出來看一下。
Bean