Struts2學(xué)習(xí)筆記(第四天)

ognl與valueStack

    ognl中有一個OgnlContext,它可以設(shè)置root與非root .root中數(shù)據(jù)獲取時,不需要加#,而非root中數(shù)據(jù)在獲取時扳缕,需要加上#.
        
    重點:學(xué)習(xí)struts2中使用ognl時忌警,最后要知道 誰是OgnlContext,誰是root瓦宜,誰是非root.

ognl

    OGNL是Object Graphic Navigation Language(對象圖導(dǎo)航語言)的縮寫筐喳,它是一個開源項目姑原。 Struts2框架使用OGNL作為默認(rèn)的表達式語言悬而。
        * xwork 提供 OGNL表達式 
        * ognl-3.0.5.jar
    OGNL 是一種比EL 強大很多倍的語言 

OGNL 提供五大類功能 
    1、支持對象方法調(diào)用锭汛,如xxx.doSomeSpecial()笨奠; 
    2、支持類靜態(tài)的方法調(diào)用和值訪問
        3唤殴、訪問OGNL上下文(OGNL context)和ActionContext般婆; (重點 操作ValueStack值棧 )
    4、支持賦值操作和表達式串聯(lián)
    5眨八、操作集合對象腺兴。
演示:在struts2中使用ognl表達式
        需要結(jié)合struts2的標(biāo)簽使用<s:property value="ognl表達式">
            <s:property value="'abc'.length()"/>  演示對象調(diào)用方法
        <s:property value="@java.lang.Math@max(10,20)"/> 演示靜態(tài)成員訪問.
            
    注意:在struts2中使用靜態(tài)成員訪問,必須設(shè)置一個常量:
                        struts.ognl.allowStaticMethodAccess=false

ValueStack

它是一個接口com.opensymphony.xwork2.util.ValueStack廉侧。
我們使用它是將其做為一個容器页响,用于攜帶action數(shù)據(jù)到頁面.
在在頁面上通過ognl表達式獲取數(shù)據(jù)。

問題1:什么是valueStack?

valueStack主要是將action數(shù)據(jù)攜帶到頁面上段誊,通過ognl獲取數(shù)據(jù)
    1.ValueStack有一個實現(xiàn)類叫OgnlValueStack.
    2.每一個action都有一個ValueStack.(一個請求闰蚕,一個request,一個action,一個valueStack) valueStack生命周期就是request生命周期连舍。
    3.valueStack中存儲了當(dāng)前action對象以及其它常用web對象(request,session,application.parameters)
    4.struts2框架將valueStack以“struts.valueStack”為名存儲到request域中没陡。

問題2:valueStack結(jié)構(gòu)?

ValueStack中 存在root屬性 (CompoundRoot) 、 context 屬性 (OgnlContext )
    * CompoundRoot 就是ArrayList
    * OgnlContext 就是 Map
        
    list集合中存儲的是action相關(guān)信息
    map集合中存儲的是相關(guān)映射信息索赏,包含  paramters,request,session,application attr等盼玄。
        
    我們想要從list中獲取數(shù)據(jù),可以不使用#號.(它就是ognl的root)
    如果從map中獲取數(shù)據(jù)潜腻,需要使用#. (其實在struts2中的map--context其實就是ognlContext)
結(jié)論:
    ValueStack它有兩部分 List  Map
    在struts2中List就是root   Map就是ognlContext.         
    默認(rèn)情況下埃儿,在struts2中從valueStack獲取數(shù)據(jù)從root中獲取。
valueStack內(nèi)部結(jié)構(gòu)

問題3: 值棧對象的創(chuàng)建 融涣,ValueStack 和 ActionContext 是什么關(guān)系 童番?

ActionContext ctx = ActionContext.getContext();
           if (ctx != null) {
              stack = ctx.getValueStack();
      }
    valueStack是每一次請求時,都會創(chuàng)建.
在ActionContext中持有了valueStack的引用威鹿。

問題4:如何獲得值棧對象?

