Java Web開發入門 - 第3章 Tomcat

#Tomcat安裝與運行 Web服務器完成底層的網絡處理,包括HTTP協議報文格式的編解碼、管理具體web請求處理線程等操做。
Tomcat目前最流行最多見的基於Java的web應用服務器軟件。 ##Tomcat Apache Tomcat 官網html

  • Apache軟件基金會出品
  • 開源軟件
  • 源代碼是Java寫的 ##安裝
  • 依賴JDK,保證Java已經安裝
  • Tomcat 安裝
    • Windows平臺安裝
    • Linux和Mac平臺,下載壓縮包解壓運行
      配置環境變量CATALINA_HOME CATALINA是Tomcat的組成部分,CATALINA這個組件會調用用戶的Java代碼。在實際部署的某些狀況下是能夠不配置該環境變量。當一個服務器配置多個Tomcat的時候,這個環境變臉必須配置。

##Tomcat安裝過程 ###下載Tomcat 7.0.x 經過官網Tomcat 7 Software Downloads頁面,咱們能夠看到zip包。經過超級連接獲取7.0.77版本的zip下載路徑爲http://mirror.bit.edu.cn/apache/tomcat/tomcat-7/v7.0.70/bin/apache-tomcat-7.0.70.zip
若是Linux系統鏈接網絡,則能夠經過以下命令進行下載:java

wget http://mirror.bit.edu.cn/apache/tomcat/tomcat-7/v7.0.70/bin/apache-tomcat-7.0.70.zip

若是沒有聯網能夠在Windows下載Tomcat,經過FileZilla軟件發送安裝包到Linux ###解壓縮Tomcat Tomcat官網提供了兩種壓縮包zip和tar.gz方式。
Windows系統能夠下載7zip軟件或者WinRAR軟件進行解壓縮。
Linux系統zip方式解壓縮命令:linux

yum install unzip -y
unzip apache-tomcat-7.0.70.tar.gz

Linux系統tar.gz方式解壓縮命令:web

tar xzvf apache-tomcat-7.0.70.tar.gz

###配置CATALINA_HOME環境變量 ####Linux 進入解壓縮後的apache-tomcat-7.0.xx的目錄,在目錄下執行apache

export CATALINA_HOME=/home/zhanpeng/build/tomcat/apache-tomcat-7.0.70

經過echo $CATALINA_HOME檢查所配置的路徑是否正確。bootstrap

zhanpeng@GE70:~/build/tomcat/apache-tomcat-7.0.70$ echo $CATALINA_HOME
/home/zhanpeng/build/tomcat/apache-tomcat-7.0.70

####Windows設置環境變量windows

set CATALINA_HOME=D:\build\tomcat\apache-tomcat-7.0.70

檢查環境變量api

echo %CATALINA_HOME%

####Mac OS X設置環境變量 兩種配置方式:第一種全局配置,編輯/etc/profile,第二種只應用到當前用戶,編輯~/.bash_profile。若是要應用環境變量,則須要使用source /etc/profile或者source ~/.bash_profile進行啓用,或者從新登錄用戶或者重啓計算機。 ##啓動Tomcat瀏覽器

  • *nix平臺
    • $CATALINA_HOME/bin/startup.sh
    • $CATALINA_HOME/bin/catalina.sh start
  • Windows平臺
    • %CATALINA_HOME%\bin\startup.bat
    • %CATALINA_HOME%\bin\catalina.bat start

###演示linux tomcat啓動過程 ####1.檢查環境變量tomcat

zhanpeng@GE70:~/build/tomcat/apache-tomcat-7.0.70$ echo $CATALINA_HOME
/home/zhanpeng/build/tomcat/apache-tomcat-7.0.70

####2.修改Tomcat執行權限 若是解壓縮tomcat這個時候執行,則沒有權限

echo $CATALINA_HOME
$CATALINA_HOME/bin/startup.sh
bash: /home/zhanpeng/build/tomcat/apache-tomcat-7.0.70/bin/startup.sh: Permission denied

