天天看點

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

  有個同學去非洲援建,剛到工地接待他的施工員是個黑人,他就用英語跟人家交流,黑人沒做聲

  然後他又用法語,黑人還是沒說話

  然後他用手去比劃

  黑人終于開口了:瞎比劃嘎哈,整個工地都中國人

  在利用maven/eclipse搭建ssm(spring+spring mvc+mybatis)一文的問題回報中,大體分兩個:404和頁面無資料;至于500,個人認為比較好解決,按照提示進行處理就好,本文就不讨論500了

    主要也是兩種

    1、webapp未釋出

      相關資源未部署,例如webapp未釋出部署,類似如下

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

      不隻是webapp,main下的java、resources、webapp,maven依賴都是需要部署到tomcat,不然就不完整,就會存在各種各樣的少内容的問題;

    2、請求URL不對

      這個确實是很多新入行的小夥伴容易出現的問題

      如果工程正常部署,請求URL出現404,很有可能是我們請求的URL不對;我們到tomcat的home目錄下看看工程是否正常部署,類似如下

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

      還可以看看工程釋出的内容(問題1中需要釋出的内容)是否都在;如果工程部署正常,而請求的URL又出現404,那不用想,就是你的URL寫錯了

    404的解決方案就是:确認工程是否正确部署到tomcat,确認請求的URL是否正确,基本隻要确認這兩點也就能找到問題了;後文不會再詳細的講404,我們将重點放到下面這個問題上

    具體的問題應該是這樣的:當我們請求:http://localhost:端口/工程名/personController/showPerson時,資料正常顯示如下

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

    當我們直接請求jsp時,隻有title沒有資料,如下

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

    這是為什麼?

    對于這個問題一開始确實沒太在意,隻是提示小夥伴去看servlet的四大作用域和jsp的九大内置對象,後面陸陸續續很多小夥伴都問了我,包括評論區留言、站内消息、QQ私聊等

    站内信

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

    評論區

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

    QQ

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

    我發現這個問題好像不是個别小夥伴的問題,很多新入門的小夥伴都存在這樣的疑問,下面我們就對此次問題就行一個詳細的探究;後續篇幅較長,基礎鋪墊較多,希望大家耐心看完!

    狹義上來講,servlet指的就是接口:javax.servlet.Servlet,廣義上來講,servlet指的是servlet規範:Java Servlet API 标準;javax.servlet.Servlet與servlet容器都是servlet規範下的産物。Java Servlet API是Servlet容器和Servlet之間的接口,它定義了Servlet的各種方法,還定義了Servlet容器傳送給Servlet的對象類,其中最重要的是請求對象ServletRequest和響應對象ServletResponseo這兩個對象都是由Servlet容器在用戶端調用Servlet時産生的,Servlet容器把客戶請求資訊封裝在ServletRequest對象中,然後把這兩個對象都傳送給要調用的Servlet,Servlet處理完後把響應結果寫入ServletResponse,然後由Servlet容器把響應結果發送到用戶端。

    Servlet與Servlet容器的關系有點像槍和子彈的關系,槍是為子彈而生,而子彈又讓槍有了殺傷力。雖然它們是彼此依存的,但是又互相獨立發展,這一切都是為了适應工業化生産的結果。從技術角度來說是為了解耦,通過标準化接口來互相協作。Servlet 容器作為一個獨立發展的标準化産品,目前它的種類很多,包括Jetty、tomcat、resin、JBoss、WebSphere、Weblogic等,這些都是成熟的産品,有專門的公司或者組織進行維護,我們直接拿來用就好。

    我們約定下,下文中的servet指的都是servlet接口:javax.servlet.Servlet,servlet容器指的是:Tomcat,Web伺服器與Servlet容器是同一個内容(實際是有差別的,具體差別大家自行去查閱)

    Tomcat容器模型如下

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

    Tomcat響應客戶請求過程

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

      其中,①處表示Web伺服器接收到用戶端發出的HTTP請求後,轉發給Servlet容器,再由Servlet容器轉發給具體的Servlet執行個體進行請求的處理;②處表示Servlet執行個體将處理結果封裝進ServletResponse中,再由Servlet容器把ServletResponse發給Web伺服器,通知Web伺服器以HTTP響應的方式把結果發送到用戶端。也就是說,與用戶端直接打交道的是tomcat(servlet容器),而不是我們的Servlet執行個體,而真正處理請求的才是我們的Servlet執行個體。

    說的簡單點,我們自定義的Servlet,其實是對servlet容器在業務層面的拓展,相當于業務定制一樣;我們可以這樣了解,servlet容器對servlet提供技術支援,而servlet對servlet容器提供業務拓展,兩者缺一不可,缺了技術支援,業務拓展實施不起來,缺了業務拓展,技術支援沒有現實意義。Servlet容器封裝了底層複雜的技術實作,使我們可以專注于業務實作,而Servlet容器與業務實作之間的紐帶就是Servlet接口,它是我們對Servlet容器進行業務拓展的标準,是以我們的業務需要實作Servlet接口。套用阿基米德的杠杆原理:給Servlet容器多個servlet執行個體,Servlet容器還你豐富的web服務。

    示例代碼:our-servlet

    我們先來看看在jsp出現之前,servlet如何輸出頁面,HelloServlet如下

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題
關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

