爲後面測試示例編寫代碼及配置以下:html
package com.zze.bean; import java.util.Date; public class User { private String name; private Integer age; private Date birthday; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", birthday=" + birthday + '}'; } }
<?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.devMode" value="true"/> <package name="test" extends="struts-default" namespace="/"> <action name="*" class="com.zze.action.{1}Action"> <result>/show.jsp</result> </action> </package> </struts>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> v1:${requestScope.key} v2:${sessionScope.key} v3:${applicationScope.key}
在使用 Struts2 的過程當中,會發現 Struts2 和 Servlet 的 API 是解耦合的。在實際開發中,常常用到 Servlet 的 API,好比將信息保存到 Session 中、使用 response 響應一些內容等等..,這些都涉及到對 Servlet 的 API 的訪問。java
package com.zze.action; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; import java.util.Arrays; import java.util.Map; public class Test1Action extends ActionSupport { /** * 解耦合方式 */ @Override public String execute() { ActionContext context = ActionContext.getContext(); // 獲取請求參數 Map<String, Object> parameters = context.getParameters(); for (String key : parameters.keySet()) { String[] values = (String[]) parameters.get(key); System.out.println(String.format("key:%s value:%s", key, Arrays.toString(values))); } // 存放參數到域對象 context.put("key", "value from context.put"); // request.setAttribute("key","value from context.put") context.getSession().put("key", "value from context.getSession().put"); // session.setAttribute("key","value from context.getSession().put") context.getApplication().put("key", "value from context.getApplication().put"); // application.setAttribute("key","value from context.getApplication().put") return SUCCESS; } }
package com.zze.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 Test2Action extends ActionSupport { @Override public String execute() throws Exception { // 獲取原生 request 對象 HttpServletRequest request = ServletActionContext.getRequest(); Map<String, String[]> parameterMap = request.getParameterMap(); for (String key : parameterMap.keySet()) { String[] values = (String[]) parameterMap.get(key); System.out.println(String.format("key:%s value:%s", key, Arrays.toString(values))); } // 存放數據到域對象 request.setAttribute("key","value from request.setAttribute"); request.getSession().setAttribute("key","value from request.getSession().setAttribute"); // ServletActionContext.getServletContext() request.getServletContext().setAttribute("key","value from request.getServletContext().setAttribute"); return super.execute(); } }
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; import org.apache.struts2.ServletActionContext; import org.apache.struts2.interceptor.ServletRequestAware; import org.apache.struts2.interceptor.ServletResponseAware; import org.apache.struts2.util.ServletContextAware; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Arrays; import java.util.Map; /** * 接口注入的方式須要實現相應接口 */ public class Test3Action extends ActionSupport implements ServletRequestAware, ServletResponseAware, ServletContextAware { private HttpServletRequest request; // 接收注入的原生 request private HttpServletResponse response; // 接收注入的原生 response private ServletContext servletContext; // 接收注入的原生 servletContext @Override public String execute() throws Exception { // 接收請求參數 Map<String, String[]> parameterMap = request.getParameterMap(); for (String key : parameterMap.keySet()) { String[] values = (String[]) parameterMap.get(key); System.out.println(String.format("key:%s value:%s", key, Arrays.toString(values))); } // 存放數據到域對象 request.setAttribute("key", "value from request.setAttribute"); request.getSession().setAttribute("key", "value from request.getSession().setAttribute"); servletContext.setAttribute("key", "value from servletContext.setAttribute"); return super.execute(); } @Override public void setServletRequest(HttpServletRequest request) { this.request = request; } @Override public void setServletResponse(HttpServletResponse response) { this.response = response; } @Override public void setServletContext(ServletContext context) { this.servletContext = context; } }
Struts2 是一個 web 層框架,提供了請求數據封裝的功能。而它的提供了以下兩種方式進行請求數據的封裝:web
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; import java.util.Date; public class Test4Action extends ActionSupport { private String name; private Integer age; private Date birthday; public void setName(String name) { this.name = name; } public void setAge(Integer age) { this.age = age; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String execute() throws Exception { System.out.println(name); System.out.println(age); System.out.println(birthday); return NONE; } }
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; import com.zze.bean.User; /** * 請求參數的參數名需按指定格式 */ public class Test5Action extends ActionSupport { // 給接收參數的對象提供 get 方法 private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String execute() throws Exception { System.out.println(user); return NONE; } }
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; import java.util.Arrays; import java.util.List; /** * 請求參數的參數名需按指定格式 */ public class Test6Action extends ActionSupport { public List<String> names; public List<String> getNames() { return names; } public void setNames(List<String> names) { this.names = names; } @Override public String execute() throws Exception { System.out.println(Arrays.toString(names.toArray())); return NONE; } }
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; import com.zze.bean.User; import java.util.List; public class Test7Action extends ActionSupport { private List<User> users; public List<User> getUsers() { return users; } public void setUsers(List<User> users) { this.users = users; } @Override public String execute() throws Exception { for (User user : users) { System.out.println(user); } return NONE; } }
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; import java.util.Arrays; import java.util.Map; public class Test8Action extends ActionSupport { private Map<String,Object> map; public Map<String, Object> getMap() { return map; } public void setMap(Map<String, Object> map) { this.map = map; } @Override public String execute() throws Exception { for (String key : map.keySet()) { String valStr= Arrays.toString((String[])map.get(key)); System.out.println(String.format("%s:%s",key,valStr)); } return NONE; } }
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; import com.zze.bean.User; import java.util.Map; public class Test9Action extends ActionSupport { private Map<String, User> map; public Map<String, User> getMap() { return map; } public void setMap(Map<String, User> map) { this.map = map; } @Override public String execute() throws Exception { for (String key : map.keySet()) { System.out.println(String.format("%s : %s", key, map.get(key))); } return NONE; } }
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; import com.zze.bean.User; /** * 實現 ModelDriven 接口 */ public class Test10Action extends ActionSupport implements ModelDriven<User> { private User user = new User(); @Override public User getModel() { return user; } @Override public String execute() throws Exception { System.out.println(user); return NONE; } }
全局結果頁指的是:在包中配置一次,其它在這個包中全部 action 只要返回了對應 name 值,就均可以跳轉到全局結果頁配置的頁面。apache
在 struts.xml 的 package 標籤下添加以下節點便可配置全局結果頁:session
<!--全局結果頁配置--> <global-results> <result name="success">/success.jsp</result> </global-results>
局部結果頁指的是:所配置的結果只對當前所在 action 有效。app
在 struts.xml 的 package>aciton 下配置:框架
<!--局部結果頁配置--> <action name="*" class="com.zze.action.{1}Action"> <result>/show.jsp</result> </action>
result 標籤用於配置頁面的跳轉。jsp
屬性:ide
<result-types> <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/> <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/> <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/> <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/> <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/> <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/> <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/> <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/> <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" /> <result-type name="postback" class="org.apache.struts2.dispatcher.PostbackResult" /> </result-types>
經常使用類型有以下幾個:post
dispatcher:默認值,請求轉發,從 當前 action 到 jsp。
redirect:從當前 action 重定向到 jsp。
chain:請求轉發,從當前 action 轉發到另外一個 action。
redirectAction:從當前 action 重定向到另外一個 action。
stream:返回流,文件下載。
在 Action 接口中提供了 5 個靜態字段,以下:
public static final String SUCCESS = "success"; // 操做成功 public static final String NONE = "none"; // 操做成功不跳轉 public static final String ERROR = "error"; // 操做失敗 public static final String INPUT = "input"; // 一般在表單提交請求參數驗證失敗時返回,標識需從新輸入提交 public static final String LOGIN = "login"; // 返回到登陸頁
"input" 返回值在 Struts2 內置攔截器中就有用到,先看以下狀況:
package com.zze.action; import com.opensymphony.xwork2.ActionSupport; public class Test11Action extends ActionSupport { private Integer age; public void setAge(Integer age) { this.age = age; } @Override public String execute() throws Exception { System.out.println(age); return NONE; } }
在上述 action 中使用屬性驅動的方式接受一個 Integer 類型的年齡字段,而參數提交時提交的是 "aa","aa" 明顯是不能夠轉成 Integer 類型的,此時 Struts2 就會返回錯誤以下:
No result defined for action com.zze.action.Test11Action and result input - action - file:/WEB-INF/classes/struts.xml:13:51
即:沒有爲 action 定義一個 name="input" 的 result 。爲何 Struts2 會返回這個結果呢?
首先咱們知道 Struts2 內部默認是有一個攔截器棧的,在 struts2-core-2.3.37.jar!/struts-default.xml 中能夠看到,以下:
<interceptor-stack name="defaultStack"> <interceptor-ref name="exception"/> <interceptor-ref name="alias"/> <interceptor-ref name="servletConfig"/> <interceptor-ref name="i18n"/> <interceptor-ref name="prepare"/> <interceptor-ref name="chain"/> <interceptor-ref name="scopedModelDriven"/> <interceptor-ref name="modelDriven"/> <interceptor-ref name="fileUpload"/> <interceptor-ref name="checkbox"/> <interceptor-ref name="datetime"/> <interceptor-ref name="multiselect"/> <interceptor-ref name="staticParams"/> <interceptor-ref name="actionMappingParams"/> <!--接收參數--> <interceptor-ref name="params"/> <!--類型轉換--> <interceptor-ref name="conversionError"/> <!--數據校驗--> <interceptor-ref name="validation"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> <interceptor-ref name="workflow"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> <interceptor-ref name="debugging"/> <interceptor-ref name="deprecation"/> </interceptor-stack>
在請求 action 時該棧下的攔截器會依次執行,而每一個攔截器都有它自身的功能。如 params 攔截器用來接收參數、conversionError 攔截器用來類型轉換、validation 攔截器用來數據校驗。
而 Struts2 有一個專門存放錯誤的區域,當這幾個操做出錯時,Struts2 就會將對應錯誤信息存到該錯誤區域。接着在 workflow 攔截器中就會檢查錯誤區域是否有錯誤,若是有,則返回 "input" 邏輯視圖,若是沒有則繼續執行後續攔截器及 action。workflow 對應攔截器部分源碼以下:
@Override protected String doIntercept(ActionInvocation invocation) throws Exception { Object action = invocation.getAction(); if (action instanceof ValidationAware) { ValidationAware validationAwareAction = (ValidationAware) action; // 若是錯誤區有錯誤 if (validationAwareAction.hasErrors()) { if (LOG.isDebugEnabled()) { LOG.debug("Errors on action [#0], returning result name [#1]", validationAwareAction, inputResultName); } String resultName = inputResultName; // "input" resultName = processValidationWorkflowAware(action, resultName); resultName = processInputConfig(action, invocation.getProxy().getMethod(), resultName); resultName = processValidationErrorAware(action, resultName); return resultName; } } return invocation.invoke(); }
瞭解了攔截器返回 "input" 邏輯視圖的緣由,咱們就能夠對症下藥了,在 struts.xml 中 action 標籤下添加一個 "input" 的結果:
<result name="input">/input.jsp</result>
而在 jsp 中咱們能夠經過 Struts2 提供的標籤輸出錯誤信息:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>Title</title> </head> <body> <s:fielderror/> </body> </html>
再次請求,結果以下: