菜鳥(niǎo)搭建web服務(wù)筆記-1

筆者最近看了Spring,MyBatis,Maven和Git等技術(shù)的相關(guān)資料,想自己試著從頭搭建一個(gè)web服務(wù),以鞏固并加深學(xué)到的知識(shí),于是便有了這一系列文章。這一系列文章將主要記錄整個(gè)搭建過(guò)程,碰到的問(wèn)題以及解決方案。注意本系列文章并不是各類(lèi)技術(shù)的入門(mén)使用教程,需要讀者對(duì)技術(shù)本身有一定的了解。

開(kāi)發(fā)環(huán)境

  • Tomcat:9.0.16
  • Maven:3.6.0
  • Git:2.20
  • 操作系統(tǒng):windows10

項(xiàng)目需求

因?yàn)闀簳r(shí)沒(méi)想好要做什么服務(wù),那么就以最簡(jiǎn)單的登錄功能開(kāi)始吧。

創(chuàng)建項(xiàng)目

  • 首先在github上創(chuàng)建了一個(gè)dizzydwarf項(xiàng)目
  • 然后在eclipse中創(chuàng)建了一個(gè)Maven項(xiàng)目,并將兩者關(guān)聯(lián)起來(lái)
    git remote add origin https://github.com/xuben/dizzydwarf.git

問(wèn)題1:Maven中創(chuàng)建web項(xiàng)目

這里筆者在創(chuàng)建Maven項(xiàng)目的目錄結(jié)構(gòu)時(shí)沒(méi)有選擇web項(xiàng)目的模板,因此需要自己將其改造成一個(gè)web項(xiàng)目。

  • 首先需要告訴Maven這是一個(gè)web項(xiàng)目,最后需要打包成war包,因此修改pom.xml
<packaging>war</packaging>
  • 然后在src/main目錄下新建如下目錄結(jié)構(gòu)
src
    main
        webapp
            WEB-INF
                web.xml

設(shè)計(jì)并實(shí)現(xiàn)

一開(kāi)始的設(shè)計(jì)思路是這樣的,用Tomcat作為web容器,寫(xiě)一個(gè)servlet,將所有的url請(qǐng)求都交給這個(gè)servlet處理,由servlet決定不同的url應(yīng)該調(diào)用哪個(gè)類(lèi)的哪個(gè)方法。

  • 寫(xiě)了個(gè)DispatchServlet,繼承HttpServlet,重寫(xiě)doGetdoPost,根據(jù)getRequestURI判斷請(qǐng)求的url,并把/login請(qǐng)求交給LoginAction處理
  • 在web.xml中配置servlet
  • 寫(xiě)了個(gè)index.html頁(yè)面,里面只有一個(gè)表單,提交的action為/login
  • mvn package生成一個(gè)war包
  • 將這個(gè)war包放到Tomcat安裝目錄的webapps子目錄下并啟動(dòng)Tomcat

問(wèn)題2:Invalid <url-pattern>

Tomcat啟動(dòng)時(shí)提示Invalid <url-pattern>,筆者在web.xml中是這樣配置servlet-mapping的

<servlet-mapping>
    <servlet-name>Dispatcher</servlet-name>
    <url-pattern>*</url-pattern>
</servlet-mapping>