修改權限:

$chmod +x $CATALINA_HOME/bin/*

執行:

$CATALINA_HOME/bin/startup.sh
Using CATALINA_BASE:   /home/zhanpeng/build/tomcat/apache-tomcat-7.0.70
Using CATALINA_HOME:   /home/zhanpeng/build/tomcat/apache-tomcat-7.0.70
Using CATALINA_TMPDIR: /home/zhanpeng/build/tomcat/apache-tomcat-7.0.70/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /home/zhanpeng/build/tomcat/apache-tomcat-7.0.70/bin/bootstrap.jar:/home/zhanpeng/build/tomcat/apache-tomcat-7.0.70/bin/tomcat-juli.jar
Tomcat started.

經過瀏覽器查看到以下界面: 輸入圖片說明 經過瀏覽器進行查看 注意:若是不是本機打開瀏覽器訪問,遠程打開Tomcat,注意Linux或者Windows的防火牆配置,開發8080端口(若是修改Tomcat端口請自行注意)。若是對防火牆配置有問題,開發時能夠關閉防火牆,進行開發。

##Tomcat資源 靜態資源 動態資源,Servlet課程

##動態資源與靜態資源概念 ###目錄結構 輸入圖片說明 ###靜態資源SoybeanMilk.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>Soybean Milk</h1>
</body>
</html>

###動態資源NoodlesServlet.java 手動編譯在WEB-INF/classes/com.netease下 idea編譯在src/com.netease下編譯

package com.netease;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Created by zhanpeng on 16-8-20.
 */
public class NoodlesServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException {

        PrintWriter writer = response.getWriter();

        String vegetable = request.getParameter("vegetable");

        if(vegetable == null)
            vegetable = "Tomato";

        writer.println("<html><body>");
        writer.println("<h1> Noodles with " + vegetable + "</h1>");
        writer.println("</html></body>");
    }
}

###添加servlet到web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    
    <display-name>Restaurant</display-name>
    <servlet>
        <servlet-name>noodles</servlet-name>
        <servlet-class>com.netease.NoodlesServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>noodles</servlet-name>
        <url-pattern>/noodles</url-pattern>
    </servlet-mapping>
</web-app>

###編譯或者添加tomcat類庫運行 ####手動編譯

javac -cp /home/zhanpeng/build/tomcat/apache-tomcat-7.0.70/lib/servlet-api.jar WEB-INF/classes/com/netease/NoodlesServlet.java

####添加tomcat類庫 輸入圖片說明 ###靜態資源

http://localhost:8080/SoybeanMilk.html

無論咱們如何加入參數,頁面不變
咱們事先準備好的,叫作靜態資源,靜態資源像圖片常見的文檔。 ###動態資源

http://localhost:8080/noodles

顯示Noodles with Tomato

http://localhost:8080/noodles?vegetable=Apple

顯示Noodles with Apple
動態頁面根據咱們參數的不一樣,會顯示不一樣內容頁面。根據不一樣的請求返回不一樣結果。

##關閉Tomcat

  • *nix平臺
    • $CATALINA_HOME/bin/shutdown.sh
    • $CATALINA_HOME/bin/catalina.sh stop
  • Windows平臺
    • %CATALINA_HOME%\bin\shutdown.bat
    • %CATALINA_HOME%\bin\catalina.bat stop

#Tomcat的組成、架構與配置部署 ##Tomcat目錄結構 輸入圖片說明

  • bin 目錄:用於存放tomcat執行腳本,例如啓動關閉,同時還提供腳本依賴的包
  • conf 目錄:放置tomcat配置文件
  • lib目錄:存放tomcat的依賴庫,也能夠把共同依賴包放到這裏
  • logs 目錄:存放log日誌
  • temp 目錄:存放臨時文件。web應用產生的臨時文件
  • webapps目錄:默認的應用部署目錄
  • work目錄:tomcat運行的 供web應用使用。
  • LICENSE許可證文件

