Servlet---ServletResponse和ServletRequest(3)

當一個 Servlet 首次被 Web 服務器創建時,會傳遞一個 Response 和 Request 對象過去。

    Web 服務器收到客戶端的 HTTP 請求時,會針對每一次請求分別創建一個用於代表請求的 Resquest 對象和代表響應的 Response 對象。

 

一、HttpServletResponse

 

       1、常用方法:

                                setStatus(int sc) --- 設置向客戶機響應的狀態碼

 

                                 setHeader(String name,String value) --- 設置一個響應頭信息

 

                                 getWriter() --- 得到向客戶機輸出的字符流

 

                                  getOutputStream() --- 得到向客戶機輸出的字節流

 

二、OutputStream 輸出中文亂碼問題

 

       當服務器向 response 中寫如中文的時候,response 會按照本地的字符編碼方式對中文進行編碼,比如本地計算機的編碼方式爲 gb2312,則服務器會按照 gb2312 的方式進行編碼。然後將數據傳遞給遠方客戶端,由於客戶端收到的是數據而不是中文,則客戶端瀏覽器會按照瀏覽器的編碼方式對數據進行解碼,如果客戶瀏覽器的編碼方式與服務器的不一致,則導致亂碼問題的出現。解決方案:

 

          (1)  向 response 對象中寫入一個消息頭信息,通知客戶瀏覽器用指定的編碼方式解碼

[java] view plain copy
 print?
  1. public void test1(HttpServletResponse response) throws IOException{  
  2.         response.setHeader("content-type""text/html;charset=utf-8");  
  3.         response.getOutputStream().write(("中國").getBytes("utf-8"));  
  4.     }  


 

          (2) 利用 <meta> 標籤模擬 HTTP 響應消息頭,此方法不是用過 HTTP 協議發送消息頭,而是直接在源文件中加如 <meta> 聲明

[java] view plain copy
 print?
  1. public void test2(HttpServletResponse response) throws IOException{  
  2.         response.getOutputStream().write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'>".getBytes());  
  3.         response.getOutputStream().write(("中國").getBytes("utf-8"));  
  4.     }  


 


          (3) 當這樣向瀏覽器輸出:response.getOutputStream().write(1); 時,瀏覽器依然會顯示亂碼,因爲瀏覽器是一個字符解析的工具,它會在它當前的編碼方式內查找 1 對應的字符,顯然會出現亂碼。應修改爲:response.getOutputStream().write((1 + "").getBytes());  將 1 轉爲字符串 1,在所有的碼錶中,字符 1 就是都是一樣的編碼方式。

 

三、PrintWriter 輸出中文亂碼問題

 

       與 OutputStream 不同,因爲無論是 PrintWriter 還是 OutputStream 都是向 response 中寫入數據,但是 response 在緩存數據的時候是採用字節數組的形式,由於 OutputStream 得到的就是二進制數據,會直接保存在緩衝區中,所以先前指定好的字符編碼方式可以正常使用。而 PrintWriter 是保存的字符數據,在保存到 response 的時候,會採用 ISO8859-1 的編碼方式對字符進行編碼,所以無論先前怎麼指定編碼方式,對最後的改動都不會起到作用,所以我們在使用 PrintWriter 寫數據的時候要先指定 response 的編碼方式。解決方案:

 

          1、先設置 response 中的編碼方式,再向客戶機寫入消息頭,指定編碼方式

[java] view plain copy
 print?
  1. <span style="font-size:18px;">public void test1(HttpServletResponse response) throws IOException{  
  2.     response.setCharacterEncoding("utf-8");  
  3.     response.getWriter().write("中國");  
  4.     response.setHeader("content-type""text/html;charset=utf-8");  
  5. }</span>  

 

   2、直接調用 response 中的 setContentType 方法,該方法除了設置客戶機的編碼方式,它還修改了 response 中的編碼方式

[java] view plain copy
 print?
  1. <span style="font-size:18px;">public void test2(HttpServletResponse response) throws IOException{  
  2.     response.setContentType("text/html;charset=utf-8");  
  3.     response.getWriter().write("中國");  
  4. }</span>  




 

四、文件下載

 

       下載步驟:1、獲得文件的絕對路徑。2、通過路徑創建出一個文件對象。3、獲得這個文件對象的輸入流。4、增加頭信息的 <content-disposition> 標籤,告訴客戶機是下載文件的方式,不是打開文件的方式。(setHeader("content-disposition","attachment;filename" + name))。5、獲取服務器的輸出流,向客戶機寫出數據,關閉文件輸入流。

 

