1. 程式人生 > 實用技巧 >【Struts2】Ognl表示式

【Struts2】Ognl表示式

5).OGNL表示式-操作資料空間

O(Object) G(Graphic) N(Navigation) L(Language) 物件 圖 導航語言
作用:通過表示式方式(非Java程式碼)的方式操作指定資料。
特點:(對比EL)
①可以呼叫方法
②可以存入資料(繫結資料)
OGNL可以操作資料空間(物件):
匯入jar: ognl.jar
① ognl向root區的物件中存入資料
Ognl.setValue("root區的物件的屬性名",root區物件,值);
②ognl從root區的物件中獲取資料
Object ognl表示式獲取的結果 = Ognl.getValue("root區物件的屬性名",root區物件);
③呼叫方法
語法: Ognl: "物件.方法名(引數)"
注意: 表示字串 "zxxx"   '1000'(如果ognl外部使用雙引號,內部字串使用單引號)
④數學運算和邏輯運算
+ - * / % == != ! && || 
注意: (1==“1”)忽略資料型別;(10/3結果為3) 數字除運算, 按照java運算規則計算
⑤Ognl訪問List集合型別資料
語法: ognl: "list集合[i]"
⑥Ognl訪問Map集合元素
語法: ognl:  
			"map物件.key"  		key不能是純數字內容。
    		"map物件['key']" 		key可以數字或者字串。
⑦Ognl從context區域獲取資料
重點: context區域是一個map結構
	key是字串、value物件型別
語法: Ognl表示式: "#key"   context中map的value
測試方法: Ognl.getValue("ognl表示式",放入context區的map,root物件);

6).OGNL表示式-值棧(ValueStack)、Struts2值棧的使用+Struts2標籤庫[重點]

(1)值棧 ValueStack(類名)
作用:
封裝ognl的root和context
使用Ognl表示式訪問值棧內部root區中的物件,context中map的key對應的value
值棧相關api:
①獲得值棧物件
ValueStack vs = ActionContext.getContext().getValueStack();
②獲得root(棧)
CompoundRoot root = vs.getRoot();
③向root中存入物件
root.push(作為root物件);
④獲得context
Map<String,Object> context = vs.getContext();
⑤如果想context中存入資料
context.put("key",值);
⑥值棧物件提供方法  vs.findValue("ognl表示式"), 使用ognl獲得值棧中的資料。
			獲取root區屬性值:			vs.findValue(“物件屬性”);
			獲取ContextMap區value:		vs.findValue(“#key”);
(2)Struts2值棧的使用+Struts2標籤庫[重點]
Struts2對值棧的管理
①值棧:
Context區(資料結構  Map)[重點]
    "request"    	RequestMap(相當於HttpServletRequest作用域)
    "session"    	SessionMap(相當於HttpSession作用域)
    "application" 	ApplicationMap(相當於ServletContext作用域)
Root區(資料結構  棧 Stack)
	將當前的Action物件放在root區棧頂。
②struts2標籤庫:
使用:
a.引入標籤庫:<%@taglib uri="/struts-tags" prefix="s" %>
b.使用property標籤:<s:property value="ognl表示式"></s:property>
作用: 
a.執行ognl獲得資料
b.將結果展示給瀏覽器
③總結:
a. 向RequestMap中存入值
	Map<String,Object> requestMap =  (...)vs.getContext().get("request");
	requestMap.put("名字key",值);
    通過Ognl表示式訪問RequestMap(相當於request作用域)
    OGNL: "#request.requestmap中的key"
b. 向SessionMap存入值
    Map<String,Object>  sessionMap = (..)vs.getContext().get("session");
    sessionMap.put("key",value)
    通過Ognl表示式訪問SessionMap(相當於session作用域)
    OGNL: "#session.sessionMap中的key"
c. 通過Ognl表示式訪問當前的Action的屬性值:
    注意: Action生命週期是一次請求過程。(請求轉發)
OGNL: "Action的屬性名"

7).OGNL表示式-常用的Struts2標籤、及在struts.xml中使用

(1)常用Struts2標籤(在JSP中使用OGNL)
①property
   語法: <s:property value="OGNL表示式,值棧的root獲取值,context獲得值"/>
   作用:
   	a.執行ognl表示式,獲得資料
b.講結果顯示給瀏覽器。
   常用:
   <s:property value="Action的屬性名"/>   [獲得action的屬性值]
   <s:property value="#request.requestMap的key"/>  [獲得相當於request作用域的requestMap的值]
   <s:property value="#session.sessionmap的key"/>  [獲得相當於session作用域的sessionMap的值]
   補充:
   	<s:property/>   [獲得的值棧的root區棧頂的物件]
②格式化日期
   <s:date name="ognl獲得要格式化顯示的日期" format="設定日期格式"/>
   日期格式:
   年yyyy     月MM     日dd