###bin目錄 輸入圖片說明

####啓動腳本 JVM啓動參數配置:可使用環境變量

  • 環境變量JAVA_OPTS配置
  • *常見參數 -server -Xms512m -Xmx512m -server告訴JVM這個是服務,由JVM以server的方式進行優化 -Xms -Xmx是設置JVM的堆大小 -Xms設置初始堆 -Xmx設置堆最大值
export JAVA_OPTS="-server =xms2048m -Xmx2048m"
echo $JAVA_OPTS

若是想要永久有效須要寫入到~/.bashrc下 ###conf目錄 輸入圖片說明 最主要的配置文件爲server.xml ####server.xml server.xml結構

<?xml version='1.0' encoding='utf-8'?>
<Server >
    <Listener></Listener>

    <Service name="Catalina">
        <Connector></Connector>
        <Connector></Connector>
        <Engine>
            <Host>
                <Context></Context>
            </Host>
        </Engine>
    </Service>
</Server>

Server下面能夠有多個Service和多個Connector。一個Service必須有一個Engine,Engine是處理Connector接收到的數據內容。JDK的java由Engine執行。Engine裏面有多個Host,Host是虛擬主機,請求加入不一樣的Host頭,跳轉到。一個Host能夠有多個Context。Context爲Web應用。 service咱們叫作Container(容器)。整個Server就是Tomcat。

  • Connector
    • Coyote
    • 默認使用BIO Connector,使用Java IO進行處理,阻塞式IO
  • Container
    • Catalina實現容器的組件
    • Servlet課程

##請求處理流程 瀏覽器發送請求,由Connector接收處理socket數據信息。Container根據Connector解析內容生成具體的響應。 輸入圖片說明

#Tomcat的Connector及線程池配置 ##Connector參數配置

  • port端口號
  • address配置Connector監聽哪幾個IP地址的響應
  • protocol默認爲protocol="HTTP/1.1",涉及調優才進行調整
  • connectionTimeout服務端當鏈接佔用不發送請求的關閉時間,單位ms
  • acceptCount指系統繁忙,若是沒有空閒線程,則配置隊列長隊,默認值爲100。若是超過承載數則拒絕鏈接(沒有在默認文檔中找到)
  • maxConnections默認最大鏈接數,當使用的是默認的BIO Connector時,最大鏈接數是和線程池最大值。爲-1時,不限制鏈接。 ##線程池 事先建立必定數據的線程,當有任務時,從線程池中取出,當用完後在釋放回鏈接池內。
  • 最小空閒線程數minSpareThreads
  • 最大線程數maxThreads 當請求處理數小於最小空閒線程數時,使用最小空閒線程。當超過期,動態增長線程數據直到到達最大線程數。當請求處理結束,自動釋放資源,則稱彈性線程池。Tomcat使用的就是彈性線程池。
    ##配置 修改apache-tomcat-x.0.xx/conf/server.xml 修改默認端口和過時時間
<Connector port="8181" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

默認沒有配置線程池,配置中被註釋掉了

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>

應用Connector應用Executor,注意要和Executor name相同

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               executor="tomcatThreadPool"
               redirectPort="8443" />

重啓Tomcat,查看效果。 命令查看請求:

curl http://localhost:8080/noodles
<html><body>
<h1> Noodles with Tomato</h1>
</html></body>

命令佔用請求:
客戶端0:

telnet localhost 8181
GET /noodles HTTP/1.1

客戶端1:

telnet localhost 8181
GET /noodles HTTP/1.1

當線程池爲1時,客戶端0阻塞線程,則客戶端1都沒法獲取結果;客戶端0結束,客戶端1也會執行完成。 ##線程池配置 *Executor配置線程池

    • minSpareThreads
    • maxThreads
  • Connector配置線程池
    • 制定依賴的線程池配置
    • 直接制定線程池配置參數
      • minSpareThreads、maxThreads 當Connector及配置Executor也配置線程池參數,則使用Executor配置。

