Struts2零散筆記

來源:互聯網
上載者:User

標籤:http   java   使用   檔案   資料   os   

Struts2-Action:
搭建MyEclipse架構,在Window/Prefrence中設定Server/Tomcat的目錄,然後設定java選項卡中JDK的路徑。

Struts的運行機制:
URL請求通過HTTP協議發送給TOMCAT(假設我們的url為http://localhost:8080/$webapplication的名字$/hello),
根據URL中請求的webapplication再交給對應的webapplication處理,然後參考其web.xml的配置,其中有:
...
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
...
被org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter接受,它又會參考struts.xml的namespace,再根據其下對應的action和result,
將請求轉到對應的JSP檔案。

struts的作用就是將請求和視圖分開。

struts.xml解釋:
<struts>

<constant name="struts.devMode" value="true" />
<package name="front" extends="struts-default" namespace="/front">//package區分重名的情況;namespace不為空白時必須用‘/‘開頭,當想訪問這個namespace中的action就需要在前面帶上這個路徑
<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>

例如要訪問帶***號的name="index"的action,則url為http://localhost:8080/$webapplication的名字$/front/index
namespace決定了action的訪問路徑,不寫時預設為"",可以接收所有路徑的action
namespace可以寫為/,或者/xxx,或者/xxx/yyy,對應的action訪問路徑為/index.action,/xxx/index.action,或者/xxx/yyy/index.action.
namespace最好也用模組來進行命名。

<constant name="struts.devMode" value="true" />
<package name="front" extends="struts-default" namespace="/">
<action name="index" class="com.bjsxt.struts2.front.action.IndexAction1">//當請求這個action的時候,找到對應的class,執行它裡面的execute()方法,傳回值時String,就把他當成一個Action。
<result name="success">/ActionIntroduction.jsp</result>
</action>
</package>

具體視圖的返回可以由使用者自己定義的Action來決定。
具體的手段是根據返回的字串找到對應的配置項,來決定視圖的內容。
具體Action的實現可以是一個普通的java類,裡面有public String execute方法即可。
或者實現Action介面。
不過最常用的是從ActionSupport繼承,好處在於可以直接使用Struts2封裝好的方法。

Struts1和Struts2的一個區別:Struts2的每一個Action都是新NEW的,而Struts1不是,故2解決了線程同步問題。

struts2中的路徑問題是根據action的路徑而不是jsp路徑來確定,所以盡量不要使用相對路徑。
雖然可以用redirect方式解決,但redirect方式並非必要。
解決辦法非常簡單,統一使用絕對路徑。(在jsp中用request.getContextRoot方式來拿到webapp的路徑)
或者使用myeclipse經常用的,指定basePath:
<%//擷取根目錄路徑
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<base href="<%=basePath%>" />//設定當前頁面下的連結的根路徑

Action執行的時候並不一定要執行execute方法。
可以在設定檔中配置Action的時候用method=來指定執行哪個方法
也可以在url地址中動態指定(動態方法引動過程DMI)(推薦):!+方法名
前者會產生太多的action,所以不推薦使用。

使用萬用字元可以將配置降到最低,不過一定要遵守“約定優於配置”。視頻14。

在action中傳參數有三種方法。

值堆棧中每一個元素都有一個名字和一個值。

//用javascript指定這個form提交的action。
<input type="button" value="submit1" onclick="javascript:document.f.action=‘login/login1‘;document.f.submit();" />

----LoginAction1.java----
public class LoginAction1 extends ActionSupport {

private Map request;
private Map session;
private Map application;

public LoginAction1() {
//利用這種方法發到request(類型為Map),session,application
request = (Map)ActionContext.getContext().get("request");
session = ActionContext.getContext().getSession();
application = ActionContext.getContext().getApplication();
}

public String execute() {
//在處理請求的時候往其中放值,在前台可以訪問
request.put("r1", "r1");
session.put("s1", "s1");
application.put("a1", "a1");
return SUCCESS;
}
前台頁面:
...
//利用<s:property value="#request.r1"/>訪問,也可以用傳統的方式<%=request.getAttribute("r1") %>來取值
<s:property value="#request.r1"/> | <%=request.getAttribute("r1") %> <br />
<s:property value="#session.s1"/> | <%=session.getAttribute("s1") %> <br />
<s:property value="#application.a1"/> | <%=application.getAttribute("a1") %> <br />
...
----LoginAction2.java----
****最常用的方法****

package com.bjsxt.struts2.user.action;

import java.util.Map;

import org.apache.struts2.interceptor.ApplicationAware;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class LoginAction2 extends ActionSupport implements RequestAware,SessionAware, ApplicationAware {

private Map<String, Object> request;
private Map<String, Object> session;
private Map<String, Object> application;

public String execute() {
//直接可以用(設計思想IoC或者DI),需要實現RequestAware,SessionAware, ApplicationAware借口
request.put("r1", "r1");
session.put("s1", "s1");
application.put("a1", "a1");
return SUCCESS;
}

//利用setRequest(Map<String, Object> request)設定request
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;
}


}


在struts.xml中增加以下語句可以解決中文編碼問題:
<constant name="struts.i18n.encoding" value="GBK" /> <!-- internationalization -->

<include file="login.xml" />//用於包含另外一個.xml檔案到struts.xml檔案中

<default-action-ref name="index"><*default-action-ref>定義預設Action,當找不到指定Action(或者不指定Action)時,轉到那個package下的Action

Action總結:
1.實現一個Action的最重用的方式:從ActionSupport繼承
2.DMI動態方法引動過程+!
3.萬用字元:*asd*--{1}{2}
*_*--{1}{2}
4.接受參數的方法(一般用屬性或者DomainModel來接受)
5.簡單參數驗證addFieldError
一般不適用Struts2的UI標籤
6.訪問Web元素
Map類型
loc(最常用)
依賴Struts2
原始類型
loc
依賴Struts2
7.包含檔案配置
8.預設Action處理

result可以指定類型,預設為dispatcher(用伺服器跳轉到結果頁面,不可以是Action),還有:
redirect(不可以跳轉到Action),chain(跳轉到一個Action),redirectAction(跳轉到另外一個Action)。
以上四種最常用,前兩中最最常用。還有freemarker,httpheader,stream,velocity,xsit,plaintext,tiles等類型。
用戶端跳轉和伺服器端跳轉--視頻27
dispatcher和chain為伺服器端跳轉,而redirect和redirectAction為用戶端跳轉。

chain類型跳轉到另一個Action要帶參數:
<result type="chain">
<param name="actionName">aasdafa</param>//指定Action的名字
<param name="namespace">/asdasd</param>//指定Action的NameSpace
</result>

global-results用於處理包裡的共有結果集,extend用於繼承其他package中的global-results。

動態指定result:在Action實作類別中可以指定字串參數來指向JSP頁面地址,如:
...
private String r;

public String execute() throws Exception {
if(type == 1) r="/user_success.jsp";
else if (type == 2) r="/user_error.jsp";
return "success";
}
...
在struts.xml中,
...
<action name="user" class="com.bjsxt.struts2.user.action.UserAction">
<result>${r}</result>
</action>
...
來確定result的展示頁面,因為Action中的參數都會存放在值堆棧中。
在index.jsp中直接用:
<li><a href="user/user?type=1">返回success</a></li>
<li><a href="user/user?type=2">返回error</a></li>
來給action實作類別中的參數傳遞參數。


一次request中若有服務端跳轉,則跳轉前後的所有Action公用值堆棧,故各個Action之間不需要傳遞參數。
但若跳轉到jsp頁面所傳遞的參數不存放在值堆棧中,只能利用actioncantext中取值。
...
<action name="user" class="com.bjsxt.struts2.user.action.UserAction">
<result type="redirect">/user_success.jsp?t=${type}</result>
</action>
...

...
from valuestack: <s:property value="t"/><br/>//從值堆棧中取值
from actioncontext: <s:property value="#parameters.t"/>//從actioncantext中取值
...

OGNL(object grapg navigation language)運算式:
必須為Action類傳遞參數,它才會構造(new)這個對象,此時必須有空的構造方法。
也可以不傳遞參數而自己直接在類中構造。

訪問靜態方法需要在struts.xml中設定如下語句:
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
訪問靜態屬性和靜態方法:
<s:property value="@[email protected]()"/>
<s:property value="@[email protected]"/>
"@類名@屬性(方法)"
"@@方法(屬性)"--只能訪問Math的方法和屬性

----ognl.jsp----

<?xml version="1.0" encoding="GB18030" ?>
<%@ page language="java" contentType="text/html; charset=GB18030"
pageEncoding="GB18030"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GB18030" />
<title>OGNL運算式語言學習</title>
</head>
<body>
<ol>
<li>訪問值棧中的action的普通屬性: username = <s:property value="username"/> </li>
<li>訪問值棧中對象的普通屬性(get set方法):<s:property value="user.age"/> | <s:property value="user[‘age‘]"/> | <s:property value="user[\"age\"]"/> | wrong: <%--<s:property value="user[age]"/>--%></li>
<li>訪問值棧中對象的普通屬性(get set方法): <s:property value="cat.friend.name"/></li>
<li>訪問值棧中對象的普通方法:<s:property value="password.length()"/></li>
<li>訪問值棧中對象的普通方法:<s:property value="cat.miaomiao()" /></li>
<li>訪問值棧中action的普通方法:<s:property value="m()" /></li>
<hr />
<li>訪問靜態方法:<s:property value="@[email protected]()"/></li>
<li>訪問靜態屬性:<s:property value="@[email protected]"/></li>
<li>訪問Math類的靜態方法:<s:property value="@@max(2,3)" /></li>
<hr />
<li>訪問普通類的構造方法:<s:property value="new com.bjsxt.struts2.ognl.User(8)"/></li>
<hr />
<li>訪問List:<s:property value="users"/></li>
<li>訪問List中某個元素:<s:property value="users[1]"/></li>
<li>訪問List中元素某個屬性的集合:<s:property value="users.{age}"/></li>
<li>訪問List中元素某個屬性的集合中的特定值:<s:property value="users.{age}[0]"/> | <s:property value="users[0].age"/></li>
<li>訪問Set:<s:property value="dogs"/></li>
<li>訪問Set中某個元素:<s:property value="dogs[1]"/></li>
<li>訪問Map:<s:property value="dogMap"/></li>
<li>訪問Map中某個元素:<s:property value="dogMap.dog101"/> | <s:property value="dogMap[‘dog101‘]"/> | <s:property value="dogMap[\"dog101\"]"/></li>
<li>訪問Map中所有的key:<s:property value="dogMap.keys"/></li>
<li>訪問Map中所有的value:<s:property value="dogMap.values"/></li>
<li>訪問容器的大小:<s:property value="dogMap.size()"/> | <s:property value="users.size"/> </li>
<hr />
<li>投影(過濾):<s:property value="users.{?#this.age==1}[0]"/></li>
<li>投影:<s:property value="users.{^#this.age>1}.{age}"/></li>
<li>投影:<s:property value="users.{$#this.age>1}.{age}"/></li>
<li>投影:<s:property value="users.{$#this.age>1}.{age} == null"/></li>
<hr />
<li>[]:<s:property value="[0].username"/></li>

</ol>

<s:debug></s:debug>
</body>
</html>

投影(過濾):{?#this.age==1}、{^#this.age>1}、{$#this.age>1}為過濾條件。
^代表第一個,$代表末尾那個。
<s:property value="[0].username"/>代表從第0個一直到末尾的集合。在伺服器端跳轉時就會有多個Action。


Struts2的標籤可以分為通用標籤,控制標籤,UI標籤,AJAX標籤,$#%的區別。

1.通用標籤:
a)property
b)set
i.預設為action scope,會將值放入request和ActionContext中
ii.page、request、session、application
c)bean
d)include(對中文檔案支援有問題,不建議使用,如需包含,改用jsp包含)
e)param
f)debug

