javascript
Head First JSP---随笔六
無腳本的JSP
Web頁面設計人員沒必要懂Java,所以我們使用EL表達式。(這一章中所說到的性質(zhì),是指對象中的字段)
使用表達式語言(EL)和標準動作構建JSP頁面
7.1 使用EL中的頂級變量編寫一個代碼片段。包括以下隱式變量:pageScope,requestScope,sessionScope和applicationScope;param和paramValues;header和headerValues;cookies;以及initParam。
7.2 使用以下EL操作符編寫一個代碼片段:性質(zhì)訪問操作符(.)和集合訪問操作符([])。
7.3 使用以下EL操作符編寫一個代碼片段:算術操作符、關系操作符和邏輯操作符。
7.4 對于EL函數(shù):使用EL函數(shù)編寫一個代碼片段;明確或創(chuàng)建用于聲明EL函數(shù)的TLD文件結構;明確或創(chuàng)建一個代碼示例來定義EL函數(shù)。
8.1 給定一個設計目標,使用以下標準動作創(chuàng)建一個代碼片段:jsp:useBean(有以下屬性:id、scope、type和class),jsp:getProperty和jsp:setProperty(包括所有屬性組合)。
8.2 給定一個設計目標,使用以下標準動作創(chuàng)建一個代碼片段:jsp:include,jsp:forward和jsp:param。
6.7 給定一個特定的設計目標,要求將一個JSP片段包含在另一個頁面中,編寫JSP代碼使用最合適的包含機制(include指令或< jsp:include >標準動作)
使用與bean相關的標準動作
我們先假設有一個名為person的屬性,它的值是一個Person類,這個類在foo包下并且有一個屬性是name和一個方法是getName()。這個person對象在request作用域中,則如下。
使用腳本時:
<html><body> <% foo.Persion p = (foo.Person) request.getAttribute("person");%> Person is: <%= p.getName()%> </body></html>使用標準動作
<html><body> <jsp:useBean id="person" class="foo.Person" scope="request"/> Person is: <jsp:getProperty name="person" property="name"> </body></html>上面兩段代碼是等價的,不過我們說過不準使用腳本代碼。
分析jsp:useBean和jsp:getProperty
先看jsp:userBean,id是聲明bean對象的標識符,class是聲明對象的類型,scope說明對象的作用域(從request中拿出一個屬性名為”person”的對象,這對象的類型是foo.Person類型的)。
在看jsp:getProperty,name表示具體的bean對象(與useBean中的id相匹配),property是只Person中的屬性(從useBean中拿出一個id名為”person”的對象,獲取這個對象的”name”屬性)。
jsp:useBean還能創(chuàng)建一個bean
jsp:useBean可以有體
正如看到的,useBean可以有體。當然下面還有一個jsp:setProperty,它可以出現(xiàn)在體外面,功能與getProperty相反。setProperty是設置屬性。
<jsp:useBean id="person" calss="foo.Person" scope="page"><jsp:setProperty name="person" property="name" value="Fred"> </jsp:useBean>放在體內(nèi)的代碼,轉換成servlet將會在這個對象為null的時候為這個對象new完之后再執(zhí)行相應的操作。如果這個對象不為null的話就不會執(zhí)行體內(nèi)的操作。
jsp:useBean有體時生成的serlvet:
可以看出最后一行寫的好復雜,但它的作用和person.setName("Fred")等價。
多態(tài)的bean引用
我們先看看我們原來jsp:useBean生成的servlet代碼:
繼承的UML圖:
如果我們使用跟原來一樣的代碼(很明顯,抽象類不能實例化):
我們增加一個type屬性(可以是一個class類型、抽象類或者一個接口):
這里指出:如果只有一個type屬性,沒有class屬性的話,結果也會報錯!
這里指出scope屬性的默認值是”page”。
直接從請求到JSP,沒有經(jīng)過servlet
假設我們的表單是:
想要獲得請求的參數(shù)就需要如下:
param屬性
要獲取請求的參數(shù)時,如果要像上面那樣做,明顯是不好的。
利用param屬性,可以把bean的性質(zhì)值設置為一個請求參數(shù)的值。只需指定請求參數(shù)!如下:
更好的方法
這樣就方便了許多!!
還有更好的···
真的特別酷!一句話搞定所有事情。
自動轉換基本類型的性質(zhì)
如果是純數(shù)字,那么String會自動轉換成int。
如果屬性不是String或基本類型
例如以下這種場景:
我需要打印出Person的Dog的name,又該如何呢?
這時候我們就需要表達式語言(EL)${person.dog.name}。
它等價于<%= (foo.Person) request.getAttribute("person").getDog().getName()%>
JSP表達式語言(EL)剖析
如圖中所說明的,除了pageContext比較特殊以外,其他都是映射。
使用點號.和括號[]
我們可以用${person.name}訪問一個bean和map。同樣的用${person["name"]}也可以訪問一個bean和map。
那如果person是一個數(shù)組或者是一個List呢?又該如何?
可以使用括號。如下:
這里指出:數(shù)組和List中的String索引會被強制轉換為int(如musicList[“1”]等價于musicList[1])。
這里還指出:如果[ ]中不是String直接量,那么就會進行計算(例如:musicList[0]=1,那么musicList[musicList[0]] = musicList[1])。
EL隱式對象
我們再次注意到最后一個pageContext對象不是一個map。那它拿來做什么呢?(這很重要!)
EL中的請求參數(shù)
想要從請求中獲取對應的參數(shù)(param),如下:
看上去不錯,我們在試試獲取”host”首部(header):
我們再來獲取一個HTTP請求方法:
好像不太行,獲取不到request的方法。
requestScope不是請求對象
隱式的requestScope只是請求作用域屬性的一個Map,而不是request對象本身!
想要得到HTTP方法,就需要先得到一個request對象。所以在于我們?nèi)绾潍@取這個request對象呢?
通過pageContext來獲得其他的一切。例如:${pageContext.request.method}這樣就可以通過request對象獲取到HTTP方法。
需要注意的:
作用域隱式對象能救你
會出現(xiàn)這樣一種情況:request.setAttribute("foo.person",p);。我們?nèi)绾卧贘SP中獲取這個鍵所對應的值呢?
顯然,用${foo.person.name}是不行的,所以我們的隱式作用域對象派上用場了!可以使用:${requestScope["foo.person"].name},完美“救場”!
得到Cookie和初始化參數(shù)
我們除了cookie和初始化參數(shù)的相應隱式對象外,其他隱式對象我們都已經(jīng)了解了。接下來我們說明cookie和初始化參數(shù)的隱式對象。
打印“userName” cookie的值
用腳本來完成:
用EL:${cookie.userName.value}就可以了。
打印一個上下文初始化參數(shù)的值
在DD中配置:
然后再用腳本:<%= application.getInitParameter("mainEmail")%>就可以了。
用EL:${initParam.mainEmail}就可以了。
該注意的地方:
EL函數(shù)
如果我們需要在JSP中用EL表達式去調(diào)用一個方法來返回一個值,那又該如何呢?
這里指出:EL函數(shù)可以有參數(shù),與普通方法一樣,只是定義TLD時參數(shù)列表是(包名.類型)。例如:int function(java.util.Map)
需要做4步事情:
一幅圖解釋工作過程:
部署環(huán)境:
需要注意:(函數(shù)名不一定要和EL中的函數(shù)名一致,EL的函數(shù)名必須與function標簽下的name標簽的內(nèi)容處于一致)
另一些EL操作符
EL能妥善處理null值
假設沒有一個名為“foo”的屬性,但確實有一個名為“bar”的屬性,而且這個“bar”沒有名為“foo”的性質(zhì)或鍵。
如下(注意,foo是null,bar是一個對象,bar[foo]不是bar[“foo”],這里指出:如果是bar[“foo”]則將報錯!):
JSP表達式語言(EL)復習
可重用的模板部件
如果我有234個JSP文件并且它們都有同一個導航欄,如果我需要改變導航欄的代碼,那么234個JSP都要改。這簡直是噩夢。
JSP中有一個對應的處理機制,這就是包含(include)。
形式如下:
<html><body> <!-- 在這里插入頁眉文件 --> Welcome to our size... blah blah blah more stuff here... <!-- 在這里插入頁腳文件 --> </html></body>include指令
include指令告訴容器:復制所包含文件中所有內(nèi)容,在把它粘貼到這個文件中,而且就放在這里…
jsp:include標準動作
上述兩者的內(nèi)部原理并不相同
<jsp:include page="Header.jsp" />標準動作和<%@ include file="Header.jsp" %>指令的內(nèi)部原理并不同。
include指令在轉換(.jsp變成.java)時發(fā)生jsp:include標準動作在運行時發(fā)生
很容易就能明白,指令是將其變?yōu)閛ut.write()輸出,而標準動作是調(diào)用方法。
這里指出:指令的效率會比標準動作的高。
對應第一個請求的include指令
執(zhí)行過程如下:
對應第一個請求的jsp:include標準動作
執(zhí)行過程如下:
兩個注意的地方
屬性名不一樣:
位置是否敏感(include指令是位置敏感的):
這里還說明了一個問題:不要把開始和結束HTML和body標記放在可重用部件中!設計和編寫布局模板時,要假設它們會包含在其他頁面中。
使用jsp:param定制包含的內(nèi)容
如果我們希望頁眉上有一個與上下文相關的子標題,它要依相應的頁面而定,該怎么做呢?
有兩種方法:
第二種辦法如下所示:
我們注意到jsp:include標準動作的體可以增加(或替換)請求參數(shù),供被包含的片段使用。
jsp:forward標準動作
有這樣一個問題,如果我的客戶訪問我的頁面,但是還沒有登錄,我想讓他轉跳到登錄頁面,該怎么做呢?
雖然這不是MVC中視圖的任務(很明顯應該給控制器處理),但我們還是提供了這么一種操作,就是<jsp:forward>。
有條件的轉發(fā)
代碼如下:
結果如下:
這里指出:利用<jsp:forward>,緩沖區(qū)會在轉發(fā)之前清空。
看下面這個有趣的問題:
是的,毫無疑問的你收貨了一個異常。
初識JSTL標記
由于我們不能在JSP頁面寫腳本,那么如果我們需要對頁面測試又該怎么辦呢?
JSTL標記解決這個問題!如下:
我們看到,有一個taglib指令,并且它的prefix的屬性值是”c”。我們先放著!
Bean相關標準動作復習(要點)
包含復習(要點)
本章完
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的Head First JSP---随笔六的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 传统品牌vs新消费品牌社交营销差异化分析
- 下一篇: 不为人知的心理学效应