• <nav id="wkkge"><strong id="wkkge"></strong></nav>
  • <menu id="wkkge"></menu>
  • 第一部分 Java基礎
    第二部分 Java進階

    Javaweb面試題及答案

     

     

    1、說下原生JDBC操作數據庫流程?

     

    ● 第一步:Class.forName()加載數據庫連接驅動;

     

    ● 第二步:DriverManager.getConnection()獲取數據連接對象;

     

    ● 第三步:根據SQL獲取sql會話對象,有2種方式 Statement、PreparedStatement ;

     

    ● 第四步:執行SQL,執行SQL前如果有參數值就設置參數值setXXX();

     

    ● 第五步:處理結果集;

     

    ● 第六步:關閉結果集、關閉會話、關閉連接。

     

     

    2、為什么要使用PreparedStatement?

     

    PreparedStatement接口繼承Statement,PreparedStatement實例包含已編譯的SQL語句,所以其執行速度要快于Statement對象。

     

    作為Statement的子類, PreparedStatement 繼承了Statement的所有功能。三種方法execute、 executeQuery和executeUpdate已被更改以使之不再需要參數。

     

    ● 在 JDBC 應用中,多數情況下使用PreparedStatement,原因如下:

     

    代碼的可讀性和可維護性。Statement需要不斷地拼接,而PreparedStatement不會。

     

    PreparedStatement盡最大可能提高性能。DB有緩存機制,相同的預編譯語句再次被調用不會再次需要編譯。

     

    最重要的一點是極大地提高了安全性。Statement容易被SQL注入,而PreparedStatement傳入的內容不會和sql 語句發生任何匹配關系。

     

     

    3、http的長連接和短連接區別?

     

    HTTP協議有HTTP/1.0版本和HTTP/1.1版本。HTTP1.1默認保持長連接(HTTP persistent connection,也翻譯為持久連接),數據傳輸完成了保持TCP連接不斷開(不發RST包、不四次握手),等待在同域名下繼續用這個通道傳輸數據;相反的就是短連接。

     

    在 HTTP/1.0 中,默認使用的是短連接。也就是說,瀏覽器和服務器每進行一次HTTP操作,就建立一次連接,任務結束就中斷連接。從HTTP/1.1起,默認使用的是長連接,用以保持連接特性。

     

     

    4、HTTP/1.1與HTTP/1.0的區別?

     

    ● 可擴展性

     

    ● HTTP/1.1在消息中增加版本號,用于兼容性判斷。

     

    ● HTTP/1.1增加了OPTIONS方法,它允許客戶端獲取一個服務器支持的方法列表。

     

    ● 為了與未來的協議規范兼容,HTTP/1.1在請求消息中包含了Upgrade頭域,通過該頭域,客戶端可以讓服務器知道它能夠支持的其它備用通信協議,服務器可以據此進行協議切換,使用備用協議與客戶端進行通信。

     

    ● 緩存

     

    在HTTP/1.0中,使用Expire頭域來判斷資源的fresh或stale,并使用條件請求(conditional request)來判斷資源是否仍有效。HTTP/1.1在1.0的基礎上加入了一些cache的新特性,當緩存對象的Age超過Expire時變為stale對象,cache不需要直接拋棄stale對象,而是與源服務器進行重新激活(revalidation)。

     

    ● 帶寬優化

     

    HTTP/1.0中,存在一些浪費帶寬的現象,例如客戶端只是需要某個對象的一部分,而服務器卻將整個對象送過來了。例如,客戶端只需要顯示一個文檔的部分內容,又比如下載大文件時需要支持斷點續傳功能,而不是在發生斷連后不得不重新下載完整的包。

     

    HTTP/1.1中在請求消息中引入了range頭域,它允許只請求資源的某個部分。在響應消息中Content-Range頭域聲明了返回的這部分對象的偏移值和長度。如果服務器相應地返回了對象所請求范圍的內容,則響應碼為206(Partial Content),它可以防止Cache將響應誤以為是完整的一個對象。

     

    另外一種情況是請求消息中如果包含比較大的實體內容,但不確定服務器是否能夠接收該請求(如是否有權限), 此時若貿然發出帶實體的請求,如果被拒絕也會浪費帶寬。HTTP/1.1 加入了一個新的狀態碼100(Continue)。客戶端事先發送一個只帶頭域的請求,如果服務器因為權限拒絕了請求,就回送響應碼401(Unauthorized);如果服務器接收此請求就回送響應碼100,客戶端就可以繼續發送帶實體的完整請求了。

     

    注意,HTTP/1.0 的客戶端不支持100響應碼。但可以讓客戶端在請求消息中加入Expect頭域,并將它的值設置為100-continue。節省帶寬資源的一個非常有效的做法就是壓縮要傳送的數據。Content-Encoding是對消息進行端到端(end-to-end)的編碼,它可能是資源在服務器上保存的固有格式(如 jpeg 圖片格式);在請求消息中加入Accept-Encoding頭域,它可以告訴服務器客戶端能夠解碼的編碼方式。

     

    ● 長連接

     

    HTTP/1.0規定瀏覽器與服務器只保持短暫的連接,瀏覽器的每次請求都需要與服務器建立一個TCP連接,服務器完成請求處理后立即斷開TCP連接,服務器不跟蹤每個客戶也不記錄過去的請求。此外,由于大多數網頁的流量都比較小,一次TCP連接很少能通過slow-start區,不利于提高帶寬利用率。

     

    HTTP 1.1支持長連接(PersistentConnection)和請求的流水線(Pipelining)處理,在一個 TCP連接上可以傳送多個HTTP請求和響應,減少了建立和關閉連接的消耗和延遲。例如:一個包含有許多圖像的網頁文件的多個請求和應答可以在一個連接中傳輸,但每個單獨的網頁文件的請求和應答仍然需要使用各自的連接。

     

    HTTP1.1還允許客戶端不用等待上一次請求結果返回,就可以發出下一次請求,但服務器端必須按照接收到客戶端請求的先后順序依次回送響應結果,以保證客戶端能夠區分出每次請求的響應內容,這樣也顯著地減少了整個下載過程所需要的時間。

     

    ● 消息傳遞

     

    HTTP消息中可以包含任意長度的實體,通常它們使用Content-Length來給出消息結束標志。但是,對于很多動態產生的響應,只能通過緩沖完整的消息來判斷消息的大小,但這樣做會加大延遲。如果不使用長連接,還可以通過連接關閉的信號來判定一個消息的結束。

     

    HTTP/1.1中引入了Chunkedtransfer-coding來解決上面這個問題,發送方將消息分割成若干個任意大小的數據塊,每個數據塊在發送時都會附上塊的長度,最后用一個零長度的塊作為消息結束的標志。這種方法允許發送方只緩沖消息的一個片段,避免緩沖整個消息帶來的過載。

     

    在HTTP/1.0中,有一個Content-MD5的頭域,要計算這個頭域需要發送方緩沖完整個消息后才能進行。而HTTP/1.1中,采用chunked分塊傳遞的消息在最后一個塊(零長度)結束之后會再傳遞一個拖尾(trailer),它包含一個或多個頭域,這些頭域是發送方在傳遞完所有塊之后再計算出值的。發送方會在消息中包含一個Trailer頭域告訴接收方這個拖尾的存在。

     

    ● Host頭域

     

    在HTTP1.0中認為每臺服務器都綁定一個唯一的IP地址,因此,請求消息中的URL并沒有傳遞主機名(hostname)。但隨著虛擬主機技術的發展,在一臺物理服務器上可以存在多個虛擬主機(Multi-homed Web Servers),并且它們共享一個 IP 地址。HTTP1.1的請求消息和響應消息都應支持 Host 頭域,且請求消息中如果沒有 Host 頭域會報告一個錯誤(400 Bad Request)。此外,服務器應該接受以絕對路徑標記的資源請求。

     

    ● 錯誤提示

     

    HTTP/1.0中只定義了16個狀態響應碼,對錯誤或警告的提示不夠具體。HTTP/1.1引入了一個Warning頭域, 增加對錯誤或警告信息的描述。此外,在HTTP/1.1中新增了24個狀態響應碼,如409(Conflict)表示請求的資源與資源的當前狀態發生沖突;410(Gone)表示服務器上的某個資源被永久性的刪除。

     

     

    5、http常見的狀態碼有哪些?

     

    ● 200 OK 客戶端請求成功

     

    ● 301Moved Permanently(永久移除),請求的URL已移走。Response中應該包含一個 Location URL,說明資源現在所處的位置

     

    ● 302found 重定向

     

    ● 400Bad Request 客戶端請求有語法錯誤,不能被服務器所理解

     

    ● 401Unauthorized 請求未經授權,這個狀態代碼必須和WWW-Authenticate報頭域一起使用

     

    ● 403 Forbidden 服務器收到請求,但是拒絕提供服務

     

    ● 404 Not Found 請求資源不存在,eg:輸入了錯誤的URL

     

    ● 500 Internal Server Error 服務器發生不可預期的錯誤

     

    ● 503 Server Unavailable 服務器當前不能處理客戶端的請求,一段時間后可能恢復正常

     

     

    6、GET和POST的區別?

     

    ● GET請求的數據會附在URL之后(就是把數據放置在HTTP協議頭中),以?分割URL和傳輸數據,參數之間以&相連,如:login.action?name=zhagnsan&password=123456。POST 把提交的數據則放置在是HTTP包的包體中。

     

    ● GET方式提交的數據最多只能是1024字節,理論上POST沒有限制,可傳較大量的數據。其實這樣說是錯誤的,不準確的:“GET方式提交的數據最多只能是1024字節",因為 GET 是通過URL提交數據,那么GET可提交的數據量就跟URL的長度有直接關系了。而實際上,URL不存在參數上限的問題,HTTP協議規范沒有對URL長度進行限制。這個限制是特定的瀏覽器及服務器對它的限制。IE對URL長度的限制是2083字節(2K+35)。對于其他瀏覽器,如Netscape、FireFox等,理論上沒有長度限制,其限制取決于操作系統的支持。

     

    ● POST的安全性要比GET的安全性高。注意:這里所說的安全性和上面 GET 提到的“安全”不是同個概念。上面“安全”的含義僅僅是不作數據修改,而這里安全的含義是真正的 Security的含義,比如:通過GET 提交數據,用戶名和密碼將明文出現在URL上,因為登錄頁面有可能被瀏覽器緩存,其他人查看瀏覽器的歷史紀錄,那么別人就可以拿到你的賬號和密碼了,除此之外,使用 GET 提交數據還可能會造成Cross-site request forgery攻擊。

     

    ● Get 是向服務器發索取數據的一種請求,而Post是向服務器提交數據的一種請求,在FORM(表單)中,Method默認為"GET",實質上GET和POST只是發送機制不同,并不是一個取一個發。

     

     

    7、http中重定向和請求轉發的區別?

     

    本質區別:轉發是服務器行為,重定向是客戶端行為。

     

    重定向特點:兩次請求,瀏覽器地址發生變化,可以訪問自己web之外的資源,傳輸的數據會丟失。

     

    請求轉發特點:一次強求,瀏覽器地址不變,訪問的是自己本身的web資源,傳輸的數據不會丟失。

     

     

    8、Cookie 和 Session 的區別?

     

    Cookie是web服務器發送給瀏覽器的一塊信息,瀏覽器會在本地一個文件中給每個web服務器存儲Cookie。以后瀏覽器再給特定的web服務器發送請求時,同時會發送所有為該服務器存儲的Cookie。

     

    Session是存儲在web服務器端的一塊信息。Session對象存儲特定用戶會話所需的屬性及配置信息。當用戶在應用程序的Web頁之間跳轉時,存儲在Session對象中的變量將不會丟失,而是在整個用戶會話中一直存在下去。

     

    ● Cookie和 Session的不同點:

     

    無論客戶端做怎樣的設置,Session都能夠正常工作。當客戶端禁用Cookie時將無法使用Cookie。

     

    在存儲的數據量方面:Session能夠存儲任意的java對象,Cookie只能存儲String類型的對象。

     

     

    9、2.session共享怎么做的(分布式如何實現session共享)?

     

    問題描述:一個用戶在登錄成功以后會把用戶信息存儲在session當中,這時session所在服務器為server1,那么用戶在session失效之前如果再次使用app,那么可能會被路由到 server2,這時問題來了,server2沒有該用戶的session,所以需要用戶重新登錄,這時的用戶體驗會非常不好,所以我們想如何實現多臺server之間共享session,讓用戶狀態得以保存。

     

    ● 服務器實現的session復制或session共享,這類型的共享session是和服務器緊密相關的,比如webSphere或JBOSS在搭建集群時候可以配置實現session復制或session共享,但是這種方式有一個致命的缺點,就是不好擴展和移植,比如我們更換服務器,那么就要修改服務器配置。

     

    ● 利用成熟的技術session復制,比如12306使用的gemfire,比如常見的內存數據庫如redis 或memorycache,這類方案雖然比較普適,但是嚴重依賴于第三方,這樣當第三方服務器出現問題的時候,那么將是應用的災難。

     

    ● 將session維護在客戶端,很容易想到就是利用cookie,但是客戶端存在風險,數據不安全,而且可以存放的數據量比較小,所以將session維護在客戶端還要對session中的信息加密。我們實現的方案可以說是第二種方案和第三種方案的合體,可以利用gemfire實現session復制共享,還可以session維護在redis中實現session共享,同時可以將session維護在客戶端的cookie中,但是前提是數據要加密。這三種方式可以迅速切換,而不影響應用正常執行。我們在實踐中,首選gemfire或者redis作為session共享的載體,一旦session不穩定出現問題的時候,可以緊急切換cookie維護session作為備用,不影響應用提供服務。

     

    這里主要講解redis和cookie方案,gemfire比較復雜大家可以自行查看gemfire工作原理。利用redis做session共享,首先需要與業務邏輯代碼解耦,不然session共享將沒有意義,其次支持動態切換到客戶端cookie模式。redis的方案是,重寫服務器中的HttpSession和HttpServletRequest,首先實現HttpSession接口,重寫session的所有方法,將session以hash值的方式存在redis中,一個session的key就是sessionID,setAtrribute重寫之后就是更新redis中的數據,getAttribute重寫之后就是獲取redis中的數據,等等需要將HttpSession的接口一一實現。實現了HttpSesson,那么我們先將該session類叫做MySession(當然實踐中不是這么命名的),當MySession出現之后問題才開始,怎么能在不影響業務邏輯代碼的情況下,還能讓原本的request.getSession()獲取到的是MySession,而不是服務器原生的session。這里,我決定重寫服務器的HttpServletRequet,這里先稱為MyRequest,但是這可不是單純的重寫,我需要在原生的request基礎上重寫,于是我決定在filter中,實現request的偷梁換柱,我的思路是這樣的,MyRequest的構建器,必須以request作為參數,于是我在filter中將服務器原生的request(也有可能是框架封裝過的request),當做參數new出來一個MyRequest,并且MyRequest也實現了HttpServletRequest接口,其實就是對原生request的一個增強,這里主要重寫了幾個request的方法,但是最重要的是重寫了request.getSession(),寫到這里大家應該都明白為什么重寫這個方法了吧,當然是為了獲取MySession,于是這樣就在filter中,偷偷的將原生的request換成MyRequest了,然后再將替換過的request傳入chan.doFilter(),這樣filter時候的代碼都使用的是MyRequest了,同時對業務代碼是透明的,業務代碼獲取session的方法仍然是request.getSession(),但其實獲取到的已經是MySession了,這樣對session的操作已經變成了對redis的操作。這樣實現的好處有兩個,第一開發人員不需要對session共享做任何關注,session共享對用戶是透明的;第二,filter是可配置的,通過filter的方式可以將session共享做成一項可插拔的功能,沒有任何侵入性。這個時候已經實現了一套可插拔的session共享的框架了,但是我們想到如果redis服務出了問題,這時我們該怎么辦呢,于是我們延續redis的想法,想到可以將session維護在客戶端內(加密的cookie),當然實現方法還是一樣的,我們重寫HttpSession接口,實現其所有方法,比如setAttribute就是寫入cookie,getAttribute就是讀取cookie,我們可以將重寫的session稱作MySession2,這時怎么讓開發人員透明的獲取到MySession2呢,實現方法還是在filter內偷梁換柱,在MyRequest加一個判斷,讀取sessionType配置,如果sessionType是redis的,那么getSession的時候獲取到的是MySession,如果sessionType是coolie的,那么getSession的時候獲取到的是MySession2,以此類推,用同樣的方法就可以獲取到MySession3,4,5,6等等。

     

    這樣兩種方式都有了,那么我們怎實現兩種session共享方式的快速切換呢,剛剛我提到一個sessionType,這是用來決定獲取到session的類型的,只要變換sessionType就能實現兩種session共享方式的切換,但是sessionType必須對所有的服務器都是一致的,如果不一致那將會出現比較嚴重的問題,我們目前是將sessionType維護在環境變量里,如果要切換sessionType就要重啟每一臺服務器,完成session共享的轉換,但是當服務器太多的時候將是一種災難。而且重啟服務意味著服務的中斷,所以這樣的方式只適合服務器規模比較小,而且用戶量比較少的情況,當服務器太多的時候,務必需要一種協調技術,能夠讓服務器能夠及時獲取切換的通知。基于這樣的原因,我們選用zookeeper作為配置平臺,每一臺服務器都會訂閱zookeeper上的配置,當我們切換sessionType之后,所有服務器都會訂閱到修改之后的配置,那么切換就會立即生效,當然可能會有短暫的時間延遲,但這是可以接受的。

     

     

    ???????10、在單點登錄中,如果cookie被禁用了怎么辦?

    ???????

    單點登錄的原理是后端生成一個sessionID,然后設置到cookie,后面的所有請求瀏覽器都會帶上cookie,然后服務端從cookie里獲取sessionID,再查詢到用戶信息。所以,保持登錄的關鍵不是cookie,而是通過cookie保存和傳輸的sessionID,其本質是能獲取用戶信息的數據。除了cookie,還通常使用HTTP請求頭來傳輸。但是這個請求頭瀏覽器不會像cookie一樣自動攜帶,需要手工處理。

    ???????

    全部教程
  • <nav id="wkkge"><strong id="wkkge"></strong></nav>
  • <menu id="wkkge"></menu>
  • 面对面棋牌游戏