日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Head First JSP---随笔六

發布時間:2025/3/15 javascript 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Head First JSP---随笔六 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

無腳本的JSP

Web頁面設計人員沒必要懂Java,所以我們使用EL表達式。(這一章中所說到的性質,是指對象中的字段


使用表達式語言(EL)和標準動作構建JSP頁面

7.1 使用EL中的頂級變量編寫一個代碼片段。包括以下隱式變量:pageScope,requestScope,sessionScope和applicationScope;param和paramValues;header和headerValues;cookies;以及initParam。
7.2 使用以下EL操作符編寫一個代碼片段:性質訪問操作符(.)和集合訪問操作符([])。
7.3 使用以下EL操作符編寫一個代碼片段:算術操作符、關系操作符和邏輯操作符。
7.4 對于EL函數:使用EL函數編寫一個代碼片段;明確或創建用于聲明EL函數的TLD文件結構;明確或創建一個代碼示例來定義EL函數。
8.1 給定一個設計目標,使用以下標準動作創建一個代碼片段:jsp:useBean(有以下屬性:id、scope、type和class),jsp:getProperty和jsp:setProperty(包括所有屬性組合)。
8.2 給定一個設計目標,使用以下標準動作創建一個代碼片段: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還能創建一個bean


jsp:useBean可以有體

正如看到的,useBean可以有體。當然下面還有一個jsp:setProperty,它可以出現在體外面,功能與getProperty相反。setProperty是設置屬性。

<jsp:useBean id="person" calss="foo.Person" scope="page"><jsp:setProperty name="person" property="name" value="Fred"> </jsp:useBean>

放在體內的代碼,轉換成servlet將會在這個對象為null的時候為這個對象new完之后再執行相應的操作。如果這個對象不為null的話就不會執行體內的操作

jsp:useBean有體時生成的serlvet:

可以看出最后一行寫的好復雜,但它的作用和person.setName("Fred")等價。


多態的bean引用

我們先看看我們原來jsp:useBean生成的servlet代碼:

繼承的UML圖:

如果我們使用跟原來一樣的代碼(很明顯,抽象類不能實例化):

我們增加一個type屬性(可以是一個class類型、抽象類或者一個接口):

這里指出:如果只有一個type屬性,沒有class屬性的話,結果也會報錯!

這里指出scope屬性的默認值是”page”


直接從請求到JSP,沒有經過servlet

假設我們的表單是:

想要獲得請求的參數就需要如下:


param屬性

要獲取請求的參數時,如果要像上面那樣做,明顯是不好的。

利用param屬性,可以把bean的性質值設置為一個請求參數的值。只需指定請求參數!如下:


更好的方法


這樣就方便了許多!!


還有更好的···


真的特別酷!一句話搞定所有事情。


自動轉換基本類型的性質

如果是純數字,那么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是一個數組或者是一個List呢?又該如何?

可以使用括號。如下:

這里指出:數組和List中的String索引會被強制轉換為int(如musicList[“1”]等價于musicList[1])。

這里還指出:如果[ ]中不是String直接量,那么就會進行計算(例如:musicList[0]=1,那么musicList[musicList[0]] = musicList[1])。


EL隱式對象


我們再次注意到最后一個pageContext對象不是一個map。那它拿來做什么呢?(這很重要!)


EL中的請求參數

想要從請求中獲取對應的參數(param),如下:

看上去不錯,我們在試試獲取”host”首部(header):

我們再來獲取一個HTTP請求方法:

好像不太行,獲取不到request的方法


requestScope不是請求對象

隱式的requestScope只是請求作用域屬性的一個Map,而不是request對象本身!

想要得到HTTP方法,就需要先得到一個request對象。所以在于我們如何獲取這個request對象呢?

通過pageContext來獲得其他的一切。例如:${pageContext.request.method}這樣就可以通過request對象獲取到HTTP方法。

需要注意的:


作用域隱式對象能救你

會出現這樣一種情況:request.setAttribute("foo.person",p);。我們如何在JSP中獲取這個鍵所對應的值呢?

顯然,用${foo.person.name}是不行的,所以我們的隱式作用域對象派上用場了!可以使用:${requestScope["foo.person"].name},完美“救場”!


得到Cookie和初始化參數

我們除了cookie和初始化參數的相應隱式對象外,其他隱式對象我們都已經了解了。接下來我們說明cookie和初始化參數的隱式對象。

打印“userName” cookie的值
腳本來完成:

<%Cookie[] cookies = request.getCookies();for(int i=0;i<cookies.length;i++){if((cookies[i].getName().equals("userName"))){out.println(cookies[i].getValue());}} %>

用EL:${cookie.userName.value}就可以了。

打印一個上下文初始化參數的值
在DD中配置:

<context-param><param-name>mainEmail</param-name><param-value>likewecare@wickedlysmart.com</param-value> </context-param>

然后再用腳本:<%= application.getInitParameter("mainEmail")%>就可以了。

EL:${initParam.mainEmail}就可以了。

該注意的地方:


EL函數

如果我們需要在JSP中用EL表達式去調用一個方法來返回一個值,那又該如何呢?

這里指出:EL函數可以有參數,與普通方法一樣,只是定義TLD時參數列表是(包名.類型)。例如:int function(java.util.Map)

需要做4步事情:

一幅圖解釋工作過程:

部署環境:

需要注意:(函數名不一定要和EL中的函數名一致,EL的函數名必須與function標簽下的name標簽的內容處于一致)


另一些EL操作符


EL能妥善處理null值

假設沒有一個名為“foo”的屬性,但確實有一個名為“bar”的屬性,而且這個“bar”沒有名為“foo”的性質或鍵

如下(注意,foo是null,bar是一個對象,bar[foo]不是bar[“foo”],這里指出:如果是bar[“foo”]則將報錯!):


JSP表達式語言(EL)復習

  • EL表達式總是用大括號括起,而且前面有一個美元符($)前綴(例如:${expression})。
  • 表達式中第一個命名變量要么是一個隱式對象,要么是某個作用域(頁面、請求、會話、應用作用域)中的一個屬性
  • 點號操作符允許你使用一個Map鍵或一個bean(點號操作符的第一個字符后面可以有數字,但是不能有其他符號)。
  • 點號右邊只能放合法的Java標識符(例如:${foo.1}是不允許的)。
  • [ ]操作符比點號功能更強大,因為利用[ ]可以訪問數組和List,可以把包含命名變量的表達式放在括號里(例如:${musicList["name"]}),而且可以作任意層次的嵌套(例如:${musicList[musicList["name"]]})。
  • 例如,如果musicList是一個ArrayList,可以是${musicList[0]}或${musicList["0"]}來訪問列表中的第一個值。EL并不關心列表索引加不加引號。
  • 如果括號里的內容沒有用引號引起來,容器就會進行計算。如果確實放在引號里,而不是一個數組或List的索引,容器就會把它看做是性質或鍵的直接量名(也就是bean或者Map)。
  • 除了一個EL隱式對象(PageContext)外,其他隱式對象都是Map。從這些Map隱式對象可以得到任意4個作用域的屬性(requestScope,responseScope,sessionScope,applicationScope)、請求參數值(param)、首部值(header)、cookie值和上下文初始化參數(initParam)。非映射的隱式對象pageContext,它是PageContext對象的一個引用。
  • 不要把隱式EL作用域對象(屬性的Map)與屬性所綁定的對象混合一談(例如:requestScope和request對象不是同一個東西,這種作用域對象有4個)。
  • EL函數允許你調用一個普通Java類中的公共靜態方法(函數名不一定與具體的方法名匹配,這個根據TLD文件來做)。
  • 使用TLD(標記庫描述文件)將函數名映射到一個具體靜態方法。
  • 要在JSP中使用函數,必須使用taglib指令聲明一個命名空間(例如:<%@ taglib prefix="mime" uri="/WEB-INF/foo.tld"%>)。
  • EL表達式調用函數的方式:${前綴:方法()}(例如:${mime:function()})。

  • 可重用的模板部件

    如果我有234個JSP文件并且它們都有同一個導航欄,如果我需要改變導航欄的代碼,那么234個JSP都要改。這簡直是噩夢

    JSP中有一個對應的處理機制,這就是包含(include)

    形式如下:

    <html><body> <!-- 在這里插入頁眉文件 --> Welcome to our size... blah blah blah more stuff here... <!-- 在這里插入頁腳文件 --> </html></body>

    include指令

    include指令告訴容器:復制所包含文件中所有內容,在把它粘貼到這個文件中,而且就放在這里…


    jsp:include標準動作


    上述兩者的內部原理并不相同

    <jsp:include page="Header.jsp" />標準動作和<%@ include file="Header.jsp" %>指令的內部原理并不同。


    include指令在轉換(.jsp變成.java)時發生jsp:include標準動作在運行時發生

    很容易就能明白,指令是將其變為out.write()輸出,而標準動作調用方法

    這里指出:指令的效率會比標準動作的高


    對應第一個請求的include指令

    執行過程如下:


    對應第一個請求的jsp:include標準動作

    執行過程如下:


    兩個注意的地方

    屬性名不一樣:

    位置是否敏感(include指令是位置敏感的):

    這里還說明了一個問題:不要把開始和結束HTML和body標記放在可重用部件中!設計和編寫布局模板時,要假設它們會包含在其他頁面中


    使用jsp:param定制包含的內容

    如果我們希望頁眉上有一個與上下文相關的子標題,它要依相應的頁面而定,該怎么做呢?

    兩種方法:

  • 笨方法:把子標題的信息放在主頁面上,作為頁眉之后的第一個內容,也就是緊挨著放在頁面中包含頁眉的include的后面。
  • 更聰明的辦法:把子標題信息作為新的請求參數傳遞給所包含的頁面!
  • 第二種辦法如下所示:

    我們注意到jsp:include標準動作的可以增加(或替換)請求參數,供被包含的片段使用。


    jsp:forward標準動作

    有這樣一個問題,如果我的客戶訪問我的頁面,但是還沒有登錄,我想讓他轉跳到登錄頁面,該怎么做呢?

    雖然這不是MVC中視圖的任務(很明顯應該給控制器處理),但我們還是提供了這么一種操作,就是<jsp:forward>。


    有條件的轉發

    代碼如下:

    結果如下:

    這里指出:利用<jsp:forward>,緩沖區會在轉發之前清空

    看下面這個有趣的問題:

    是的,毫無疑問的你收貨了一個異常


    初識JSTL標記

    由于我們不能在JSP頁面寫腳本,那么如果我們需要對頁面測試又該怎么辦呢?

    JSTL標記解決這個問題!如下:

    我們看到,有一個taglib指令,并且它的prefix的屬性值是”c”。我們先放著!


    Bean相關標準動作復習(要點)

  • <jsp:useBean>標準動作會定義一個變量,它可能是一個現有bean屬性的引用,如果還不存在這樣一個bean,則會創建一個新的bean,這個變量就是新bean的引用。
  • <jsp:useBean>必須有一個“id”屬性,這個屬性聲明了JSP中引用bean時所用的變量名。
  • 如果<jsp:useBean>中沒有“scope”屬性,作用域默認為頁面(page)作用域。
  • “class”屬性是可選的,它聲明了創建一個新bean時使用的類類型。這個類型必須是公共的、非抽象的,而且有一個公共的無參數構造函數。
  • 如果在<jsp:useBean>中放了一個“type”屬性,bean必須能強制轉換為這種類型。
  • 如果有一個“type”屬性,但是沒有“class”屬性,bean必須已經存在,因為你沒有指定為這個新bean實例化哪個類類型。
  • <jsp:useBean>標記可以有一個體,體中的內容會有條件的運行,只有當創建一個新的bean作為<jsp:useBean>的結果時,才會運行體中的內容(這說明,指定或默認作用域中不存在有該“id”的bean)。
  • <jsp:useBean>體的主要作用是使用<jsp:setProperty>設置新bean的性質。
  • <jsp:userProperty>必須有一個name屬(它要與<jsp:useBean>的“id”匹配),還有一個“property”屬性必須有一個具體的性質名,或者是通配符“*”。
  • 如果沒有包含“value”屬性,只有當一個請求參數的名字與性質名匹配時,容器才會設置性質值。如果“property”屬性使用通配符(*),容器會為所有與某個請求參數名匹配的性質設置值。(其他性質不受影響)
  • 如果請求參數名與性質名不同,但是你想把性質的值設置為請求參數值,可以在<jsp:setProperty>標記中使用“param”屬性。
  • <jsp:setProperty>動作使用自省將“性質”匹配到一個JavaBean設置方法。如果性質是“*”,JSP將迭代處理所有請求參數來設置JavaBean性質。
  • 性質值可以是String或基本類型,<jsp:setProperty>標準動作會自動轉換。

  • 包含復習(要點)

  • 通過使用兩種包含機制之一(include指令或<jsp:include>標準動作),可以利用可重用的組件建立頁面。
  • include指令在轉換時完成包含,只發生一次。所以如果包含的內容已經部署后不太可能改變,使用include指令就很合適。
  • include指令實際上只是復制被包含文件中的所有內容,把它粘貼到有include指令的頁面中。容器把所有被包含文件的內容合并起來,只編譯一個文件來生成servlet。在運行時,有include指令的頁面將成為一個“大”頁面,就像是你自己把所有源代碼鍵入一個文件中一樣。
  • <jsp:include>標準動作在運行時把包含頁面的響應包含到原頁面中。所以如果包含的內容在部署之后可能更新,include標準動作就很實用,此時不適用include指令。
  • 這兩種機制都能包含靜態html頁面,也可以包含動態元素(例如,有EL表達式的JSP代碼)。
  • include指令是唯一一個對位置敏感的指令,所包含的內容會插入到頁面中include指令所在的位置。
  • include指令和include標準動作的屬性命名不一致,指令使用“file”屬性,而標準動作使用“page”屬性。
  • 在你的可重用組件中,一定要去掉開始和結束標記(html和body)。否則,生成的輸出會有嵌套的開始和結束標記,對于這種嵌套的開始和結束標記,并非所有瀏覽器都能處理。設計和構造可重用部件時,要知道它們會包含/插入到別的頁面中。
  • 可以在<jsp:include>的體中使用<jsp:param>標準動作設置(或替換)請求參數,用來定制所包含的文件。
  • 盡管在這一章沒有介紹,但是要知道,<jsp:param>也可以用在<jsp:forward>標記的體中。
  • <jsp:param>只能放在<jsp:include>或<jsp:forward>標準動作中。
  • 如果<jsp:param>中使用的參數名已經有一個值(作為請求參數),新值會覆蓋原來的值。否則,就會向請求增加一個新的請求參數。
  • 對被包含資源有一些限制:它不能改變響應狀態碼或設置首部。
  • <jsp:forward>標準動作可以把請求轉發到同一個Web應用中的另一個資源(就像使用RequestDispatcher一樣)。
  • 發送轉發時,會首先清空響應緩沖區!請求轉發到目標資源會先清空輸出。所以轉發前挾制響應的所有內容都會清掉。
  • 如果在轉發之前先提交響應(例如,通過調用out.flush()),會把刷新輸出的內容發送給客戶,但是僅此而已。不會發送轉發,原頁面的余下部分不會得到處理。

  • 本章完

    與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的Head First JSP---随笔六的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。