View Code

    不僅僅是業務資料,還包括靜态頁面的内容,通通在servlet傳回,如果頁面簡單,這麼處理也能接受,但是如果頁面像淘寶、京東那樣非常複雜,你能想象嗎?太容易出錯了,一旦靜态頁面的元素少了或者多了内容,都不知道如何排查,面對茫茫多的out.write,就隻有哭的份了。是以jsp就應運而生了。

    JSP全稱:Java Server Pages,允許在傳統靜态網頁HTML中插入Java代碼片段(Scriptlet)和JSP标簽,以簡化頁面靜态内容的開發。但需要注意的是,JSP檔案的本質還是Servlet,隻不過與Servlet不同的是,JSP是專門用于進行資料展示的Servlet;JSP最終會被Tomcat解析成Servlet,在Tomcat内置了一個JSP解析引擎,當第一次通路該JSP頁面時,解析引擎會将JSP頁面解析成Servlet,然後再由Servlet将動态資料、靜态内容全部輸出到浏覽器供展示。我們來看看jsp解析後的檔案在哪裡、内容是什麼,以示例中的index.jsp為例。路徑如下圖

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

    index_jsp.java

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題
關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

    發現熟悉的out.write又回來了,隻是此時的out.write不是我們手動寫的,而是Tomcat解析jsp後生成的;如果jsp沒變動,jsp隻會在第一次被調用時解析、編譯一次,後續的請求都會由編譯後的servlet處理,我們來驗證下,如何驗證了? 不變index.jsp内容再請求index.jsp,看看上圖中檔案的修改時間會不會變

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

    發現檔案的修改時間沒有變動,也就是說上面的的結論:如果jsp沒變動,jsp隻會在第一次被調用時解析、編譯一次是對的。感興趣的朋友可以去看下Tomcat的源碼,看看具體的實作細節。

    有人可能會問:為什麼不将jsp的内容直接傳回給浏覽器?我們要明白一點:浏覽器隻能解析html、css、js,除此之外的内容它解析不了,那麼我們能直接将jsp的内容傳回給浏覽器嗎?是以中間有處理過程,最終由servlet将靜态内容傳回給浏覽器。有些愛問的小夥伴可能又會問了:浏覽器為什麼隻能解析:html、css、js,這涉及到浏覽器規範的問題,除非你有能力改變這個規範,讓浏覽器支援你想要的内容,這個問題不做過深的讨論,我們姑且認為這是浏覽器的限制,既然我們改變不了這個限制,那就适應這個限制。

    Servlet四大作用域包括:page域、request域、session域、application域,作用域指的是變量的有效期限,具體如下

      當變量的作用域是page,它的有效範圍隻在目前jsp頁面裡有效;

      當變量的作用域是request,它的有效範圍是目前請求周期,所謂請求周期,就是指從http請求發起,到伺服器處理結束,傳回響應的整個過程,在這個過程中可能使用forward的方式跳轉了多個jsp頁面,在這些頁面裡你都可以使用這個變量;

      當變量的作用域是session,它的有效範圍是目前會話,何為目前會話,就是指從使用者打開浏覽器開始,到使用者關閉浏覽器的整個過程,這個過程可能包含多個請求響應;

      當變量的作用域是application,它的有效範圍是整個應用,何為整個應用,就是指從應用啟動,到應用結束;

    JSP九大内置對象包括:page、request 、response、pageContext、session、application、out、config、exception,内置對象指的是Servlet容器建立的一組對象,不需使用new關鍵字就可以直接使用的内置對象。

    四大作用域與九大内置對象對應關系如下

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

    更多詳情需要大家自己去查閱資料了

    我們知道jsp中可以插入Java代碼片段,類似如下

    其中<% %>包裹的就是java片段,<%= %>輸出表達式值到頁面;可以看到不夠簡潔,閱讀性也不太友好,是以EL表達式就應運而生了,上述代碼可以替換成如下代碼

    EL能夠通路頁面的上下文以及不同作用域中的對象 ,取得對象屬性的值,或執行簡單的運算或判斷操作,用來簡化JSP中的java代碼。EL表達式是JSP1.2之後内置支援的,可以直接在JSP中使用,它從servlet四大作用域(範圍servletContext > session > request > pageContext)中取值,這四個域都有setAttribute("",object)方法和getAttribute("")方法, EL表達式會自動按作用範圍從小到大的順序從四大作用域中尋找對應名字的值,找到了就立即傳回不再繼續尋找,其内部調用的就是pageContext的findAttribute("")方法。

    EL固然能簡化JSP中的java代碼,但是它功能非常簡單,不能滿足一些複雜的代碼邏輯,是以就誕生了JSTL。JSP标準标簽庫(JSTL)是一個JSP标簽集合,它封裝了JSP應用的通用核心功能,支援通用的、結構化的任務,比如疊代,條件判斷,XML文檔操作,國際化标簽,SQL标簽,另外還支援自定義标簽,它實作了JSP頁面中的代碼複用、簡化了代碼的書寫,同時也保證了JSP的可讀性更強。JSTL功能比較豐富,但它不是JSP内置支援的,是以需要導入标簽庫到JSP頁面(還要添加jstl的jar包依賴)。JSTL往往會集合EL表達式來使用,簡單示例如下

    這代碼看起來就清爽多了,沒有java代碼,前端開發者也很容易看懂;關于EL表達式與JSTL标簽更詳細資訊,需要大家自行去查閱資料了,本文篇幅有限,不做過多的講解了。

