用 Servlet 來寫一個 Hello World~
- 一 . 基本部署方式
- 1.1 創建 Servlet 項目
- 1.2 引入依賴
- 1.3 創建目錄
- 1.4 編寫代碼
- 繼承 HttpServlet
- 重寫 doGet 方法
- 刪除 super 方法
- 加上 @WebServlet 注解
- 寫業務邏輯
- 1.5 打包
- 1.6 部署
- 1.7 驗證
- 1.8 小結
- 二 . 更方便的部署方式
- 2.1 Smart Tomcat 的安裝
- 2.2 Smart Tomcat 的配置
- 2.3 Smart Tomcat 的使用
- 2.4 Smart Tomcat 的原理
- 三 . 常見錯誤
- 3.1 404
- 3.2 405
- 3.3 500
- 3.4 返回空白頁面
- 3.5 無法訪問此網站
- 3.6 返回中文亂碼
- 四 . 擴展 : 什么是 JSP ?
Hello , 大家好 , 今天給大家帶來的是我們 Java 當中最基礎的框架 : Servlet , 那 Servlet 最核心的作用就是用來制作網頁端的程序 , 我們通過學習 Servlet 的語法以及相關 API , 就可以寫出一些網頁程序 .
那這個階段的程序與之前學習的單機程序不同 , 難度上也加大了 , 代碼的題量也更大了 , 這就要求大家跟進腳步 , 不要掉隊 , 以練帶學 !
博主這篇文章主要給大家講解一下 怎樣創建一個 Servlet 程序并且寫出第一個 Servlet 版本的 Hello World
那希望大家跟緊步伐 , 站穩腳跟 !
大家也可以訂閱 JavaWeb 專欄 , 點擊即可跳轉
準備好 , 我們要開始發車了 !
一 . 基本部署方式
1.1 創建 Servlet 項目
這樣就成功創建一個 Servlet 程序了
那么 , 我們首先需要了解我們創建的 Maven 是用來干什么的?
Maven 是一個構建工具 , 我們主要用它來進行依賴管理以及打包 .
我們首次使用 Maven , 可能會出現問題 .
由于 Maven 有很多依賴 , 需要通過網絡來加載 , 而 Maven 的服務器是在國外 , 所以咱們下載速度會有點慢 , 30min~1h 都是正常現象
像這種情況 , 就是在下載依賴
另外 , 其實如果真的下載特別慢 , 可以去嘗試修改一下鏡像源為國內的鏡像源 . 但是輕易不要更改 , 很有可能就改壞了 , 那就不好整了
那么我們來看一下 Servlet 程序的基本構成吧
1.2 引入依賴
我們剛才不是提到了依賴了嗎 , Maven 里面自己就有依賴啊 ? 咋還導入呢?
我們這里引入的依賴 , 是寫 Servlet 程序 , 需要的依賴 , 也就是 Servlet 的 jar 包
我們需要把 jar 包下載導入到項目中
我們之前學習 JDBC 的時候 , 就手動導入過依賴 , 假如依賴比較少 , 我們可以手動導入 , 那依賴要是很多呢?
我們的 Maven 就可以幫我們自動下載 , 然后導入依賴
那么怎么弄呢 ?
我們先要去 Maven中央倉庫 下載
https://mvnrepository.com/
剛開始進去會有驗證 , 驗證一下就可以了
進來之后就是這樣 , 然后搜索 Servlet 即可
往下翻 , 找到 3.1.0 (劃重點)
我們使用的是 JDK 8 , Tomcat 8.5 , Servlet 3.1 ,這個搭配就是 Tomcat 官方推薦的 , 放心使用
點擊之后 , 下面就有個 Maven , 復制下來
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope>
</dependency>
接下來回到我們的 IDEA , 點擊 pom.xml , 在 里面寫 標簽 , 然后把剛才復制過來的粘貼進去
如果以后還有依賴 , 放在 標簽里面就行了
由于我們是第一次使用 , 他爆紅了 , 沒關系. 他會在中央倉庫下載依賴 , 需要一定時間.
如果沒有自動下載的話 , 我們還可以手動刷新一下
點擊右側的Maven
點擊圓圈按鈕
這樣的話 , Maven 就會重新刷新 , 就會繼續下載需要的依賴
1.3 創建目錄
右鍵 main -> New -> Directory
輸入 webapp
右鍵 webapp -> New -> Directory
輸入 WEB-INF
然后右鍵 WEB-INF -> New -> File
名字叫做 web.xml
完事之后就是這個效果
webapp -> WEN-INF -> web.xml
那么這個 web.xml 也不能空著啊 , 現在空著就報錯了
那么我們復制進去這段代碼
<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app><display-name>Archetype Created Web Application</display-name>
</web-app>
有的人這里是標紅的 , 那也沒事.
其實是 IDEA 慣的咱們 , 標紅就會認為出錯了 . 其實不然 , IDEA 只對 .java 程序特別敏感
在 xml 文件中 , 就很容易出現誤報的現象
那么這段代碼是什么意思呢 , 我們不需要知道 , 我們只需要知道 tomcat 加載你自己寫的程序 , 就會先來讀取 web.xml 里面的內容 , 具體讀取什么咱們不用管
1.4 編寫代碼
先創建 Java 文件
我們的 HelloWorld 程序已經創建好了 , 就長這個樣子
接下來 , 我們需要修改以及增加一些東西
繼承 HttpServlet
import javax.servlet.http.HttpServlet;public class HelloWorld extends HttpServlet {
}
我們需要讓程序繼承 HttpServlet
如果發現 HttpServlet 類提示不出來 , 或者手動輸入后標紅了 , 那就去檢查一下剛才的 pom.xml 里面引入的依賴是否成功
未成功的話點擊旁邊的Maven , 然后上面有個刷新按鈕
那么這個 HttpServlet 就來自于我們剛才通過 pom.xml , 基于 Maven 從中央倉庫導入的 jar 包
重寫 doGet 方法
接下來 , 我們在 HelloWorld 類中重寫 doGet 方法
具體如下圖
然后代碼就變成了這個樣子
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class HelloWorld extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {super.doGet(req, resp);}
}
我們來仔細琢磨琢磨這個 doGet 方法
刪除 super 方法
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class HelloWorld extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//把自動生成的super()方法一定要刪除掉或者注釋掉,不然會有問題//super.doGet(req, resp);}
}
加上 @WebServlet 注解
在完成 doGet 方法之后 , 千萬不要忘記在類的上面加上 @WebServlet 注解
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;//這個位置:前面一定要加/,后面一定不要加/,有一個位置出錯,就會報錯
@WebServlet("/hello")
public class HelloWorld extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//把自動生成的super()方法一定要刪除掉或者注釋掉,不然會有問題//super.doGet(req, resp);}
}
這個注解其實就是約定了 HTTP 請求 里面的 URL 里面的 Content-Path 是什么樣的 , 才能調用當前這個 Servlet 類
比如 : Tomcat 收到的請求有很多種
- GET /aaa 不會觸發上面的 doGet 方法 , 因為Path不同
- GET /bbb 不會觸發上面的 doGet 方法 , 因為Path不同
- GET /hello 觸發 doGet 方法
- POST /hello 不會觸發上面的 doGet 方法 , 因為這個是 POST 請求
所以不是所有的 GET 請求都會觸發上面的 doGet 方法 , 只有特定的路徑的請求 , 才會觸發
根據請求的路徑 , 找到對應的類 , 在調用其對應的 doXXX 方法 , 這個過程就是"路由"
路由 : 根據不同的路徑 , 找到不同的要執行的代碼
那么上面的代碼我們發現 , 并沒有主方法 (main 方法)
我們之前說 : Java 程序的入口是 main 方法 , 那上面的代碼他也沒 main 方法 , 那不是執行不了嗎 ? 那我們寫他干嘛?
實際上 , 我們的 Servlet 程序是通過 Tomcat 運行的 , 我們可以看作 main 方法是在 Tomcat 里面的 . 所以我們需要部署到 Tomcat 里面才能去運行.
寫業務邏輯
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/hello")
public class HelloWorld extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//把自動生成的super()方法一定要刪除掉或者注釋掉,不然會有問題//super.doGet(req, resp);//這條語句是打印到服務器的控制臺上//也就是打印到 IDEA 的控制臺上 System.out.println("hello");//這條語句才是添加到響應報文中,顯示在頁面上//就是把"hello world"作為響應報文的body部分了,瀏覽器就把這個body顯示到頁面上了resp.getWriter().write("hello world");}
}
1.5 打包
打包操作十分簡單 , 可以通過 Maven 一鍵式完成
右邊的 Maven -> ServletDemo1 -> Lifecycle -> package
右鍵 Run 或者 雙擊即可進行打包操作
看到BUILD SUCCESS字樣就打包成功了 , 打包失敗的話會有報錯信息
我們來分析一下右邊結構
我們再看 , 這里生成的是 jar 包 , 雖然 jar 包是 Java 語言里面最通用的壓縮包 , 但是 Tomcat 就隔路 , 它能識別的是一個 war 包 , 并不支持 jar 包
所以我們還需要去設置一下
打開 pom.xml
在這個位置輸入以下代碼
<packaging>war</packaging>
<build><finalName>Hello_servlet</finalName>
</build>
這個 finalName 同時也是我們在瀏覽器中輸入 URL 的一部分
注意這兩個標簽的位置不要寫錯 , 在的上邊
接下來我們重新打包 , 我們就可以看到 war 包生成成功了
我們還可以在文件資源管理器里面查看
1.6 部署
我們把剛才生成的 war 包 , 拷貝到 Tomcat 里面的 webapps 目錄中
實際上 , 部署就是復制粘貼 , 說得好聽其實啥也不是
接下來 , 啟動 Tomcat
還是正常的一堆亂碼 , 但是我們往上翻翻 , 就會發現一些蛛絲馬跡
意思就是 Tomcat 發現了這個 war 包 , 對他進行解壓以及加載了
我們再回到 webapps 目錄里面 , 發現 Hello_Servlet 已經被解壓了
1.7 驗證
我們已經把程序部署在 Tomcat 上了 , 我們接下來可以檢驗一下了
在瀏覽器輸入
127.0.0.1:8080/Hello_servlet/hello
我們可以看到 , 已經完美運行了
然后我們來分析一下我們剛剛輸入的東西吧
一般情況下 , 訪問 Servlet 程序對應的路徑 , 一般是兩級路徑 , 但是也不絕對
第一級路徑 Context-Path 代表當前的 webapp(網站)
一個 Tomcat 上面是可以同時部署多個 webapp (網站)的 , Tomcat 路徑底下的 webapps 目錄下的每個目錄實際上都是一個 webapp (網站)
有的資料也把 Tomcat 叫做 “容器” , 意思就是能容納多個 webapp
那么一般情況下 ,我們的 Context-Path 怎么確定 ?
- 如果是通過 startup.bat 啟動的 , 那么他的 Context-Path 就是 webapps 目錄底下的 war 包 (目錄名)
- 如果是通過 Smart Tomcat 啟動的 (稍后介紹) , 那么他的 Context-Path 就是配置啟動項的時候那個 Context-Path
第二級路徑就是 ServletPath , 是根據代碼中的 @WebServlet(“/”) 來確定的 , 或者是 webapp下面的靜態文件/目錄
比如 : 我們在 webapp 路徑下面創建個 css 文件夾 , 里面創建個文件 style.css
運行 Smart Tomcat , 我們輸入 URL
127.0.0.1:8080/MessageWall/css/style.css
什么都沒有 , 是因為我們的 CSS 文件沒寫任何代碼那么我們剛開始學習 , 可能會出現以下幾種情況情況
情況 1 :
404 代表資源 not found 了 , 意思是對應資源要么沒找到 , 要么丟了
遇見 404 , 我們首先要做的就是排查路徑是否正確
上面的就是因為 Hello_Servlet 寫成 hello_Servlet 了
情況 2 :
這種情況就是 Tomcat 沒啟動 , 啟動之后再次試一下就好了
目前為止 , 我們已經把 Tomcat 的創建講解完了 , 我們還需要注意以下幾個問題
問題 1 : Tomcat 已經啟動的狀態下 , 啟動一個新的 , 就會被重新分配一個端口號 , 新啟動的 Tomcat 端口號就不一定是 8080 了
一個端口號 , 只能被一個進程綁定
問題 2 : 我已經部署完了 , 之后我又更新了代碼 , 那回到瀏覽器刷新怎么還是不變的 ?
這個時候我們就需要重新打包部署 , 不然怎么刷新頁面都沒用
1.8 小結
- 創建項目 : Maven 項目
- 引入依賴 : Servlet 對應的依賴
- 創建目錄 : webapp -> WEB-INF -> web.xml
- 編寫代碼 :
a. 繼承 HttpServlet 類
b. 重寫 doGet 方法
c. 加上 @WebServlet 注解 - 打包程序 : 使用 Maven 提供的 package , 然后還需要修改 pom.xml , 通過 packing 標簽設置打包類型為 war , 通過 finalName 屬性設置包名
- 部署程序 : 把 war 包拷貝到 Tomcat 里面的 webapps 目錄里面 , 然后重啟 Tomcat 服務器
- 驗證程序 : 通過瀏覽器構造 HTTP 請求 , 訪問 Tomcat 服務器
URL 路徑 = Context Path(war 包的名字) + Servlet Path(注解里面的路徑)
如果后續代碼發生改變 , 那么必須要重新進行5 ~ 7 操作
開發環境 VS 運行環境
開發環境 : 寫代碼的環境 , 對應的是項目目錄
運行環境 : 運行程序的環境 , 對應的是 Tomcat 目錄
直接修改代碼 , 只是針對開發環境進行了修改 , 我們只有重新進行打包 -> 部署 , 才能在運行環境生效
二 . 更方便的部署方式
那么我們可以借助 IDEA 里面的一個插件 : Smart Tomcat , 它可以幫助我們進行打包和部署
那么我教大家怎么進行安裝
2.1 Smart Tomcat 的安裝
-
File -> Settings
-
在 Plugins 里面搜索 Smart Tomcat , 點擊 Install
這樣 , 我們的 Smart Tomcat 就安裝好了
我們還可以通過網頁進行下載 , 然后拖入到 IDEA 里面
https://plugins.jetbrains.com/plugin/9492-smart-tomcat
那么安裝完了 Smart Tomcat , 我們怎么來使用呢?
2.2 Smart Tomcat 的配置
第一步 : 點擊 Add Configuration
第二步 : 點擊加號 , 然后選擇 Smart Tomcat
第三步 :
配置 tomcat 的路徑不用進入到 bin 目錄
點擊 Tomcat server 右邊的 Configure
選擇 Tomcat 的路徑 , 然后OK
這就 OK 了
2.3 Smart Tomcat 的使用
點擊這里的綠色三角號 , 編譯打包部署程序 , 并且運行 Tomcat
我們看到底下紅彤彤的 , 就是成功了
要看到底下的 startup in xxx ms 這種字樣 , 才算成功
但是我們之前的 Tomcat 不是彈出來一個黑框框嗎 , 所以這就是這個插件的厲害之處 , 把黑框框集成在 IDEA 里面了 , 而且沒有亂碼了!
我們再去驗證一下
成功了
要注意的是 , Content Path 要保持一致 , 我們之前說過 finalName 就是 Content Path , 我們之前設過的 Content Path 是 Hello_servlet ,而 Smart Tomcat 里面是 /ServletDemo1 , 所以要修改一下才能成功
但是我們不寫 finalName 就不會有這種問題
2.4 Smart Tomcat 的原理
Smart Tomcat 是運行 Tomcat 的時候 , 通過其他手段 , 讓 Tomcat 直接加載了咱們的代碼當中的 webapp 目錄 , 這個時候跳過了打包+拷貝的過程 , 也起到了部署的效果 .
我們之前通過 startup.bat 運行 Tomcat , 運行的是 他目錄底下的 webapps , webapps 里面有很多目錄 , 他的每一個子目錄都是一個 webapp , 也就是一個個小的網站 . 我們通過 startup.bat 啟動 , 其實是加載了所有的 webapp , 那么 Smart Tomcat 只是運行了咱們 IDEA 項目對應的 webapp (也就是咱們自己的 webapp 目錄) .
三 . 常見錯誤
3.1 404
大概率是 URL 寫錯了 , 也有可能是 webapp 沒有正確加載(比如 : web.xml 寫錯了 , Smart Tomcat 里面的 Content Path 與 URL 不匹配、finalName 與 URL 中的 Content-Path 不匹配等)
3.2 405
method not allowed
比如 : 請求是 Get , 但是我們沒實現 doGet , 就會405
或者寫了 doGet , 但是沒把 super.doGet(); 刪掉 , 也會405
就會產生未知情況的 405
3.3 500
服務器內部錯誤 , 也就是服務器掛了
可能是代碼拋異常了
3.4 返回空白頁面
應該是忘記寫 write 方法了
3.5 無法訪問此網站
沒啟動 Tomcat
3.6 返回中文亂碼
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/hello")
public class HelloWorld extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().write("你好世界");}
}
當服務器返回的數據是中文的時候 , 此時我們的頁面上就會出現亂碼
這是因為我們的 IDEA 指定的默認字符是 utf8 , 而瀏覽器解析字符的時候 , 默認跟操作系統一致 , 我們大多數人都是 windows 簡體中文版 , 默認編碼是 GBK , 那么瀏覽器按 GBK 解析 , 必然會出錯 , 所以我們要讓瀏覽器按照 utf8 的解析方式來進行解碼
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/hello")
public class HelloWorld extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//加上這句代碼resp.setContentType("text/html;charset=utf8");resp.getWriter().write("你好世界");}
}
我們再次運行 , 這次就成功了
那么這條語句加的位置也是大有講究 , 那我加在輸出語句后面可不可以 ?
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/hello")
public class HelloWorld extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().write("你好世界");//把這句代碼加到了輸入語句后面resp.setContentType("text/html;charset=utf8");}
}
又亂碼了 , 所以大家記得必須要保證構造響應的 header 要在構造 body 之前 , 否則 header 不生效
讓瀏覽器按照 utf8 的解析方式來進行解碼 這條語句其實就是在更改header .
resp.getWriter().write(“你好世界”); 這條語句其實就是通過構造body , 讓瀏覽器返回 body 的內容
我們來看一下
這是在沒有指定字符集之前 , 抓包的結果
那么我們指定字符集之后 , 我們發現 字符集被設置成功了 , 而且我們的"你好世界"也完美被打印了
四 . 擴展 : 什么是 JSP ?
我們有的同學會在學校學到 JSP 這種東西 , 那 JSP 到底是什么 , 他跟 Servlet 又有什么關系
JSP 可以認為是 Servlet 的一部分 , 在 200x 年很常用 , 但是現在已經退出歷史舞臺了
我們之前講過靜態頁面和動態頁面
靜態頁面就是內容始終固定的頁面 , 即使用戶不同/時間不同/輸入的參數不同 , 頁面內容也不會發生變化
比如我們的 Tomcat 歡迎頁就是一個靜態頁面
動態頁面就是隨著用戶輸入的不同 , 頁面呈現出來的效果也不同
比如我們搜索 鮮花 和 蛋糕 這兩個關鍵字
我們輸入不同的關鍵字 , 顯示出來的是不同的頁面 , 那么我們的 JSP 就是專門用來做動態頁面的
制作動態頁面的方式基本有兩種 :
- 客戶端渲染 : 服務器返回數據 , 由頁面通過 js 來生成對應的界面
- 服務器渲染 : 服務器直接組裝好完整的 html , 直接返回給瀏覽器
由于我們現在普遍的工作方式都是前后端交互 , 大家各干各的事 , 我們不需要考慮具體的頁面 , 所以 jsp 慢慢的就退出歷史舞臺了 , 而且即使我們使用服務器渲染的方式 , 那么我們也有更好的模板引擎 , jsp 就更沒優勢了