③判斷
   語法: 	<s:if test="OGNL獲得資料並邏輯判斷1">條件1成立</s:if>
   		<s:elseif test="ognl條件2">條件2成立</s:elseif>
   		<s:else>都不成立</s:else>
④遍歷ListJ集合
  <s:iterator value="OGNL被遍歷的集合">
<s:property/>當前被遍歷的物件:被遍歷的當前物件被放在了root區的棧頂位置
      <s:property value="當前物件的屬性名"/>當前被遍歷的物件的屬性
  </s:iterator>
  作用: a. value屬性遍歷集合;b. 遍歷過程中,每個被遍歷的當前物件,暫時放在值棧的root區的棧頂。
  屬性介紹:
 	 	value: 			OGNL獲得被遍歷集合
begin: 			起始下標
  		end: 			截止下標
  		step: 			步長      	[配合  begin="0"]
 		status="vs"		(vs.index(下標序號);   vs.count(排序序號))
  注意: 將vs存入值棧的context中。key="vs"
⑤遍歷Map
  <s:interator value="ognl獲得map">
  		將遍歷的每個當前物件(Map.Entry key+value),放入root棧頂。
      	展示key:  <s:property value="key"/>
      	獲得value: <s:property value="value"/>
  </s:interator>
⑥url重寫
<s:url value="請求資源的路徑"></s:url>
    作用:
 	a. 自動補全 "/專案名"
      b. cookie被禁用的請情況下對url進行重寫。(url;jsessionid=1234asdd1234asd);
⑦action請求標籤
   語法:  s:action name="" namespace="" executeResult="true"></s:action>
   作用:向action發起請求,接收伺服器響應的結果。
   屬性:
   name: 		請求的action的name
   namespace: 	請求的action的名稱空間namespace
   executeResult: 	是否包含action的執行結果頁面。
(2)Struts2標籤在struts.xml中使用
struts.xml書寫OGNL表示式
ognl在struts.xml獲得root中當前Action的屬性名,作用域對應的map中的值。 
語法: ${ognl表示式}
在跳轉路徑中使用超連結傳值:

8).OGNL表示式-值棧的生命週期、及其原理(如何替代作用域)

(1)值棧的生命週期
生命週期: 一次請求過程.
 
(2)#值棧如何替代作用域的(原理)
原理:值棧的生命週期一次請求過程,但是值棧的context中的sessionMap中的資料可以跨請求存在,是因為其
	  最終儲存在HttpSession作用域中,HttpSession可跨多次請求。
SessionMap底層原始碼實現:
存入: 講put方法接受的key和value,session.setAttribute(key,value);儲存在session作用域中,。
取出: 講get方法接受key,session.getAttribute(key);,從session作用域中獲的值

9).攔截器(Interceptor)、攔截器棧(組)

(1)攔截器
概念: 攔截瀏覽器請求struts2的Action.
作用(應用): 提取多個Action中的共同程式碼(通用功能),到攔截器中完成。
執行機制:
   ①請求訪問Action,會先經過攔截器中程式碼。
   ②請求經過攔截呼叫方法: intercept(ActionInvocation ai)
       ai.invoke();//放行action的請求。
攔截器核心工作機制:(類比Filter)
 編碼實現攔截器:
①自定義一個類,實現Interceptor介面
public class MyInterceptor implements Interceptor{
	//請求到達攔截器的執行方法。(類似filter中doFilter)
	intercept(ai){
	    Action之前執行的程式碼
		ai.invoke();//放行請求。
		Action執行之後的程式碼
	}
}
②註冊配置攔截器(攔截器被struts2管理)
<interceptors>
   <intercept name="名字" class=""></intercept>
</interceptors>
③在需要攔截的action中引用攔截器(名字)
 
④攔截器修改跳轉路徑:
 
⑤攔截器和Action+跳轉的完整流程。
 
(2)攔截器棧(組)
 
攔截器注意事項:
如果aciton引用自定義攔截器的話,預設攔截器就失效了。
struts-default[筆試]
struts.xml中, `extends="struts-default"`
預設攔截器中配置大量struts核心攔截器,(請求引數自動接收,檔案上傳,值棧,編碼設定),如果action要使用這些攔截器,必須繼承struts-default配置檔案的額資訊。而且還要引入Struts預設的攔截器,放到自己定義的攔截器棧的首個位置:

10).Struts應用-檔案的上傳、下載