2.控制標籤
a)if elseif else
b)iterator
i.collections map enumeration iterator array
c)subset

3.UI標籤
a)theme
i.simple xhtml(預設) css_xhtml ajax

4.AJAX標籤
a)補充

5.$ # %的區別
a)$用於i18n和struts設定檔
b)#取得ActionContext的值
c)%將原本的文字屬性解析為ognl,對於本來就是ognl的屬性不起作用
i. 參考<s:property 和 <s:include

 

 


命名規範:

1.資料庫命名:
表命名(簡單就是美):
_表名,如:
_Topic(使用駝峰標示,儘管資料庫不區分大小寫)

欄位命名:
保持與屬性名稱一致(盡量不要和資料庫的命名衝突)
如:ID屬性id
外鍵topicId

庫名:
使用項目的名稱


2.類和檔案的命名:
有兩種方式:1.先分模組再分層次2.先分層次再分模組
採用層次劃分(包的命名都用小寫):
com.bjsxt.bbs.action.model.service

Action類採用Action結尾,如:xxxAction.java

JSP命名:*_*

namespace:前台直接使用"/"
後台使用"/admin"

package:
前台:aciton
後台:adminAction


項目開發順序:
1.建立介面原型
2.建立Struts.xml
a.確定namespace
b.確定package
c.確定Action的名稱,空的方法
d.確定Rssult
e.將介面原形頁面進行修改,匹配現有設定
f.測試
g.做好規劃
3.建立資料庫(或者實體類)
4.建立Model層
5.建立Service層(hibernate)
使用Junit進行單元測試
6.著手開發