[java] view plain copy
 print?
  1. public void download(HttpServletResponse response) throws FileNotFoundException, IOException{  
  2.         response.setHeader("content-type""text/html;charset=utf-8");  
  3.         String realpath = this.getServletContext().getRealPath("/download/1.gif");  
  4.         File file = new File(realpath);  
  5.         OutputStream out = response.getOutputStream();  
  6.           
  7.         if(!file.exists()){  
  8.             out.write("對不起,該文件已被刪除".getBytes("utf-8"));  
  9.             return;  
  10.         }  
  11.         String filename = realpath.substring(realpath.lastIndexOf("\\") + 1);  
  12.         response.setHeader("content-disposition""attachment;filename=" + filename);  
  13.           
  14.         FileInputStream in = new FileInputStream(file);  
  15.         int len = 0;  
  16.         byte[] b = new byte[1024];  
  17.           
  18.         while((len=in.read(b))!=-1){  
  19.             out.write(b, 0, len);  
  20.         }  
  21.         in.close();  
  22.     }  


 

            這種方式對於中文的文件名並不適用。如果是中文文件名要經過 URL 編碼,如果文件名中包含空格,那麼 URL 編碼後會用 + 號替換掉,所以在編碼後的名字中要用 %20 來替換

 

[java] view plain copy
 print?
  1. public void download1(HttpServletResponse response) throws FileNotFoundException, IOException{  
  2.         response.setHeader("content-type""text/html;charset=utf-8");  
  3.         String realpath = this.getServletContext().getRealPath("/download/超級瑪 麗.gif");  
  4.         File file = new File(realpath);  
  5.         OutputStream out = response.getOutputStream();  
  6.           
  7.         if(!file.exists()){  
  8.             out.write("對不起,該文件已被刪除".getBytes("utf-8"));  
  9.             return;  
  10.         }  
  11.         String filename = realpath.substring(realpath.lastIndexOf("\\") + 1);  
  12.         filename = URLEncoder.encode(filename, "utf-8");  
  13.         filename = filename.replaceAll("\\+""%20");  
  14.         response.setHeader("content-disposition""attachment;filename=" + filename);  
  15.           
  16.         FileInputStream in = new FileInputStream(file);  
  17.         int len = 0;  
  18.         byte[] b = new byte[1024];  
  19.           
  20.         while((len=in.read(b))!=-1){  
  21.             out.write(b, 0, len);  
  22.         }  
  23.         in.close();  
  24.     }  


 

五、編寫驗證碼

 

       步驟:1、在內存中創建一個緩衝圖片

                     2、得到這個圖片的圖形 Graphics

                     3、在這個圖形上填充矩形

                     4、在這個圖形上畫邊框

                     5、在這個圖形上畫干擾線

                     6、在這個圖形上畫字符串

                     7、利用圖像流寫入到客戶端瀏覽器上

 

