* default.properties -- 在org/apache/struts2/目錄下,表明的是配置的是Struts2的常量的值html
* struts-default.xml -- 在Struts2的核心包下,表明的是Struts2核心功能的配置(Bean、攔截器、結果類型等)前端
* struts-plugin.xml -- 配置插件的信息java
* struts.xml -- 重點中的重點配置,表明WEB應用的默認配置,能夠配置常量,基本就配置它就能夠web
* struts.properties -- 該文件是Struts的默認配置文件 (能夠配置常量 )正則表達式
* web.xml -- 配置前端控制器(能夠配置常量)express
注意:後加載的配置文件會覆蓋掉以前加載的配置文件(在這些配置文件中能夠配置常量)apache
若是要配置<Action>的標籤,那麼必需要先配置<package>標籤,表明的包的概念。數組
包含的屬性瀏覽器
name 包的名稱,要求是惟一的,管理action配置。緩存
extends 繼承,能夠繼承其餘的包,只要繼承了,那麼該包就包含了其餘包的功能,通常都是繼承struts-default
namespace 名稱空間,通常與<action>標籤中的name屬性共同決定訪問路徑,常見的配置以下:
* namespace="" -- 默認的名稱空間(訪問的方式和namespace="/"是同樣的)
* namespace="/" -- 根名稱空間
* namespace="/aaa" -- 帶有名稱的名稱空間
* abstract -- 抽象的。這個屬性基本不多使用,值若是是true,那麼編寫的包是被繼承的。
<action>標籤
表明配置action類,包含的屬性
name 和<package>標籤的namespace屬性一塊兒來決定訪問路徑的。
class 配置Action類的全路徑(默認值是ActionSupport類)
method Action類中執行的方法,若是不指定,默認值是execute
action類中方法執行,返回的結果跳轉的頁面
name 結果頁面邏輯視圖名稱
type 結果類型(默認值是轉發,也能夠設置其餘的值)
在地址欄上輸入一個不存在的action請求,程序會報404的異常。
可是在<package>標籤中經過<default-action-ref name="指定action標籤name屬性"></default-action-ref>來該請求。
在地址欄上輸入一個正確的action請求,可是<action>標籤中的class屬性沒有寫具體的Action類
在<package>標籤中經過<default-class-ref class="指定action類的全路徑"></default-class-ref>
struts.xml
<constant name="key" value="value"></constant>
web.xml
在StrutsPrepareAndExecuteFilter配置文件中配置初始化參數
struts.i18n.encoding=UTF-8 指定默認編碼集,做用於HttpServletRequest的setCharacterEncoding方法
struts.action.extension=action,, 該屬性指定須要Struts 2處理的請求後綴,該屬性的默認值是action,即全部匹配*.action的請求都由Struts2處理。若是用戶須要指定多個請求後綴,則多個後綴之間以英文逗號(,)隔開
struts.serve.static.browserCache=true 設置瀏覽器是否緩存靜態內容,默認值爲true(生產環境下使用),開發階段最好關閉
struts.configuration.xml.reload=false 當struts的配置文件修改後,系統是否自動從新加載該文件,默認值爲false(生產環境下使用),開發階段最好打開
struts.devMode = false 開發模式下使用,這樣能夠打印出更詳細的錯誤信息
struts.enable.DynamicMethodInvocation = true 開啓對Action的動態方法訪問
在大部分應用裏,隨着應用規模的增長,系統中Action的數量也會大量增長,致使struts.xml配置文件變得很是臃腫。
爲了不struts.xml文件過於龐大、臃腫,提升struts.xml文件的可讀性,咱們能夠將一個struts.xml配置文件分解成多個配置文件,而後在struts.xml文件中包含其餘配置文件。
能夠在<package>標籤中,使用<include>標籤來引入其餘的struts_xx.xml的配置文件。例如:
<struts> <include file="struts-part1.xml"/> <include file="struts-part2.xml"/> </struts>
POJO類:
POJO(Plain Ordinary Java Object)簡單的Java對象。簡單來講,沒有繼承某個類,沒有實現接口,就是POJO的類。
Action接口中定義了5個常量,5個常量的值對應的是5個邏輯視圖跳轉頁面(跳轉的頁面仍是須要本身來配置),還定義了一個方法,execute方法。
你們須要掌握5個邏輯視圖的常量
SUCCESS -- 成功.
INPUT -- 用於數據表單校驗.若是校驗失敗,跳轉INPUT視圖.
LOGIN -- 登陸.
ERROR -- 錯誤.
NONE -- 頁面不轉向.
對請求參數進行校驗
設置錯誤信息
讀取國際化信息
在Action類中也能夠獲取到Servlet一些經常使用的API,有以下三種方式獲取
* 徹底解耦合的方式
* 使用接口注入的方式
* 使用ServletActionContext中靜態方法直接訪問Servlet的API
若是使用該種方式,Struts2框架中提供了一個類,ActionContext類,該類中提供一些方法,經過方法獲取Servlet的API
一些經常使用的方法以下:
static ActionContext getContext() 獲取ActionContext對象實例
java.util.Map<java.lang.String,java.lang.Object> getParameters() 獲取請求參數,至關request.getParameterMap();
java.util.Map<java.lang.String,java.lang.Object> getSession() 獲取的表明session域的Map集合,就至關於操sessio域
java.util.Map<java.lang.String,java.lang.Object> getApplication() 獲取表明application域的Map集合
void put(java.lang.String key, java.lang.Object value) 注意:向request域中存入值。
使用接口注入的方式
Struts2框架中提供了一些接口,編寫的Action類能夠是去實現這些接口,而後實現這些接口中的方法,這些方法都是把一些Servlet的經常使用對象經過參數的方式傳遞進來。
經常使用的接口以下:
* ServletRequestAware -- 注入request
* ServletContextAware -- 注入ServletContext
* ServletResponseAware -- 注入response.
Struts2框架提供了一個類,ServletActionContext,該類中提供了一些靜態的方法
具體的方法以下
* getPageContext();
* getRequest()
* getResponse();
* getServletContext();
經過<action>標籤中的method屬性,訪問到Action中的具體的方法
具體的實例以下:
頁面代碼
<a href="${pageContext.request.contextPath}/addBook.action">添加圖書</a> <a href="${pageContext.request.contextPath}/deleteBook.action">刪除圖書</a>
配置文件的代碼
<package name="demo" extends="struts-default" namespace="/"> <action name="addBook" class="cn.zlq.demo.BookAction" method="add"></action> <action name="deleteBook" class="cn.zlq.demo.BookAction" method="delete"></action> </package>
Action的代碼
public String add(){ System.out.println("添加圖書"); return NONE; } public String delete(){ System.out.println("刪除圖書"); return NONE; }
使用通配符的方式能夠簡化配置文件的代碼編寫,並且擴展和維護比較容易。
具體實例以下:
頁面代碼
<a href="${pageContext.request.contextPath}/order_add.action">添加訂單</a> <a href="${pageContext.request.contextPath}/order_delete.action">刪除訂單</a>
配置文件代碼
<action name="order_*" class="cn.zlq.demo.OrderAction" method="{1}"></action>
Action的代碼
public String add(){ System.out.println("添加訂單"); return NONE; } public String delete(){ System.out.println("刪除訂單"); return NONE; }
通配符更抽象的寫法
具體的實例以下:
頁面的代碼
<a href="${pageContext.request.contextPath}/OrderAction_add.action">添加訂單</a>
配置文件代碼
<action name="*_*" class="cn.zlq.demo.{1}" method="{2}"></action>
Action的代碼
public class OrderAction extends ActionSupport{ public String add(){ System.out.println("添加訂單"); return NONE; } }
若是想完成動態方法訪問的方式須要開啓一個常量,struts.enable.DynamicMethodInvocation = false,把值設置成true。
注意:不一樣的Struts2框架的版本,該常量的值不必定是true或者false,須要本身來看一下。若是是false,須要本身開啓。
在struts.xml中開啓該常量。
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
具體代碼以下
頁面的代碼
<a href="${pageContext.request.contextPath}/product!add.action">添加商品</a> <a href="${pageContext.request.contextPath}/product!delete.action">刪除商品</a>
配置文件代碼
<action name="product" class="cn.zlq.demo.ProductAction"></action>
Action的類的代碼
public class ProductAction extends ActionSupport{ public String add(){ System.out.println("添加訂單"); return NONE; } public String delete(){ System.out.println("刪除訂單"); return NONE; } }
條件:
若是<package>包中的一些action都返回success,而且返回的頁面都是同一個JSP頁面,這樣就能夠配置全局的結果頁面。
全局結果頁面針對的當前的包中的全部的Action,可是若是局部還有結果頁面,會優先局部的。
使用的標籤是
<global-results> <result>/demo/suc.jsp</result> </global-results>
<result>/demo/suc.jsp</result>
結果頁面使用<result>標籤進行配置,包含兩個屬性
name -- 邏輯視圖的名稱
type -- 跳轉的類型,值一些,須要掌握一些經常使用的類型。常見的結果類型去struts-default.xml中查找。
* dispatcher -- 轉發.type的默認值.Action--->JSP
* redirect -- 重定向. Action--->JSP
* chain -- 多個action之間跳轉.從一個Action轉發到另外一個Action. Action---Action
* redirectAction -- 多個action之間跳轉.從一個Action重定向到另外一個Action. Action---Action
* stream -- 文件下載時候使用的.
注意:當使用一個Action標籤完成多個Action配置時,會出現Input結果視圖衝突的狀況,也就是說,在不一樣邏輯中跳入的input邏輯視圖是同一個,此時咱們能夠在本身的Action方法上加上 @InputConfig(resultName="邏輯視圖的名稱")的註解而後再在Result中配置便可。
這個爲何這樣呢?你們能夠看源碼:
* 表單的哪些屬性須要封裝數據,那麼在對應的Action類中提供該屬性的set方法便可。
* 表單中的數據提交,最終找到Action類中的setXxx的方法,最後賦值給全局變量。
* 注意:Struts2的框架採用的攔截器完成數據的封裝。
* 注意:這種方式不是特別好:由於屬性特別多,提供特別多的set方法,並且還須要手動將數據存入到對象中.
* 注意:這種狀況下,Action類就至關於一個JavaBean,就沒有體現出MVC的思想,Action類又封裝數據,又接收請求處理,耦合性較高。
* 在頁面中使用OGNL表達式進行數據的封裝,就能夠直接把屬性封裝到某一個JavaBean的對象中。
* 在頁面中定義一個JavaBean,而且提供set方法:例如:private User user;
* 頁面中的編寫發生了變化,須要使用OGNL的方式,表單中的寫法:<input type="text" name="user.username">
* 注意:只提供一個set方法還不夠,若是沒有user實例化,必須還須要提供user屬性的get和set方法,先調用get方法,判斷一下是否有user對象的實例對象,若是沒有,調用set方法把攔截器建立的對象注入進來。
使用模型驅動的方式,也能夠把表單中的數據直接封裝到一個JavaBean的對象中,而且表單的寫法和以前的寫法沒有區別!
編寫的頁面不須要任何變化,正常編寫name屬性的值。
* 手動實例化JavaBean,即:private User user = new User();
* 必須實現ModelDriven<T>接口,實現getModel()的方法,在getModel()方法中返回user便可!!
封裝複雜類型的參數(集合類型 Collection 、Map接口等)
需求:頁面中有可能想批量添加一些數據,那麼如今就可使用上述的技術了。把數據封裝到集合中。
* 由於Collection接口都會有下標值,全部頁面的寫法會有一些區別,注意:
<input type="text" name="products[0].name" />
* 在Action中的寫法,須要提供products的集合,而且提供get和set方法。
* Map集合是鍵值對的形式,頁面的寫法
<input type="text" name="map['one'].name" />
* Action中提供map集合,而且提供get和set方法。
在Action中不推薦使用模型驅動的方式來封裝數據到集合中。
Struts2內部提供了大量轉換器,用來完成數據類型轉換的問題,有以下
* boolean 和 Boolean
* char和 Character
* int 和 Integer
* long 和 Long
* float 和 Float
* double 和 Double
* Date 能夠接收 yyyy-MM-dd 格式字符串
* 數組 能夠將多個同名參數,轉換到數組中
* 集合 支持將數據保存到 List 或者 Map 集合
當發生類型轉換錯誤的時候,根據報錯的信息提示,跳轉input類型的結果視圖。
* 說明若是程序出現異常,會跳轉到input結果視圖,那能夠在<action>標籤中配置input結果視圖
在跳轉的頁面中能夠經過一個固定的標籤來顯示錯誤的信息:
* 能夠先須要先引入Struts2的標籤庫,而後使用標籤顯示錯誤!
<%@ taglib prefix="s" uri="/struts-tags" %>
* <s:fielderror/>,這是Struts2提供的標籤,使用它顯示錯誤的提示信息。
若是類型轉換的攔截器中發生了錯誤,那麼會把錯誤信息放在Struts2錯誤區域中(Struts2的錯誤區域分紅兩部分,一部分是字段錯誤,一部分是Actionc錯誤)
* 等執行到最後一個攔截器(workflow)時,workflow攔截器會去Struts2的錯誤區域中找是否存在錯誤。
* 若是存在錯誤,就跳轉到input視圖。
* 若是不存在錯誤,執行目標Action類中具體的方法。
若是一些特殊的數據類型不能轉換,那麼須要自定義數據類型的轉換器。
實現TypeConverter接口,實現一個方法
Object convertValue(Map<String,Object> context,Object target, Member member,String propertyName,Object value,Class toType);
繼承DefaultTypeConverter類,重寫一個方法
Object convertValue(Map<String,Object> context,Object value,Class toType)
繼承StrutsTypeConverter類,重寫兩個方法
Object convertFromString(Map context,String[] values,Class toClass)
> 從字符串轉換成具體類型
> values數組,存入的值就是用戶輸入的值
> toClass 要轉換的數據的類型 Date.class
* String convertToString(Map context,Object o)
> 把具體的類型轉換成字符串
> o 表明的要轉換的數據
注意:類型轉換自己就是一個雙向的過程:
* JSP ---> Action String ---> 某個類型
* Action ---> JSP 某個類型 ---> String
* 類型轉換的代碼,以 1990/10/10 爲例,自定義日期轉換器,完成轉換,下面這段代碼是第二種方法,也就是繼承了DefaultTypeConverter類。
public Object convertValue(Map<String, Object> context, Object value, Class toType) { // 根據toType判斷 是請求封裝 仍是 數據回顯 DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); if (toType == Date.class) { // 請求參數封裝 (value是字符串) String[] params = (String[]) value; String strVal = params[0]; // 轉換爲 日期類型 try { return dateFormat.parse(strVal); } catch (ParseException e) { e.printStackTrace(); } } else { // 回顯(value是 Date) Date date = (Date) value; return dateFormat.format(date); } return null; }
局部註冊:針對某個表單中的某個字段生效的!
* 屬性驅動的方式:使用set方法接收數據
> 注意:在Action所在的包下建立一個文件,文件的格式是:Action類名-conversion.properties文件,該文件中配置要轉換數據的字段和對應的轉換器全路徑
* 例如:birthday=cn.zlq.demo3.MyDateConverter
* 模型驅動的方式:實現ModelDriven接口的方式
> 注意:在實體類所在的包下建立一個文件,文件的格式是:實體類名-conversion.properties文件,該文件中配置要轉換數據的字段和對應的轉換器全路徑
* 例如:birthday=cn.zlq.demo3.MyDateConverter
全局註冊:針對整個項目的全部的日期類型都會生效的!
* 在src的目錄下,建立一個xwork-conversion.properties (名稱是固定的)
> 例如:java.util.Date=cn.zlq.demo3.MyDateConverter
數據校驗包含兩種方式,第一種是手動編碼完成數據校驗方式,第二種是經過配置文件完成數據校驗方式。
> 步驟一: 封裝數據
> 步驟二: 實現校驗Action ,必須繼承ActionSupport 類
> 步驟三: 覆蓋validate方法,完成對Action的業務方法 數據校驗 this.addFieldError (ActionSupport提供)
> 步驟四: 在jsp中 經過 <s:fieldError/> 顯示錯誤信息
讓Action繼承ActionSupport類,重寫ActionSupport類中的validate()方法,在該方法中完成數據校驗。
手動在Action中編寫一個方法,方法名稱是validate方法名稱() 例如:public void validateAdd(){ }
* Action中有一個save的方法,只校驗save方法。
* validateSave() -- 使用該方法去校驗save的方法
xml配置校驗原理 : 將不少校驗規則代碼已經寫好,只須要在xml中定義數據所使用校驗規則就能夠了
> 步驟一 :編寫jsp
> 步驟二 :編寫Action 繼承ActionSupport 或者 實現 Validateable 接口
> 步驟三 :封裝請求參數
* 使用xml校驗 必須提供get方法
> 步驟四 :編寫校驗規則xml文件
* 具體的配置文件相關標籤和屬性詳解
<field name="password"> <!-- 校驗器類型 --> <field-validator type="requiredstring"> <message>密碼不能爲空</message> </field-validator> <!-- 規定密碼的長度 --> <field-validator type="stringlength"> <param name="minLength">3</param> <param name="maxLength">8</param> <message>密碼在3-8位之間</message> </field-validator> </field>
> 在Action所在的包中建立一個XML文件,命名規則:Action類名-validation.xml。而且須要引入指定的DTD的約束:xwork-core-2.3.15.3.jar/xwork-validator-1.0.3.dtd
> 具體的值:
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
在Action所在的包中建立一個XML文件,命名規則:Action類名-方法對應的訪問路徑-validation.xml。引入DTD文件等。
* 例如:Reg6Action-reg6-validation.xml
* required (必填校驗器,要求被校驗的屬性值不能爲null),空格沒問題。
* requiredstring (必填字符串校驗器,要求被校驗的屬性值不能爲null,而且長度大於0,默認狀況下會對字符串去先後空格)
* stringlength (字符串長度校驗器,要求被校驗的屬性值必須在指定的範圍內,不然校驗失敗,minLength參數指定最小長度,maxLength參數指定最大長度,trim參數指定校驗field以前是否去除字符串先後的空格)
* regex (正則表達式校驗器,檢查被校驗的屬性值是否匹配一個正則表達式,expression參數指定正則表達式,caseSensitive參數指定進行正則表達式匹配時,是否區分大小寫,默認值爲true)
* int(整數校驗器,要求field的整數值必須在指定範圍內,min指定最小值,max指定最大值)
* double(雙精度浮點數校驗器,要求field的雙精度浮點數必須在指定範圍內,min指定最小值,max指定最大值)
* fieldexpression (字段OGNL表達式校驗器,要求field知足一個ognl表達式,expression參數指定ognl表達式,該邏輯表達式基於ValueStack進行求值,返回true時校驗經過,不然不經過)
* email(郵件地址校驗器,要求若是被校驗的屬性值非空,則必須是合法的郵件地址)
* url(網址校驗器,要求若是被校驗的屬性值非空,則必須是合法的url地址)
* date(日期校驗器,要求field的日期值必須在指定範圍內,min指定最小值,max指定最大值)
* 攔截器就是AOP(Aspect-Oriented Programming)的一種實現。
* 過濾器:過濾從客服端發送到服務器端請求的.
* 攔截器:攔截對目標Action中的某些方法進行攔截.
* 攔截器不能攔截JSP.
* 攔截到Action中某些方法.
1)攔截器是基於JAVA反射機制的,而過濾器是基於函數回調的。
2)過濾器依賴於Servlet容器,而攔截器不依賴於Servlet容器
3)攔截器只能對Action請求起做用,而過濾器能夠對幾乎全部的請求起做用。
4)在Action的生命週期中,攔截器能夠屢次被調用,而過濾器只能在容器初始化時被調用一次
* 攔截器 採用 責任鏈 模式
> 在責任鏈模式裏,不少對象由每個對象對其下家的引用而鏈接起來造成一條鏈。
> 責任鏈每個節點,均可以繼續調用下一個節點,也能夠阻止流程繼續執行
* 在struts2 中能夠定義不少個攔截器,將多個攔截器按照特定順序 組成攔截器棧 (順序調用 棧中的每個攔截器 )
須要實現Interceptor接口,實現接口中的三個方法。
* interceptor接口有不少的實現類,編寫最簡單的方式就是繼承AbstractInterceptor實現類。
* 代碼例如:
public String intercept(ActionInvocation invocation) throws Exception { User user = (User) ServletActionContext.getRequest().getSession().getAttribute("existUser"); if(user == null){ ActionSupport as = (ActionSupport) invocation.getAction(); as.addActionError("您沒有登錄!"); return as.LOGIN; }else{ // 放行 return invocation.invoke(); } }
配置一共有兩種方式
在<package>包中定義攔截器,出如今<package>包的上方
<interceptors> <interceptor name="loginInterceptor" class="cn.zlq.interceptor.LoginInterceptor"></interceptor> </interceptors>
在某個action中引入攔截器
<interceptor-ref name="loginInterceptor"></interceptor-ref>
注意:若是引入了本身定義的攔截器,那麼Struts2框架默認的攔截器就不會再執行了,因此須要引入Struts2默認的攔截器。
<interceptor-ref name="defaultStack"></interceptor-ref>
在<package>包中定義攔截器的時候,本身直接定義一個攔截器棧
<interceptors> <interceptor name="loginInterceptor" class="cn.zlq.interceptor.LoginInterceptor"/> <interceptor-stack name="myStack"> <interceptor-ref name="loginInterceptor"/> <interceptor-ref name="defaultStack"/> </interceptor-stack> </interceptors>
在Action包中引入本身定義的攔截器棧
<action name="book_*" class="cn.zlq.action.BookAction" method="{1}"> <interceptor-ref name="myStack"/> </action>
底層使用也是FileUpload開源的組件。
* 提供 FileUpload 攔截器,用於解析 multipart/form-data 編碼格式請求,解析上傳文件的內容
* fileUpload攔截器 默認在 defaultStack 棧中, 默認會執行的
* 在Action中編寫文件上傳,須要定義三個屬性
文件類型File ,屬性名與表單中file的name屬性名一致.
字符串類型String , 屬性名:前段是name屬性名一致 +ContentType;
字符串類型String , 屬性名:前段是name屬性名一致+FileName;
最後須要爲上述的三個屬性提供set方法。
能夠經過FileUtils提供 copyFile 進行文件複製,將上傳文件 保存到服務器端
* 先配置input邏輯視圖
* 在頁面中顯示錯誤信息
* 文件上傳的總大小默認值是2M,若是超過了2M,程序會報出異常。可使用<s:actionError>來查看具體信息!
> 解決總大小的設置,找到常量:
* struts.multipart.parser=jakarta -- 默認文件上傳解析器,就是FileUpload組件
* struts.multipart.saveDir= -- 文件上傳的臨時文件存儲目錄
* struts.multipart.maxSize=2097152 -- 文件上傳的最大值(總大小),默認是2M
> 能夠在struts.xml中設置常量,修改文件上傳的默認總大小!!!
<constant name="struts.multipart.maxSize" value="5000000"></constant>
先在<action>標籤中引入文件上傳的攔截器
<interceptor-ref name="defaultStack"> <!-- 設置單個上傳文件的大小 --> <param name="fileUpload.maximumSize">2097152</param> <!-- 設置擴展名 --> <param name="fileUpload.allowedExtensions">.txt</param> </interceptor-ref>
* 在Action中仍是編寫三個屬性
> 屬性須要是數組或者List集合,這樣就能夠完成多文件上傳了。
> 注意:是數組或者List集合
private File [] upload; // 表明上傳的文件
private String [] uploadContentType; // 表明文件的類型
private String [] uploadFileName; // 上傳文件的名稱
提供屬性的set方法
Action類必需要有返回結果,而且返回結果中必需要依賴stream結果類型。
* 在<action>標籤中配置stream的結果類型。
* 能夠經過<result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>源碼發現有一些須要設置的屬性。
<result name="success" type="stream"> <param name="contentType">${contentType}</param> <param name="contentDisposition">attachment;filename=${downFileName}</param> <param name="inputName"></param> </result>
上面的代碼的${contentType}這種寫法須要Action類提供對應的方法,對應的方法以下
// 獲取文件的MIME類型 public String getContentType(){ return ServletActionContext.getServletContext().getMimeType(filename); } // 設置文件的輸入流 public InputStream getInputStream(){ return ServletActionContext.getServletContext().getResourceAsStream("/download/"+filename); } // 設置Content-Disposition屬性 public String getDownFilename() throws IOException{ String agent = ServletActionContext.getRequest().getHeader("User-Agent"); return this.encodeDownloadFilename(filename, agent); }
解決下載文件中文亂碼的問題
public String encodeDownloadFilename(String filename, String agent) throws IOException{ if(agent.contains("Firefox")){ // 火狐瀏覽器 filename = "=?UTF-8?B?"+new BASE64Encoder().encode(filename.getBytes("utf-8"))+"?="; }else{ // IE及其餘瀏覽器 filename = URLEncoder.encode(filename,"utf-8"); } return filename; }
OGNL是Object Graphic Navigation Language(對象圖導航語言)的縮寫,它是一個開源項目。
* 所謂對象圖,即以任意一個對象爲根,經過OGNL能夠訪問與這個對象關聯的其它對象。
* 經過它簡單一致的表達式語法,能夠存取對象的任意屬性,調用對象的方法,遍歷整個對象的結構圖,實現字段類型轉化等功能。它使用相同的表達式去存取對象的屬性。
Struts2框架使用OGNL做爲默認的表達式語言
* OGNL是一種比EL強大不少倍的語言
* xwork 提供 OGNL表達式
OGNL 提供五大類功能
* 支持對象方法調用,如xxx.doSomeSpecial();
* 支持類靜態的方法調用和值訪問
* 訪問OGNL上下文(OGNL context)和ActionContext; (重點 操做ValueStack值棧 )
* 支持賦值操做和表達式串聯
* 操做集合對象。
* 值棧就至關於Struts2框架的數據的中轉站,向值棧存入一些數據。從值棧中獲取到數據。
* ValueStack 是 struts2 提供一個接口,實現類 OgnlValueStack ---- 值棧對象 (OGNL是從值棧中獲取數據的 )
* Action是多例的,有一塊兒請求,建立Action實例,建立一個ActionContext對象,表明的是Action的上下文對象,還會建立一個ValueStack對象。線程安全的
* 每一個Action實例都有一個ValueStack對象 (一個請求 對應 一個ValueStack對象 )
* 在其中保存當前Action 對象和其餘相關對象 (值棧中 是有Action 引用的 )
* Struts 框架把 ValueStack 對象保存在名爲 「struts.valueStack」 的請求屬性中,request中 (值棧對象 是 request一個屬性)
* ValueStack vs = (ValueStack)request.getAttribute("struts.valueStack");
* 值棧由兩部分組成
> root -- Struts把動做和相關對象壓入 ObjectStack 中--List
> context -- Struts把各類各樣的映射關係(一些 Map 類型的對象) 壓入 ContextMap 中
* Struts 會把下面這些映射壓入ContextMap中
> parameters: 該 Map 中包含當前請求的請求參數 ?name=xxx&password=123
> request: 該 Map 中包含當前 request 對象中的全部屬性
> session: 該 Map 中包含當前 session 對象中的全部屬性
> application:該 Map 中包含當前 application 對象中的全部屬性
> attr: 該 Map 按以下順序來檢索某個屬性: request, session, application
* ValueStack中 存在root屬性 (CompoundRoot) 、 context 屬性 (OgnlContext )
> CompoundRoot 就是ArrayList
> OgnlContext 就是 Map
* context 對應Map 引入 root對象
> context中還存在 request、 session、application、 attr、 parameters 對象引用
> OGNL表達式訪問值棧中的數據
* 訪問root中數據時 不須要 #
* 訪問 request、 session、application、 attr、 parameters 對象數據 必須寫 #
> 操做值棧 默認指 操做 root 元素
* 值棧對象是請求時建立的
* ActionContext是綁定到當前的線程上,那麼在每一個攔截器或者Action中獲取到的ActionContext是同一個。
* ActionContext中存在一個Map集合,該Map集合和ValueStack的contextMap是同一個地址。
* ActionContext中能夠獲取到ValueStack的引用。
* ValueStack vs1 = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");
* ValueStack vs2 = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
* ValueStack vs3 = ActionContext.getContext().getValueStack();
向值棧保存數據,主要針對 root
* 兩種方式
valueStack.push(Object obj);
* push方法的底層調用root對象的push方法(把元素添加到0位置)
valueStack.set(String key, Object obj);
* 源碼獲取map集合(map有多是已經存在的,有多是新建立的),把map集合push到棧中,再把數據存入到map集合中。
在jsp中 經過 <s:debug /> 查看值棧的內容
*屬性驅動方式:
當ActionContext中提供了一個JavaBean的get方法,就能不將這個JavaBean放到值棧中而取到這個值
這是由於值棧的中有ActionContext對象,能夠經過這個對象取到JavaBean
*模型驅動方式:
當Action中經過模型驅動獲取到對象的時候,會將模型驅動中的對象壓入值棧的root棧頂,因此此時能夠獲取到經過Action模型驅動封裝的對象
* StrutsPreparedAndExecuteFilter的doFilter代碼中 request = prepare.wrapRequest(request);
對Request對象進行了包裝 ,StrutsRequestWrapper
加強了request的 getAttribute
Object attribute = super.getAttribute(s);
if (attribute == null) {
attribute = stack.findValue(s);
}
訪問request範圍的數據時,若是數據找不到,去值棧中找
request對象 具有訪問值棧數據的能力 (查找root的數據)
具體在Struts2中怎麼使用呢?以下步驟:
* 須要先引入Struts2的標籤庫
<%@ taglib prefix="s" uri="/struts-tags" %>
* 使用Struts2提供的標籤中的標籤
<s:property value="OGNL表達式"/>
* 訪問對象方法:
<s:property value="'hello'.length()"/>
* 訪問對象的靜態方法:
> struts2中靜態方法訪問被禁止的.開啓一個常量.
<constant name="struts.ognl.allowStaticMethodAccess" value="true"/>
> 在頁面中:
<s:property value="@java.lang.Math@random()"/>
<s:property value="#request.name"/>
<s:property value="#session.name"/>
<s:property value="#application.name"/>
<s:property value="#attr.name"/>
<s:property value="#parameters.id"/>
<s:property value="#parameters.name"/>
強制字符串解析成OGNL表達式。
例如:在request域中存入值,而後在文本框(<s:textfield>)中取值,如今到value上。
<s:textfield value="%{#request.msg}"/>
{ }中值用''引發來,此時再也不是ognl表達式,而是普通的字符串
例如:<s:property value="%{'#request.msg'}"/>
在配置文件中可使用OGNL表達式