Struts2中的國際化、Ognl(對象圖導航語言)表達式語言
回顧:Servlet 中國際化:
1). 寫資源文件
基礎名.properties 【默認的語言環境的配置】
基礎名語言簡稱國家簡稱.properties
2). 讀取資源文件,再使用
程序:ResourceBundle
Jsp: jstl提供的格式化與國際化標籤庫。
一、Struts2中國際化:
1. 寫資源文件 (同servlet)
2. 讀資源文件
程序:ResourceBundle (同servlet)
JSP:
1)jstl表親啊 (同servlet)
2)struts標籤獲取資源文件內容
區別:
Struts2加載資源文件更加簡單!通過常量加載即可!再在jsp頁面直接使用!
- 寫資源文件
Msg.properties 默認的語言環境; 找不到配置就找它
Msg_en_US.properties 美國 - 加載
<constant name="struts.custom.i18n.resources" value="cn.itcast.config.msg"></constant>
- 使用: 標籤name值直接寫配置文件中的key
<s:text name="title"></s:text>
另外一點,
(推薦)加載資源文件通過常量加載
還可以在頁面加載, 這樣用:
<s:i18n name="cn.itcast.config.msg">
<s:text> 標籤必須放到標籤體中。
</s:i18n>
二、 Ognl表達式語言
概述
OGNL表達式
OGNL是Object Graphic Navigation Language(對象圖導航語言)的縮寫,它是一個開源項目。 Struts2框架使用OGNL作爲默認的表達式語言。
OGNL優勢
1、支持對象方法調用,如xxx.doSomeSpecial();
2、支持類靜態的方法調用和值訪問,表達式的格式:
@[類全名(包括包路徑)]@[方法名 | 值名],例如:
@java.lang.String@format(‘foo %s’, ‘bar’)
或@tutorial.MyConstant@APP_NAME;
3、支持賦值操作和表達式串聯,如price=100, discount=0.8,
calculatePrice(),這個表達式會返回80;
4、訪問OGNL上下文(OGNL context)和ActionContext;
5、操作集合對象。
總結
OGNL 有一個上下文(Context)概念,說白了上下文就是一個MAP結構,它實現了 java.utils.Map 的接口。 OgnlContext對象
分析:
Struts框架默認就支持Ognl表達式語言。
(struts必須引用的包:ognl.jar)
作用
頁面取值用。
El表達式語言,用於頁面取值,jsp頁面取值的標準。(默認直接可以使用)
(應用範圍更廣。)
Ognl表達式語言, struts標籤默認支持的表達式語言。
必須配置struts標籤用,不能離開struts標籤直接用。
OgnlContext對象(瞭解)
OgnlContext對象是ognl表達式語言的核心。
源碼類:
public class OgnlContext extends Object implements Map{..}
硬編碼方式,瞭解OgnlContext對象:
// OgnlContext用法
public class OgnlDemo1 {
/**
* 1. Ognl表達式語言語言取值,取非根元素的值,必須用#號
* @throws Exception
*/
@Test
public void testOgnl() throws Exception {
// 創建一個Ognl上下文對象
OgnlContext context = new OgnlContext();
// 放入數據
User user = new User();
user.setId(100);
user.setName("Jack");
// 【往非根元素放入數據, 取值的時候表達式要用"#"】
context.put("user", user);
// 獲取數據(map)
// 先構建一個Ognl表達式, 再解析表達式
Object ognl = Ognl.parseExpression("#user.name");
Object value = Ognl.getValue(ognl, context, context.getRoot());
System.out.println(value);
}
/**
* 2. Ognl表達式語言語言取值,取根元素的值,不用帶#號
* @throws Exception
*/
@Test
public void testOgn2() throws Exception {
// 創建一個Ognl上下文對象
OgnlContext context = new OgnlContext();
// 放入數據
User user = new User();
user.setId(100);
user.setName("Jack");
// 【往根元素放入數據】
context.setRoot(user);
// 獲取數據(map)
// 先構建一個Ognl表達式, 再解析表達式
Object ognl = Ognl.parseExpression("address.province");
Object value = Ognl.getValue(ognl, context, context.getRoot());
System.out.println(value);
}
/**
* 3.Ognl對 靜態方法調用的支持
* @throws Exception
*/
@Test
public void testOgn3() throws Exception {
// 創建一個Ognl上下文對象
OgnlContext context = new OgnlContext();
// Ognl表單式語言,調用類的靜態方法
//Object ognl = Ognl.parseExpression("@Math@floor(10.9)");
// 由於Math類在開發中比較常用,所以也可以這樣寫
Object ognl = Ognl.parseExpression("@@floor(10.9)");
Object value = Ognl.getValue(ognl, context, context.getRoot());
System.out.println(value);
}
}
ValueStack對象
ValueStack, 即值棧對象。
值棧對象:
是整個struts數據存儲的核心,或者叫中轉站。
用戶每次訪問struts的action,都會創建一個Action對象、值棧對象、ActionContext對象; 然後把Action對象放入值棧中; 最後再把值棧對象放入request中,傳入jsp頁面。
(key: struts.valueStack); 開發者只需要通過ActionContext對象就可以訪問struts的其他的關鍵對象。 (ActionContext是給開發者用的,便於學習與使用。)
問題:
OgnlContext與ValueStack對象的關係?
Struts標籤
Struts標籤取值,就使用了Ognl表達式語言。
Struts數據效驗
表單數據的驗證:
前臺驗證:主要是通過JS驗證, 表達數據是否合法!
後臺驗證:通過後臺java代碼進行驗證!
Struts也提供了數據效驗的方式!
Struts數據效驗, 通過攔截器完成:
public synchronized void addFieldError(String fieldName, String errorMessage) {
// 1. 保存錯誤信息的map集合
final Map<String, List<String>> errors = internalGetFieldErrors();
// 2. Map的value值 (一個key,對應的多個值用list存儲)
List<String> thisFieldErrors = errors.get(fieldName);
// 3. 如果錯誤信息的map中沒有當前的key,就直接創建集合
if (thisFieldErrors == null) {
// 創建
thisFieldErrors = new ArrayList<String>();
errors.put(fieldName, thisFieldErrors);
}
// 4. 添加錯誤信息
thisFieldErrors.add(errorMessage);
}
Action實現:
/**
* 注意:如果要想用struts的數據效驗功能,必須繼承ActionSupport或實現相關接口
* @author Jie.Yuan
*
*/
public class UserAction extends ActionSupport {
// 封裝請求數據
private User user = new User();
public void setUser(User user) {
this.user = user;
}
public User getUser() {
return user;
}
// 重寫數據驗證的方法
@Override
public void validate() {
// 用戶名非空
if (user.getUserName() == null || "".equals(user.getUserName())) {
// 保存錯誤信息
super.addFieldError("userName", "用戶名必須填寫!");
}
// 密碼
if (user.getPwd() == null || "".equals(user.getPwd())) {
super.addFieldError("pwd", "密碼必填");
}
}
…..
}
代碼方式驗證Action中指定的方法:
寫驗證方法命名規則:
validate + 要驗證的方法名
如:
public void validateRegister() {
只會驗證當前action的register方法!
XML方式驗證Action中所有的方法:
總結代碼方式驗證:
繁瑣,設計很多重複的驗證邏輯!例如:非空驗證、數值驗證、email、日期等。
Struts對於常用的驗證,進行了封裝,即提供了驗證器, 驗證指定的常用業務邏輯!
Struts提供的所有驗證器:
路徑:
xwork-core-2.3.4.1.jar/com.opensymphony.xwork2.validator.validators/default.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator Definition 1.0//EN"
"http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd">
<!-- START SNIPPET: validators-default -->
<validators>
<validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>
<validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>
<validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/>
<validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/>
<validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/>
<validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/>
<validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/>
<validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/>
<validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/>
<validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/>
<validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/>
<validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/>
<validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/>
<validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/>
<validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/>
<validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/>
</validators>
<!-- END SNIPPET: validators-default -->
如果寫xml,從而定義驗證規則:
1)XML文件名稱語法: ActionClassName-validation.xml
注意:此xml需要與當期要驗證的action在同一個目錄:
舉例:UserAction-validation.xml
2) 寫XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<!-- 驗證的每一個字段用field表示 -->
<field name="user.userName">
<!-- 指定使用的驗證器 -->
<field-validator type="requiredstring">
<!-- 驗證失敗的錯誤提示信息 -->
<message>用戶名不能爲空!</message>
</field-validator>
</field>
<!-- 驗證pwd -->
<field name="user.pwd">
<!-- 非空 -->
<field-validator type="requiredstring">
<message>密碼不能爲空!</message>
</field-validator>
<!-- 長度 -->
<field-validator type="stringlength">
<param name="minLength">6</param>
<param name="maxLength">8</param>
<message>密碼必須爲6-8位!</message>
</field-validator>
</field>
<!-- 驗證日期 -->
<field name="user.birth">
<field-validator type="date">
<message>日期格式不對!</message>
</field-validator>
</field>
<!-- 驗證Email -->
<field name="user.email">
<field-validator type="email">
<message>郵箱格式錯誤!</message>
</field-validator>
</field>
</validators>
XML方式驗證Action中指定的方法:
與上面xml驗證方式大致相同: 驗證xml文件內容不變;
文件命名:
語法:ActionClassName-ActionName-validation.xml
舉例:UserAction-user_register-validation.xml
驗證UserAction中的register方法
驗證總結
代碼:
重寫validate() , 驗證action所有方法
Validate方法名(), 驗證指定“方法名”的方法
Xml:
驗證所有方法: ActionClassName-validation.xml
驗證指定方法: ActionClassName-actionName-validation.xml
代碼驗證,
比較靈活,可以滿足所有的需求.
比較繁瑣,要寫重複的驗證判斷邏輯!
適合: 表單字段較少的情況用!
XML驗證:
通用,但不夠靈活; 可以驗證特定簡單的業務。
適合: 驗證表單字段較多,可以大大簡化代碼!
(配置文件過多)
驗證錯誤處理
Struts在進行數據效驗的時候,驗證失敗,會返回input視圖,要求我們要在struts.xml中配置input視圖對應的錯誤頁面!
配置:
Struts.xml
<!-- 註冊失敗跳轉到註冊頁面,顯示失敗信息 -->
<global-results>
<result name="input">/register.jsp</result>
</global-results>
Jsp顯示錯誤
方式1:顯示所有錯誤
<%@taglib uri="/struts-tags" prefix="s" %>
<!-- 顯示的是struts在運行時期產生的所有錯誤 -->
<s:fielderror></s:fielderror>
方式2:顯示指定的錯誤
<!-- 修改struts標籤默認的樣式: 不讓換行 -->
<style type="text/css">
ul{
display: inline;
}
ul li{
display: inline;
color: red;
}
</style>
顯示指定的錯誤:
<s:fielderror fieldName="user.userName"></s:fielderror>
方式3: 修改標籤定義的模板
找到fielderror標籤定義的模板文件:
Struts-core.jar\template\simple\ fielderror.ftl
把修改後的fielderror.ftl文件,放到src/ template/ simple/ fielderror.ftl
這樣標籤顯示的樣式就修改了!
- Struts 簡單UI標籤
<!-- 服務器標籤 : 最終別解析爲html標籤-->
<s:form action="/user_login" method="post" name="frmLogin" id="frmLogin" theme="simple">
用戶名:<s:textfield name="user.name"></s:textfield>
密碼:<s:textfield name="user.pwd"></s:textfield>
<s:submit value="登陸"></s:submit>
</s:form>
注意:
給form指定主題,form下所有的表單元素都應用此主題!
對於struts標籤默認的主題樣式:default.xml/struts.ui.theme=xhtml
可以通過常量修改, 改爲簡單主題:
<!-- 修改主題 (當前項目所有的標籤都用此主題)-->
<constant
name="struts.ui.theme" value="simple"></constant>
- Struts ognl表達式語言幾個符號
1) # 獲取非根元素值 、 動態都建map集合
2) $ 配置文件取值
3) % 提供一個ognl表達式運行環境
<body>
<br/>獲取request域數據<br/>
<!-- property 標籤是對象類型的標籤,默認支持ognl表達式, 會從根元素去China名稱對應的值 -->
<s:property value="China"/> <br/>
<!-- 如果直接賦值,需要用單引號 -->
<s:property value="'China'"/> <br/>
<s:property value="%{#request.cn}"/> <br/>
<!-- 值類型的標籤,value值默認就是值類型,不支持ognl表達式 -->
國家:<s:textfield name="txtCountry" value="%{#request.cn}"></s:textfield>
</body>
- Struts中常用的幾個技術
數據回顯
數據回顯,必須要用struts標籤!
Action中:
// 進入修改頁面
public String viewUpdate() {
// 模擬一個對象(先獲取一個id,再根據id調用service查詢,把查到的結果保存到域)
User userInfo = new User();
userInfo.setUserName("Jack");
userInfo.setEmail("[email protected]");
ActionContext ac = ActionContext.getContext();
// Map<String,Object> request = (Map<String, Object>) ac.get("request");
// request.put("userInfo", userInfo);
/************* 數據回顯***************/
// 獲取值棧
ValueStack vs = ac.getValueStack();
vs.pop();// 移除棧頂元素
vs.push(userInfo); // 入棧
// 進入修改頁面
return "viewUpdate";
}
JSP頁面:
<body>
<%@taglib uri="/struts-tags" prefix="s" %>
<br/>
<!-- 在頁面文本框內,顯示要修改記錄的數據 -->
<!-- 手動通過value設置顯示的值
<s:form action="#">
用戶名: <s:textfield name="user.userName" value="%{#request.userInfo.userName}"></s:textfield> <br/>
郵箱: <s:textfield name="user.email" value="%{#request.userInfo.email}"></s:textfield> <br/>
</s:form>
-->
<!-- 數據回顯技術:s:textfield會自動查找根元素數據(Ognl表達式語言取值) -->
<s:form action="#">
用戶名: <s:textfield name="userName"></s:textfield> <br/>
郵箱: <s:textfield name="email"></s:textfield> <br/>
</s:form>
<s:debug></s:debug>
</body>
模型驅動
Struts運行時候,會執行默認的攔截器棧,其中有一個攔截器,模型驅動攔截器:
<interceptor
name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
@Override
public String intercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
if (action instanceof ModelDriven) {
ModelDriven modelDriven = (ModelDriven) action;
ValueStack stack = invocation.getStack();
Object model = modelDriven.getModel();
if (model != null) {
stack.push(model);
}
if (refreshModelBeforeResult) {
invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
}
}
return invocation.invoke();
}
引入
prams攔截器,可以把請求數據自動填充的action的屬性中
舉例1:
JSP
<input type=text name=userName />
<input type=text name=pwd />
Action
class UserAction{
// 封裝請求數據
private String userName;
private String pwd;
//.. set方法
}
舉例2:
JSP
<input type=text name=user.userName />
<input type=text name=user.pwd />
Action
class UserAction{
// 封裝請求數據
private User user;
..
}
舉例3:(模型驅動)
JSP
<input type=text name=userName />
<input type=text name=pwd />
Action
class UserAction{
// 封裝請求數據
private User user;
..
}
步驟及原理
步驟:
1. 實現ModelDriver接口
2. 實現接口方法: 接口方法返回的就是要封裝的對象
3. 對象一定要實例化。
分析:
/**
* 1. 數據回顯
* 2. 模型驅動
* @author Jie.Yuan
*
*/
public class UserAction extends ActionSupport implements ModelDriven<User> {
// 封裝請求數據
private User user = new User();
public void setUser(User user) {
this.user = user;
}
public User getUser() {
return user;
}
// 實現模型驅動接口方法
@Override
public User getModel() {
return user;
}
public String add() {
// 測試: 使用了模型驅動,是否數據正常? Ok
System.out.println(user);
return "success";
}
防止表單重複提交
Struts提供了防止表單重複提交攔截器:
<interceptor name="token"
class="org.apache.struts2.interceptor.TokenInterceptor"/>
綜合案例:
1. 建庫、建表
-- 刪除數據庫
DROP DATABASE hib_demo;
-- 創建數據庫
CREATE DATABASE hib_demo DEFAULT CHARACTER SET utf8;
-- 建表
CREATE TABLE employee (
id INT PRIMARY KEY AUTO_INCREMENT,
empName VARCHAR(20),
workDate DATE -- 入職時間
)
2. 搭建環境
搭建struts環境
組件:c3p0/dbutils/驅動