關于利用maven搭建ssm的部落格,我們一起來探讨下問的最多的問題

    那麼可想而知,重定向的request作用域的變量是會失效的,而轉發則不會

    還記得我們是如何配置Spring MVC的嗎, 我們會在web.xml中配置如下代碼

    這樣就配置了Spring MVC;大家可以留意下DispatcherServlet,去看他的類圖會發現,他就是一個Servlet的實作,也就是說Sprinv MVC就是基于Servlet的拓展。

    我們在Spring MVC基礎上進行開發的時候,将資料綁定到作用域的時候,一般用的是SpringMVC的資料模型:Model或者ModelMap,例如這樣

    而不是顯示的直接綁定到Servlet四大作用域,資料難道沒有綁定到四大作用域? 我們說過,EL表達式隻能在四大作用域中取值,否則取不到,是以SpringMVC中的資料綁定最終還是會到四大作用域的某一個中,至于是何時、何地、如何将Model中的屬性綁定到哪個作用域,這個不是本文要說的了,篇幅太大了,有興趣的可以去看看這篇部落格:springmvc的工作原理,我們來看看其源碼實作。這裡給個結論:在預設情況下,Model中的屬性作用域是request級别。

    有些小夥伴會抱怨了:上面哔哔了那麼多,怎麼就是不講答案,淨說一些沒用的

    如果大家堅持看到這了,再堅持會,答案馬上揭曉,上面鋪墊了那麼多,絕對是有用的。

    我們回到問題:當我們請求http://localhost:端口/工程名/personController/showPerson時,資料正常顯示,而當我們直接請求jsp時,隻有title卻沒有資料,這是為什麼?title是靜态頁面内容,這個不用管,那為什麼直接請求jsp為什麼沒有資料庫的person清單呢? jsp源代碼如下

    裡面用到了<c:forEach>和EL表達式,解釋下這個流程:EL表達式先從四大作用域擷取名為persons的集合,然後<c:forEach>周遊該集合,每次周遊的結果放到page作用域,并取名叫person,最後通過EL表達式輸出person的name和age到頁面。那麼請問:直接通路JSP,四大作用域中有名叫persons的屬性嗎?很顯然沒有,persons不存在,周遊它會有結果輸出嗎?這就是為什麼直接通路jsp沒有資料的答案。

    我們再回到Controller層

    代碼也非常簡單,先從資料庫擷取person集合,然後将該集合設定到了model的屬性persons中,我們知道model的屬性預設情況下會設定到request作用域;然後将請求轉發到showperson.jsp,轉發過程中,request作用域的變量仍然有效,是以jsp中EL表達式能夠讀取到persons變量,是以就有資料輸出到頁面了。

  1、Servlet與Servlet容器的關系比較暧昧,兩者互相作用,實作web服務;簡單點說,我們自定義的Servlet就是對Servlet容器的業務拓展,而Servlet容器是對Servlet的支撐;

  2、JSP的出現時為了簡化靜态頁面的開發,EL表達式與JSTL的出現則是為了簡化JSP頁面的Java代碼;JSP本質還是Servlet,在第一次被通路的時候會被Servlet容器解析成Servlet、編譯Servlet,最終還是有Servlet将頁面内容out.write到浏覽器;

  3、Spring MVC本質還是Servlet,它的出現是為了簡化web開發,同時可以與spring無縫對接,享受spring帶來的好處;Spring MVC的資料綁定,依托的還是Servlet的的四大作用域,隻是中間存在轉換過程;

  4、EL表達式的取值必須存在于四大作用域中,在jsp中用EL表達式時,一定要保證資料正确地添加到了四大作用域中,不然,EL表達式會取不到值;

  《深入分析JavaWeb技術内幕》

  《Tomcat 系統架構與模式設計分析》

  Java Web(一) Servlet詳解!!