請求到來後被Filter過濾,調用特定的Action的特定方法,攔截器就是在調用的時候加東西。
(其實先調用攔截器,攔截器再調用Action,再返回給攔截器,又返回給Filter)

I18N
在普通Editer直接寫中文會亂碼。
國際化檔案可以用propertiesEditer外掛程式,在這裡面寫的中文會轉為UTF-8儲存。

Struts2的國際化有三種方式:
Action-Package-App級
主要用App,對整個項目有效。


struts2的實際執行過程:
1.Struts2Flter接受頁面請求
2.調用Dispatcher的serviceAction()方法
3.Dispatcher建立一個ActionProxy對象,並調用它的execute()方法
4.execute()方法又會調用ActionInvocation的invoke()方法
5.invoke()方法又會調用第一個inerceptor對象的interceptor()方法
6.interceptor()方法又會調用ActionInvocation對象的invoke()方法
7.nvoke()方法又會調用下一個inerceptor對象的interceptor()方法
8.反覆直到所有inerceptor調用完畢,ActionInvocation對象調用最中的Action類的execute()方法

 

傳遞多個相同參數的時候,可以使用集合容器,但是要使用泛型。
比如在action類中有屬性:
......
List<interst>; //不用new
......

使用token攔截器控制重複提交(很少用)

寫自己的轉換器:
public class MyPointConverter extends DefaultTypeConverter{

@Override
public Object convertValue(Object value, Class toType) {
if(toType == Point.class) {
Point p = new Point();
String[] strs = (String[])value;
String[] xy = strs[0].split(",");
p.x = Integer.parseInt(xy[0]);
p.y = Integer.parseInt(xy[1]);
return p;
}
if(toType == String.class) {
return value.toString();
}
return super.convertValue(value, toType);
}

}
public class MyPointConverter extends StrutsTypeConverter{



@Override
public Object convertFromString(Map context, String[] values, Class toClass) {

Point p = new Point();
String[] strs = (String[])values;
String[] xy = strs[0].split(",");
p.x = Integer.parseInt(xy[0]);
p.y = Integer.parseInt(xy[1]);
return p;


}

@Override
public String convertToString(Map context, Object o) {
// TODO Auto-generated method stub
return o.toString();
}

}

三種註冊方式:
i. 局部:XXXAction-conversion.properties
1. p(屬性名稱) = converter
ii. 全域:xwork-conversion.properties
1. com.xxx.XXX(類名)= converter
iii. Annotation
d) 如果遇到非常麻煩的映射轉換
i. request.setAttribute();
ii. session

 

 

 

 

 

 

 

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.