到底什么樣的url-pattern是合法的,具體規(guī)則可以參見(jiàn)servlet specification的Mapping Requests to Servlets部分。如果我們只是想要匹配所有url,可以把*改成/*

<servlet-mapping>
    <servlet-name>Dispatcher</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

問(wèn)題3:Tomcat在命令行輸出中文亂碼

  • 找到注冊(cè)表項(xiàng)HKEY_CURRENT_USER\Console\Tomcat,如果沒(méi)有則新建。
  • 新建CodePage,類(lèi)型為DWORD(32位)值,值為fde9,也就是65001

問(wèn)題4:web項(xiàng)目的地址

筆者在瀏覽器中輸入的訪問(wèn)地址是http://localhost:8080/index.html,結(jié)果跳到了Tomcat自帶的web項(xiàng)目。原來(lái)要訪問(wèn)這個(gè)新添加的web項(xiàng)目需要輸入相對(duì)于host的路徑。
這里webapps是host的根目錄,而新添加的war包被解壓到了webapps/dizzydwarf-0.0.1-SNAPSHOT目錄,因此訪問(wèn)的時(shí)候需要輸入http://localhost:8080/dizzydwarf-0.0.1-SNAPSHOT/index.html,雖然有夠麻煩的,不過(guò)暫時(shí)不是什么大問(wèn)題,畢竟我們可以在必要的時(shí)候?qū)⑵洳渴鸬絟ost根目錄。

問(wèn)題5:url-pattern匹配

輸入正確的地址,還是沒(méi)有看到表單。原來(lái)是筆者將servlet的url-pattern配置為了/*,因此就算是請(qǐng)求靜態(tài)的html頁(yè)面,也會(huì)被匹配到然后交給servlet處理。查了下網(wǎng)上的資料,似乎并沒(méi)有什么簡(jiǎn)單的方法可以在url-pattern中排除指定類(lèi)型的文件,無(wú)奈之下把url-pattern改回了/login

問(wèn)題5:表單action的絕對(duì)路徑和相對(duì)路徑問(wèn)題

再次輸入正確的地址,終于看到表單了。點(diǎn)擊登錄按鈕,返回404錯(cuò)誤,怎么回事?仔細(xì)一看瀏覽器的地址欄,發(fā)現(xiàn)地址欄變成了http://localhost:8080/login
原來(lái)表單的action屬性的值為/login,而這個(gè)url地址也是相對(duì)于host根目錄,而不是當(dāng)前web應(yīng)用根目錄的地址,正確的值應(yīng)該是login。

問(wèn)題6:getRequestURI獲得的路徑

把a(bǔ)ction改成login,重新打包部署后提交表單還是一片空白,在servlet中輸出getRequestURI結(jié)果一看,發(fā)現(xiàn)url是/dizzydwarf-0.0.1-SNAPSHOT/login,而不是預(yù)期的/login。因?yàn)樵趕ervlet配置中已經(jīng)有url映射了,所以這里刪除這部分的代碼,改成直接處理請(qǐng)求。
至此,用一個(gè)servlet處理所有url請(qǐng)求,然后在servlet內(nèi)部分發(fā)的想法算是徹底破滅。但是事實(shí)上,關(guān)于url的映射通過(guò)web.xml方式配置也有其靈活性,只不過(guò)需要寫(xiě)多個(gè)servlet類(lèi)處理。

JSP中的解決方案

對(duì)于前端請(qǐng)求使用絕對(duì)路徑的問(wèn)題,在jsp中可以用${pageContext.request.contextPath}表示web根目錄的路徑

struts2的解決方案

簡(jiǎn)單看了下struts2的StrutsPrepareAndExecuteFilter類(lèi),關(guān)于uri的處理調(diào)用了RequestUtils.getUri方法。大致的思路是用到了getServletPath方法,這個(gè)方法返回的是與url-pattern匹配的部分,不包括通過(guò)*匹配的部分。結(jié)合getServletPath、getRequestURIgetPathInfo方法最終得到相對(duì)于web服務(wù)根目錄的uri路徑。
另外struts2中的請(qǐng)求都以.do結(jié)尾,因此可以很好的排除對(duì)靜態(tài)html文件的匹配。

結(jié)論

  • 前端url請(qǐng)求的絕對(duì)路徑是相對(duì)于host根目錄,后端url-pattern則是相對(duì)于web服務(wù)的根目錄
  • url-pattern無(wú)法簡(jiǎn)單排除所有的靜態(tài)html文件,同時(shí)servlet中也無(wú)法簡(jiǎn)單獲得相對(duì)于web服務(wù)根目錄的url請(qǐng)求路徑,因此用單個(gè)servlet處理所有請(qǐng)求并在內(nèi)部進(jìn)行分發(fā)的想法實(shí)現(xiàn)起來(lái)并不簡(jiǎn)單。解決辦法可以參考struts2。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 我們把富裕的客人叫做“豬仔”,一點(diǎn)點(diǎn)把他們胃口養(yǎng)大的過(guò)程叫“喂豬”??崎L(zhǎng)是我養(yǎng)過(guò)最肥的“豬仔”,二十天里,他刷完了...
    真實(shí)故事計(jì)劃閱讀 719評(píng)論 0 2
  • 今天的上午我上了第一節(jié)英語(yǔ)課,英語(yǔ)老師很厲害也很棒,老師讓我們做了個(gè)自我介紹并帶我們學(xué)習(xí)了加拿大和中國(guó)的不同,午餐...
    張瀚心閱讀 386評(píng)論 1 1
  • 時(shí)間過(guò)去了什么都不能留下,有些茫然,怕過(guò)的太快惘費(fèi)了大好時(shí)光,只留遺憾;怕過(guò)的太慢消遣了無(wú)聊虛度光陰,無(wú)所長(zhǎng)進(jìn)。 ...
    大嬸冷不丁閱讀 148評(píng)論 0 2

友情鏈接更多精彩內(nèi)容