目錄
Tomcat
Servlet的工作
創(chuàng)建Servlet
①項目
②依賴?
③目錄?
④代碼
⑤打包
⑥部署
⑦驗證
Servlet的運行原理
Servlet API
HttpServlet
方法
處理Get/POST請求?
HttpServletRequest
方法
獲取請求中的信息?
獲取GET請求中的參數(shù)
獲取POST請求中的參數(shù)
FORM表格形式
JSON形式
方法一:
方法二:
HttpServletResponse?
Servlet是一種由Tomcat提供的開發(fā)動態(tài)頁面的技術(shù)
動態(tài)頁面指的就是,能夠根據(jù)用戶給予參數(shù)的不同,返回不同頁面的效果.
Tomcat
Tomcat是一個HTTP服務器.我們可以將程序部署到其中的webapps目錄下,就可以通過Tomcat服務器對其進行訪問.
Tomcat8的下載??:Apache Tomcat? - Apache Tomcat 8 Software Downloads
Servlet的工作
Servlet由Tomcat提供的一組API
主要是功能是:
- 允許創(chuàng)建一個類,幫助在Tomcat收到特定的請求后,根據(jù)請求執(zhí)行程序
- 幫助解析HTTP請求,將HTTP請求從一個字符串解析成一個HttpRuquest對象方便對其進行處理
- 幫助構(gòu)造HTTP響應,填寫屬性到HttpResponse,Servlet就會自動的根據(jù)HTTP協(xié)議構(gòu)造出一個HTTP響應字符串,并通過Socket返回給客戶端
創(chuàng)建Servlet
①項目
在IDEA中創(chuàng)建一個項目,選擇Maven.
再點擊next,即可創(chuàng)建.
Maven是一個項目管理工具,給到一定的項目結(jié)果,與創(chuàng)建的流程方便開發(fā)與管理.
創(chuàng)建成功后,會出現(xiàn)一個名為pom的xml文件
pom.xml文件主要是作為項目對象模型,規(guī)定了項目的一定行為,或是存放一些屬性.
②依賴?
要使用Servlet就要在pom.xml中引入Servlet API依賴的jar包
在此網(wǎng)頁中尋找Servlet的依賴:Maven Repository: Search/Browse/Explore (mvnrepository.com)?
找到Tomcat版本對應的Servlet版本
可以在此網(wǎng)頁查詢Tomcat與Servlet的對應關系:Apache Tomcat? - Which Version Do I Want?
在pom.xml的<poject>中,創(chuàng)建一個<dependencies>標簽,再把剛剛Servlet的xml給復制進去.
復制后,IDEA中就會下載相應的依賴到本地中.下載成功后就不會標紅啦.?
③目錄?
在main目錄下,創(chuàng)建一個webapp目錄.
并在其下創(chuàng)建一個WEB-INF目錄,在WEB-INF目錄中創(chuàng)建一個web.xml.
此作用是,告知Tomcat這個項目你得認識噢.
在創(chuàng)建好的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>
④代碼
前面準備這么多,終于可以編寫代碼啦.
在java目錄當中,創(chuàng)建一個類.
此類繼承HttpServlet
(如果顯示庫中還沒有HttpServlet這個類,可以去右側(cè)的maven刷新一下噢)
public class HelloServlet extends HttpServlet {
}
此處要寫的就是,永恒的Hello啦.在網(wǎng)頁中寫上一個HELLO
在HelloServlet類中,重寫HttpSerlvet的doGet方法.
此方法是,Tomcat當中對此網(wǎng)頁使用了一個GET方法才會運行到.
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HELLO");
resp.getWriter().write("HELLO");//獲取到一個流對象,并使用其write方法寫一個hello
}
}
要注意doGet的兩個參數(shù),一個是HTTP請求對象,一個是HTTP響應的對象.
- 將HTTP請求的字符串經(jīng)過相應的格式轉(zhuǎn)換成HTTP請求對象,可以在HTTP請求對象中,獲取到請求的信息,像是方法(get或post...),URL,header和body等
- 在HTTP響應的對象中,可以根據(jù)我們的想法構(gòu)造一個HTTP響應的字符串格式.
關于resp.getWriter.write方法,獲取到HTTP響應對象的一個流對象.
再通過流對象的write方法,寫入相應的字符串.
寫入的數(shù)據(jù),就會變成HTTP的body部分.Tomcat服務器再將HTTP響應轉(zhuǎn)化成字符串,通過Socket發(fā)給客戶端接收.
@WebServlet("/HELLO")//注釋
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HELLO");
resp.getWriter().write("HELLO");
}
}
最后要記得在創(chuàng)建的類上寫上一個@WebServlet("/")的注釋噢.
在Tomcat服務器收到路徑為/HELLO的URL請求才會調(diào)用HelloServlet類的代碼.
⑤打包
打包的作用是,為了讓項目能在別處(服務器)運行,將一整個打包帶走的感覺.
打包之前可以先對將要打的包制定一些規(guī)矩.
在pom.xml的<poject>標簽下,給上下面的代碼.
給要打的包命名,并指定其格式為war包.(默認打出來的是jar包)
要打成war包才會被Tomcat識別
//命名一下打的包
<build>
<finalName>HelloServlet</finalName>//注意命名噢
</build>
//打成一個war包
<packaging>war</packaging>
在IDEA右側(cè),點擊maven按鈕.打開圖中相應的目錄,找到"package"?
打包完成后,會發(fā)現(xiàn)又新生成了一個目錄.打出來的包則會在其的底下
⑥部署
部署,就是將你剛剛所寫的項目提交到Tomcat服務器當中.
找到Tomcat文件中的webapps,將剛剛打包好的war包復制粘貼進去.
?啟動一下Tomcat服務器,就會自動的對war包進行解壓縮.就把項目扔給了Tomcat服務器啦.
⑦驗證
到了驗證成果的時候了.
在啟動Tomcat服務器的基礎下,通過Tomcat服務器訪問我們剛剛創(chuàng)建的Hello項目.
在地址上輸入
127.0.0.1:8080/HelloServlet/HELLO
此處的URL是一個環(huán)回地址啦,訪問本機的.其中的端口號就是Tomcat服務器的端口號.
后面的兩個路徑對應:
- 第一個是war包解壓出的目錄的名稱.
- 第二個是我們給創(chuàng)建的類@WebServlet()注釋的字符串.
?最終的結(jié)果就是:
以上是Servlet的創(chuàng)建與手動打包的過程.
還可以在IDEA中安裝一個Smart Tomcat插件.對其自動的打包和部署,一點即成.
Servlet的運行原理
在上面的代碼中,我們可以發(fā)現(xiàn)與以往的代碼不同,他是沒有創(chuàng)建main方法的.
是由Tomcat服務器來承擔起了啟動程序的重任.
當我們想要設計一個程序,他可以在任意時刻被任意用戶所使用.那么這個程序該在什么時候打開,又在什么時候關上呢?
用戶所使用的時間是不固定的,隨機的.程序員們不可能接收到用戶要使用的信號后再去手動的打開相應的程序.
那么這個時候,服務器出現(xiàn)了.服務器存儲著將要被使用的代碼,當用戶想要使用的時候:
- 首先用戶向服務器發(fā)出請求,申請使用某一程序?qū)崿F(xiàn)某一功能.
- 在服務器接收到請求后,解析此請求再根據(jù)請求中的內(nèi)容找到相應的程序并將其運行,
- 計算所得的結(jié)果再由服務器返回響應給用戶,達到用戶的需求
而此處的Servlet與Tomcat服務器的過程也是差不多的.
①請求
用戶在網(wǎng)頁上輸入URL,訪問Tomcat服務器中的文件,此時瀏覽器就會構(gòu)建一個HTTP請求.
這個HTTP請求就會按照網(wǎng)絡協(xié)議棧層逐層的封裝,轉(zhuǎn)換成比特流,通過物理層進行傳輸給Tomcat服務器.
服務器收到此比特流后,根據(jù)相應的協(xié)議對其進行分用,最終還原成為一個HTTP請求,交給Tomcat處理.
Tomcat通過Socket讀取到此請求(讀取到的是一個字符串),并根據(jù)HTTP請求的格式對其進行解析成為一個HttpServletRequest對象.
根據(jù)請求中的路徑,找到服務器當中要被使用的webapp和具體的某一個類.再根據(jù)請求中的方法去決定調(diào)用這個類的doGet方法還是doPost方法.
②執(zhí)行
執(zhí)行doGet或doPost方法中可以給HttpServletResponse對象設置其header或body.
執(zhí)行完后,Tomcat會自動的把HttpSeverletResponse對象構(gòu)造成一個符合Http協(xié)議的字符串.再由Socket發(fā)送出去.
③響應
這個被Socket發(fā)送的數(shù)據(jù),又經(jīng)過網(wǎng)絡協(xié)議棧層的封裝,通過物理層傳輸?shù)竭_客戶端后.又被響應的協(xié)議分用,構(gòu)造成了一個Http響應.
瀏覽器的Socket收到響應后,通過Http響應的格式進行解析,最終呈現(xiàn)到瀏覽器界面上.
Servlet API
HttpServlet
Servlet繼承的類
方法
方法名稱 | 調(diào)用時機 |
init | 在 HttpServlet 實例化之后被調(diào)用一次 |
destory | 在 HttpServlet 實例不再使用的時候調(diào)用一次 |
service | 收到 HTTP 請求的時候調(diào)用 |
doGet | 收到 GET 請求的時候調(diào)用(由 service 方法調(diào)用) |
doPost | 收到 POST 請求的時候調(diào)用(由 service 方法調(diào)用) |
doPut/doDelete/doOptions/... | 收到其他請求的時候調(diào)用(由 service 方法調(diào)用) |
init,destory和service三個方法,正是代表了Servlet的生命周期(什么時候干什么時).
- init是實例時調(diào)用一次
- service是在接收HTTP請求時被調(diào)用
- destory是結(jié)束前被調(diào)用一次
處理Get/POST請求?
在HttpServlet中是如何處理Get請求的
創(chuàng)建一個Servlet,記得要完成上面打包部署的步驟噢.也可以借助SmartTomcat
@WebServlet("/DOGET")
public class DoGet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("doGet");
}
}
生成一個html文件在項目的webapp目錄下,并寫下ajax代碼.
URL上寫的是類的注釋名,即是@WebServlet中的.?
<body>
<script src = "http://lib.sinaapp.com/js/jquery/1.7.2/jquery.min.js"></script>
<script>
$.ajax({
type: 'get',
url : 'DOGET', //這里寫的是相對路徑,也可以寫成絕對路徑.
success: function(data){
console.log("OK")
}
});
</script>
</body>
此處是,通過ajax創(chuàng)建了一個http請求.是向Tomcat服務器上的DOGET申請.
Tomcat服務器接收到后,就會相應的調(diào)用DoGet類中的doGet方法.在瀏覽器顯示頁中寫下doGet字樣.
可以在瀏覽器輸入URL:127.0.0.1:8080/ServletHello/doGet.html來訪問
并可以在瀏覽器-右鍵-檢查中的控制器看到打印的"OK"
POST方法也是一樣的,只要把ajax的type改成post,并再重寫doPost方法就可以了
HttpServletRequest
這個類是當Tomcat讀取到HTTP請求,按照HTTP請求的格式將字符串解析成為HttpServletRequest對象
方法
方法 | 描述 |
String getProtocol() | 返回請求協(xié)議的名稱和版本。 |
String getMethod() | 返回請求的 HTTP 方法的名稱,例如,GET、POST 或 PUT。 |
String getRequestURI() | 從協(xié)議名稱直到 HTTP 請求的第一行的查詢字符串中,返回該請 求的 URL 的一部分。 |
String getContextPath() | 返回指示請求上下文的請求 URI 部分。 |
String getQueryString() | 返回包含在路徑后的請求 URL 中的查詢字符串。 |
Enumeration getParameterNames() |
返回一個 String 對象的枚舉,包含在該請求中包含的參數(shù)的名 稱。 |
String getParameter(String name) |
以字符串形式返回請求參數(shù)的值,或者如果參數(shù)不存在則返回 null。 |
String[] getParameterValues(String name) |
返回一個字符串對象的數(shù)組,包含所有給定的請求參數(shù)的值,如 果參數(shù)不存在則返回 null。 |
Enumeration getHeaderNames() |
返回一個枚舉,包含在該請求中包含的所有的頭名。 |
String getHeader(String name) |
以字符串形式返回指定的請求頭的值。 |
String getCharacterEncoding() |
返回請求主體中使用的字符編碼的名稱。 |
String getContentType() | 返回請求主體的 MIME 類型,如果不知道類型則返回 null。 |
int getContentLength() | 以字節(jié)為單位返回請求主體的長度,并提供輸入流,或者如果長 度未知則返回 -1。 |
InputStream getInputStream() |
用于讀取請求的 body 內(nèi)容. 返回一個 InputStream 對象. |
獲取請求中的信息?
@WebServlet("/req")
public class ShowServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");//文本格式,編譯符為utf-8
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(req.getProtocol());//獲取協(xié)議的名稱與版本
stringBuilder.append("<br>");//在StringBuilder中添加換行符
stringBuilder.append(req.getMethod());//返回請求的方法的名稱
stringBuilder.append("<br>");
stringBuilder.append(req.getRequestURI());//返回該請求URL的部分
stringBuilder.append("<br>");
stringBuilder.append(req.getContextPath());//返回請求URI的部分
stringBuilder.append("<br>");
stringBuilder.append(req.getQueryString());//返回請求URL中的查詢字符串。
stringBuilder.append("<br>");
stringBuilder.append("header:");
stringBuilder.append("<br>");
Enumeration<String> headerNames = req.getHeaderNames();
while(headerNames.hasMoreElements()){//如果header中還存在鍵值對,就繼續(xù)執(zhí)行
String headName = headerNames.nextElement();
stringBuilder.append(headName);//header名
stringBuilder.append(" : ");
stringBuilder.append(req.getHeaders(headName));//header值
stringBuilder.append("<br>");
}
resp.getWriter().write(stringBuilder.toString());
}
}
訪問到的結(jié)果?
獲取GET請求中的參數(shù)
在get方法中,請求的參數(shù)一般是URL中的query string鍵值對.
https:/ /www.baidu.com/?name=wow HTTP/1.1
就像這樣的,URL中的query string為name=wow.
這里的參數(shù)就是name,值為wow.
在服務器就可以通過getParameter來獲取參數(shù).
@WebServlet("/getParameter")
public class GetParameter extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text ; charset = utf-8");
String name = req.getParameter("name");
resp.getWriter().write("name:" + name);
}
}
當URL中沒有query string時,值為空?
當含有query string時,就會得到相應的值?
獲取POST請求中的參數(shù)
post請求中的參數(shù)形式,可以為form表格,也可以為json的格式
FORM表格形式
如果為form表格的形式進行傳輸,仍然可以使用getParameter來獲取參數(shù).
在類上重寫doPost方法
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text ; charset = utf-8");
String name = req.getParameter("name");
resp.getWriter().write("name:" + name);
}
在項目的webapp目錄下,創(chuàng)建一個html.用來發(fā)出form表格的請求?
<body>
<form action="getParameter" meth = "post">
<input type="text" name = "name">
<input type="submit" value="提交">
</form>
</body>
訪問剛剛創(chuàng)建的html文件?
JSON形式
方法一:
我們可以知道,POST方法中的鍵值對會存在于其body部分,我們可以通過流對象直接讀取其body部分即可.
重寫doPost方法
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf8");
int len = req.getContentLength();//得到body的長度
byte[] arr = new byte[len];//根據(jù)長度創(chuàng)建一個數(shù)組
InputStream inputStream = req.getInputStream();
inputStream.read(arr);
String body = new String(arr,"utf8");//構(gòu)建出字符串
System.out.println(body);
//resp.getWriter().write(body)這條語句在此處是不會成功的
//write是通過文本的格式發(fā)送給瀏覽器,而瀏覽器要接收的是json格式
}
發(fā)送一個json請求
<body>
<script src = "http://lib.sinaapp.com/js/jquery/1.7.2/jquery.min.js"></script>
<button onclick="sendJson()">發(fā)送 JSON 格式 POST 請求</button>
<script>
let body={
"name":'john',
"age":34
};
function sendJson() {
$.ajax({
type : 'post',
url : 'getParameter',
data : JSON.stringify(body),
contentType: "application/json;charset=utf8",
});
}
</script>
</body>
通過抓包查看結(jié)果
服務器控制臺
?
方法二:
方法一通過觀察代碼可以發(fā)現(xiàn),他只能獲取到json格式的一串字符串,并不能通過鍵值對的key來獲取對應的value值
所以可以使用jackson這個庫,來解析json.
在pom.xml中引入Jackson庫的依賴
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
重寫doPost方法
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf8");
//首先要將請求的body變成一串字符串
int len = req.getContentLength();//得到body的長度
byte[] arr = new byte[len];//根據(jù)長度創(chuàng)建一個數(shù)組
InputStream inputStream = req.getInputStream();
inputStream.read(arr);
String body = new String(arr,"utf8");//構(gòu)建出字符串
//創(chuàng)建一個objectMapper對象,此類為Jackson的核心類
ObjectMapper objectMapper = new ObjectMapper();
//再通過objectMapper類的readValue方法,將字符串轉(zhuǎn)換成JsonData對象
JsonData jsonData = objectMapper.readValue(body,JsonData.class);
//就可以根據(jù)key來獲取value啦
System.out.println("name: " + jsonData.name + " age: " + jsonData.age);
}
上面的代碼方便理解,后面熟悉后可以把body直接換乘成inputstream
JsonData jsonData1 = objectMapper.readValue(req.getInputStream(),JsonData.class);
這樣就可以單獨的獲取某一個鍵值對了?
HttpServletResponse?
Servlet 中的 doXXX 方法的目的就是根據(jù)請求計算得到相應, 然后把響應的數(shù)據(jù)設置到
HttpServletResponse 對象中.然后 Tomcat 就會把這個 HttpServletResponse 對象按照 HTTP 協(xié)議的格式, 轉(zhuǎn)成一個字符串, 并通過Socket 寫回給瀏覽器
方法 | 描述 |
void setStatus(int sc) | 為該響應設置狀態(tài)碼。 |
void setHeader(String name, String value) |
設置一個帶有給定的名稱和值的 header. 如果 name 已經(jīng)存在, 則覆蓋舊的值. |
void addHeader(String name, String value) |
添加一個帶有給定的名稱和值的 header. 如果 name 已經(jīng)存在, 不覆蓋舊的值, 并列添加新的鍵值對 |
void setContentType(String type) |
設置被發(fā)送到客戶端的響應的內(nèi)容類型。 |
void setCharacterEncoding(String charset) |
設置被發(fā)送到客戶端的響應的字符編碼(MIME 字符集)例如, UTF-8。 |
void sendRedirect(String location) |
使用指定的重定向位置 URL 發(fā)送臨時重定向響應到客戶端。 |
PrintWriter getWriter() | 用于往 body 中寫入文本格式數(shù)據(jù). |
OutputStream getOutputStream() |
用于往 body 中寫入二進制格式數(shù)據(jù) |
這么多就不一一展開啦.
此處講一下setStatus設置狀態(tài)碼與sendRedirect重定向.
resp.sendRedirect("http://www.sogou.com");
像是這樣,把URL放在重定向的代碼中.當別人訪問到此程序的時候,就會去訪問重定向中的網(wǎng)站.
而設置狀態(tài)碼,是可以通過getPamameter來獲取URL中的參數(shù).
可以把重定向中的URL加上一個status=404的query string鍵值對.文章來源:http://www.zghlxwxcb.cn/news/detail-661551.html
在某種情況下,就可以先進行重定向跳轉(zhuǎn)網(wǎng)頁,再通過獲取status的值來設置狀態(tài)碼.文章來源地址http://www.zghlxwxcb.cn/news/detail-661551.html
到了這里,關于[JAVAee]Tomcat - Servlet的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!