[java] view plain copy
 print?
  1. public class ValidatePic extends HttpServlet {  
  2.   
  3.     private static final int WIDTH = 130;  
  4.     private static final int HEIGHT = 30;  
  5.   
  6.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  7.             throws ServletException, IOException {  
  8.   
  9.         // 在內存中創建一個圖片  
  10.         BufferedImage image = new BufferedImage(WIDTH, HEIGHT,  
  11.                 BufferedImage.TYPE_INT_RGB);  
  12.         // 得到這個內存圖形  
  13.         Graphics g = image.getGraphics();  
  14.         // 填充矩形背景  
  15.         setbgcolor(g);  
  16.         // 畫矩形邊框  
  17.         drawRect(g);  
  18.         // 畫干擾線  
  19.         drawLine(g);  
  20.         // 畫文字  
  21.         drawString((Graphics2D)g);  
  22.   
  23.         // 用圖片io流寫入瀏覽器  
  24.         response.setContentType("image/gif");  
  25.         response.setDateHeader("Expries", -1);  
  26.         response.setHeader("Pragma""no-cache");  
  27.         response.setHeader("Cache-Control""no-cache");  
  28.         ImageIO.write(image, "gif", response.getOutputStream());  
  29.         g.dispose();  
  30.     }  
  31.   
  32.     public void drawRect(Graphics g) {  
  33.         g.setColor(Color.RED);  
  34.         g.drawRect(11, WIDTH - 2, HEIGHT - 2);  
  35.     }  
  36.   
  37.     public void setbgcolor(Graphics g) {  
  38.         g.setColor(Color.YELLOW);  
  39.         g.fillRect(00, WIDTH, HEIGHT);  
  40.     }  
  41.   
  42.     public void drawLine(Graphics g) {  
  43.         for (int i = 0; i < 7; i++) {  
  44.             int x = new Random().nextInt(WIDTH);  
  45.             int y = new Random().nextInt(HEIGHT);  
  46.   
  47.             int x1 = new Random().nextInt(WIDTH);  
  48.             int y1 = new Random().nextInt(HEIGHT);  
  49.   
  50.             g.drawLine(x, y, x1, y1);  
  51.         }  
  52.     }  
  53.   
  54.     public void drawString(Graphics2D g) {  
  55.         String words = "\u7684\u4e00\u4e86\u662f\u6211\u4e0d\u5728\u4eba\u4eec\u6709\u6765\u4ed6\u8fd9\u4e0a\u7740\u4e2a\u5730\u5230\u5927\u91cc\u8bf4\u5c31\u53bb\u5b50\u5f97\u4e5f\u548c\u90a3\u8981\u4e0b\u770b\u5929\u65f6\u8fc7\u51fa\u5c0f\u4e48\u8d77\u4f60\u90fd\u628a\u597d\u8fd8\u591a\u6ca1\u4e3a\u53c8\u53ef\u5bb6\u5b66\u53ea\u4ee5\u4e3b\u4f1a\u6837\u5e74\u60f3\u751f\u540c\u8001\u4e2d\u5341\u4ece\u81ea\u9762\u524d\u5934\u9053\u5b83\u540e\u7136\u8d70\u5f88\u50cf\u89c1\u4e24\u7528\u5979\u56fd\u52a8\u8fdb\u6210\u56de\u4ec0\u8fb9\u4f5c\u5bf9\u5f00\u800c\u5df1\u4e9b\u73b0\u5c71\u6c11\u5019\u7ecf\u53d1\u5de5\u5411\u4e8b\u547d\u7ed9\u957f\u6c34\u51e0\u4e49\u4e09\u58f0\u4e8e\u9ad8\u624b\u77e5\u7406\u773c\u5fd7\u70b9\u5fc3\u6218\u4e8c\u95ee\u4f46\u8eab\u65b9\u5b9e\u5403\u505a\u53eb\u5f53\u4f4f\u542c\u9769\u6253\u5462\u771f\u5168\u624d\u56db\u5df2\u6240\u654c\u4e4b\u6700\u5149\u4ea7\u60c5\u8def\u5206\u603b\u6761\u767d\u8bdd\u4e1c\u5e2d\u6b21\u4eb2\u5982\u88ab\u82b1\u53e3\u653e\u513f\u5e38\u6c14\u4e94\u7b2c\u4f7f\u5199\u519b\u5427\u6587\u8fd0\u518d\u679c\u600e\u5b9a\u8bb8\u5feb\u660e\u884c\u56e0\u522b\u98de\u5916\u6811\u7269\u6d3b\u90e8\u95e8\u65e0\u5f80\u8239\u671b\u65b0\u5e26\u961f\u5148\u529b\u5b8c\u5374\u7ad9\u4ee3\u5458\u673a\u66f4\u4e5d\u60a8\u6bcf\u98ce\u7ea7\u8ddf\u7b11\u554a\u5b69\u4e07\u5c11\u76f4\u610f\u591c\u6bd4\u9636\u8fde\u8f66\u91cd\u4fbf\u6597\u9a6c\u54ea\u5316\u592a\u6307\u53d8\u793e\u4f3c\u58eb\u8005\u5e72\u77f3\u6ee1\u65e5\u51b3\u767e\u539f\u62ff\u7fa4\u7a76\u5404\u516d\u672c\u601d\u89e3\u7acb\u6cb3\u6751\u516b\u96be\u65e9\u8bba\u5417\u6839\u5171\u8ba9\u76f8\u7814\u4eca\u5176\u4e66\u5750\u63a5\u5e94\u5173\u4fe1\u89c9\u6b65\u53cd\u5904\u8bb0\u5c06\u5343\u627e\u4e89\u9886\u6216\u5e08\u7ed3\u5757\u8dd1\u8c01\u8349\u8d8a\u5b57\u52a0\u811a\u7d27\u7231\u7b49\u4e60\u9635\u6015\u6708\u9752\u534a\u706b\u6cd5\u9898\u5efa\u8d76\u4f4d\u5531\u6d77\u4e03\u5973\u4efb\u4ef6\u611f\u51c6\u5f20\u56e2\u5c4b\u79bb\u8272\u8138\u7247\u79d1\u5012\u775b\u5229\u4e16\u521a\u4e14\u7531\u9001\u5207\u661f\u5bfc\u665a\u8868\u591f\u6574\u8ba4\u54cd\u96ea\u6d41\u672a\u573a\u8be5\u5e76\u5e95\u6df1\u523b\u5e73\u4f1f\u5fd9\u63d0\u786e\u8fd1\u4eae\u8f7b\u8bb2\u519c\u53e4\u9ed1\u544a\u754c\u62c9\u540d\u5440\u571f\u6e05\u9633\u7167\u529e\u53f2\u6539\u5386\u8f6c\u753b\u9020\u5634\u6b64\u6cbb\u5317\u5fc5\u670d\u96e8\u7a7f\u5185\u8bc6\u9a8c\u4f20\u4e1a\u83dc\u722c\u7761\u5174\u5f62\u91cf\u54b1\u89c2\u82e6\u4f53\u4f17\u901a\u51b2\u5408\u7834\u53cb\u5ea6\u672f\u996d\u516c\u65c1\u623f\u6781\u5357\u67aa\u8bfb\u6c99\u5c81\u7ebf\u91ce\u575a\u7a7a\u6536\u7b97\u81f3\u653f\u57ce\u52b3\u843d\u94b1\u7279\u56f4\u5f1f\u80dc\u6559\u70ed\u5c55\u5305\u6b4c\u7c7b\u6e10\u5f3a\u6570\u4e61\u547c\u6027\u97f3\u7b54\u54e5\u9645\u65e7\u795e\u5ea7\u7ae0\u5e2e\u5566\u53d7\u7cfb\u4ee4\u8df3\u975e\u4f55\u725b\u53d6\u5165\u5cb8\u6562\u6389\u5ffd\u79cd\u88c5\u9876\u6025\u6797\u505c\u606f\u53e5\u533a\u8863\u822c\u62a5\u53f6\u538b\u6162\u53d4\u80cc\u7ec6";  
  56.         int x = 10;  
  57.         for (int i = 0; i < 4; i++) {  
  58.             char word = words.charAt(new Random().nextInt(words.length()));  
  59.             g.setFont(new Font("隸書", Font.BOLD, 20));  
  60.             g.setColor(Color.BLUE);  
  61.               
  62.             int degree = new Random().nextInt()%30;  
  63.             g.rotate(degree*Math.PI/180,x,20);  
  64.             g.drawString(word+"",x, 20);  
  65.               
  66.             g.rotate(-degree*Math.PI*180,x,20);  
  67.             x = x + 30;  
  68.         }  
  69.     }  
  70. }  


 