#Tomcat日誌配置與war包部署 ##Tomcat日誌 服務發生中斷,則須要知道

  • 日誌的做用
    • Tomcat運行狀況獲知
    • 調試利器
  • Tomcat日誌分類
    • 系統運行日誌 - 捕獲Tomcat系統錯誤
    • 訪問日誌 - 記錄用戶請求的訪問,根據日誌統計一共有多少次請求
    • 應用日誌 - 程序日誌

###訪問日誌配置文件server.xml

<!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

###修改日誌文件命名 ####日誌實現AccessLogValve ####direcory Valve的directory日誌存放目錄 ####pattern prefix日誌文件的前綴 ####suffix suffix日誌文件的後綴 ####pattern pattern指日誌的格式。
pattern內%r指HTTP 請求行;%s HTTP相應號;%t訪問時間;%m請求方法,%a請求的IP地址;%s用戶響應碼;%b服務端下發多少字節;%{User-Agent}i指User-Agent;&quot;

###日誌文件切割

fileDateFormat="yyyy-MM-dd.HH." #按照參數進行切割
               rotatable="true" #是否切分

修改後的日誌配置

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="hava_access_log." suffix=".log"
               fileDateFormat="yyyy-MM-dd.HH."
               rotatable="true"
               pattern="method: %m,client ip: %a,time: %t,&quot;%r&quot; statusCode: %s,byteSent: %b,User-Agent: %{User-Agent}i" />

重啓Tomcat後,產生日誌文件hava_access_log.2016-08-20.14.35.log,Chrome訪問內容爲:

method: GET,client ip: 127.0.0.1,time: [20/Aug/2016:14:36:30 +0800],"GET / HTTP/1.1" statusCode: 200,byteSent: 11418,User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36

curl訪問內容爲:

method: GET,client ip: 127.0.0.1,time: [20/Aug/2016:14:37:43 +0800],"GET / HTTP/1.1" statusCode: 200,byteSent: 11418,User-Agent: curl/7.35.0

##Tomcat文檔 Tomcat 7 文檔

##Tomcat部署Web應用

  • Web應用程序結構
    • Servlet課程
  • 手動部署
  • 打war包,Web應用打war包,方便程序共享 ###手動打包 在idea的輸出目錄out內,能夠看到war_exploded目錄,經過jar cvf package.war .進行打包
jar cvf Restaurant.war .
added manifest
adding: SoybeanMilk.html(in = 143) (out= 110)(deflated 23%)
adding: index.jsp(in = 295) (out= 224)(deflated 24%)
adding: WEB-INF/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/com/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/com/netease/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/com/netease/NoodlesServlet.class(in = 1371) (out= 687)(deflated 49%)
adding: WEB-INF/web.xml(in = 632) (out= 270)(deflated 57%)
zhanpeng@GE70:~/Workspace/J2ee/TomcatStudy/out/artifacts/TomcatStudy_war_exploded$

注意:這種方式會把隱藏文件也打包到war包內。 把war包放到webapps目錄下,能夠直接訪問。Tomcat會自動解壓縮war包內容。 #附錄 ##Tomcat FAQ ###Q:Tomcat使用哪一個版本的?
A: 目前Tomcat最新開發版是9.0.x,最新穩定版是8.0.x,通常在生產環境使用比較多的版本仍是7.0.x。本微專業選擇的Tomcat版本是7.0.x。更新的版本之間不過是實現了更多的一些新特性,咱們的微專業中並無涉及到這些新特性,所以7.0.x是足夠的