對于valueStack獲取有兩種方式:
    1.通過 request獲取
        ValueStack vs=(ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
        
    2.通過ActionContext獲取.
        ValueStack vs=ActionContext.getContext().getValueStack();

問題5:向值棧保存數(shù)據(jù) (主要針對 root)

    主要有兩個方法
        push(Object obj)------->底層就是 root.add(0,obj) 將數(shù)據(jù)存儲到棧頂剃斧。
        set(String name,Object obj);----->底層是將數(shù)據(jù)封裝到HashMap中,在將這個HashMap通過push存儲忽你。
            
        在jsp中 通過 <s:debug /> 查看值棧的內(nèi)容    

問題6: 在JSP中獲取值棧的數(shù)據(jù)

root中數(shù)據(jù)不需要#幼东,而context中數(shù)據(jù)需要#
        
1.如果棧頂是一個Map集合,獲取時,可以直接通過Map集合的key來獲取value.
                <s:property  value="username"/>
2.如果棧頂數(shù)據(jù)不是一個Map筋粗,沒有key值策橘,可以使用序號來獲取。
    <s:property value="[0]">  從0的位置向下查找所有娜亿。
            
    <s:property value="[0].top"> 只查找0位置上數(shù)據(jù)丽已。
            
如果獲取OgnlContext中數(shù)據(jù):
    1.request數(shù)據(jù)    request.setAttribute() 
    2.session數(shù)據(jù)    session.setAttribute()
    3.application數(shù)據(jù)  application.setAttribute()
    4.attr   依次從request,session.application中查找
    5.parameters 獲取請求參數(shù)    

ValueStack主流應(yīng)用:就是解決將action數(shù)據(jù)攜帶到j(luò)sp頁面。

問題:action向jsp攜帶數(shù)據(jù),都是什么樣的數(shù)據(jù)?

    1.文本(字符串)
        1.fieldError   校驗數(shù)據(jù)錯誤信息提示
        2.actionError 關(guān)于邏輯操作時錯誤信息(例如登錄失敗)
        3.message 就是一個信息.
                
        this.addFieldError("msg", "字段錯誤信息");
        this.addActionError("Action全局錯誤信息");
        this.addActionMessage("Action的消息信息");

        * fieldError 針對某一個字段錯誤信息 (常用于表單校驗)买决、actionError (普通錯誤信息沛婴,不針對某一個字段 登陸失敗)、 actionMessage 通用消息   

        在jsp中使用 struts2提供標(biāo)簽 顯示消息信息
            <s:fielderror fieldName="msg"/>
            <s:actionerror/>
            <s:actionmessage/>
            
    2.復(fù)雜數(shù)據(jù)
        可以使用valueStack存儲.
                
        在action中存儲數(shù)據(jù):
            List<User> users = new ArrayList<User>();
            users.add(new User("tom", "123", 20, "男"));
            users.add(new User("james", "456", 21, "男"));
            users.add(new User("fox", "789", 26, "男"));
                 vs.push(users);

在頁面上獲取數(shù)據(jù):

使用了<s:iterator>標(biāo)簽來迭代集合督赤。
    <s:iterator value="[0].top" var="user"> 這是將集合中迭代出來每一個元素起個名稱叫user,而user是存儲在context中嘁灯,不在root中.l
                    
        <s:iterator value="[0].top" var="user">
            username:<s:property value="#user.username"/><br>
                password:<s:property value="#user.password"/>
            <hr>
        </s:iterator>
                    
        注意:如果我們在使用<s:iterator>進行迭代時,沒有給迭代出的元素起名.
        <s:iterator value="[0].top">
                username:<s:property value="username"/><br>
                password:<s:property value="password"/>
                <hr>
        </s:iterator>

關(guān)于默認(rèn)壓入到valueStack中的數(shù)據(jù).

1.訪問的action對象會被壓入到valueStack中.
      DefaultActionInvocation 的 init方法 stack.push(action);
                  
      * Action如果想傳遞數(shù)據(jù)給 JSP躲舌,只有將數(shù)據(jù)保存到成員變量丑婿,并且提供get方法就可以了 
                  
2.ModelDriveInterceptor會執(zhí)行下面操作
      ModelDriven modelDriven = (ModelDriven) action;
      ValueStack stack = invocation.getStack();
      Object model = modelDriven.getModel();
      if (model !=  null) {
          stack.push(model);
      }
      將實現(xiàn)了ModelDrive接口的action中g(shù)etModel方法的返回值,也就是我們所說的model對象壓入到了
      valueStack.
模型驅(qū)動modle壓入值棧調(diào)用問題
相關(guān)件結(jié)構(gòu)

問題7:為什么el表達式可以訪問valueStack中數(shù)據(jù)没卸?

struts2框架中所使用的request對象羹奉,是增強后的request對象。
${username}---->request.getAttribute("username");   
            
增強后的request,會首先在request域范圍查找约计,如果查找不到诀拭,會在valueStack中查找。
            
StrutsPreparedAndExecuteFilter的doFilter代碼中 request = prepare.wrapRequest(request);  
* 對Request對象進行了包裝 煤蚌,StrutsRequestWrapper 
* 重寫request的 getAttribute 
    Object attribute = super.getAttribute(s);
    if (attribute == null) {
        attribute = stack.findValue(s);
    }
訪問request范圍的數(shù)據(jù)時耕挨,如果數(shù)據(jù)找不到,去值棧中找 
request對象 具備訪問值棧數(shù)據(jù)的能力 (查找root的數(shù)據(jù))

OGNL表達式常見使用($ % #)

1.#號
用法一  # 代表 ActionContext.getContext() 上下文
     <s:property value="#request.name" />  ------------>  ActionContext().getContext().getRequest().get("name");
     #request
    #session
     #application
     #attr
    #parameters 
用法二 : 不寫# 默認(rèn)在 值棧中root中進行查找 
    <s:property value="name" /> 在root中查找name屬性 
    * 查詢元素時尉桩,從root的棧頂元素 開始查找筒占, 如果訪問指定棧中元素   
    <s:property value="[1].name" />  訪問棧中第二個元素name屬性 
    * 訪問第二個元素對象 <s:property value="[1].top" />
用法三 :進行投影映射 (結(jié)合復(fù)雜對象遍歷 )
         1)集合的投影(只輸出部分屬性
            <h1>遍歷集合只要name屬性</h1>
            <s:iterator value="products.{name}" var="pname"> 
            <s:property value="#pname"/>
            </s:iterator>
        2)遍歷時,對數(shù)據(jù)設(shè)置條件 
            <h1>遍歷集合只要price大于1500商品</h1>
            <s:iterator value="products.{?#this.price>1500}" var="product"> 
            <s:property value="#product.name"/> --- <s:property value="#product.price"/>    
            </s:iterator>
        3)綜合
                 <h1>只顯示價格大于1500 商品名稱</h1>
            <s:iterator value="products.{?#this.price>1500}.{name}" var="pname"> 
            <s:property value="#pname"/>
            </s:iterator>   
