Struts2 快速筆記1
路線:
- Struts2的概述、Struts2的入門、Struts2常見的配置、Struts2的Action的編寫
- Struts2的資料的封裝、結果頁面配置
- Struts2的值棧和OGNL表示式
- Struts2的標籤庫
基礎
定義:基於MVC的模式的WEB層框架,Struts2和Struts1的架構完全不同。
常見的Web層框架:Struts2、WebWork、SpringMVC等。
從Servlet到框架的變化:傳統的請求處理是對每一個請求進行相應的Servlet的處理,會產生許多的Servlet;WEB層的框架是基於前端控制器模型對請求進行處理的分發(過濾器)來設計的。
環境
下載:https://struts.apache.org/ 練習版本:2.3.34
Struts2解壓目錄
- apps:Struts提供的應用案例,幾個WAR包
- docs:開發文件,API
- lib:開發框架的JAR包
- src:原始碼
使用:建立WEB專案,引入JAR包,配置
執行過程的順序:當用戶訪問某一個Action的時候,先經過核心過濾器,在核心過濾器中執行一組攔截器(這組攔截器實現部分功能),執行目標Action,根據Action的返回值,進行頁面跳轉。
Struts配置檔案的載入順序:
-
init_DefaultProperties() ----載入default.properties
-
init_TraditionalXmlConfigurations(); ----載入struts-default.xml、struts-plugin.xml、struts.xml
-
init_LegacyStrutsProperties(); ----載入struts.properties
-
init_CustomConfigurationProviders(); ----載入配置提供類
-
init_FilterInitParameters() ; // [6] ----載入web.xml中過濾器初始化引數
-
init_AliasStandardObjects() ; // [7] ----載入Bean物件
-
載入順序
-
default.properties
-
struts-default.xml
-
struts-plugin.xml
-
struts.xml
-
struts.properties
-
web.xml
注意:後配置的常量的值會覆蓋先配置的常量的值。
-
配置
-
Package包,Struts中的包,為了更好地管理
- name
- extends:一般繼承自struts-default,實現更多功能
- namespace:名稱空間,與action標籤中的name共同標記為訪問路徑,先查詢有名稱的如“aaa”,再找“/”,最後查詢預設的“ ”;
- abstract:為true即可被繼承
-
action
- name:訪問的名,相當於Servlet的名字,和namespace決定請求訪問路徑
- class:對應執行的類
- method:class類中執行的方法,預設為execute
- converter:用於設定某些型別轉換器
-
常量:在Struts2的框架中,提供了非常多的常量:default.properties中。
-
struts.i18n.encoding=UTF-8 ----Struts2中所有的post請求的中文亂碼不用處理。
-
struts.action.extension=action, ----Struts2請求的預設的副檔名。預設副檔名是.action或者什麼都不寫。
-
在Struts中可以在Struts.xml,Struts.properties,web.xml三個地方修改常量配置。
-
-
action的三種編寫方式
- POJO類:普通的一個Java類,寫一個public的execute方法,返回一個string的值
- 實現Action介面,Action介面提供execute方法和5個返回常量,如SUCCESS/ERROR/LOGIN等
- 繼承ActionSupport類:推薦,同樣實現了Action的介面,還實現了一類驗證等其他功能的介面
-
action的三種訪問方式
-
通過method訪問
-
使用萬用字元訪問
-
動態訪問
-
總結:Struts的執行過程:請求API----核心過濾器(StrutsPrepareAndExecuteFilter)-----執行一組攔截器(完成部分的功能)-----Action-------Result.
Struts2 常見API
Struts2的Servlet的API訪問
struts中的action中,沒有Servlet的request和response物件,可視作是解耦的。實際開發中,經常使用到Servlet的API,如session,response等物件。
Servlet是單例的,多個程式訪問同一個Servlet只會建立一個Servlet的例項。Action是多例的,一次請求,建立一個Action的例項(不會出現執行緒安全的問題)
三種方式:
-
完全解耦方式:這種方式只能獲得代表request、session、application的資料的Map集合,不能操作這些物件的本身的方法。
// 獲取Servlet的API ActionContext actionContext = ActionContext.getContext(); Map<String, Object> map = actionContext.getParameters(); // 類似於request.getParametersMap(),返回一個map for (String key : map.keySet()) { String[] values = (String[]) map.get(key); System.out.println(key + " ... " + Arrays.toString(values)); } // 二、向域物件中存入資料 actionContext.put("reqName", "reqValue22");// 相當於request.setAttribute(); actionContext.getSession().put("sessName", "sessValue22"); // 相當於session.setAttribute(); actionContext.getApplication().put("appName", "appValue22"); // 相當於application.setAttribute(); return "demo1Success";
-
原生API:注意:這種方式可以操作域物件的資料,同時也可以獲得物件的方法。
// 獲取Servlet的API HttpServletRequest request = ServletActionContext.getRequest(); Map<String, String[]> map = request.getParameterMap(); for (String key : map.keySet()) { String[] values = (String[]) map.get(key); System.out.println(key + " ... " + Arrays.toString(values)); } // 二、向域物件中存入資料 request.setAttribute("reqName", "reqValue22"); request.setAttribute("sessName", "sessValue22"); ServletActionContext.getServletContext().setAttribute("appName", "appValue22"); return "demo1Success";
-
介面注入方式:
public class RequestDemo2 extends ActionSupport implements ServletRequestAware, ServletContextAware{ private ServletContext context; private HttpServletRequest request; //action是多例的,所以成員變數不會存線上程安全問題 @Override public String execute() { Map<String, String[]> map = request.getParameterMap(); for (String key : map.keySet()) { String[] values = (String[]) map.get(key); System.out.println(key + " ... " + Arrays.toString(values)); } // 二、向域物件中存入資料 request.setAttribute("reqName", "reqValue33"); request.setAttribute("sessName", "sessValue33"); context.setAttribute("appName", "appValue332"); return "demo1Success"; } @Override public void setServletContext(ServletContext context) { this.context = context; } @Override public void setServletRequest(HttpServletRequest request) { this.request = request; } }
Struts的資料——結果頁面的轉發
-
全域性結果頁面:對當前包(xml下的package)中的所有action均有效,只要返回相應的result,則可以跳轉。
<!-- 配置Struts2的常量 --> <constant name="struts.action.extension" value="action"/> <package name="demo1" extends="struts-default" namespace="/"> <global-results> <result name="demo1Success">/demo1/demo2.jsp</result> </global-results> <action name="requestDemo1" class="com.leehao.struts_servlet.demo1.RequestDemo1"> <result name="demo1Success">/demo1/demo2.jsp</result> </action> <!-- 原生Servlet API --> <action name="requestDemo2" class="com.leehao.struts_servlet.demo1.RequestDemo2"> <result name="demo1Success">/demo1/demo2.jsp</result> </action> <!--介面注入 --> <action name="requestDemo3" class="com.leehao.struts_servlet.demo1.RequestDemo3"> <result name="demo1Success">/demo1/demo2.jsp</result> </action> </package>
-
區域性結果頁面:只針對當前action生效,相同配置下,區域性的先生效
-
result的屬性配置
- name屬性 :邏輯檢視的名稱。預設值:success
- type屬性 :頁面跳轉的型別。
- dispatcher :預設值,請求轉發。(Action轉發到JSP)
- redirect :重定向。(Action定向到JSP)
- chain :轉發。(Action轉發到Action)
- redirectAction :重定向。(Action重定向到Action)
- stream :Struts2中提供檔案下載的功能。
Struts2的資料封裝
Struts2框架是一個web層框架,web層框架(框架:軟體的半成品,完成一部分功能)。Struts2提供了資料封裝的功能。
在struts中,請求經過核心過濾器時,需要在初始化時,執行許多預設的初始攔截器來處理資料。其中,就有params/modelDriven/conversionError等,來實現引數的校驗,型別轉化和封裝等功能。
-
屬性驅動:提供屬性set方法的方式(不常用)
-
屬性驅動:頁面中提供表示式方式。
public class UserAction2 extends ActionSupport { //一個私有的物件,名字和頁面相同,表示直接將資料注入到該物件中 //struts生成一個User的物件,封裝資料,將值賦給當前action的物件屬性中,必須有getUser方法,否則只能生成一個屬性的物件。 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; } } --------------------------------jsp----------------------------------------- <h3>方式二:屬性驅動,通過頁面表示式</h3> <form action="${pageContext.request.contextPath }/userAction2.action" method="post"> 姓名:<input name="user.username" type="text"><br/> 密碼:<input name="user.password" type="password"><br/> 生日:<input name="user.birthday" type="text"><br/> 年齡:<input name="user.age" type="text"><br/> 工資:<input name="user.salary" type="text"><br/> <input type="submit" value="提交"><br/> </form>
-
模型驅動:
模型驅動方式最常用的方式:
-
缺點:只能同時向一個物件中封裝資料。
-
使用第二種可以向多個物件中同時封裝資料
public class UserAction3 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; } } ----------------------------jsp------------------------------ <h3>方式三:模型驅動方法</h3> <form action="${pageContext.request.contextPath }/userAction3.action" method="post"> 姓名:<input name="username" type="text"><br/> 密碼:<input name="password" type="password"><br/> 生日:<input name="birthday" type="text"><br/> 年齡:<input name="age" type="text"><br/> 工資:<input name="salary" type="text"><br/> <input type="submit" value="提交"><br/> </form>
-
-
Input邏輯檢視錯誤
INPUT的邏輯檢視的配置,Action介面中提供了五個邏輯檢視的名稱:
- SUCCESS
- ERROR
- LOGIN
- INPUT :input****在某些攔截器中會使用。
- NONE
示例圖:![圖一 INPUT邏輯檢視的配置](assets/圖一 INPUT邏輯檢視的配置.bmp)
Struts複雜資料模型的封裝
在實際開發中,有可能遇到批量向資料庫中插入記錄,需要在頁面中將資料封裝到集合中。
-
向集合List中封裝
public class ProductAction1 extends ActionSupport { private List<Product> products; //必須設定set,get方法 public List<Product> getProducts() { return products; } public void setProducts(List<Product> products) { this.products = products; } @Override public String execute() throws Exception { for (Product product : products) { System.out.println(product); } return NONE; } } ---------------------jsp------------------------------------------ <h3>一:List型別資料集合</h3> <form action="${pageContext.request.contextPath }/productAction1.action" method="post"> 名稱:<input name="products[0].pname" type="text"> 價格:<input name="products[0].price" type="text"><br/> 名稱:<input name="products[1].pname" type="text"> 價格:<input name="products[1].price" type="text"><br/> 名稱:<input name="products[2].pname" type="text"> 價格:<input name="products[2].price" type="text"><br/> <input type="submit" value="提交"><br/> </form>
-
向Map中封裝
public class ProductAction2 extends ActionSupport { private Map<String, Product> map; //必須設定set,get方法 public Map<String, Product> getMap() { return map; } public void setMap(Map<String, Product> map) { this.map = map; } @Override public String execute() throws Exception { for (Entry<String, Product> entry : map.entrySet()) { System.out.println(entry.getKey() + " " + entry.getValue()); } return NONE; } } -----------------------------JSP------------------------------------------ <h3>二:MAP型別資料集合</h3> <form action="${pageContext.request.contextPath }/productAction2.action" method="post"> 名稱:<input name="map['one'].pname" type="text"> 價格:<input name="map['one'].price" type="text"><br/> 名稱:<input name="map['two'].pname" type="text"> 價格:<input name="map['two'].price" type="text"><br/> 名稱:<input name="map['three'].pname" type="text"> 價格:<input name="map['three'].price" type="text"><br/> <input type="submit" value="提交"><br/> </form>