[標題]:[原]Struts2-深入探索
[時間]:2009-8-26
[摘要]:Struts2中一些零碎的知識點:struts.xml詳解、模型驅動、Preparable接口、防止表單重復提交、ActionContext、動態方法調用、異常
[關鍵字]:浪曦視頻,Struts2應用開發系列,WebWork,Apache,深入探索
[環境]:struts-2.1.6、JDK6、MyEclipse7、Tomcat6
[作者]:Winty (wintys@gmail.com) http://www.tkk7.com/wintys
[正文]:
1、struts.xml詳解
a. struts.properties
在struts.xml中可以定義constant覆蓋struts-core.jar/org/apache/struts2/default.properties中的設置。
例:<constant name="struts.custom.i18n.resources" value="message"/>
也可以直接新建
struts.properties(與struts.xml在同一目錄),在struts.properties中配置。推薦在struts.properties中進行配置。
例:struts.custom.i18n.resources = message
b. abstract package
struts-core.jar/struts-default.xml,中有如下定義。
<package name="struts-default"
abstract="true">
......
</package>
其中abstract="true"中,表示在此package中不能定義Action(與Java abstract類相似),僅供繼承。
c. namespace
strut.xml中:
<package name="MyStruts" extends="struts-default"
namespace="
/mystruts">
......
</package>
默認命名空間為namespace="",命名空間要以"/"開頭。
JSP訪問:<s:form action="miscellaneous"
namespace="/mystruts">。
不能寫成<s:form action="/mystruts/miscellaneous"> ,否則會發生錯誤:"No configuration found for the specified action: '/mystruts/miscellaneous' in namespace: '/miscellaneous'. Form action defaulting to 'action' attribute's literal value."[2]。
d. 模塊化配置
......
<struts>
<
include file="struts1.xml" />
<package ...>
......
</package>
</struts>
include中struts1.xml的編寫與struts.xml是類似的。
2、屬性驅動與模型驅動
屬性驅動:直接在Action中寫表單屬性。
/StrutsHelloWorld/src/wintys/struts2/miscellaneous/MiscellaneousAction.java:
package wintys.struts2.miscellaneous;
import com.opensymphony.xwork2.ActionSupport;
/**
*
* @author Winty (wintys@gmail.com)
* @version 2009-8-24
* @see http://wintys.blogjava.net
*/
@SuppressWarnings("serial")
public class MiscellaneousAction extends ActionSupport {
private String name;
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
}
模型驅動:將屬性放到JavaBean中,Action需要實現com.opensymphony.xwork2.ModelDriven接口。ModelDrivenInterceptor 必須在之前StaticParametersInterceptor and ParametersInterceptor。這個順序已在defaultStack Interceptor中定義。
/StrutsHelloWorld/src/wintys/struts2/miscellaneous/User.java:
package wintys.struts2.miscellaneous;
/**
* 模型驅動Action中的模型
* @author Winty (wintys@gmail.com)
* @version 2009-8-25
* @see http://wintys.blogjava.net
*/
public class User {
private String name;
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
/StrutsHelloWorld/src/wintys/struts2/miscellaneous/MiscellaneousModelDrivenAction.java:
package wintys.struts2.miscellaneous;
import com.opensymphony.xwork2.ModelDriven;
@SuppressWarnings("serial")
public class MiscellaneousModelDrivenAction extends ActionSupport implements
ModelDriven<User>{
private User user = new User();
@Override
public User getModel() {
return user;
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
}
3、Preparable接口
Action還可以實現com.opensymphony.xwork2.Preparable接口,用于準備Action自己。Preparable中的prepare方法在Action執行其它方法前執行。
4、使用simple 主題時,如何單獨格式化Struts錯誤提示信息
單獨顯示name字段的fielderror:
<s:fielderror>
<s:param>name</s:param>
</s:fielderror>
5、Struts防止表單重復提交
JSP頁面中加入token和actionerror:
<s:actionerror />
<s:form .../>
<s:token />
</s:form>
token產生的actionerror的i18n key為:struts.message.invalid.token。
在struts.xml中的Action配置中加入token interceptor,和invalid.token result:
<action name="miscellaneous" class="wintys.struts2.miscellaneous.MiscellaneousModelDrivenAction">
<result name="success">/miscellaneous/output.jsp</result>
<result name="input">/miscellaneous/input.jsp</result>
<result name="invalid.token" >/miscellaneous/input.jsp</result>
<interceptor-ref name="token" />
<interceptor-ref name="defaultStack" />
</action>
生成的JSP頁面如下:
<input type="hidden" name="struts.token.name" value="
struts.token" />
<input type="hidden" name="
struts.token" value="ORU0RZIP8JWQ7BDZG4P1NJSEKITGG6X5" />
struts.token.name指<s:token />中的name,默認為struts.token。也可以自己指定<s:token name="mytoken" />。則生成如下token:
<input type="hidden" name="struts.token.name" value="mytoken" />
<input type="hidden" name="mytoken" value="GFD13EW206G2DY9AB3SRIAVXXT1S915C" />
6、通過Struts獲取Servlet API
一般Java Web程序不能離開容器進行測試。容器內測試常用框架:Cactus(jakarta.apache.org/cactus/index.html) 、Mock。
通過Struts獲取Servlet API,使程序可脫離容器測試。Struts中可通過如下方法獲取Servlet API:ActionContext 、ServletActionContext、ServletXXXAware。首選ActionContext,其次選擇ServletActionContext,再次ServletXXXAware。
a. ActionContext
com.opensymphony.xwork2.ActionContext.getActionContext()獲取ActionContext實例。
ActionContext的get()和put()方法與HttpServletRequest的對應關系:
ActionContext.get() <=> HttpServletRequest.getAttribute()
ActionContext.put() <=> HttpServletRequest.setAttribute()
例:
ActionContext context = ActionContext.getContext();
context.put("info", "this is ActionContext value");
但是ActionContext無法獲取Servlet HttpResponse對象。
b. ServletActionContext
org.apache.struts2.ServletActionContext是com.opensymphony.xwork2.ActionContext的子類。
使用靜態方法直接獲取Servlet對象:
Request: ServletActionContext.getRequest();
Response: ServletActionContext.getResponse();
Session: ServletActionContext.getRequest().getSession();
例:
Cookie cookie = new Cookie("mycookie" , "10000");
HttpServletResponse response = ServletActionContext.getResponse();
response.addCookie(cookie);
c. ServletXXXAware接口
org.apache.struts2.util.ServletContextAware接口
org.apache.struts2.interceptor.ServletRequestAware接口
org.apache.struts2.interceptor.ServletResponseAware接口
org.apache.struts2.interceptor.SessionAware接口
實現ServletXXXAware接口的Action會被Struts自動注入相應的Servlet對象。
例:
package wintys.struts2.miscellaneous;
import org.apache.struts2.interceptor.ServletRequestAware;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings("serial")
public class MiscellaneousModelDrivenAction extends ActionSupport implements
ServletRequestAware {
private HttpServletRequest request;
......
@Override
public String execute() throws Exception {
//實現ServletRequestAware接口,Struts自動注入的request
Cookie[] cookies = this.request.getCookies();
for(Cookie ck : cookies){
System.out.print("cookie:" + ck.getName());
System.out.println(" = " + ck.getValue());
}
return SUCCESS;
}
......
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
}
7、動態方法調用
a. Action配置中,由method指定動態調用方法的名稱。
<action name="myaction" class="com.tests.MyAction" method="
myexecute">
......
</action>
b.在JSP頁面中,調用Action時加感嘆號指定動態調用方法的名稱。
<s:form action="myaction
!myexecute" />
c.通配符
<action name="
*action" class="com.tests.MyAction" method="
{1}">
則請求中helloaction對應到action中的hello()方法,以此類推。
8、異常
發生異常時,可轉到指定的result。由exception-mapping配置
<action name="miscellaneous" class="wintys.struts2.miscellaneous.MiscellaneousModelDrivenAction">
<result name="success">/miscellaneous/output.jsp</result>
<result name="input">/miscellaneous/input.jsp</result>
<exception-mapping exception="wintys.struts2.miscellaneous.NameInvalidException" result="nameInvalid" />
<result name="nameInvalid">/miscellaneous/nameInvalidException.jsp</result>
</action>
也可以配置全局exception mapping
<global-exception-mapping>
<exception-mapping result="nameInvalid" />
</global-exception-mapping>
nameInvalidException.jsp:
<s:property value="exception"/>
<s:property value="exceptionStack" />
NameInvalidException.java:
package wintys.struts2.miscellaneous;
@SuppressWarnings("serial")
public class NameInvalidException extends Exception {
public NameInvalidException(String message) {
super(message);
}
}
9、詳細代碼
/StrutsHelloWorld/WebRoot/miscellaneous/input.jsp:
<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Input</title>
</head>
<body>
<s:actionerror/>
<s:form action="miscellaneous" method="post" theme="simple" namespace="/mystruts">
<s:token name="mytoken"/>
用戶名:<s:textfield name="name" />
<s:fielderror >
<s:param>name</s:param>
</s:fielderror>
<br />
密碼:<s:textfield name="password"/>
<s:fielderror >
<s:param>password</s:param>
</s:fielderror>
<br />
<s:submit name="提 交" />
</s:form>
<hr />
動態方法調用方法二: miscellaneous!myexecute
<s:form action="miscellaneous!myexecute" namespace="/mystruts">
<s:token name="mytoken"/>
<s:hidden name="name" value="test" />
<s:hidden name="password" value="test" />
<s:submit name="提交執行myexecute() " />
</s:form>
</body>
</html>
/StrutsHelloWorld/WebRoot/miscellaneous/output.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Output</title>
</head>
<body>
提交結果:<br/>
用戶名:<s:property value="name"/> <br />
密碼:<s:property value="password"/> <br />
<hr />
${request.info}
${cookie.mycookie.value }
</body>
</html>
/StrutsHelloWorld/src/wintys/struts2/miscellaneous/MiscellaneousModelDrivenAction.java:
package wintys.struts2.miscellaneous;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.interceptor.ServletRequestAware;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
/**
* Struts2深入探索
* @author Winty (wintys@gmail.com)
* @version 2009-8-26
* @see http://wintys.blogjava.net
*/
@SuppressWarnings("serial")
public class MiscellaneousModelDrivenAction extends ActionSupport implements
ModelDriven<User> , ServletRequestAware {
private User user = new User();
private HttpServletRequest request;
@Override
public User getModel() {
return user;
}
@Override
public String execute() throws Exception {
System.out.println("this is model driven action");
if(user.getName().equals("admin")){
throw new NameInvalidException("name 'admin' is invalid");
}
//ActionContext.put相當于HttpServletRequest.setAttribute()
ActionContext context = ActionContext.getContext();
context.put("info", "this is ActionContext value");
//ServletActionContext.getResponse得到Response對象
Cookie cookie = new Cookie("mycookie" , "10000");
HttpServletResponse response = ServletActionContext.getResponse();
response.addCookie(cookie);
//實現ServletRequestAware接口,Struts自動注入的request
Cookie[] cookies = this.request.getCookies();
for(Cookie ck : cookies){
System.out.print("cookie:" + ck.getName());
System.out.println(" = " + ck.getValue());
}
return SUCCESS;
}
public String myexecute()throws Exception{
System.out.println("myexecute()");
return SUCCESS;
}
@Override
public void validate() {
if(user.getName() == null || user.getName().equals("")){
this.addFieldError("name", "invalid name");
}
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
}
/src/struts.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="MyStruts" extends="struts-default" namespace="/mystruts">
<!-- Struts2深入探索 -->
<action name="miscellaneous" class="wintys.struts2.miscellaneous.MiscellaneousModelDrivenAction">
<result name="success">/miscellaneous/output.jsp</result>
<result name="input">/miscellaneous/input.jsp</result>
<exception-mapping exception="wintys.struts2.miscellaneous.NameInvalidException" result="nameInvalid" />
<result name="nameInvalid">/miscellaneous/nameInvalidException.jsp</result>
<result name="invalid.token" >/miscellaneous/input.jsp</result>
<interceptor-ref name="token" />
<interceptor-ref name="defaultStack" />
</action>
</package>
</struts>
[參考資料]:
[1]《浪曦視頻之Struts2應用開發系列》
[2] No configuration found for the specified action :
http://javasunnyboy.javaeye.com/blog/254753
[附件]:
源代碼 :
http://www.tkk7.com/Files/wintys/struts_miscellaneous.zip
posted on 2009-08-29 20:32
天堂露珠 閱讀(916)
評論(0) 編輯 收藏 所屬分類:
Struts