深入分析JavaWeb Item7 -- HttpServletResponse详解
Web服務(wù)器收到客戶端的http請(qǐng)求,會(huì)針對(duì)每一次請(qǐng)求,分別創(chuàng)建一個(gè)用于代表請(qǐng)求的request對(duì)象、和代表響應(yīng)的response對(duì)象。request和response對(duì)象即然代表請(qǐng)求和響應(yīng),那我們要獲取客戶機(jī)提交過來的數(shù)據(jù),只需要找request對(duì)象就行了。要向客戶機(jī)輸出數(shù)據(jù),只需要找response對(duì)象就行了。
一、HttpServletResponse對(duì)象介紹
HttpServletResponse對(duì)象代表服務(wù)器的響應(yīng)。這個(gè)對(duì)象中封裝了向客戶端發(fā)送數(shù)據(jù)、發(fā)送響應(yīng)頭,發(fā)送響應(yīng)狀態(tài)碼的方法。查看HttpServletResponse的API,可以看到這些相關(guān)的方法。
1.1、負(fù)責(zé)向客戶端(瀏覽器)發(fā)送數(shù)據(jù)的相關(guān)方法
1.2、負(fù)責(zé)向客戶端(瀏覽器)發(fā)送響應(yīng)頭的相關(guān)方法
1.3、負(fù)責(zé)向客戶端(瀏覽器)發(fā)送響應(yīng)狀態(tài)碼的相關(guān)方法
1.4、響應(yīng)狀態(tài)碼的常量
HttpServletResponse定義了很多狀態(tài)碼的常量(具體可以查看Servlet的API),當(dāng)需要向客戶端發(fā)送響應(yīng)狀態(tài)碼時(shí),可以使用這些常量,避免了直接寫數(shù)字,常見的狀態(tài)碼對(duì)應(yīng)的常量:
-
狀態(tài)碼404對(duì)應(yīng)的常量
-
狀態(tài)碼200對(duì)應(yīng)的常量
-
狀態(tài)碼500對(duì)應(yīng)的常量
二、HttpServletResponse對(duì)象常見應(yīng)用
2.1、使用OutputStream流向客戶端瀏覽器輸出中文數(shù)據(jù)
使用OutputStream流輸出中文注意問題:
<font color="red">在服務(wù)器端,數(shù)據(jù)是以哪個(gè)碼表輸出的,那么就要控制客戶端瀏覽器以相應(yīng)的碼表打開,比如:outputStream.write("中國".getBytes("UTF-8"));使用OutputStream流向客戶端瀏覽器輸出中文,以UTF-8的編碼進(jìn)行輸出,此時(shí)就要控制客戶端瀏覽器以UTF-8的編碼打開,否則顯示的時(shí)候就會(huì)出現(xiàn)中文亂碼,那么在服務(wù)器端如何控制客戶端瀏覽器以以UTF-8的編碼顯示數(shù)據(jù)呢?可以通過設(shè)置響應(yīng)頭控制瀏覽器的行為,例如:response.setHeader("content-type", "text/html;charset=UTF-8");通過設(shè)置響應(yīng)頭控制瀏覽器以UTF-8的編碼顯示數(shù)據(jù)。</font>
范例:使用OutputStream流向客戶端瀏覽器輸出"中國"這兩個(gè)漢字
package gacl.response.study;import java.io.IOException; import java.io.OutputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ResponseDemo01 extends HttpServlet { private static final long serialVersionUID = 4312868947607181532L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { outputChineseByOutputStream(response);//使用OutputStream流輸出中文 } /** * 使用OutputStream流輸出中文 * @param request * @param response * @throws IOException */ public void outputChineseByOutputStream(HttpServletResponse response) throws IOException{ /**使用OutputStream輸出中文注意問題: * 在服務(wù)器端,數(shù)據(jù)是以哪個(gè)碼表輸出的,那么就要控制客戶端瀏覽器以相應(yīng)的碼表打開, * 比如:outputStream.write("中國".getBytes("UTF-8"));//使用OutputStream流向客戶端瀏覽器輸出中文,以UTF-8的編碼進(jìn)行輸出 * 此時(shí)就要控制客戶端瀏覽器以UTF-8的編碼打開,否則顯示的時(shí)候就會(huì)出現(xiàn)中文亂碼,那么在服務(wù)器端如何控制客戶端瀏覽器以以UTF-8的編碼顯示數(shù)據(jù)呢? * 可以通過設(shè)置響應(yīng)頭控制瀏覽器的行為,例如: * response.setHeader("content-type", "text/html;charset=UTF-8");//通過設(shè)置響應(yīng)頭控制瀏覽器以UTF-8的編碼顯示數(shù)據(jù) */ String data = "中國"; OutputStream outputStream = response.getOutputStream();//獲取OutputStream輸出流 response.setHeader("content-type", "text/html;charset=UTF-8");//通過設(shè)置響應(yīng)頭控制瀏覽器以UTF-8的編碼顯示數(shù)據(jù),如果不加這句話,那么瀏覽器顯示的將是亂碼 /** * data.getBytes()是一個(gè)將字符轉(zhuǎn)換成字節(jié)數(shù)組的過程,這個(gè)過程中一定會(huì)去查碼表, * 如果是中文的操作系統(tǒng)環(huán)境,默認(rèn)就是查找查GB2312的碼表, * 將字符轉(zhuǎn)換成字節(jié)數(shù)組的過程就是將中文字符轉(zhuǎn)換成GB2312的碼表上對(duì)應(yīng)的數(shù)字 * 比如: "中"在GB2312的碼表上對(duì)應(yīng)的數(shù)字是98 * "國"在GB2312的碼表上對(duì)應(yīng)的數(shù)字是99 */ /** * getBytes()方法如果不帶參數(shù),那么就會(huì)根據(jù)操作系統(tǒng)的語言環(huán)境來選擇轉(zhuǎn)換碼表,如果是中文操作系統(tǒng),那么就使用GB2312的碼表 */ byte[] dataByteArr = data.getBytes("UTF-8");//將字符轉(zhuǎn)換成字節(jié)數(shù)組,指定以UTF-8編碼進(jìn)行轉(zhuǎn)換 outputStream.write(dataByteArr);//使用OutputStream流向客戶端輸出字節(jié)數(shù)組 } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }運(yùn)行結(jié)果如下:
客戶端瀏覽器接收到數(shù)據(jù)后,就按照響應(yīng)頭上設(shè)置的字符編碼來解析數(shù)據(jù),如下所示:
2.2、使用PrintWriter流向客戶端瀏覽器輸出中文數(shù)據(jù)
使用PrintWriter流輸出中文注意問題:
<font color="red"> 在獲取PrintWriter輸出流之前首先使用"response.setCharacterEncoding(charset)"設(shè)置字符以什么樣的編碼輸出到瀏覽器,如:response.setCharacterEncoding("UTF-8");設(shè)置將字符以"UTF-8"編碼輸出到客戶端瀏覽器,然后再使用response.getWriter();獲取PrintWriter輸出流</font>. 這兩個(gè)步驟不能顛倒,如下:
response.setCharacterEncoding("UTF-8");//設(shè)置將字符以"UTF-8"編碼輸出到客戶端瀏覽器 /*** PrintWriter out = response.getWriter();這句代碼必須放在response.setCharacterEncoding("UTF-8");之后 * 否則response.setCharacterEncoding("UTF-8")這行代碼的設(shè)置將無效,瀏覽器顯示的時(shí)候還是亂碼 */ PrintWriter out = response.getWriter();//獲取PrintWriter輸出流然后再使用response.setHeader("content-type", "text/html;charset=字符編碼");設(shè)置響應(yīng)頭,控制瀏覽器以指定的字符編碼編碼進(jìn)行顯示,例如:
//通過設(shè)置響應(yīng)頭控制瀏覽器以UTF-8的編碼顯示數(shù)據(jù),如果不加這句話,那么瀏覽器顯示的將是亂碼response.setHeader("content-type", "text/html;charset=UTF-8");上述兩步可以合成一步完成:
response.setContentType("text/html; charset=UTF-8");除了可以使用response.setHeader("content-type", "text/html;charset=字符編碼");設(shè)置響應(yīng)頭來控制瀏覽器以指定的字符編碼編碼進(jìn)行顯示這種方式之外,還可以用如下的方式來模擬響應(yīng)頭的作用.
/*** 多學(xué)一招:使用HTML語言里面的<meta>標(biāo)簽來控制瀏覽器行為,模擬通過設(shè)置響應(yīng)頭控制瀏覽器行為*response.getWriter().write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'/>"); * 等同于response.setHeader("content-type", "text/html;charset=UTF-8"); */ response.getWriter().write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'/>");范例:使用PrintWriter流向客戶端瀏覽器輸出"中國"這兩個(gè)漢字
package gacl.response.study;import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ResponseDemo01 extends HttpServlet { private static final long serialVersionUID = 4312868947607181532L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { outputChineseByPrintWriter(response);//使用PrintWriter流輸出中文 } /** * 使用PrintWriter流輸出中文 * @param request * @param response * @throws IOException */ public void outputChineseByPrintWriter(HttpServletResponse response) throws IOException{ String data = "中國"; //通過設(shè)置響應(yīng)頭控制瀏覽器以UTF-8的編碼顯示數(shù)據(jù),如果不加這句話,那么瀏覽器顯示的將是亂碼 //response.setHeader("content-type", "text/html;charset=UTF-8"); response.setCharacterEncoding("UTF-8");//設(shè)置將字符以"UTF-8"編碼輸出到客戶端瀏覽器 /** * PrintWriter out = response.getWriter();這句代碼必須放在response.setCharacterEncoding("UTF-8");之后 * 否則response.setCharacterEncoding("UTF-8")這行代碼的設(shè)置將無效,瀏覽器顯示的時(shí)候還是亂碼 */ PrintWriter out = response.getWriter();//獲取PrintWriter輸出流 /** * 多學(xué)一招:使用HTML語言里面的<meta>標(biāo)簽來控制瀏覽器行為,模擬通過設(shè)置響應(yīng)頭控制瀏覽器行為 * out.write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'/>"); * 等同于response.setHeader("content-type", "text/html;charset=UTF-8"); */ out.write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'/>"); out.write(data);//使用PrintWriter流向客戶端輸出字符 } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }當(dāng)需要向?yàn)g覽器輸出字符數(shù)據(jù)時(shí),使用PrintWriter比較方便,省去了將字符轉(zhuǎn)換成字節(jié)數(shù)組那一步。
2.3、使用OutputStream或者PrintWriter向客戶端瀏覽器輸出數(shù)字
比如有如下的代碼:
package gacl.response.study;import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ResponseDemo01 extends HttpServlet { private static final long serialVersionUID = 4312868947607181532L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { outputOneByOutputStream(response);//使用OutputStream輸出1到客戶端瀏覽器 } /** * 使用OutputStream流輸出數(shù)字1 * @param request * @param response * @throws IOException */ public void outputOneByOutputStream(HttpServletResponse response) throws IOException{ response.setHeader("content-type", "text/html;charset=UTF-8"); OutputStream outputStream = response.getOutputStream(); outputStream.write("使用OutputStream流輸出數(shù)字1:".getBytes("UTF-8")); outputStream.write(1); } }運(yùn)行上面代碼顯示的結(jié)果如下:
運(yùn)行的結(jié)果和我們想象中的不一樣,數(shù)字1沒有輸出來,下面我們修改一下上面的outputOneByOutputStream方法的代碼,修改后的代碼如下:
/*** 使用OutputStream流輸出數(shù)字1* @param request* @param response* @throws IOException */public void outputOneByOutputStream(HttpServletResponse response) throws IOException{ response.setHeader("content-type", "text/html;charset=UTF-8"); OutputStream outputStream = response.getOutputStream(); outputStream.write("使用OutputStream流輸出數(shù)字1:".getBytes("UTF-8")); //outputStream.write(1); outputStream.write((1+"").getBytes()); }1+""這一步是將數(shù)字1和一個(gè)空字符串相加,這樣處理之后,數(shù)字1就變成了字符串1了,然后再將字符串1轉(zhuǎn)換成字節(jié)數(shù)組使用OutputStream進(jìn)行輸出,此時(shí)看到的結(jié)果如下:
這次可以看到輸出來的1了,這說明了一個(gè)問題:在開發(fā)過程中,如果希望服務(wù)器輸出什么瀏覽器就能看到什么,那么在服務(wù)器端都要以字符串的形式進(jìn)行輸出。
如果使用PrintWriter流輸出數(shù)字,那么也要先將數(shù)字轉(zhuǎn)換成字符串后再輸出,如下:
/*** 使用PrintWriter流輸出數(shù)字1* @param request* @param response* @throws IOException */public void outputOneByPrintWriter(HttpServletResponse response) throws IOException{ response.setHeader("content-type", "text/html;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter();//獲取PrintWriter輸出流 out.write("使用PrintWriter流輸出數(shù)字1:"); out.write(1+""); }2.4、文件下載
文件下載功能是web開發(fā)中經(jīng)常使用到的功能,使用HttpServletResponse對(duì)象就可以實(shí)現(xiàn)文件的下載
文件下載功能的實(shí)現(xiàn)思路:
1.獲取要下載的文件的絕對(duì)路徑
2.獲取要下載的文件名
3.設(shè)置content-disposition響應(yīng)頭控制瀏覽器以下載的形式打開文件
4.獲取要下載的文件輸入流
5.創(chuàng)建數(shù)據(jù)緩沖區(qū)
6.通過response對(duì)象獲取OutputStream流
7.將FileInputStream流寫入到buffer緩沖區(qū)
8.使用OutputStream將緩沖區(qū)的數(shù)據(jù)輸出到客戶端瀏覽器
范例:使用Response實(shí)現(xiàn)文件下載
package gacl.response.study; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author gacl * 文件下載 */ public class ResponseDemo02 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { downloadFileByOutputStream(response);//下載文件,通過OutputStream流 } /** * 下載文件,通過OutputStream流 * @param response * @throws FileNotFoundException * @throws IOException */ private void downloadFileByOutputStream(HttpServletResponse response) throws FileNotFoundException, IOException { //1.獲取要下載的文件的絕對(duì)路徑 String realPath = this.getServletContext().getRealPath("/download/1.JPG"); //2.獲取要下載的文件名 String fileName = realPath.substring(realPath.lastIndexOf("\\")+1); //3.設(shè)置content-disposition響應(yīng)頭控制瀏覽器以下載的形式打開文件 response.setHeader("content-disposition", "attachment;filename="+fileName); //4.獲取要下載的文件輸入流 InputStream in = new FileInputStream(realPath); int len = 0; //5.創(chuàng)建數(shù)據(jù)緩沖區(qū) byte[] buffer = new byte[1024]; //6.通過response對(duì)象獲取OutputStream流 OutputStream out = response.getOutputStream(); //7.將FileInputStream流寫入到buffer緩沖區(qū) while ((len = in.read(buffer)) > 0) { //8.使用OutputStream將緩沖區(qū)的數(shù)據(jù)輸出到客戶端瀏覽器 out.write(buffer,0,len); } in.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }運(yùn)行結(jié)果如下所示:
范例:使用Response實(shí)現(xiàn)中文文件下載
下載中文文件時(shí),需要注意的地方就是中文文件名要使用URLEncoder.encode方法進(jìn)行編碼(URLEncoder.encode(fileName, "字符編碼")),否則會(huì)出現(xiàn)文件名亂碼。
package gacl.response.study; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author gacl * 文件下載 */ public class ResponseDemo02 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { downloadChineseFileByOutputStream(response);//下載中文文件 } /** * 下載中文文件,中文文件下載時(shí),文件名要經(jīng)過URL編碼,否則會(huì)出現(xiàn)文件名亂碼 * @param response * @throws FileNotFoundException * @throws IOException */ private void downloadChineseFileByOutputStream(HttpServletResponse response) throws FileNotFoundException, IOException { String realPath = this.getServletContext().getRealPath("/download/張家界國家森林公園.JPG");//獲取要下載的文件的絕對(duì)路徑 String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);//獲取要下載的文件名 //設(shè)置content-disposition響應(yīng)頭控制瀏覽器以下載的形式打開文件,中文文件名要使用URLEncoder.encode方法進(jìn)行編碼,否則會(huì)出現(xiàn)文件名亂碼 response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8")); InputStream in = new FileInputStream(realPath);//獲取文件輸入流 int len = 0; byte[] buffer = new byte[1024]; OutputStream out = response.getOutputStream(); while ((len = in.read(buffer)) > 0) { out.write(buffer,0,len);//將緩沖區(qū)的數(shù)據(jù)輸出到客戶端瀏覽器 } in.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }運(yùn)行結(jié)果如下所示:
文件下載注意事項(xiàng):編寫文件下載功能時(shí)推薦使用OutputStream流,避免使用PrintWriter流,因?yàn)镺utputStream流是字節(jié)流,可以處理任意類型的數(shù)據(jù),而PrintWriter流是字符流,只能處理字符數(shù)據(jù),如果用字符流處理字節(jié)數(shù)據(jù),會(huì)導(dǎo)致數(shù)據(jù)丟失。
范例:使用PrintWriter流下載文件
package gacl.response.study; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author gacl * 文件下載 */ public class ResponseDemo02 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { downloadFileByPrintWriter(response);//下載文件,通過PrintWriter流 } /** * 下載文件,通過PrintWriter流,雖然也能夠?qū)崿F(xiàn)下載,但是會(huì)導(dǎo)致數(shù)據(jù)丟失,因此不推薦使用PrintWriter流下載文件 * @param response * @throws FileNotFoundException * @throws IOException */ private void downloadFileByPrintWriter(HttpServletResponse response) throws FileNotFoundException, IOException { String realPath = this.getServletContext().getRealPath("/download/張家界國家森林公園.JPG");//獲取要下載的文件的絕對(duì)路徑 String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);//獲取要下載的文件名 //設(shè)置content-disposition響應(yīng)頭控制瀏覽器以下載的形式打開文件,中文文件名要使用URLEncoder.encode方法進(jìn)行編碼 response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8")); FileReader in = new FileReader(realPath); int len = 0; char[] buffer = new char[1024]; PrintWriter out = response.getWriter(); while ((len = in.read(buffer)) > 0) { out.write(buffer,0,len);//將緩沖區(qū)的數(shù)據(jù)輸出到客戶端瀏覽器 } in.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }運(yùn)行結(jié)果如下:
正常彈出下載框,此時(shí)我們點(diǎn)擊【保存】按鈕將文件下載下來,如下所示:
可以看到,只下載了5.25MB,而這張圖片的原始大小卻是
這說明在下載的時(shí)候數(shù)據(jù)丟失了,所以下載不完全,所以這張圖片雖然能夠正常下載下來,但是卻是無法打開的,因?yàn)閬G失掉了部分?jǐn)?shù)據(jù),如下所示:
所以使用PrintWriter流處理字節(jié)數(shù)據(jù),會(huì)導(dǎo)致數(shù)據(jù)丟失,這一點(diǎn)千萬要注意,因此在編寫下載文件功能時(shí),要使用OutputStream流,避免使用PrintWriter流,因?yàn)镺utputStream流是字節(jié)流,可以處理任意類型的數(shù)據(jù),而PrintWriter流是字符流,只能處理字符數(shù)據(jù),如果用字符流處理字節(jié)數(shù)據(jù),會(huì)導(dǎo)致數(shù)據(jù)丟失。
?
from:?https://segmentfault.com/a/1190000004113284
總結(jié)
以上是生活随笔為你收集整理的深入分析JavaWeb Item7 -- HttpServletResponse详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何零基础入门产品经理
- 下一篇: 《Java 核心技术 卷1》 笔记 第六