六、定時刷新(瀏覽器登錄跳轉、論壇帖子刷新)

 

       HTTP 定時刷新的消息頭:"Refresh","3"

 

         

[java] view plain copy
 print?
  1. public class Refresh extends HttpServlet {  
  2.   
  3.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  4.             throws ServletException, IOException {  
  5.   
  6.         response.setHeader("Refresh""3");  
  7.         int num = new Random().nextInt();  
  8.         response.getWriter().write(num+"");  
  9.     }  
  10. }  


 

[java] view plain copy
 print?
  1. private void director(HttpServletResponse response){  
  2.         response.setHeader("Refresh""2;url=/day05/index.jsp");  
  3.     }  

 

            通常我們不這樣跳轉頁面,我們會將消息放在域對象裏面,帶給顯示層的 jsp 然後在 jsp 的 <meta> 標籤內加入

                   <meta equiv="refresh" content="3";/project/index.jsp>

七、讓瀏覽器緩存數據

 

       我們可以在響應消息頭中增加 "expires",System.currentTimeMillis() + 3600*1000 注意是當前的系統毫秒數加上緩存的時間

 

八、response 的請求重定向

 

       請求重定向是指:一個 Web 資源收到客戶請求後,通知客戶端應去訪問另外一個 Web 資源,這就是請求重定向。一次請求重定向需要像服務器發送兩次請求,並且地址欄有變化,應用場景多爲用戶登錄。

 

           1、response.sendRedirect() 實現請求重定向

[java] view plain copy
 print?
  1. public void doGet(HttpServletRequest request, HttpServletResponse response)  
  2.             throws ServletException, IOException {  
  3.         response.sendRedirect("/day05/index.jsp");  
  4.     }  


 

 

            2、302 狀態碼和 location 頭實現請求重定向

