若是說DOM是javascript與HTML的橋樑,那麼servlet就是前端與後端的橋樑,HttpServletRequest和HttpServletResponse就是之間的信使,好了,廢話很少說!javascript
Web服務器收到一個http請求,會針對每一個請求建立一個HttpServletRequest和HttpServletResponse對象,向客戶端發送數據找HttpServletResponse,從客戶端取數據找HttpServletRequest.html
HTTP 協議是基於請求-響應的協議,客戶端請求一個文件,服務器對該請求進行響應。HTTP 使用 TCP 協議,默認使用 80 端口。最初的 HTTP 協議版本是 HTTP/0.9,後被 HTTP/1.0 替代。目前使用的版本是 HTTP/1.1,前端
在 HTTP 協議中,老是由主動創建鏈接、發送 HTTP 請求的客戶端來初始化一個事務。服務器不負責鏈接客戶端,或建立一個到客戶端的回調鏈接(callback connection)。java
公共接口類HttpServletRequest繼承自ServletRequest.客戶端瀏覽器發出的請求被封裝成爲一個HttpServletRequest對象。全部的信息包括請求的地址,請求的參數,提交的數據,上傳的文件客戶端的ip甚至客戶端操做系統都包含在其內。web
一個 HTTP 請求包含如下三部分:編程
a.請求地址(URL)json
b.請求頭(Request headers)後端
c.實體數據(Entity body)數組
舉例以下瀏覽器
POST /examples/default.jsp HTTP/1.1
Accept: text/plain; text/html
Accept-Language: en-gb
Connection: Keep-Alive
Host: localhost
User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)
Content-Length: 33
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
lastName=Franks&firstName=Michael
每一個 HTTP 請求都會有一個請求方法,HTTP1.1 中支持的方法包括,GET、POST、HEAD、OPTIONS、
PUT、DELETE 和 TRACE。互聯網應用中最經常使用的是 GET 和 POST。
URI 指明瞭請求資源的地址,一般是從網站更目錄開始計算的一個相對路徑,所以它老是以斜線 「/」開頭的。URL 其實是 URI 的一種類型,請求頭(header)中包含了一些關於客戶端環境和請求實體(entity)的有用的信息。例如,客戶端瀏覽器所使用的語言,請求實體信息的長度等。每一個請求頭使用 CRLF(回車換行符,「\r\n」)分隔。注意請求頭的格式:
請求頭名+英文空格+請求頭值
1.得到客戶機信息
getRequestURL方法返回客戶端發出請求時的完整URL。
getRequestURI方法返回請求行中的資源名部分。
getQueryString 方法返回請求行中的參數部分。
getRemoteAddr方法返回發出請求的客戶機的IP地址
getRemoteHost方法返回發出請求的客戶機的完整主機名
getRemotePort方法返回客戶機所使用的網絡端口號
getLocalAddr方法返回WEB服務器的IP地址。
getLocalName方法返回WEB服務器的主機名
getMethod獲得客戶機請求方式
getServerPath()獲取請求的文件的路徑
2.得到客戶機請求頭
getHeader(string name)方法
getHeaders(String name)方法
getHeaderNames方法
3. 得到客戶機請求參數(客戶端提交的數據)
getParameter(name)方法 獲取請求中的參數,該參數是由name指定的
getParameterValues(String name)方法 獲取指定名稱參數的全部值數組。它適用於一個參數名對應多個值的狀況。如頁面表單中的複選框,多選列表提交的值。
getParameterNames方法 返回一個包含請求消息中的全部參數名的Enumeration對象。經過遍歷這個Enumeration對象,就能夠獲取請求消息中全部的參數名。
getCharacterEncoding() 返回請求的字符編碼方式
getAttributeNames()返回當前請求的全部屬性的名字集合賦值:setAttribute()
getAttribute(String name) 返回name指定的屬性值
getsession()返回和客戶端相關的session,若是沒有給客戶端分配session,則返回null
getParameterMap():返回一個保存了請求消息中的全部參數名和值的Map對象。Map對象的key是字符串類型的參數名,value是這個參數所對應的Object類型的值數組
RequestDispatcher.forward 方法的請求轉發過程結束後,瀏覽器地址欄保持初始的URL地址不變。方法在服務器端內部將請求轉發給另一個資源,瀏覽器只知道發出了請求並獲得了響應結果,並不知道在服務器程序內部發生了轉發行爲。
request.setCharacterEncoding("utf-8");
getReader() 獲取請求體的數據流
getInputStream() 獲取請求的輸入流中的數據
經過輸入輸出流獲取 :getInputStream() 和 getReader()
在讀取的時候經過流對象.read()方法讀取
Eg:
StringBuffer receiveMessage = new StringBuffer();
Scanner scanner = new Scanner(request.getInputStream(), "GBK");
while (scanner.hasNext()) {
receiveMessage.append(scanner.next());
}
scanner.close();
String json =receiveMessage.toString()
JSONObject obj = new JSONObject(json);
openId = obj.get("openid").toString();
1. java程序中默認的是中文字符----unicode
2. 系統會把在java程序中的unicode字符按照某種字符集編碼的方式轉換成字節數組,再經過瀏覽器輸出,瀏覽器在輸出的時候要進行解碼,只有在這兩種方式同樣的狀況下,纔不會出現亂碼。
注:(1)某種字符編碼是用reponse對象去設置的,並且必須是在out.println以前使用,要不會出現錯誤,會拋找不到設置的字符編碼而出錯。
設置編碼的兩種方式:
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
(2)瀏覽器會把字節數組轉換成字符
解決辦法以下
Post方式提交出現亂碼
request.setCharacterEncoding("UTF-8");
請求中之因此會產生亂碼,就是由於服務器和客戶端溝通的編碼不一致形成的,所以解決的辦法是:在客戶端和服務器之間設置一個統一的編碼,以後就按照此編碼進行數據的傳輸和接收。
因爲客戶端是以UTF-8字符編碼將表單數據傳輸到服務器端的,所以服務器也須要設置以UTF-8字符編碼進行接收,要想完成此操做,服務器能夠直接使用從ServletRequest接口繼承而來的"setCharacterEncoding(charset)"方法進行統一的編碼設置。使用request.setCharacterEncoding("UTF-8");設置服務器以UTF-8的編碼接收數據後,此時就不會產生中文亂碼問題了
Get方式提交出現亂碼
對於以get方式傳輸的數據,request即便設置了以指定的編碼接收數據也是無效的,默認的仍是使用ISO8859-1這個字符編碼來接收數據,客戶端以UTF-8的編碼傳輸數據到服務器端,而服務器端的request對象使用的是ISO8859-1這個字符編碼來接收數據,服務器和客戶端溝通的編碼不一致所以纔會產生中文亂碼的。
解決辦法:在接收到數據後,先獲取request對象以ISO8859-1字符編碼接收到的原始數據的字節數組,而後經過字節數組以指定的編碼構建字符串,解決亂碼問題。代碼以下:
String name = request.getParameter("name");//接收數據
name =new String(name.getBytes("ISO8859-1"), "UTF-8") ;//獲取request對象以ISO8859-1字符編碼接收到的原始數據的字節數組,而後經過字節數組以指定的編碼構建字符串,解決亂碼問題
HttpServletResponse繼承了ServletResponse接口,並提供了與Http協議有關的方法,這些方法的主要功能是設置HTTP狀態碼和管理Cookie。HttpServletResponse對象表明服務器的響應。這個對象中封裝了向客戶端發送數據、發送響應頭,發送響應狀態碼的方法
HttpServletResponse對象能夠向客戶端發送三種類型的數據:
a.響應頭(Response headers)
b.狀態碼(Protocol—Status code—Description)
c.實體數據(Entity body )
舉例以下:
HTTP/1.1 200 OK
Server: Microsoft-IIS/4.0
Date: Mon, 5 Jan 2004 13:13:33 GMT
Content-Type: text/html
Last-Modified: Mon, 5 Jan 2004 13:13:12 GMT
Content-Length: 112
<html><head><title>HTTP Response Example</title></head>....</html>
addHeader(String name,String value) 將指定的名字和值加入到響應的頭信息中
encodeURL(String url) 編碼指定的URL
sendError(int sc) 使用指定狀態碼發送一個錯誤到客戶端
setDateHeader(String name,long date 將給出的名字和日期設置響應的頭部
setHeader(String name,String value) 將給出的名字和值設置響應的頭部
setStatus(int sc) 給當前響應設置狀態碼
HttpServletResponse.sendRedirect 方法對瀏覽器的請求直接做出響應,響應的結果就是告訴瀏覽器去從新發出對另一個URL的訪問請求;方法調用者與被調用者使用各自的request對象和response對象,它們屬於兩個獨立的訪問請求和響應過程。
response.setContentType("text/html;charset=utf-8");
setContentType(String ContentType) 設置響應的MIME類型 ,頁面的設置文本類型,獲取或設置輸出流的 HTTP MIME 類型。輸出流的 HTTP MIME 類型。默認值爲「text/html」。
MIME類型就是設定某種擴展名的文件用一種應用程序來打開的方式類型,當該擴展名文件被訪問的時候,瀏覽器會自動使用指定應用程序來打開。多用於指定一些客戶端自定義的文件名,以及一些媒體文件打開方式。
使用輸出流輸出一張圖片的時候,好比作驗證碼圖片的時候 若是在Firefox中直接瀏覽驗證碼是亂碼,放在<img>裏面則不會
這時候就要事先指定Response.ContentType = "image/jpeg";//設定MIME類型
response.setHeader(「Refresh」,」2;url=」http://www.baidu.com」); 頁面的刷新
消息實體內容 經過輸出流對象進行設置,用如下兩個方法:
Response.getOutputStream() 字節輸出流對象
Response.getWriter() 字符的輸出流對象
getOutputStream和getWriter方法的比較
(1)getOutputStream方法用於返回Servlet引擎建立的字節輸出流對象,Servlet程序能夠按字節形式輸出響應正文。
(2)getWriter方法用於返回Servlet引擎建立的字符輸出流對象,Servlet程序能夠按字符形式輸出響應正文。
(3)getOutputStream和getWriter這兩個方法互相排斥,調用了其中的任何一個方法後,就不能再調用另外一方法。要不會出現錯誤java.lang.IllegalStateException
(4)getOutputStream方法返回的是字節輸出流對象的類型爲ServletOutputStream,它能夠直接輸出字節數組中的二進制數據。
(5)getWriter方法將Servlet引擎的數據緩衝區包裝成PrintWriter類型的字符輸出流對象後返回,PrintWriter對象能夠直接輸出字符文本內容。
(6)Servlet程序向ServletOutputStream或PrintWriter對象中寫入的數據將被Servlet引擎獲取,Servlet引擎將這些數據看成響應消息的正文,而後再與響應狀態行和各響應頭組合後輸出到客戶端。
(7)Serlvet的service方法結束後,Servlet引擎將檢查getWriter或getOutputStream方法返回的輸出流對象是否已經調用過close方法,若是沒有,Servlet引擎將調用close方法關閉該輸出流對象。
注:out.close();系統會本身釋放,但通常寫上
選擇getOutputStream和getWrite方法的要點
(1)PrintWriter對象輸出字符文本內容時,它內部仍是將字符串轉換成了某種字符集編碼的字節數組後再進行輸出,使用PrintWriter對象的好處就是不用編程人員本身來完成字符串到字節數組的轉換。
(2)使用ServletOutputStream對象也能輸出內容全爲文本字符的網頁文檔,可是,若是網頁文檔內容是在Servlet程序內部使用文本字符串動態拼湊和建立出來的,則須要先將字符文本轉換成字節數組後輸出。
(3)若是一個網頁文檔內容所有爲字符文本,可是這些內容能夠直接從一個字節輸入流中讀取出來,而後再原封不動地輸出到客戶端,那麼就應該使用ServletOutputStream對象直接進行輸出,而不要使用PrintWriter對象進行輸出。
使用OutputStream向客戶端寫入中文:
String data = "中國";
OutputStream stream = response.getOutputStream();//獲取一個向Response對象寫入數據的流,當tomcat服務器進行響應的時候,會將Response中的數據寫給瀏覽器
stream.write(data.getBytes("UTF-8"));//此時在html頁面會出現亂碼,這是由於:服務器將"中國"按照UTF-8碼錶進行編碼,獲得對應的碼值假設是98,99,服務器將碼值發送給瀏覽器.瀏覽器默認按照GB2312進行解碼,在GB2312碼錶中對應的字符已不是"中國"
正確代碼以下:
response.setHeader("Content-type","text/html;charset=UTF-8");//向瀏覽器發送一個響應頭,設置瀏覽器的解碼方式爲UTF-8
String data = "中國";
OutputStream stream = response.getOutputStream();
stream.write(data.getBytes("UTF-8"));
使用PrintWriter向客戶端寫入中文:
PrintWriter writer = response.getWriter();
writer.write("中國");
//一樣會出現亂碼,這是由於咱們將"中國"寫入response對象時,tomcat服務器爲了將數據經過網絡傳輸給瀏覽器,必須進行編碼,因爲沒有指定編碼方式,默認採用ISO8859-1,當瀏覽器接收到數據後,根據GBK解碼必然出現亂碼
正確代碼以下:
response.setCharacterEncoding("UTF_8");//設置Response的編碼方式爲UTF-8
response.setHeader("Content-type","text/html;charset=UTF-8");//向瀏覽器發送一個響應頭,設置瀏覽器的解碼方式爲UTF-8,其實設置了本句,也默認設置了Response的編碼方式爲UTF-8,可是開發中最好兩句結合起來使用 ,設置響應頭,控制瀏覽器以指定的字符編碼編碼進行顯示,
//response.setContentType("text/html;charset=UTF-8");同上句代碼做用同樣
PrintWriter writer = response.getWriter();
writer.write("中國");
在獲取PrintWriter輸出流以前首先使用"response.setCharacterEncoding(charset)"設置字符以什麼樣的編碼輸出到瀏覽器,如:response.setCharacterEncoding("UTF-8");設置將字符以"UTF-8"編碼輸出到客戶端瀏覽器,而後再使用response.getWriter();獲取PrintWriter輸出流,這兩個步驟不能顛倒
文件下載功能是web開發中常用到的功能,使用HttpServletResponse對象就能夠實現文件的下載
文件下載功能的實現思路:
1.獲取要下載的文件的絕對路徑
2.獲取要下載的文件名
3.設置content-disposition響應頭控制瀏覽器如下載的形式打開文件
4.獲取要下載的文件輸入流
5.建立數據緩衝區//緩衝區解釋見下文
6.經過response對象獲取OutputStream流
7.將FileInputStream流寫入到buffer緩衝區
8.使用OutputStream將緩衝區的數據輸出到客戶端瀏覽器
案例1
private void downloadFileByOutputStream(HttpServletResponse response){
//1.獲取要下載的文件的絕對路徑
String realPath = this.getServletContext().getRealPath("/download/1.JPG");
//2.獲取要下載的文件名
String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);
//3.設置content-disposition響應頭控制瀏覽器如下載的形式打開文件
response.setHeader("content-disposition", "attachment;filename="+fileName);
//4.根據文件路徑獲取要下載的文件輸入流
InputStream in = new FileInputStream(realPath);
int len = 0;
//5.建立數據緩衝區
byte[] buffer = new byte[1024];
//6.經過response對象獲取OutputStream流
OutputStream out = response.getOutputStream();
//7.將FileInputStream流寫入到buffer緩衝區 while ((len = in.read(buffer)) > 0) {
//8.使用OutputStream將緩衝區的數據輸出到客戶端瀏覽器
out.write(buffer,0,len);
}
in.close();
}
案例2
@RequestMapping("/download")
public void download(HttpServletRequest req,HttpServletResponse res){
String fileName = "plcdmb.xls";//要下載的文件名
//1.獲取要下載的文件的絕對路徑
String realPath = req.getSession().getServletContext().getRealPath("/wbms/download");
File file=new File(realPath+"/"+fileName); //設置content-disposition響應頭控制瀏覽器如下載的形式打開文件
res.setCharacterEncoding("utf-8");
res.setContentType("application/octet-stream");
res.setHeader("Content-Disposition", "attachment;fileName="+ URLEncoder.encode("批量出單模板.xls", "UTF-8"));
InputStream inputStream=new FileInputStream(file);根據路徑獲取要下載的文件輸入流
OutputStream out = res.getOutputStream();
byte[] b=new byte[1024]; //建立數據緩衝區
int length;
while((length=inputStream.read(b))>0){ 把文件流寫到緩衝區裏
out.write(b,0,length);
}
out.flush();
out.close();
inputStream.close();
}
在編寫下載文件功能時,要使用OutputStream流,避免使用PrintWriter流,由於OutputStream流是字節流,能夠處理任意類型的數據,而PrintWriter流是字符流,只能處理字符數據,若是用字符流處理字節數據,會致使數據丟失。
在jsp嵌套的java代碼中執行js
<%
//保存登陸信息
Cookie[] cookies=request.getCookies();//從request中得到cookie對象的集合
String phone="";//電話號
String state="";//
if(cookies!=null){
for(int i=0;i<cookies.length;i++){
if(cookies[i].getName().equals("state")){
state=cookies[i].getValue();
if(state.equals("cont_failed")){
out.write("<script language='javascript'> alert('hello'); </script>;");
}
}
}
}
%>
getWriter()輸出js代碼的案例
1.res.getWriter().write("<script language=\"javascript\">location.href='"+req.getContextPath()+"/wbms/ecm//init.action';</script>");//在原頁面輸出
res.getWriter().flush();
2.response.getWriter().write("<script language='javascript'>alert('請上傳正確格式的文件!!!');window.history.back();</script>");
3.res.getWriter().flush();
若是不使用這種形式,傳值用request.setAttribute()來傳值跳轉用重定向或者轉發頁面取值能夠用jstl的$()取值能夠在input標籤的value中使用$()取值
ServletRequest
表明一個HTTP請求,請求在內存中是一個對象,這個對象是一個容器,能夠存放請求參數和屬性。
請求對象什麼時候被建立,當經過URL訪問一個JSP或者Servlet的時候,也就是當調用Servlet的service()、doPut()、doPost()、doXxx()方法時候的時候,執行Servlet的web服務器就自動建立一個ServletRequest和ServletResponse的對象,傳遞給服務方法做爲參數。
請求對象由Servlet容器自動產生,這個對象中自動封裝了請求中get和post方式提交的參數,以及請求容器中的屬性值,還有http頭等等。當Servlet或者JSP獲得這個請求對象的時候,就知道這個請求時從哪裏發出的,請求什麼資源,帶什麼參數等等。經過請求對象,能夠得到Session對象和客戶端的Cookie。請求須要指定URL,瀏覽器根據URL生成HTTP請求併發送給服務器.
ServletResponse
也是由容器自動建立的,表明Servlet對客戶端請求的響應,響應的內容通常是HTML,而HTML僅僅是響應內容的一部分。請求中若是還包含其餘資源會依次獲取,如頁面中含有圖片,會進行第二個http請求用來得到圖片內容。
相應對象有如下功能:
一、向客戶端寫入Cookie
二、重寫URL
三、獲取輸出流對象,向客戶端寫入文本或者二進制數據
四、設置響應客戶端瀏覽器的字符編碼類型
五、設置客戶端瀏覽器的MIME類型。
Servlet 接口須要實現下面的 5 個方法:
public void init(ServletConfig config) throws ServletException
public void service(ServletRequest request, ServletResponse response) throws ServletException,
java.io.IOException
public void destroy()
public ServletConfig getServletConfig()
public java.lang.String getServletInfo()
在某個 servlet 類被實例化以後,init 方法由 servlet 容器調用。servlet 容器只調用該方法一次,調用後則能夠執行服務方法了。在 servlet 接收任何請求以前,必須是通過正確初始化的。
當一個客戶端請求到達後,servlet 容器就調用相應的 servlet 的 service 方法,並將 Request 和 Response對象做爲參數傳入。在 servlet 實例的生命週期內,service 方法會被屢次調用。
在將 servlet 實例從服務中移除前,會調用 servlet 實例的 destroy 方法。通常狀況下,在服務器關閉前,會發生上述狀況,servlet 容器會釋放內存。只有當 servlet 實例的 service 方法中全部的線程都退出或執行超時後,纔會調用 destroy 方法。當容器調用了 destroy 方法後,就不會再調用 service 方法了。
下面從 servlet 容器的角度觀察 servlet 的開發。在一個全功能 servlet 容器中,對 servlet 的每一個 HTTP 請求來講,容器要作下面幾件事:
1.當第一次調用 servlet 時,要載入 servlet 類,調用 init 方法(僅此一次);
2.針對每一個 request 請求,建立一個 Request 對象和一個 Resposne 對象;
3.調用相應的 servlet 的 service 方法,將 Request 對象和 Response 對象做爲參數傳入;
4.當關閉 servlet 時,調用 destroy 方法,並卸載該 servlet 類。
1.輸出緩衝區的介紹
(1)Servlet程序輸出的HTTP消息的響應正文首先被寫入到Servlet引擎提供的一個輸出緩衝區中,直到輸出緩衝區被填滿或者Servlet程序已經寫入了全部的響應內容,緩衝區中的內容纔會被Servlet引擎發送到客戶端。
(2)使用輸出緩衝區後,Servlet引擎就能夠將響應狀態行、各響應頭和響應正文嚴格按照HTTP消息的位置順序進行調整後再輸出到客戶端。
(3)若是在提交響應到客戶端時,輸出緩衝區中已經裝入了全部的響應內容,Servlet引擎將計算響應正文部分的大小並自動設置Content-Length頭字段。
(4)若是在提交響應到客戶端時,輸出緩衝區中裝入的內容只是所有響應內容的一部分,Servlet引擎將使用HTTP1.1的chunked編碼方式(經過設置Transfer-Encoding頭字段來指定)傳輸響應內容。
輸出緩衝區的有關方法
System.out.println(response.getBufferSize()); //讀取緩存區的大小
response.setBufferSize(1024); //設置緩衝區的的大小,會小與你設置的值
System.out.println(response.getBufferSize());
int len=response.getBufferSize(); //填滿緩衝區
for(int i =0;i<len;i++){
System.out.println("w");
}