###Q: 我在Windows下,Tomcat怎麼安裝以及使用?
A:

  1. 由於Java是跨平臺的,所以,在Windows下同樣可使用視頻中講述的方式進行安裝,而後經過命令行的方式來啓動中止Tomcat
  2. 針對於Windows,Tomcat還提供了更簡單的方式,你們能夠直接下載Tomcat的Windows Installer,http://tomcat.apache.org/download-70.cgi, 在這個頁面上下載Windows Service Installer這個,而後直接雙擊安裝就行了,同時這個Installer還爲你們提供了一個圖形界面的工具,能夠完成Tomcat的配置、啓動以及中止
  3. 在Windows vista之後的Windows版本中,因爲增長了UAC,所以在雙擊Tomcat的安裝文件的時候,可能須要提供管理員權限,具體操做爲右鍵,選擇使用管理員權限運行

###Q: 我徹底不會Linux,在windows下,跟老師的演示環境不同,怎麼辦?
A:

  1. Java語言是跨平臺的,Tomcat也是跨平臺的,不管是在windows,仍是在Linux下,他們的使用方法,命令行參數含義等等都是一致的
  2. 即便是在linux操做,也無非是創建新文件,創建文件夾,手寫點代碼而已,使用的都是一些簡單的命令。在Windows下同樣可使用鼠標點擊完成創建新文件,創建文件夾等操做,你可使用記事本,notepad++等等,任意一款編輯器寫代碼。
  3. 對於Tomcat的啓動中止,同樣能夠不用命令行,Windows提供了經過Windows Service Installer進行安裝的方式,能夠經過圖形界面進行Tomcat的啓動中止操做
  4. 建議你們稍微學習一點Linux操做,這是做爲一個服務端開發者的基本技能,任何知識都是從不會到會的

###Q: 我都跟老師作的同樣,爲何出錯了?
A: 當你們遇到錯誤的時候,但願能按下面給出的步驟進行排查

  1. 做爲初學者,你們最常遇到的問題就是拼寫錯誤,所以首先檢查有沒有出現拼寫錯誤。
  2. 若是沒查出來錯誤,先嚐試去理解報錯來的錯誤信息,通常狀況下,錯誤信息中都會給出解決建議
  3. 藉助搜索引擎,貼出報錯信息,搜索解決方案,stackoverflow之類的網站上,每每就有你要的解決方案
  4. 實在搞不定,到論壇上看看有沒有同窗已經遇到了相似的問題,而且已經有了解決方案
  5. 到論壇發帖,或直接經過郵件等方式將問題發給老師 在實際工做中,遇到問題解決問題是一個比較重要的能力。所以在學習過程當中,就要有意識地去提升本身這方面的能力。咱們不但願你們一旦遇到問題就當即提問,由於在實際工做中,你的提問是不會有人給你回答的。你們能夠先嚐試解決,在嘗試解決問題的過程當中,每每你們也能學到一些其餘方面的知識。當實在搞不定的時候,再告訴老師,咱們會在第一時間爲你們解答。

###Q: 經過一些書和其餘教程,我學會了在eclipse中直接建立一個Web項目,跟這裏純手動建立一個web項目相比有一些疑問:

  1. eclipse 默認建立tomcat7的項目裏面並無web.xml文件,那麼tomcat是如何找到相關servlet的?
  2. 經過eclipse建立的項目中會有一個叫WebContent的目錄,這個和咱們純手動建立的Restaurant項目有何不一樣?
  3. 爲何將eclipse建立的項目手動拷貝到tomcat7.0.x下webapps目錄下,啓動後沒法訪問裏面的servlet?我應該如何訪問這個servlet?