[java] view plain copy
 print?
  1. public void doGet(HttpServletRequest request, HttpServletResponse response)  
  2.             throws ServletException, IOException {  
  3.         response.setStatus(302);  
  4.         response.setHeader("location""/day05/index.jsp");  
  5.     }  


 

           請求重定向過程:

 

           1、瀏覽器向服務器發請求

           2、服務器收到請求後,如果是首次訪問將創建一個新的 Servlet

           3、調用 Servlet 的 service() 方法(調用之前準備好 request 和 response 對象)

           4、在 service() 運行時向 response 中寫數據,向 response 中寫如 sendRedirect() 命令

           5、service() 方法執行完後返回給服務器

           6、服務器發現 response 中有 302 和 location ,於是就將 302 和 location 寫給瀏覽器

           7、瀏覽器收到 302 和 location 後,就又去找資源,再次發送請求

           8、服務器就又找第二個 Servlet

           9、服務器又準備一個 request 和 response 對象

           10、服務器再調用第二個 service() 方法

           11、service() 方法返回給服務器信息

           12、服務器再將信息返回給瀏覽器

 

九、response 中的細節

 

       1、getOutputStream 和 PrintWiter 兩個方法相排斥,調用了一個方法後就不能再調用另一個

            2、getOutputStream 和 PrintWiter 寫的數據是寫在 response 裏面去,在 response 裏面有一個字節數組的緩衝區,然後服務器再從 response 裏面獲取數據返回給瀏覽器

          3、我們一般不要手動關閉 getOutputStream 和 PrintWiter ,因爲在服務器調用完 service() 後,會檢查這兩個流有沒有被關閉,如果沒有,則會自動關閉。

 

十、HttpServletRequest對象

 

       1、HttpServletRequest 對象代表客戶端的請求,當客戶端通過 HTTP 協議訪問服務器時, HTTP 請求中的所有信息都封裝在這個對象中(用 HashMap 進行保存)。

 

          HTTP 請求由:請求行、請求頭、請求數據 。三部分組成

 

           (1)、請求行包括: 請求方式、請求資源、採用的協議 (GET /aa/1.html Http/1.1)

                 request.getMethod() --- 獲取請求方式

                 request.getURI() --- 獲取請求的資源 (URI:定位資源,URL:定位互聯網上的資源)

 

            (2)、有多個方法可以得到請求頭

 

            (3)、有多個方法可以得到請求數據 ,其中 getParamatersMap() 中得到的 Map 值是一個 String 數組,getInpuStream 可以以流的形式返回給服務器,用作文件上傳

 

           2、HTTP 中常見的請求頭

              

                 Host、Accept、Cookie、Connection、Pragma、Accept-Encoding、Content-Length、Refere ……

 

十一、防盜鏈

 

          

[java] view plain copy
 print?
  1. <span style="font-size:18px;">public void doGet(HttpServletRequest request, HttpServletResponse response)  
  2.             throws ServletException, IOException {  
  3.   
  4.         String from = request.getParameter("referer");  
  5.           
  6.         if(from != null || !from.startsWith("/project/index.jsp")){  
  7.             response.sendRedirect("/project/index.jps");  
  8.             return;  
  9.         }  
  10.         System.out.println("…………");  
  11.     }</span>  


 

十二、request 提交數據的亂碼問題

 

           1、當用 post 方式提交時,首先瀏覽器將中文字符轉爲瀏覽器當前的字符編碼,然後提交給服務器並存在 request 的字節緩衝區中,當我們使用 request.getParamater() 時,request 會根據 ISO8859-1 的編碼方式對字節進行解碼,所以會出現亂碼。究其願意,是因爲 request 用錯了碼錶,導致無法正常解析字符,所以我們只需要 request.setCharacterEncoding("..."); 即可。也就是說 request 在進行解碼的時候必須與客戶機瀏覽器的編碼方式相一致。

 

                2、當使用 get 方式提交時,由於 get 提交數據,其數據是在地址欄可顯示的,所以 get 提交的數據會進行 URL 編碼,URL會採用 ISO8859-1 的方式進行編碼,當傳給服務器的時候存在了 request 的對象裏面,然後在 getParamater() 的時候等於是用 ISO8859-1 對中文進行編碼,即便是指定了 request 的編碼方式,也是沒有用的。因爲用其他編碼方式對 ISO8859-1 進行解碼,依然找不到對應的中文字符,所以我們應該先將字符數據以 ISO8859-1 的方式進行編碼,就得到了客戶機傳遞過來的原始數據,然後再以其他方式進行解碼。正確方式應是:

 

                String username = new String((request.getParamater("username").getBytes("ISO8859-1")),"utf-8");

 

十三、Web 工程中的地址訪問寫發

 

           如果這個地址是給瀏覽器用的,那麼 / 就代表你的主機,就是代表網站;如果地址是給服務器用的,那麼 / 就代表當前的 Web 應用。就是以誰爲使用目標的原則爲基準。代表主機的話,就可以通過  /index.jsp 直接訪問,如果代表瀏覽器則 /project/index.jsp

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章