當用戶和瀏覽器其進行交互時,會給服務器發送http請求,Web服務器收到客戶端的http請求,會針對每一次請求,分別創建一個用於代表請求的request對象、和代表響應的response對象。request和response對象即然代表請求和響應,那我們要獲取客戶機提交過來的數據,只需要找request對象就行了。要向客戶機輸出數據,只需要找response對象就行了。
最近在做一個oa的項目,有一個圖片下載的接口,通過總結對比,總結一下response.getWriter().和response.getOutputStream(),這兩個方法的區別!
首先看一下HttpServletResponse的API對着兩個對象的介紹:
不同的是response.getOutputStream()向瀏覽器輸出的是二進制數據,是字節流,可以處理任意類型的數據,而response.getWriter()輸出的是字符型數據,是字符流。
1、使用OutputStream流和PrintWriter流向客戶端瀏覽器輸出中文數據
在服務器端,數據的輸出碼表要和控制客戶端瀏覽器相應的碼表一致,比如:outputStream.write("中文".getBytes("UTF-8"));使用OutputStream流向客戶端瀏覽器輸出中文,以UTF-8的編碼進行輸出,此時就要控制客戶端瀏覽器以UTF-8的編碼打開,否則顯示的時候就會出現中文亂碼。
在服務器端如何控制客戶端瀏覽器以以UTF-8的編碼顯示數據呢?
可以通過設置響應頭控制瀏覽器的行為,例如:response.setHeader("content-type", "text/html;charset=UTF-8");通過設置響應頭控制瀏覽器以UTF-8的編碼顯示數據。
1.1使用OutputStream流向瀏覽器輸出中文
1 package controller; 2 3 import java.io.IOException; 4 import java.io.OutputStream; 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 public class ServletDemo01 extends HttpServlet { 11 private static final long serialVersionUID = 1L; 12 13 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 14 this.doPost(request, response); 15 } 16 17 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 18 19 String str="使用OutputStream輸出中文:我心自在"; 20 //在服務器設置響應頭,告訴瀏覽器以utf-8的編碼顯示數據,如果不寫會出現中文亂碼 21 response.setHeader("content-type", "text/html;charset=UTF-8"); 22 //獲取OutputStream輸出流 23 OutputStream os=response.getOutputStream(); 24 /** 25 * getBytes的作用是將字符轉化為字節數組,如果不帶參數,默認根據系統環境來進行轉化 26 * 這里指定以utf-8的編碼進行轉換 27 */ 28 byte[]b=str.getBytes("utf-8"); 29 //想客戶端(瀏覽器)輸出數據 30 os.write(b); 31 } 32 }
瀏覽器中輸入:http://localhost:8080/servlet_study/ServletDemo01,運行結果如下:
打開瀏覽器調試工具,可以看到相關編碼信息:
1.2使用PrintWriter流向瀏覽器輸出中文
1 package controller; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 public class ServletDemo02 extends HttpServlet { 11 private static final long serialVersionUID = 1L; 12 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 13 this.doPost(request, response); 14 } 15 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 16 String str="使用PrintWriter輸出中文:我心自在"; 17 //設置中文編碼格式 18 response.setCharacterEncoding("utf-8"); 19 //獲取流 20 PrintWriter pw=response.getWriter(); 21 //輸出 22 pw.write(str); 23 pw.close(); 24 } 25 26 }
瀏覽器中輸入:http://localhost:8080/servlet_study/ServletDemo02,運行結果如下:
這里需要注意的是: 在獲取PrintWriter輸出流之前首先使用"response.setCharacterEncoding(charset)"設置字符以什么樣的編碼輸出到瀏覽器,如:response.setCharacterEncoding("UTF-8");設置將字符以"UTF-8"編碼輸出到客戶端瀏覽器,然后再使用response.getWriter();獲取PrintWriter輸出流,這兩個步驟不能顛倒.如果顛倒,設置將無效,還是會出現中文亂碼!
通過比較可以看出,當需要向瀏覽器輸出字符數據時,使用PrintWriter比較方便,因為不需要將字符轉化為字節這一步!
1、使用OutputStream流和PrintWriter流下載文件
最近在做一個項目,涉及到文件的下載,所以特意整理出來做個比較。
文件下載,在實際開發中用到的很多,最近做的項目便是,查看圖片的時候,點擊圖片的時候進行圖片下載,這里將這兩個下載文件的區別做簡要比較。
文件下載,運用的步驟比較固定,大致分為以下幾步:
1.獲取要下載的文件的絕對路徑(注意是絕對路徑)
2.獲取要下載的文件名(獲取文件名要注意中文文件名的問題,需進行編碼)
3.設置content-disposition響應頭控制瀏覽器,告訴瀏覽器以下載的形式打開文件
4.獲取要下載的文件輸入流
5.創建數據緩沖區
6.通過response對象獲取OutputStream流
7.將FileInputStream流寫入到buffer緩沖區
8.使用OutputStream將緩沖區的數據輸出到客戶端瀏覽器
2.1使用OutputStream流下載中文文件
package controller; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletDemo03 extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //獲取文件的下載絕對路徑 String downloadPath=this.getServletContext().getRealPath("/download/陽光海灘.jpg"); //獲取文件名 String fileName=downloadPath.substring(downloadPath.lastIndexOf("\\")+1); //設置響應頭,告訴瀏覽器以下載的方式打來文件,設置中文編碼,如果不設置會出現亂碼 response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8")); //獲取文件流 InputStream is=new FileInputStream(downloadPath); int len=0; byte[]b=new byte[1024]; OutputStream os=response.getOutputStream(); while((len=is.read(b))!=-1){ //將緩沖區數據輸出到瀏覽器 os.write(b,0,len); } is.close(); } }
瀏覽器中輸入:http://localhost:8080/servlet_study/ServletDemo03可以成功下載圖片並且可以順利打開,
2.1使用PrintWriter流下載中文文件
package controller; import java.io.FileInputStream; 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; public class ServletDemo03 extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //獲取文件的下載絕對路徑 String downloadPath=this.getServletContext().getRealPath("/download/陽光海灘.jpg"); //獲取文件名 String fileName=downloadPath.substring(downloadPath.lastIndexOf("\\")+1); //設置響應頭,告訴瀏覽器以下載的方式打來文件,設置中文編碼,如果不設置會出現亂碼 response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8")); //獲取文件流 FileReader fr=new FileReader(downloadPath); int len=0; char[] b=new char[1024]; PrintWriter os=response.getWriter(); while((len=fr.read(b))!=-1){ //將緩沖區數據輸出到瀏覽器 os.write(b,0,len); } fr.close(); } }
瀏覽器中輸入:http://localhost:8080/servlet_study/ServletDemo03可以成功下載,但是打開的過程中卻出現了一下情況:
這是什么原因造成的呢?
PrintWriter流處理節數據,會導致數據丟失,因此在編寫下載文件功能時,要使用OutputStream流,避免使用PrintWriter流,因為OutputStream流是字節流,可以處理任意類型的數據,而PrintWriter流是字符流,只能處理字符數據,如果用字符流處理字節數據,會導致數據丟失。