A:

  1. eclipse 默認建立tomcat7的項目裏面並無web.xml文件,那麼tomcat是如何找到相關servlet的? 若是沒有servlet,僅僅是jsp加上靜態文件的話,web.xml是能夠省略的 即便生成了servlet,在新的servlet規範裏面,也支持了使用Annotation的方式來配置servlet,跟使用web.xml的方式是等價的 你看一下生成的類上面應該有 @WebServlet 的定義

  2. 經過eclipse建立的項目中會有一個叫WebContent的目錄,這個和咱們手動建立的Restaurant項目有何不一樣? 源碼層面的文件結構能夠千差萬別,可是最終部署的時候,項目文件結構必須知足servlet規範。只是eclipse默認建立的項目是這樣作的而已,eclipse默認建立的項目跟咱們手動建立的Restaurant項目沒有啥本質不一樣。後面咱們還會講到Maven,讓Maven來管理咱們的Web項目,他們最終編譯打包後的文件結構是同樣的。

  3. 爲何將eclipse建立的項目手動拷到tomcat7.0.65下webapps目錄下,啓動後 沒法訪問裏面的servlet 我應該如何訪問這個servlet? 估計你是搞混了源碼跟編譯打包後的二進制。你把eclipse建立的項目編譯後打成一個war包,而後把這個war包放到webapps目錄下,就能夠跑了 另外,war包自己是一個zip格式的壓縮包,你能夠把它解壓開,而後看一下里面的內容,以及裏面的文件結構,跟咱們Restaurant的文件結構必定是一致的,全部這一切工做都是eclipse在背後默默幫你完成了 咱們在Restaurant裏面,只是把這一切都純手動化了,爲了是讓你們真正地明白一個Web項目在部署的時候長什麼樣子,而不是簡單地告訴你怎樣在IDE裏面作

###Q: 我使用了網易蜂巢提供的Java Web鏡像,裏面的安裝的tomcat7的目錄結構怎麼找不到? A: 咱們在網易蜂巢提供的Java Web鏡像,其是一個Debian系統,裏面的tomcat7是使用包管理工具apt-get/aptitude 進行安裝管理的。Debian在打包tomcat7的時候,遵循了其系統的管理,那就是對任何一個軟件,其不一樣的功能的文件會分到不一樣的目錄中,對於tomcat7,具體對應以下:
bin -> /usr/share/tomcat7/bin
lib -> /usr/share/tomcat7/lib
conf -> /var/lib/tomcat7/conf
webapps -> /var/lib/tomcat7/webapps
logs -> /var/lib/tomcat7/logs
work -> /var/lib/tomcat7/work

對於啓動/中止 tomcat,請直接使用已經封裝好的服務方式,使用的命令爲

service tomcat7 start service tomcat7 stop

想看運行狀態,可使用命令

service tomcat7 status

###Q: 我運行Tomcat報錯,Class com.netease.NoodlesServlet is not a Servlet,怎麼辦? A: 不少同窗會納悶,個人類明明是從HttpServlet繼承下來的,怎麼就不是Servlet了。這個是由於JVM在肯定一個類的時候,不只僅根據這個類的名字,還有加載這個類的類加載器,只有這兩個都一致的時候,才認爲是同一個類。因爲在JVM在不一樣的加載階段使用不一樣的類加載器,Tomcat內部也實現了本身的類加載器,形成這個問題的緣由就是類加載器衝突形成的。解決方案以下:

  1. 確認一下在pom.xml配置的javax.servlet-api這個依賴的scope是provided
  2. 確認沒有把servlet-api.jar 這個文件放到 java的 lib/ext目錄下,若是有放置,刪除掉
  3. 確認一下有沒有配CLASSPATH環境變量,而且CLASSPATH中有指向servlet-api.jar這個文件。若是有配置,清除掉
  4. 因爲這類錯誤還有依賴版本不統一,原來安裝的一些軟件遺留等緣由形成,雖然表現出來的症狀同樣,可是實際狀況可能比上面說出來的狀況還要多一些。在搞不定的時候,能夠嘗試重裝大法,重裝你的JDK
  5. 關於類加載器以及Java的一些路徑的知識,能夠參考這篇文章http://www.ibm.com/developerworks/cn/java/j-classpath-windows/, 裏面有一句話「強烈建議您在編譯和運行時老是顯式地指定類路徑」,這個也是爲何在演示編譯的時候,是經過指定-cp(與-classpath等價)參數,而不是經過其餘方式,引入對servlet-api.jar的依賴
相關文章
相關標籤/搜索