上下文對象-請求對象-響應對象
ServletContext
什么是ServletContext
- ServletContext代表是一個web應用的上下文對象(web應用對象)
- 里面封裝的都是web應用信息
- 一個ServletContext對應一個應用
ServletContext的生命周期
- 在服務器一啟動的時候就會創建
- 在服務器關閉的時候銷毀
如何獲得上下文
1.通過init方法當中一個參數ServletConfig來獲取
2.直接在HttpServlet當中獲取
-
this.getServletContext
-
這種方法本質還是通過config來去獲取的
獲取全局的初始化參數
- 初始化參數不能再某一個Servlet當中來去配置。在最外層來去配置
- 獲取全局初始化參數
獲得Web應用中某一個資源的資源的絕對路徑
- context.getRealPath("文件")
- 相對的是web應有根目錄
context.getRealPath("index.html")
D:\Java\Tomcat\apache-tomcat-7.0.85\webapps\bei\index.html
在你寫的名稱前面自動拼接上當前工程的絕對地址
ServletContext是一個域對象
什么是域?
- 能夠存儲數據
域對象
- 能夠存取數據流的對象
ServletContext域對象的作用范圍
- 整個web應用
- 所有的web資源都可以進行存取數據
- 數據是可以共享的
獲取完ServletContext之后向里面寫數據
context.setAttribute(String name,Object value);
獲取完ServletContext之后,通過name取出存放的數據
context.getAttribute(String name);
獲取完ServletContext之后,刪除指定名稱的值
Context.removeAttribute(String name);
response
response響應過程
- 在去發送一個請求時, 會找到tomcat引擎
- 引擎會找到對應的web應用
- 並且會創建request對象和response對象
- 找到應用后, 會執行應用的web.xml再去根據url-pattern的內容創建Servlet對象
- 並且會調用Servlet對象的service方法,把創建的request對象和response對象傳入到方法當中
- 拿到response對象后, 自己可以往響應當中寫入一些自己給客戶端的內容
- 通過response.getwrite().wirte("寫的內容")方法進行寫入
- 寫的內容,是存到一個response緩沖區當中
- 當方法執行結束之后, tomcat就會從response緩沖區當中取出數據
- 取出你的數據同時,它自己還會自動的往里面添加一些服務器相關的信息進去
- 所以響應給瀏覽器時, 可以看到除了自己寫的內容, 還會有一些服務器相關的信息
流程圖
通過response設置響應行,響應頭 ,響應體
設置響應行
response.setState(Int code)
設置響應頭
add
- add代表添加新的內容
- addHeader(String name,String value)
- addIntHeader(String name,int value)
- addDateHeader(String name,date)
set
- set代表設置,已經存在的內容
- setHeader(String name,String value)
- setIntHeader(String name,int value)
- setDateHeader(String name,Date value)
- 添加兩個相同的name
重定向
什么是重定向
- 到服務器當中去找servlet1
- servlet1當中沒有這個資源,告訴你去找servlet2
- 再去發送一個請求到servlet2
狀態碼
302
特點
1.要訪問兩次服務器
- 第一次訪問是人為的去訪問
- 第二次是自動的訪問
2.瀏覽器地址欄已經發生變化
設置重定向
-
設置響應碼
-
設置響應頭
封裝的重寫向
-
每次都要寫狀態碼,和location比較麻煩
-
就給封裝了一個方法 response.sendRedirect("/bei/servlet2")
定時刷新重定向
response.setHeader("refresh","5;url=http://www.baidu.com") -
5代表5秒
-
url的值為5秒后要去跳轉的地址
設置響應體
1.通過write方法來寫
response.getwrite().wirte(“要寫的內容”)
默認情況下寫的中文內容會亂碼
把寫的內容存到緩存區中使用的是ISO8859
ISO8859不支持中文,所以會亂碼
在存之前設置可以設置存放的編碼
response.setCharacterEncoding("UTF-8")
告知瀏覽器使用的是utf-8編碼
response.setHeader("Content-Type", "text/html;charset=UTF-8");
上面代碼只需要寫第二句就行, tom看到設置了為utf-8的編碼,它在存在的時候也會使用utf-8的編碼
使用封裝寫法
response.setContentType("text/html;charset=UTF-8");
2.通過OutPutStream來寫
FileInputSteam
read方法讀取一個字節
read(byte[] b)
- 一次讀取多個字節,並存放到數組b中
- 上面是一次一滴一滴給你,這種是一次裝一水桶再給你
讀取全部的數據
FileOutputSteam
write()
一次性寫一個字符
write(buffer)
一個性寫多個字符
write(buffer,0,len)
一次性寫指定個數的字符
response注意點
getWrite()和getOutputSteam不能同時調用
下載功能
下載文件
1.直接使用a標簽來去下載,存在的問題
- 有些內容會瀏覽器自動解析
- 瀏覽器不能解析的文件才會被下載
2.通過發送Servlet請求來去下載
通過發送一個Servlet請求,把文件名發送給服務器
發送給服務器后,接收到文件名參數,獲取文件的絕對地址
通過流的形式來去寫到瀏覽器
還得要告訴文件是什么類型
瀏覽器是以MIME的類型來識別類型
this.getServletContext().getMimeType(“文件名稱”)
設置響應的類型
res.setContentType("MIME類型")
設置響應頭,告訴瀏覽器不要去解析,是以附件的形式打開,
res.setHeader("Content-Dsiposition","attachment;filename="+文件名)
步驟
1.接收文件名參數
2.獲取mime類型
3.設置瀏覽器響應類型
4.告訴瀏覽器以附件形式下載
5.獲取文件的絕對路徑
6.讀取文件流
7.獲取輸出流
8.把內容寫出到輸出流
//1.接收文件名參數
String filename = request.getParameter("filename");
String mime = this.getServletContext().getMimeType(filename);
response.setContentType(mime);
response.setHeader("Content-Disposition", "attachment;filename="+filename);
//2.獲取文件的絕對路徑
String path = this.getServletContext().getRealPath("download/"+filename);
System.out.println(path);
//3.讀取文件流
FileInputStream in = new FileInputStream(path);
//4.獲取輸出流
ServletOutputStream out = response.getOutputStream();
//5.把內容寫出到輸出流
byte[] buffer = new byte[1024];
int len = 0;
while((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
解決中文名稱亂碼問題
獲取中文參數報錯問題
高版本tomcat中的新特性:就是嚴格按照 RFC 3986規范進行訪問解析,而 RFC 3986規范定義了Url中只允許包含英文字母(a-zA-Z)、數字(0-9)、-_.~4個特殊字符以及所有保留字符(RFC3986中指定了以下字符為保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])
.../conf/catalina.properties中,找到最后注釋掉的一行 #tomcat.util.http.parser.HttpParser.requestTargetAllow=| ,改成tomcat.util.http.parser.HttpParser.requestTargetAllow=|{},表示把{}放行
1.把獲取的字符串參數的字節碼獲取,再重新使用utf-8編碼
2.在設置以附件形式打開時, 不同的瀏覽器會對默認的名字進行解碼
所以根據不同的瀏覽器,要對名稱進行編碼之后,再放入文件名
對文件名進行編碼
不同的瀏覽器編碼不一樣
要先獲取agent,取出瀏覽器的類型
根據不同的瀏覽器類型進行編碼
步驟
1.接收文件名稱
2.獲取mimeType
3.設置瀏覽器響應類型
4.先對傳入的參數轉成二進制流,再使用UTF-8進行編碼
5.獲取瀏覽器的信息
6.判斷是哪一種瀏覽器,根據不同的瀏覽器獲取一個編碼的文件名
7.設置以附件形式下載,傳的名稱是編碼過的名稱
8.獲取文件的絕對路徑
9.讀取文件流
10.獲取輸出流
11.把文件寫到響應當中
// 獲取客戶端信息
String agent = request.getHeader("User-Agent");
// 定義一個變量記錄編碼之后的名字
String filenameEncoder = "";
if (agent.contains("MSIE"))
{
// IE編碼
filenameEncoder = URLEncoder.encode(filename, "utf-8");
filenameEncoder = filenameEncoder.replace("+", " ");
}
else if (agent.contains("Firefox"))
{
// 火狐編碼
BASE64Encoder base64Encoder = new BASE64Encoder();
filenameEncoder = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
}
else
{
// 瀏覽器編碼
filenameEncoder = URLEncoder.encode(filename, "utf-8");
}
注冊驗證碼功能
1.把別人寫好的驗證碼Servlet拿到程序當中
2.編寫靜態頁面
3.編寫判斷驗證碼是否正確Servlet
1.設置響應編碼
2.從ServletContext當中獲取驗證碼
3.獲取傳入的請求參數
4.從servletContext當中取出存放的驗證碼
5.把接收的驗證碼與取出的驗證碼時行比較
6.相同時,顯示成功
7.不同時, 顯示失敗,隔3秒鍾跳轉到輸入驗證碼界面
request
如何獲取請求行, 請求頭,請求體
獲取請求行
獲取請求方法
String getMethod()
獲取請求資源
String getRequestURL()
String getRequestURI()
獲取應用名稱
String getContextPath()
獲取get查詢參數
String getQueryString()
獲取請求頭
1.獲取所有的請求頭名稱
2.獲取指定的頭信息
3.打印所有的請求頭和請求頭內容
referer
告訴服務器我是從哪個頁面鏈接過來的
注意事項
通過以下方式發送請求才會獲取
通過以下方式不會有referer
- 從收藏夾鏈接
- 單擊主頁或自定義的地址
- 在瀏覽器中直接輸地址
獲取請求體
1.獲取一個值
req.getParameter("名稱")
2.獲取多個值
req.getParameterValues("名稱")
返回的是一個數組
3.獲取所有請求參數名稱
req.getParameterNames()
返回的是一個枚舉
4.獲取所有請求參數
req.getParameterMap()
獲取所有請求參數的key-value集合Map<String,String[]>
解決中文亂碼問題
什么時候使用get方式與post方式
1.發送的參數不需要寫到數據庫當中使用get
2.發送的參數需要保存到數據庫當中使用post
form一般提交數據的數據為post
造成亂碼的原因
發送請求時, 會對參數進行編碼,編碼使用的是ISO8859-1 不支持中文,所以亂碼
通用解決辦法
獲取對應的參數
通過iso8859-1轉回二進制位,再以utf-8的形式轉成字符串
存在的問題,每一個參數都必須得要轉回二進制位,再轉為字符串
request方法解決中文亂碼
只適用於post
請求轉發
重定向與請求轉發的區別
重定向
- 找servlet1,通過設置響應,告訴瀏覽器, 再讓瀏覽器發送請求到servlet2
- 發兩次請求
- 地址欄會發生變化
請求轉發
- 請求轉發只需要發送一次直接,找servlet1,在servlet1當中直接轉發給servlet2,不要再告訴瀏覽器
- 只發送一次請求
- 瀏覽器地址欄當中還是servlet1,不會發生變化
實現轉發
1.通過請求對象獲取一個轉發器
- request.getRequestDispatcher(String path)
- 返回一個RequestDispatcher
2.通過轉發器進行轉發
- 調用轉發器的forward方法進行轉發
- disp.forward(req,rep)
request域對象
在一次請求過程當中
request是共享的。在一個servlet當中設置的參數,轉發到另外一個servlet,取出來的是同一個
生命周期
創建
發送一個請求時創建一個request對象
銷毀
請求結束,瀏覽器給出響應時,銷毀
作用范圍
一次請求當中
客戶端地址與服務器端地址
客戶端地址
- 客戶端訪問服務器使用的地址
- 服務器外部地址
- 在寫的時候要寫上web應用的名稱 /應用名稱/資源
服務器地址
- 在服務內部當中使用的地址
- 不需要寫web應用名稱 /資源名稱