Servlet---ServletRequest和ServletResponse(2)

来源:互联网 发布:闪电站小猪知乎 编辑:程序博客网 时间:2024/03/29 04:12

 当一个 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

原创粉丝点击