(1)檔案上傳
步驟:
①瀏覽器頁面(檔案選擇輸入框
   a. 檔案輸入框
   b. 表單提交方式 post
   c. 設定表單以二進位制流提交: form enctyp="multipart/form-data"
②Action接受檔案
   public class FileAction{
      	private File 檔案輸入框的name;
       	//set get;
   }
③在action講接受file物件拷貝儲存在tomcat專案所在的目錄下
    //動態獲得伺服器中專案下的資料夾路徑
   	ServletContext ctx = ServletActionContext.getServletContext();
   	String realPath = ctx.getRealPath("/upload");//upload資料夾的真實路徑
   	String fileName = "hehe.jpg";
   	String filePath = realPath+"/"+fileName;
   	
   	//headPic檔案----->filePath路徑
   	OutputStream os = new FileOutputStream(filePath);
   	BufferedOutputStream bos = new BufferedOutputStream(os);
   	BufferedInputStream bis = new BufferedInputStream(new FileInputStream(headPic));
   	byte[] bs = new byte[1024];
   	while(true){
   		int i = bis.read(bs);//讀入bs陣列多少長度
   		if(i<0)break;
   		bos.write(bs, 0, i);
   	}
   	bos.flush();
   	bos.close();
   	bis.close();
④獲得上傳檔名:
 
檔案上傳優化
①檔案大小
    預設struts接受上傳檔案大小上限: 2M;
	<!-- 常量配置設定檔案上傳的大小 -->
	<!-- struts.multipart.maxSize=2097152   100M  1位元組*100000000 -->
	<constant name="struts.multipart.maxSize" value="100000000"></constant>
②檔名
    問題: 檔名在伺服器端衝突。
    解決: 使用UUID生成唯一的名字作為檔名。
    程式碼: UUID.randomUUID().toString();"1234-1234-asdfg-2345-435"
    檔名設計: UUID+".字尾";
③儲存路徑
    問題: 儲存檔案的目錄寫死在程式碼中,耦合,不便於維護。
解決辦法: 儲存目錄名轉移到配置檔案。
 
④ io工具類:commons-io的jar包
檔案拷貝程式碼簡化:FileUtils.copyFile();
(2)檔案下載
使瀏覽器儲存該檔案,而不是解析展示該檔案?
給瀏覽器設定頭資訊: "content-disposition" "attachment;filename=檔案.字尾"
①設定下載;
    response.setHeader("content-disposition", "attachment;filename="+fileName);
②讀入伺服器端檔案輸入流
③指向瀏覽器的輸入流
④邊讀邊寫
補充:
	對下載的檔名編碼:
    URLEncoder.encode(字串,"UTF-8");

11).Struts應用-驗證碼、令牌、日期轉化(String/util.Date/sql.Date)

(1)驗證碼
作用:
①防止機器人登陸,對系統新增無效資訊
②防止機器人,惡意註冊無效使用者資訊
使用java生成驗證碼圖片:
①產生一個隨機驗證碼字串
②如何將字串生成圖片中
public static BufferedImage getSafeCodeImage(String code) throws IOException {
    BufferedImage bi = new BufferedImage(80, 30, BufferedImage.TYPE_INT_BGR);
    Graphics g = bi.getGraphics();
    g.fillRect(0, 0, 80, 30);
    g.setColor(Color.BLUE);
    g.drawString(code, 20, 12);
    /*ImageIO.write(bi, "jpg", new FileOutputStream("D:\\a.jpg"));*/
    return bi;
}

public static String getGenerateCode(int n) {
    String str = "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
    Random rd = new Random();
    StringBuilder sb = new StringBuilder("");
    for (int i = 0; i < n; i++) {
        sb.append(str.charAt(rd.nextInt(62)));
    }
    return sb.toString();
}

在jsp中產生一個驗證碼:
驗證碼工具類:
Hutool(工具包)
匯入hutool的jar包。
 CaptchaUtil   	功能: 生成隨機驗證碼(字串)、 生成驗證碼圖片,直接通過流寫出
程式碼步驟:
①生成驗證碼物件: 
			Captcha captcha = CaptchaUtil.createLineCaptcha(寬度,高度,字元個數,干擾線個數);
			Captcha captcha = CaptchaUtil.createLineCaptcha(寬度,高度);
②生成驗證碼:
			captcha.getCode();//code字串
			captcha.write(outputStream);//將驗證碼圖片通過輸出流,寫出到對應位置

jsp使用驗證碼核心思路:依靠image的src,請求生成驗證碼圖片的action,響應寫回去
 
使用:
 
(2)Struts2令牌機制
防止表單重複提交
①分發令牌
Struts中給使用者分發令牌方式:	<s:token></s:token>
作用: 
a. 給使用者的瀏覽器的表單放入一個隨機字串。
b. 將字串(令牌),向session中存入一份。
核心機制:
 

②驗證令牌
驗證令牌核心機制
 

編碼步驟:
a. 書寫一個驗證令牌的攔截器(struts已經提供了) 
b. 配置令牌攔截器攔截防止重複提交的action
c. Action必須繼承ActionSupport.
 

(3)日期格式
	①java.util.Date和java.sql.Date之間的轉換:
中間值:Date.getTime();
例:
long l = (new java.util.Date()).getTime();
java.sql.Date d = new java.sql.Date(l);
	②String格式轉換為日期格式
	日期格式化工具: SimpleDateFormat
	String s = "1999-9-9";
	//1. 建立日期格式化工具,(匹配日期格式)
	SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
	//2. 呼叫轉發方法
	Date parse = format.parse(s);