用法四: 使用#構(gòu)造map集合 
            經(jīng)常結(jié)合 struts2 標(biāo)簽用來生成 select蜘犁、checkbox赋铝、radio
            <h1>使用#構(gòu)造map集合 遍歷</h1>
            <s:iterator value="#{'name':'aaa','age':'20', 'hobby':'sport' }" var="entry">
            key : <s:property value="#entry.key"/> , value:  <s:property value="#entry.value"/> <br/>
            </s:iterator>

2.%號
        %作用:就是用于設(shè)定當(dāng)前是否要解析其為 ognl表達式.
            
        %{表達式}  當(dāng)前表達式會被做為ognl解析.
        %{'表達式'} 當(dāng)前表達式不會被做為ognl解析。
            
        <s:property value="表達式"> 對于s:property標(biāo)簽沽瘦,它的value屬性會被默認(rèn)做為ognl.
            
        以后,所有表達式如果想要讓其是ognl  %{表達式}
    
3.$號
        $作用:就是在配置文件中使用ognl表達式來獲取valueStack中數(shù)據(jù).
            
    1.struts.xml
        <result type="stream">
            <param name="contentType">${contentType}</param>
        </result>
            
    2.在校驗文件中使用
        ${min}  ${max}
        ${minLength} ${maxLength}
            
    3.在國際化文件中使用
                
        在properties文件中
            username=${#request.username}
        在jsp頁面
            <s:text name="username">
            
總結(jié): #就是用于獲取數(shù)據(jù)  %就是用于設(shè)置是否是ognl表達式  $就是在配置文件中使用ognl.  

防止表單重復(fù)提交

問題:什么是表單重復(fù)提交农尖?           
        regist.jsp----->RegistServlet
        表單重復(fù)提交 危害: 刷票析恋、 重復(fù)注冊、帶來服務(wù)器訪問壓力(拒絕服務(wù)) 
解決方案:
        在頁面上生成一個令牌(就是一個隨機字符串),將其存儲到session中盛卡,并在表單中攜帶.
        在服務(wù)器端助隧,獲取數(shù)據(jù)時,也將令牌獲取,將它與session中存儲的token對比并村,沒問題巍实,
        將session中令牌刪除。
        
struts2中怎樣解決表單重復(fù)提交:
    在struts2中解決表單重復(fù)提交哩牍,可以使用它定義的一個interceptor棚潦。
    <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
    步驟:
        1.在頁面上需要使用一個token tag
            在表單中添加一個標(biāo)簽  <s:token/>
                    
            就會在頁面上生成一個令牌,并存在于表單中膝昆。
        
        2.需要在action中引入token攔截器
            <interceptor-ref name="token"/>
            
        3.需要配置視圖
            <result name="invalid.token">/token.jsp</result>
                
         通過 <s:actionError/> 顯示錯誤信息 
         覆蓋重復(fù)提交信息  struts.messages.invalid.token=您已經(jīng)重復(fù)提交表單丸边,請刷新后重試

struts2中json插件使用

1.struts2中怎樣處理異步提交(ajax)
    
    原始:
    HttpServletResponse response = ServletActionContext.getResponse();
    response.getWriter().write("hello " + msg);
    response.getWriter().close();
        
    還可以使用struts2中提供的json插件:
        
        1.導(dǎo)入json插件包
                在struts2的lib包下  struts2-json-plugin-2.3.15.1.jar。
                
        2.在struts.xml文件中配置
            1.<package extends="json-default">
            2.設(shè)置視圖<result type="json">
                
        這樣設(shè)置后荚孵,會將valueStack棧頂數(shù)據(jù)變成json妹窖。
        對于我們的程序,也就是會將action對象轉(zhuǎn)換成json收叶。
            
            
        <param name="root">p</param> 如果沒有設(shè)置骄呼,可以理解成將整個action都轉(zhuǎn)換成json的數(shù)據(jù)。也就是
         在action中提供的getXxx方法判没,就是json中的一個屬性蜓萄。
             
        如果設(shè)置了root,那么,只將指定數(shù)據(jù)轉(zhuǎn)換成json.
            
        
怎樣設(shè)置轉(zhuǎn)換成json的對象中不包含特定的屬性?
        
    1. @JSON(serialize=false) 在getXxx方法上設(shè)置 
    2. 還可以通過json插件的interceptor完成.
        <param name="includeProperties">ps\[\d+\]\.name,ps\[\d+\]\.price,ps\[\d+\]\.count</param>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末哆致,一起剝皮案震驚了整個濱河市绕德,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌摊阀,老刑警劉巖耻蛇,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異胞此,居然都是意外死亡臣咖,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門漱牵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來夺蛇,“玉大人,你說我怎么就攤上這事酣胀〉笊猓” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵闻镶,是天一觀的道長甚脉。 經(jīng)常有香客問我,道長铆农,這世上最難降的妖魔是什么牺氨? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上猴凹,老公的妹妹穿的比我還像新娘夷狰。我一直安慰自己,他們只是感情好郊霎,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布沼头。 她就那樣靜靜地躺著,像睡著了一般歹篓。 火紅的嫁衣襯著肌膚如雪瘫证。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天庄撮,我揣著相機與錄音背捌,去河邊找鬼。 笑死洞斯,一個胖子當(dāng)著我的面吹牛毡庆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播烙如,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼么抗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了亚铁?” 一聲冷哼從身側(cè)響起蝇刀,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎徘溢,沒想到半個月后吞琐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡然爆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年站粟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片曾雕。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡奴烙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出剖张,到底是詐尸還是另有隱情切诀,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布搔弄,位于F島的核電站趾牧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏肯污。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蹦渣。 院中可真熱鬧哄芜,春花似錦、人聲如沸柬唯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锄奢。三九已至失晴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拘央,已是汗流浹背涂屁。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留灰伟,地道東北人拆又。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像栏账,于是被迫代替她去往敵國和親帖族。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容