Java Web專題攻關(guān)
servlet概念
servlet其實(shí)就是運(yùn)行在服務(wù)器的一個(gè)小程序
如何去理解呢?我們訪問服務(wù)器的資源包括靜態(tài)資源和動(dòng)態(tài)資源,其中靜態(tài)資源是我們放置的模板,CSS、JS等文件,是不變的。而我們訪問的動(dòng)態(tài)資源,是根據(jù)我們訪問的請求路徑,路由到指定的類去加載,運(yùn)行其對應(yīng)的方法而給出瀏覽器資源的響應(yīng)。那么憑什么我們的服務(wù)器會(huì)幫我們?nèi)ゼ虞d,去運(yùn)行指定的方法呢?或者說服務(wù)器是怎么做到的呢?我們一定是需要遵循服務(wù)器某些規(guī)則才行的,而規(guī)則在 Java 中 就是接口,Servlet就是被服務(wù)器(Tomcat)識(shí)別的接口,我們需要根據(jù)這個(gè)接口來定義響應(yīng)的方法。
快速入門
-
創(chuàng)建一個(gè) Java EE 項(xiàng)目,定義一個(gè)類,實(shí)現(xiàn) Servlet 接口
public class ServletDemo1 implements Servlet -
實(shí)現(xiàn)接口中的抽象方法
-
在web.xml中配置 Servlet
<!-- 配置Servlet --> <servlet> <servlet-name>demo1</servlet-name> <servlet-class>org.taoguoguo.web.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>demo1</servlet-name> <url-pattern>/demo1</url-pattern> </servlet-mapping>
Servlet執(zhí)行原理:
- 當(dāng)服務(wù)器接受客戶端瀏覽器的請求后,會(huì)解析請求的URL路徑,獲取訪問Servlet的資源路徑
- 查找web.xml文件,是否有對應(yīng)的
<url-pattern>標(biāo)簽體內(nèi)容 - 如果有,則會(huì)找到對應(yīng)的
<servlet-class>全類名 - tomcat 會(huì)將字節(jié)碼文件加載進(jìn)內(nèi)存,并且創(chuàng)建其對象
- 調(diào)用其方法
Servlet中的生命周期:
-
被創(chuàng)建:執(zhí)行 init 方法,只執(zhí)行一次
-
Servlet 什么時(shí)候被創(chuàng)建?
-
默認(rèn)情況下, 第一次訪問時(shí),Servlet被創(chuàng)建
-
可以配置Servlet的創(chuàng)建時(shí)機(jī),如下:
<!-- 配置Servlet --> <servlet> <servlet-name>demo2</servlet-name> <servlet-class>org.taoguoguo.web.ServletDemo2</servlet-class> <!--指定Servlet的創(chuàng)建時(shí)機(jī) 1.第一次被訪問時(shí)創(chuàng)建,創(chuàng)建 <load-on-startup>的值為負(fù)數(shù),默認(rèn)為 -1,或者不配置 也是在第一次訪問被創(chuàng)建 2.在服務(wù)器啟動(dòng)時(shí),創(chuàng)建 <load-on-startup>的值為0或正整數(shù) 一般設(shè)置為 1 --> <load-on-startup>-1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>demo2</servlet-name> <url-pattern>/demo2</url-pattern> </servlet-mapping>注意:Servlet的 init 方法只執(zhí)行一次,說明servlet在內(nèi)存中只存在一個(gè)對象,是單例的,所以多個(gè)用戶線程同時(shí)訪問時(shí),可能存在線程安全問題。解決方案:1.盡量不要在Servlet中定義成員變量,因?yàn)槌蓡T變量時(shí)每個(gè)線程共享的資源,可能有的線程會(huì)修改,而部分線程會(huì)去獲取,容易出現(xiàn)數(shù)據(jù)安全問題。盡量在方法內(nèi)部定義局部變量代替成員變量。因?yàn)榫植孔兞渴窃诿總€(gè)線程方法棧中獨(dú)享的一份資源,可以保證數(shù)據(jù)安全性。2.如果必須要定義成員變量,不要在方法中去修改成員變量的值,僅用于線程獲取,是不會(huì)有線程安全問題的。3.在servlet解決多線程安全問題時(shí),切記使用同步鎖,因?yàn)闀?huì)非常的消耗性能
-
-
-
提供服務(wù): 執(zhí)行 service 方法,執(zhí)行多次
- 每次訪問 Servlet 時(shí),service 方法都會(huì)被調(diào)用一次
-
被銷毀:執(zhí)行 destory 方法,只執(zhí)行一次
- servlet 被銷毀時(shí)執(zhí)行,只有服務(wù)器正常關(guān)閉時(shí),servlet 被銷毀 才會(huì)執(zhí)行destory 方法。destory 是在被銷毀之前執(zhí)行,一般用于釋放資源
Servlet 3.0:
-
支持注解配置,可以不需要web.xml了
-
使用方法:在創(chuàng)建的servlet 上 加上注解
@WebServlet("資源路徑"),支持如下寫法@WebServlet(urlPatterns = "/demo3")@WebServlet("/demo3")
HTTP
概念:
Hyper Text Transfer Protocol 超文本傳輸協(xié)議
傳輸協(xié)議:
定義了 客戶端 和 服務(wù)器端通信時(shí),發(fā)送數(shù)據(jù)的格式
特點(diǎn):
1.基于TCP/IP的高級(jí)協(xié)議(安全的,需要經(jīng)過三次握手)
2.默認(rèn)端口號(hào):80
3.基于 請求/響應(yīng) 模型 (請求響應(yīng) 一 一 對應(yīng),一次請求,一次響應(yīng))
4.無狀態(tài)的:每次請求之間相互獨(dú)立,不能交互數(shù)據(jù)
歷史版本:
1.0:每一次請求,建立一次新的連接
1.1: 復(fù)用連接,對緩存性能較好
請求消息數(shù)據(jù)格式:
-
請求行
-
組成格式:請求方式 請求url 請求協(xié)議/版本
請求行: GET /login.html HTTP/1.1 -
HTTP協(xié)議有7種請求方式,常用的有兩種請求頭
-
GET
-
請求參數(shù)在請求行中,在url后。
-
請求的url長度有限制
-
相對安全
-
-
POST
-
請求參數(shù)在請求體中
-
請求的url是沒有限制的
-
相對安全
-
-
-
-
請求頭(客戶端告知服務(wù)端自身信息)
-
組成格式: 請求頭名稱:請求頭值
Host:localhost 當(dāng)前主機(jī) User-Agent:瀏覽器告訴服務(wù)器,我訪問你使用的瀏覽器版本信息 //作用:服務(wù)端可以根據(jù)這個(gè)頭信息區(qū)分不同瀏覽器解決瀏覽器兼容問題 Accept:告訴服務(wù)器,瀏覽器可以解析哪些格式類型的信息 如 text/html Accept-Language: 告訴服務(wù)器所支持的語言環(huán)境 Accept-Encoding: 告訴服務(wù)器所支持的壓縮格式 Referer:http://localhost:8080/login.html 告訴服務(wù)器,當(dāng)前請求從那里來 Referer的常用場景: 1.防盜鏈 2.統(tǒng)計(jì)工作 Connection: keep-alive 連接狀態(tài) 保持活躍服用 Upgrade-Insecure-Requests:1 瀏覽器升級(jí)信息
-
-
請求空行
- 空行,用于用于分割POST請求的請求頭,和請求體的
-
請求體
- 封裝POST請求消息的請求參數(shù)
username=zhangsan
- 封裝POST請求消息的請求參數(shù)
響應(yīng)消息數(shù)據(jù)格式:
服務(wù)端發(fā)送給客戶端的數(shù)據(jù)
1.響應(yīng)行
- 格式:協(xié)議/版本 響應(yīng)狀態(tài)碼 狀態(tài)碼描述
HTTP/1.1 200 OK
響應(yīng)狀態(tài)碼:服務(wù)器告訴客戶端本次請求和響應(yīng)的一個(gè)狀態(tài)
-
狀態(tài)碼都是三位數(shù)字:
1xx: 服務(wù)器接收客戶端消息,但是沒有接收完成,等待一段時(shí)間后,發(fā)送1xx 狀態(tài)碼詢問客戶端
2xx: 成功。代表: 200
3xx: 重定向。
302(重定向) 服務(wù)器響應(yīng)狀態(tài)碼302 并給客戶端響應(yīng)一個(gè)地址,客戶端收到302狀態(tài)碼后自動(dòng)請求對應(yīng)地址進(jìn)行重定向。 304 (訪問緩存)例如請求訪問圖片等大二進(jìn)制數(shù)據(jù)時(shí)較慢,當(dāng)瀏覽器請求服務(wù)器,服務(wù)器返回圖片資源時(shí),瀏覽器會(huì)進(jìn)行圖片的本地緩存,當(dāng)再次訪問時(shí),如果服務(wù)器資源沒有變化, 并且當(dāng)前瀏覽器存在圖片緩存,可返回狀態(tài)碼 304 告知瀏覽器訪問緩存,提高交互體驗(yàn)。4xx: 客戶端錯(cuò)誤
404 客戶端訪問路徑錯(cuò)誤,未找到訪問資源 - 405 請求方式?jīng)]有對應(yīng)的 doXXX 方法5xx: 服務(wù)端錯(cuò)誤
500 服務(wù)器內(nèi)部異常
2.響應(yīng)頭
1.格式: 頭名稱:值
2.常見的響應(yīng)頭:
Content-Type: 服務(wù)器告訴客戶端本次響應(yīng)體數(shù)據(jù)格式及編碼格式
Content-Length: 響應(yīng)字節(jié)長度
Date: 響應(yīng)時(shí)間
Content-disposition: 服務(wù)器告訴客戶端以什么格式打開響應(yīng)體數(shù)據(jù)
默認(rèn)值: in-line 在當(dāng)前頁面打開
attachment;filename 以附件形式打開響應(yīng)體,文件下載中使用
3.響應(yīng)空行
4.響應(yīng)體
響應(yīng)體就是傳輸?shù)捻憫?yīng)數(shù)據(jù),有整個(gè)頁面的解析響應(yīng),也有二進(jìn)制數(shù)據(jù)
Request
request對象和response對象的原理
- request對象和response對象是由服務(wù)器創(chuàng)建的,我們來使用它
- request對象是來獲取請求消息,response對象是來設(shè)置響應(yīng)消息的
Request對象繼承體系結(jié)構(gòu)
- ServletRequest -- 接口
- HttpServletRequest -- 子接口(繼承 ServletRequest)
- org.apache.catalina.connector.RequestFacade 類(Tomcat)
- HttpServletRequest -- 子接口(繼承 ServletRequest)
request功能:
1.獲取請求消息數(shù)據(jù)
1.獲取請求行數(shù)據(jù)
*GET /day14/demo1?name=zhangsan HTTP/1.1
-
獲取請求方式:GET
String getMethod(); -
獲取虛擬目錄:/day14
String getContextPath(); -
獲取servlet路徑:/demo1
String getServletPath(); -
獲取get方式請求參數(shù):name=zhangsan
String getQueryString(); -
獲取請求的URI:/day14/demo1
//URI: 統(tǒng)一資源標(biāo)識(shí)符 共和國 //URL: 統(tǒng)一資源定位符 中華人民共和國 String getRequestURI(); //URI如: /day14/demo1 StringBuffer getRequestURL(); //URL如: http://localhost/day14/demo1 -
獲取協(xié)議及版本:HTTP/1.1
String getProtocol(); //ServletRequest中的方法 -
獲取客戶機(jī)的IP地址
String getRemoteAddr();
2.獲取請求頭數(shù)據(jù)
-
String getHeader(String var1); //通過請求頭的名稱獲取請求頭的值 -
Enumeration<String> getHeaders(String var1); //獲取所有的請求頭名稱
根據(jù)所有請求頭獲取所有的請求頭對應(yīng)的值:
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
Enumeration<String> names = request.getHeaderNames();
while(names.hasMoreElements()){
String s = names.nextElement();
System.out.println(s +":" + request.getHeader(s));
}
}
-
判斷瀏覽器版本,根據(jù)請求頭
1user-agent的值來判斷 是否包含指定瀏覽器關(guān)鍵字,比如Chromeuser-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36 -
判斷請求來源,用于防盜鏈 可根據(jù)請求頭
referer的值來判斷referer:http://localhost:8080/hello.html
3.獲取請求體數(shù)據(jù)
請求體:只有POST請求,才有請求體,在請求體中封裝了POST請求的請求參數(shù)
步驟:
1.獲取流對象
BufferedReader getReader() //獲取字符輸入流,只能操作字符數(shù)據(jù)
獲取頁面表單提交數(shù)據(jù)
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//獲取請求消息體-請求參數(shù)
//1.獲取字符流
BufferedReader br = request.getReader();
//2.讀取數(shù)據(jù)
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
}
2.再從流對象中拿數(shù)據(jù)
ServletInputStream getInputStream() //獲取字節(jié)輸入流 可以操作所有類型數(shù)據(jù) 文件上傳中使用
4.其他功能
1.獲取請求參數(shù)通用方式:
不論是get 還是post 請求方式都可以使用下列方法來獲取請求參數(shù)
-
String getParameter(String name) 根據(jù)請求參數(shù)獲取參數(shù)值 username=zhangsan&password=123
@WebServlet("/demo5") public class ServletDemo5 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //post獲取請求參數(shù) String username = request.getParameter("username"); System.out.println("post"); System.out.println(username); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //get獲取請求參數(shù) String username = request.getParameter("username"); System.out.println("get"); System.out.println(username); } } -
String[] getParameter(String name) 根據(jù)請求參數(shù)獲取參數(shù)值的數(shù)組 hobby=study&hobby=eat
-
Enumeration
getParameterNames() 獲取所有請求的參數(shù)名稱 -
Map<String, String[]>getParameterMap()獲取所有的請求參數(shù)和值 封裝為一個(gè)Map返回
技巧:獲取前臺(tái)參數(shù)時(shí),可創(chuàng)建一個(gè)Java Bean對象,然后使用BeanUtils.populate(Object obj,Map map)
將map集合的鍵值信息,封裝到 Java Bean對象中
獲取請求參數(shù)亂碼問題
-
get方式:Tomcat 8 已經(jīng)將get方式亂碼問題解決
-
post方式:會(huì)亂碼
解決方法:獲取參數(shù)前設(shè)置一下流的編碼,編碼來自于請求提交頁面編碼格式
request.setCharacterEncoding("utf-8");
2.請求轉(zhuǎn)發(fā):
一種在服務(wù)器內(nèi)部資源跳轉(zhuǎn)的方式
步驟:
1.通過 request 對象獲取請求轉(zhuǎn)發(fā)器對象,RequestDispatcher getRequestDispatcher(String var1);
2.使用 RequestDispatcher 來進(jìn)行轉(zhuǎn)發(fā):forward(ServletRequest var1, ServletResponse var2)
特點(diǎn):
1.瀏覽器地址欄不發(fā)生變化
2.轉(zhuǎn)發(fā)只能轉(zhuǎn)發(fā)當(dāng)前服務(wù)器的內(nèi)部資源,比如不能轉(zhuǎn)發(fā)到訪問百度
3.轉(zhuǎn)發(fā)是一次請求
3.共享數(shù)據(jù)
域?qū)ο螅阂粋€(gè)有作用范圍的對象,可以在范圍內(nèi)共享數(shù)據(jù)。
request域:代表一次請求,一般用于一次請求轉(zhuǎn)發(fā)的訪問多個(gè)資源中共享數(shù)據(jù)
方法:
1.setAttribute(String name,Object obj); 存儲(chǔ)對象
2.Object getAttribute(String name); 通過鍵獲取值
3.removeAttribute(String name); 通過鍵移除值
4.獲取ServletContext
ServletContext getServletContext()
Response
功能:設(shè)置響應(yīng)消息
1.設(shè)置響應(yīng)行
1.格式:HTTP /1.1 200
一般是設(shè)置響應(yīng)狀態(tài)碼 :setStatus(int sc)
2.設(shè)置響應(yīng)頭
setHeader(String name, String value)
3.響應(yīng)體
使用步驟:
1.獲取輸出流
1.字符輸出流:PrintWriter getWriter()
2.字節(jié)輸出流:ServletOutputStream getOutputStream()
2.使用輸出流,將數(shù)據(jù)輸出到客戶端瀏覽器
案例:
1.完成重定向
重定向是客戶端瀏覽器訪問服務(wù)器時(shí),服務(wù)器響應(yīng)客戶端訪問重定向另一個(gè)資源進(jìn)行處理的過程
第一種方式:
設(shè)置響應(yīng)狀態(tài)碼為302 response.setStatus(302);
設(shè)置響應(yīng)頭location 值為要跳轉(zhuǎn)的路徑 response.setHeader("location","/demo7");
第二種方式:
使用response對象的重定向方法: response.sendRedirect("/demo7");
重定向特點(diǎn)
1.地址欄發(fā)生變化
2.重定向可以訪問其他站點(diǎn)服務(wù)器資源
3.重定向是多次請求,不能使用request域?qū)ο髞砉蚕頂?shù)據(jù)
路徑分類
-
相對路徑:通過相對路徑不可以確定唯一資源
- 如:./index.html
- 相對路徑通常以 . 開頭
- 寫法規(guī)則:先確定當(dāng)前資源和訪問的目標(biāo)資源之間的相對位置關(guān)系
- ./ 代表當(dāng)前目錄,也可省略 , ../ 代表上一級(jí)目錄
相對目錄路徑寫法舉例:
比如一個(gè)項(xiàng)目,有個(gè)路徑為 demo1的 Servlet,訪問路徑為::
http://localhost:8080/project/demo1 -> 目標(biāo)資源
項(xiàng)目的web目錄下有個(gè)index.html,訪問路徑為:
http://localhost:8080/project/index.html -> 當(dāng)前資源
當(dāng)前資源和目標(biāo)資源在同一個(gè)層級(jí)上,那么從 index.html訪問 demo1的路徑通常為
<a href="./demo1">訪問Demo1</a>當(dāng)前目錄的 ./ 是可以省略的,所以也可以簡寫為:demo1 -
絕對路徑:通過絕對路徑可以確定唯一資源
-
如:http://localhost:8080/project/demo1 這是完整的絕對路徑
-
也可以簡寫,以 / 開頭的路徑 如:/project/demo1 因?yàn)閰f(xié)議和主機(jī)端口等通常都是固定的
-
寫法規(guī)則:判斷路徑是給誰用的的?如何判斷,就是看請求從哪里發(fā)出。客戶端發(fā)出就是給客戶端用,服務(wù)端發(fā)出就是給服務(wù)端用。
-
給客戶端使用:需要加虛擬目錄(項(xiàng)目的訪問路徑),常見的比如標(biāo)簽,
-
給服務(wù)器用:不需要加虛擬目錄路徑,直接填寫訪問路徑即可。
request.getRequestDispatcher("/demo7").forward(request,response); //比如轉(zhuǎn)發(fā)
-
-
2.服務(wù)器輸出字符數(shù)據(jù)到瀏覽器
-
獲取字符輸出流,這個(gè)流是獲取的不是創(chuàng)建的,說明流向是到客戶端瀏覽器的
-
輸出數(shù)據(jù)
//1.獲取字符輸出流 PrintWriter pw = response.getWriter(); //2.輸出數(shù)據(jù) pw.write("hello world");-
亂碼問題:
-
設(shè)置輸出流的默認(rèn)編碼及設(shè)置響應(yīng)頭,服務(wù)器告訴客戶端本次響應(yīng)體數(shù)據(jù)格式及編碼格式
//設(shè)置流的默認(rèn)編碼 response.setCharacterEncoding("utf-8"); //設(shè)置一下響應(yīng)頭 Content-Type: 服務(wù)器告訴客戶端本次響應(yīng)體數(shù)據(jù)格式及編碼格式 response.setContentType("text/html;charset=utf-8");
-
-
3.服務(wù)器輸出字節(jié)數(shù)據(jù)到瀏覽器
-
獲取字節(jié)輸出流,可以輸出任意類型字節(jié)數(shù)據(jù),如果輸出是中文,同樣需要注意編碼一致問題。
//1.獲取字節(jié)輸出流 ServletOutputStream outputStream = response.getOutputStream(); //2.輸出數(shù)據(jù) outputStream.write("hello world".getBytes());
4.驗(yàn)證碼
驗(yàn)證碼的實(shí)現(xiàn)非常簡單,就是后臺(tái)生成隨機(jī)數(shù),然后通過畫筆畫出驗(yàn)證碼圖案進(jìn)行填充,實(shí)現(xiàn)如下:
-
html表單
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注冊頁面</title> </head> <body> <img src="/CheckCodeServlet" id="checkCode" /> <a id="changeCheckCode" href="#" onclick="clickChangeCheckCode()">看不清,換一張?</a> </body> <script> /** * 分析:點(diǎn)擊超鏈接或者圖片,需要換一張 * 1.給超鏈接和圖片綁定單機(jī)事件 * 2.重新設(shè)置的src屬性值 */ window.onload = function () { //1.獲取圖片對象 var img = document.getElementById("checkCode"); //2.綁定單機(jī)事件 img.onclick = function () { //加時(shí)間戳,防止瀏覽器緩存,驗(yàn)證碼刷新重復(fù)問題 var date = new Date().getTime(); img.src = "/CheckCodeServlet?"+date; } } function clickChangeCheckCode() { var img = document.getElementById("checkCode"); var date = new Date().getTime(); img.src="/CheckCodeServlet?"+date; } </script> </html> -
驗(yàn)證碼生成Servlet
package org.taoguoguo.web; import javax.imageio.ImageIO; 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.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; /** * 驗(yàn)證碼生成Servlet */ @WebServlet(name = "CheckCodeServlet", value = "/CheckCodeServlet") public class CheckCodeServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.創(chuàng)建一個(gè)圖像緩沖區(qū)對象 int width = 100; int height = 50; BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); //2.美化圖片 //2.1填充背景色 Graphics graphics = image.getGraphics(); //畫筆對象 graphics.setColor(Color.pink); //設(shè)置畫筆顏色 graphics.fillRect(0,0,width,height); //2.2畫邊框 graphics.setColor(Color.blue); graphics.drawRect( 0,0,width-1,height-1); //2.3寫驗(yàn)證碼 String code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789"; //生成隨機(jī)角標(biāo) Random random = new Random(); for (int i=1; i<=4; i++){ int index = random.nextInt(code.length()); //獲取字符 char c = code.charAt(index); graphics.drawString(String.valueOf(c),width/5*i,height/2); } //2.4畫干擾線 graphics.setColor(Color.green); for(int i=0; i<10; i++){ int x1 = random.nextInt(width); int y1 = random.nextInt(height); int x2 = random.nextInt(width); int y2 = random.nextInt(height); graphics.drawLine(x1,y1,x2,y2); } //3.將圖片輸出到頁面展示 ImageIO.write(image,"jpg",response.getOutputStream()); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } }
ServletContext對象
概念:
代表整個(gè) web 應(yīng)用,可以和程序的容器(服務(wù)器)來進(jìn)行通信
獲取
-
通過request對象獲取
request.getServletContext(); -
通過HttpServlet獲取
this.getServletContext();
注意:ServletContext 既然代表整個(gè)應(yīng)用,那么它只有唯獨(dú)一份,無論通過哪種方式獲取,都是同一個(gè)對象。
舉例:
//1.通過request對象獲取
ServletContext context1 = request.getServletContext();
//2.通過HttpServlet獲取
ServletContext context2 = this.getServletContext();
System.out.println(context1);
System.out.println(context2);
System.out.println(context1 == context2);
輸出:
org.apache.catalina.core.ApplicationContextFacade@586b90db
org.apache.catalina.core.ApplicationContextFacade@586b90db
true
功能
-
獲取 MIME 類型
MIME類型:在互聯(lián)網(wǎng)通信過程中定義的一種文件數(shù)據(jù)類型
格式:大類型/小類型 比如: text/html image/jpeg
用途:響應(yīng)返回時(shí),設(shè)置響應(yīng)頭 Content-Type 告知瀏覽器用對應(yīng)的引擎來解析返回?cái)?shù)據(jù)
獲取方式
String getMimeType(String var1);舉例:
public class ServletContextDemo2 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext context = this.getServletContext(); String fileName = "a.jpg"; String mimeType = context.getMimeType(fileName); System.out.println(mimeType); } 輸出: image/jpeg -
域?qū)ο螅汗蚕頂?shù)據(jù)
范圍:所有用戶所有請求數(shù)據(jù)
- setAttribute(String name, Object value);
- getAttribute(String name);
- removeAttribute(String name);
/* * 在Servlet1中存儲(chǔ)值,在Servlet2中獲取值 */ @WebServlet("/servletContextDemo1") public class ServletContextDemo1 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext context = this.getServletContext(); context.setAttribute("zhangsan","token123456"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } } package org.taoguoguo.web.servletcontext; import javax.servlet.ServletContext; 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; /** * @author taoGG * @description * @create 2020-10-28 22:21 */ @WebServlet("/servletContextDemo2") public class ServletContextDemo2 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext context = this.getServletContext(); String str = (String) context.getAttribute("zhangsan"); System.out.println(str); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } } 輸出: token123456 -
獲取文件的真實(shí)(服務(wù)器)路徑
package org.taoguoguo.web.servletcontext; import javax.servlet.ServletContext; 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; /** * @author taoGG * @description * @create 2020-10-28 22:21 */ @WebServlet("/servletContextDemo1") public class ServletContextDemo1 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext context = this.getServletContext(); String realPath1 = context.getRealPath("/b.txt"); // web目錄下 String realPath2 = context.getRealPath("/WEN-INF/a.txt"); // WEB-INF目錄下的資源訪問 String realPath3 = context.getRealPath("/WEB-INF/calsses/a.txt"); //src目錄下 System.out.println("web目錄下:" + realPath1); System.out.println("WEB-INF下" + realPath2); System.out.println("src目錄下" + realPath3); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } } -
文件下載案例
-
download.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>文件下載</title> </head> <body> <a href="/downloadServlet?fileName=001.jpg">圖片下載</a> <a href="/downloadServlet?fileName=代碼.jpg">圖片(中文名稱)下載</a> </body> </html> -
DownloadServlet
package org.taoguoguo.web.download; import utils.DownLoadUtils; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.FileInputStream; import java.io.IOException; /** * @author taoGG * @description * @create 2020-10-28 23:14 */ @WebServlet("/downloadServlet") public class DownloadServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.獲取請求文件名稱 String fileName = request.getParameter("fileName"); //2.使用字節(jié)輸入流加載文件進(jìn)入內(nèi)存 //2.1找到文件在服務(wù)器的真實(shí)路徑 ServletContext context = this.getServletContext(); String realPath = context.getRealPath("/img/" + fileName); //2.2使用字節(jié)流關(guān)聯(lián) FileInputStream fis = new FileInputStream(realPath); //3.設(shè)置response響應(yīng)頭 //3.1設(shè)置響應(yīng)頭類型 content-type String mimeType = context.getMimeType(fileName); //獲取文件MIME類型 response.setHeader("content-type",mimeType); //3.2解決中文文件名問題,設(shè)置響應(yīng)頭打開方式 String agent = request.getHeader("user-agent"); fileName = DownLoadUtils.getFileName(agent, fileName); response.setHeader("content-disposition","attachment;filename="+fileName); //4將輸入流的數(shù)據(jù)寫出到輸出流中 ServletOutputStream outputStream = response.getOutputStream(); byte[] buff = new byte[1024*8]; //字節(jié)緩沖數(shù)組 int len = 0; //讀到的個(gè)數(shù) while ((len = fis.read(buff))!=-1){ //未讀到末尾 outputStream.write(buff,0,len); //從0開始寫,寫讀到的長度 } fis.close(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } }
中文文件名稱問題
解決思路:
- 獲取客戶端使用的瀏覽器版本信息
- 根據(jù)不同的版本信息,設(shè)置fileName的編碼方式不同
-

浙公網(wǎng)安備 33010602011771號(hào)