Struts2國際化
1、 國際化原理 ? 什麼是國際化 ?
同一款軟件 可以爲不同用戶,提供不同語言界面 —- 國際化軟件
需要一個語言資源包(很多properties文件,每個properties文件 針對一個國家或者語言 ,通過java程序根據來訪者國家語言,自動讀取不同properties文件 )
2、 資源包編寫
properties文件命名 : 基本名稱語言(小寫)國家(大寫).properties
例如 :
messages_zh_CN.properties 中國中文
messages_en_US.properties 美國英文
3、 ResourceBundle 根據不同Locale(地域信息),讀取不同國家 properties文件
ResourceBundle bundle = ResourceBundle.getBundle(“messages”, Locale.US);
國際化配置
第一種 全局國際化信息文件 (所有Action都可以使用 ) ——- 最常用
* properties文件可以在任何包中
* 需要在struts.xml 中配置全局信息文件位置
struts.xml
<constant name="struts.custom.i18n.resources" value="messages"></constant> messages.properties 在src根目錄
<constant name="struts.custom.i18n.resources" value="cn.itcast.resources.messages"></constant>
messages.properties 在 cn.itcast.resources 包
國際化信息
在Action中使用 : this.getText(“msg”);
在jsp中使用 :
在配置文件中(校驗xml) :
第二種 Action範圍信息文件 (只能在某個Action中使用 )
數據只能在對應Action中使用,在Action類所在包 創建 Action類名.properties ——— 無需配置
第三種 package範圍信息文件 (package中所有Action都可以使用 )
數據對包 (包括子包)中的所有Action 都有效 , 在包中創建 package.properties —– 無需配置
第四種 臨時信息文件 (主要在jsp中 引入國際化信息 )
在jsp指定讀取 哪個properties文件
* 向信息中傳遞參數 {0} {1} ———— MessageFormat 動態消息文本
this.getText(“required”, new String[] { “用戶名” });
Struts2攔截器
攔截器介紹
攔截器 的使用 ,源自Spring AOP(面向切面編程)思想
攔截器 採用 責任鏈 模式
* 在責任鏈模式裏,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。
* 責任鏈每一個節點,都可以繼續調用下一個節點,也可以阻止流程繼續執行
在struts2 中可以定義很多個攔截器,將多個攔截器按照特定順序 組成攔截器棧 (順序調用 棧中的每一個攔截器 )
1、 struts2 所有攔截器 都必須實現 Interceptor 接口
2、 AbstractInterceptor 類實現了 Interceptor 接口. 併爲 init, destroy 提供了一個空白的實現
所有實際開發中,自定義攔截器 只需要 繼承 AbstractInterceptor類, 提供 intercept 方法實現
3、 常用struts2 攔截器
<interceptor-ref name="modelDriven"/> 模型驅動
<interceptor-ref name="fileUpload"/> 文件上傳
<interceptor-ref name="params"> 參數解析封裝
<interceptor-ref name="conversionError"/> 類型轉換錯誤
<interceptor-ref name="validation"> 請求參數校驗
<interceptor-ref name="workflow"> 攔截跳轉 input 視圖
自定義攔截器案例
案例 : 登陸,對其它Action訪問 通過自定義攔截器 進行權限控制
導入jar包 (struts2 jar、c3p0、 dbutils、 mysql驅動)
web.xml
struts.xml
JDBCUtils 工具類
第一步 : 編寫index.jsp 提供 圖書增刪改查 四個功能
編寫BookAction ,提供四個業務方法
第二步: 完成登陸功能
第三步 :必須要登陸 才能進行圖書管理
使用Filter 進行權限控制 —- 過濾所有web請求 (所有web資源訪問)
使用攔截器 進行權限控制 —- 主要攔截對Action訪問 (不能攔截JSP)
定義攔截器 繼承AbstractInterceptor
配置攔截器
方式一
<!-- 註冊攔截器 -->
<interceptors>
<interceptor name="privilege" class="cn.itcast.interceptor.PrivilegeInterceptor"></interceptor>
</interceptors>
<action name="book_*" class="cn.itcast.action.BookAction" method="{1}" >
<!-- 使用攔截器 -->
<!-- 當使用自定義攔截器 後,默認攔截器 就會失效 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
nterceptor-ref name="privilege"></interceptor-ref>
</action>
方式二
<!-- 註冊攔截器 -->
<interceptors>
<interceptor name="privilege" class="cn.itcast.interceptor.PrivilegeInterceptor"></interceptor>
<!-- 自定義攔截器棧 -->
<interceptor-stack name="privilegeStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="privilege"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 設置當前包 所有Action 都使用 自定義攔截器棧 -->
<default-interceptor-ref name="privilegeStack"></default-interceptor-ref>
Struts2文件上傳下載
Struts2文件上傳
提供 FileUpload 攔截器,用於解析 multipart/form-data 編碼格式請求,解析上傳文件的內容
fileUpload攔截器 默認在 defaultStack 棧中, 默認會執行的
在Action需要對上傳文件內容進行接收
頁面:
<input type="file" name="upload" />
Action :
public class UploadAction extends ActionSupport {
// 接收上傳內容
// <input type="file" name="upload" />
private File upload; // 這裏變量名 和 頁面表單元素 name 屬性一致
private String uploadContentType;
private String uploadFileName;
}
* 格式 : 上傳表單項name屬性 + ContentType 、 上傳表單項name屬性 + FileName
* 爲三個對象 提供 setter 方法
通過FileUtils 提供 copyFile 進行文件複製,將上傳文件 保存到服務器端
Struts2文件上傳問題解決
配置 input 視圖 ,作爲上傳出錯後 跳轉頁面
在文件上傳時,如果發生錯誤 ,fileUpload攔截器 會設置錯誤信息,workflow攔截器 跳轉到 input 視圖
struts.multipart.parser=jakarta 定義文件上傳,採用 commons-fileupload 技術
* 同時支持 cos 、pell 上傳技術 (如果使用其它上傳技術,單獨下載jar包 )
通過 struts.multipart.maxSize 常量設置文件上傳總大小限制
* struts.multipart.maxSize=2097152 默認上傳文件總大小 2MB
* 超過文件總大小,跳轉input 視圖, 通過 回顯錯誤信息
在struts.xml 設置上傳總大小
設置上傳文件總大小,對所有上傳form有效,只想對當前form進行設置,可以設置fileUpload攔截器屬性
FileUpload 攔截器有 3 個屬性可以設置.
* maximumSize: 上傳文件的最大長度(以字節爲單位), 默認值爲 2 MB
* allowedTypes: 允許上傳文件的類型, 各類型之間以逗號分隔
* allowedExtensions: 允許上傳文件擴展名, 各擴展名之間以逗號分隔
如果針對fileUpload 進行參數設置,當出錯時,在頁面通過 回顯錯誤信息
struts-messages.properties 文件裏預定義 上傳錯誤信息,通過覆蓋對應key 顯示中文信息
struts.messages.error.uploading=Error uploading: {0}
struts.messages.error.file.too.large=The file is to large to be uploaded: {0} "{1}" "{2}" {3}
struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}
struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}
修改爲
struts.messages.error.uploading=上傳錯誤: {0}
struts.messages.error.file.too.large=上傳文件太大: {0} "{1}" "{2}" {3}
struts.messages.error.content.type.not.allowed=上傳文件的類型不允許: {0} "{1}" "{2}" {3}
struts.messages.error.file.extension.not.allowed=上傳文件的後綴名不允許: {0} "{1}" "{2}" {3}
多文件上傳
第一步:在WEB-INF/lib下加入commons-fileupload-1.2.1.jar、commons-io-1.3.2.jar。這兩個文件可以從http://commons.apache.org/下載。
第二步:把form表的enctype設置爲:“multipart/form-data“,如下:
<form enctype="multipart/form-data" action="${pageContext.request.contextPath}/xxx.action" method="post">
<input type="file" name="uploadImages">
<input type="file" name="uploadImages">
</form>
第三步:在Action類中添加以下屬性,屬性紅色部分對應於表單中文件字段的名稱:
public class uploadAction{
private File[] uploadImages;//得到上傳的文件
private String[] uploadImagesContentType;//得到文件的類型
private String[] uploadImagesFileName;//得到文件的名稱
//這裏略省了屬性的getter/setter方法
public String saveFiles() throws Exception{
ServletContext sc = ServletActionContext.getServletContext();
String realpath = sc.getRealPath("/uploadfile");
try {
if(uploadImages!=null&&uploadImages.length>0){
for(int i=0;i<uploadImages.length;i++){
File destFile = new File(realpath,uploadImageFileNames[i]);
FileUtils.copyFile(uploadImages[i], destFile);
}
}
} catch (IOException e) {
e.printStackTrace();}return "success";}}
Struts2文件下載
1) struts2 完成文件下載,通過 結果集類型 (Result Type) stream 來完成的
struts-default.xml 定義
2) 使用Stream結果集 完成文件下載
文件下載原理: 服務器讀取下載文件內容,通過Response響應流寫回, 設置 ContentType、 ContentDisposition 頭信息
public class StreamResult extends StrutsResultSupport {
protected String contentType = "text/plain"; // contentType頭信息 (下載文件對應 MIME協議規定類型 )
* html --- text/html . txt--- text/plain
protected String contentDisposition = "inline"; // ContentDisposition頭信息 (下載文件打開方式 inline瀏覽器內部打開, attachment 以附件形式打開)
protected String inputName = "inputStream"; // 需要Action中 提供 getInputStream 方法 返回 InputStream 提供下載文件 內容
}
Action 提供 InputStream 返回值 getInputStream 方法 ——- 指定下載文件流
配置 stream 結果集 參數
* 下載附件名亂碼問題 , IE和火狐 解決不同
* 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表示式使用 和 值棧
OGNL是Object Graphic Navigation Language(對象圖導航語言)的縮寫,它是一個開源項目。 Struts2框架使用OGNL作爲默認的表達式語言。
* xwork 提供 OGNL表達式
* ognl-3.0.5.jar
OGNL 是一種比EL 強大很多倍的語言
OGNL 提供五大類功能
1、支持對象方法調用,如xxx.doSomeSpecial();
2、支持類靜態的方法調用和值訪問
3、訪問OGNL上下文(OGNL context)和ActionContext; (重點 操作ValueStack值棧 )
4、支持賦值操作和表達式串聯
5、操作集合對象。
1、 使用OGNL訪問 對象方法 和 靜態方法
* OGNL 在jsp 結合 struts2 標籤庫 使用 , 執行 ognl表達式
調用 實例方法 : 對象.方法() —-
調用 靜態方法 : @[類全名(包括包路徑)]@[方法名] —
* 使用 靜態方法調用 必須 設置 struts.ognl.allowStaticMethodAccess=true
2、 訪問OGNL上下文(OGNL context)和ActionContext
OGNL上下文(OGNL context) 對象 —– 值棧 ValueStack
問題一 : 什麼是值棧 ValueStack ?
ValueStack 是 struts2 提供一個接口,實現類 OgnlValueStack —- 值棧對象 (OGNL是從值棧中獲取數據的 )
每個Action實例都有一個ValueStack對象 (一個請求 對應 一個ValueStack對象 )
在其中保存當前Action 對象和其他相關對象 (值棧中 是有Action 引用的 )
Struts 框架把 ValueStack 對象保存在名爲 “struts.valueStack” 的請求屬性中,request中 (值棧對象 是 request一個屬性)
問題二 : 值棧的內部結構 ?
值棧由兩部分組成
ObjectStack: Struts 把動作和相關對象壓入 ObjectStack 中–List
ContextMap: Struts 把各種各樣的映射關係(一些 Map 類型的對象) 壓入 ContextMap 中
Struts 會把下面這些映射壓入 ContextMap 中
parameters: 該 Map 中包含當前請求的請求參數
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 元素
問題三 : 值棧對象的創建 ,ValueStack 和 ActionContext 是什麼關係 ?
值棧對象 是請求時 創建的
doFilter中 prepare.createActionContext(request, response);
* 創建ActionContext 對象過程中,創建 值棧對象ValueStack
* ActionContext對象 對 ValueStack對象 有引用的 (在程序中 通過 ActionContext 獲得 值棧對象 )
Dispatcher類 serviceAction 方法中 將值棧對象保存到 request範圍
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
問題四 : 如何獲得值棧對象
獲得值棧對象 有兩種方法
ValueStack valueStack = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
ValueStack valueStack2 = ActionContext.getContext().getValueStack();
問題五: 向值棧保存數據 (主要針對 root)
兩種方式
// 將數據保存root的索引0位置,放置到第一個元素 ArrayList add(0,element);
valueStack.push("itcast");
// 在值棧創建參數map, 將數據保存到map中
valueStack.set("company", "傳智播客");
在jsp中 通過 <s:debug /> 查看值棧的內容
問題六: 在JSP中獲取值棧的數據
訪問root中數據 不需要#
訪問 其它對象數據 加 #
通過下標獲取root中對象
//取值棧頂對象
直接在root中查找對象屬性 (自上而下自動查找)
valueStack:
在OgnlContext中獲取數據
request:<s:property value="#request.username"/>
session:<s:property value="#session.username"/>
application:<s:property value="#application.username"/>
attr:<s:property value="#attr.username"/>
parameters:<s:property value="#parameters.cid[0]"/>