• Servlet Request常用方法


    接下来记录一下Servlet Request和Response的常用API,以及乱码问题。

    Request

    Request即HttpRequest,可以获取客户端相关的信息、获取请求头以及获取请求参数等。

    获取客户端相关的信息

    常使用的API有如下

    (1)getRequestURL方法 -- 返回客户端发出请求完整URL
    (2)getRequestURI方法 -- 返回请求行中的资源名部分
    (3)getQueryString方法 -- 返回请求行中的参数部分
    (4)getRemoteAddr方法 -- 返回发出请求的客户机的IP地址
    (5)getMethod -- 得到客户机请求方式
    (6)getContextPath -- 获得当前web应用虚拟目录名称 -- 在写路径时不要将web应用的虚拟路径的名称写死, 应该在需要写web应用的名称的地方通过getContextPath方法动态获取

    代码

     1 package com.boe.request;
     2 
     3 import javax.servlet.ServletException;
     4 import javax.servlet.annotation.WebServlet;
     5 import javax.servlet.http.HttpServlet;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 import java.io.IOException;
     9 
    10 /**
    11  * 获取客户端相关信息
    12  */
    13 @WebServlet("/RequestDemo1")
    14 public class RequestDemo1 extends HttpServlet {
    15 
    16     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    17         /*getRequestURL方法 -- 返回客户端发出请求完整URL
    18         getRequestURI方法 -- 返回请求行中的资源名部分
    19         getQueryString方法 -- 返回请求行中的参数部分
    20         getRemoteAddr方法 -- 返回发出请求的客户机的IP地址
    21         getMethod -- 得到客户机请求方式
    22         getContextPath -- 获得当前web应用虚拟目录名称 -- 在写路径时不要将web应用的虚拟路径的名称写死, 应该在需要写web应用的名称的地方通过getContextPath方法动态获取*/
    23 
    24         //url
    25         StringBuffer requestURL = request.getRequestURL();
    26         System.out.println("url:"+requestURL);//统一完整路径名,包括协议,虚拟主机和资源,url:http://localhost/day09-reqres/RequestDemo1
    27         //uri
    28         String uri=request.getRequestURI();
    29         System.out.println("uri:"+uri);// 统一资源路径名 uri:/day09-reqres/RequestDemo1
    30         //queryString
    31         String qs=request.getQueryString();
    32         System.out.println("qs:"+qs);
    33         //ip
    34         String addr = request.getRemoteAddr();//alt+shift+L,可以默认提示变量名
    35         System.out.println("addr:"+addr);//addr:127.0.0.1
    36         //method
    37         String method = request.getMethod();
    38         System.out.println(method);//GET
    39         //contextpath
    40         String contextPath = request.getContextPath();
    41         System.out.println(contextPath);///day09-reqres 会动态变化,万分注意!
    42     }
    43 
    44     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    45         doPost(request, response);
    46     }
    47 }

    访问后控制台

    获取请求头信息

    上面是获取客户端信息的相关api,这个是获取请求头的api,就F12 request请求内容比较多的那一部分内容里的信息,它常用的方法如下。

    (1)getHeader(name)方法 --- String
    (2)getHeaders(String name)方法 --- Enumeration<String>
    (3)getHeaderNames方法 --- Enumeration<String>
    (4)getIntHeader(name)方法 --- int
    (5)getDateHeader(name)方法 --- long(日期对应毫秒)

    代码部分

     1 package com.boe.request;
     2 
     3 import javax.servlet.ServletException;
     4 import javax.servlet.annotation.WebServlet;
     5 import javax.servlet.http.HttpServlet;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 import java.io.IOException;
     9 import java.util.Enumeration;
    10 
    11 /**
    12  * 获取请求头的信息
    13  */
    14 @WebServlet("/RequestDemo2")
    15 public class RequestDemo2 extends HttpServlet {
    16     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    17         /*name getHeader(name)方法 --- String
    18         getHeaders(String name)方法 --- Enumeration<String>
    19         getHeaderNames方法 --- Enumeration<String>
    20         getIntHeader(name)方法 --- int
    21         getDateHeader(name)方法 --- long(日期对应毫秒)*/
    22 
    23         //获取请求头名称为host的请求头中包含的信息
    24         String host = request.getHeader("host");
    25         System.out.println("host:"+host);
    26         System.out.println("-------------分割线-------------");
    27         //获取请求头名称为host的请求头们中包含的信息,返回一个枚举类型
    28         Enumeration<String> hosts = request.getHeaders("host");
    29         while(hosts.hasMoreElements()){
    30             String s = hosts.nextElement();
    31             System.out.println("hosts value:"+s);
    32         }
    33         System.out.println("-------------分割线-------------");
    34         //获取全部请求头的名称
    35         Enumeration<String> headerNames = request.getHeaderNames();
    36         while(headerNames.hasMoreElements()){
    37             String head = headerNames.nextElement();
    38             String value=request.getHeader(head);
    39             System.out.println("head:"+head+", "+"value:"+value);
    40         }
    41         System.out.println("-------------分割线-------------");
    42     }
    43 
    44     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    45         doPost(request, response);
    46     }
    47 }

    访问后控制台输出效果

    web中实际信息

    可以看出,代码中获取的内容和网页中的信息一致。

    获取请求参数

    可以使用request获取请求参数,这个比较常用,如获取用户登录的用户名和密码等,常用的方法如下。

    (1)getParameter(String name) --- String 通过name获得值
    (2)getParameterValues(String name) --- String[ ] 通过name获得多值 checkbox
    (3)getParameterMap() --- Map<String,String[ ]> key :name value: 多值 将查询的参数保存在一个Map中
    (5)getParameterNames() --- Enumeration<String> 获得所有name

    提交参数分为POST和GET提交的方式,这里先准备一个页面进行测试,因此需要Servlet的代码和html的代码。

    html页面

     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset="utf-8" /><!---->
     5     </head>
     6     <body>
     7         <h1>GET提交</h1>
     8         <form action="/day09-reqres/RequestDemo3" method="GET">
     9             用户名: <input type="text" name="username" />
    10             昵称: <input type="text" name="nickname" />
    11             <input type="submit" value="提交" />
    12         </form>
    13         <h1>POST提交</h1>
    14         <form action="/day09-reqres/RequestDemo3" method="POST">
    15             用户名: <input type="text" name="username" />
    16             昵称: <input type="text" name="nickname" />
    17             爱好: <input type="checkbox" name="like" value="lanqiu" />篮球
    18                 <input type="checkbox" name="like" value="zuqiu" />足球
    19                 <input type="checkbox" name="like" value="taiqiu" />台球
    20             <input type="submit" value="提交" />
    21         </form>
    22     </body>
    23 </html>

    servlet代码

     1 package com.boe.request;
     2 
     3 import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
     4 
     5 import javax.servlet.ServletException;
     6 import javax.servlet.annotation.WebServlet;
     7 import javax.servlet.http.HttpServlet;
     8 import javax.servlet.http.HttpServletRequest;
     9 import javax.servlet.http.HttpServletResponse;
    10 import java.io.IOException;
    11 import java.util.Arrays;
    12 import java.util.Enumeration;
    13 import java.util.Map;
    14 
    15 //请求参数相关的api
    16 @WebServlet("/RequestDemo3")
    17 public class RequestDemo3 extends HttpServlet {
    18     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    19         /*getParameter(String name) --- String 通过name获得值
    20         getParameterValues(String name) --- String[ ] 通过name获得多值 checkbox
    21         getParameterMap() --- Map<String,String[ ]> key :name value: 多值 将查询的参数保
    22         存在一个Map中
    23         getParameterNames() --- Enumeration<String> 获得所有name*/
    24 
    25         //获取单个参数值
    26         String encoding = request.getCharacterEncoding();
    27         System.out.println("服务器默认使用字符集"+encoding);
    28         //设置字符集为utf-8 ,只对post请求有效
    29         //request.setCharacterEncoding("utf-8");
    30         System.out.println("设置完成之后的字符集"+request.getCharacterEncoding());
    31 
    32         String method = request.getMethod();
    33         if("GET".equals(method)){
    34             System.out.println("GET请求");
    35             //getBytes先编码,可以指定系统的字符集,执行后返回一个byte[]数组
    36             //new String后解码,需传入byte[]数组,以及解码字符集
    37             String user=new String(request.getParameter("username").getBytes("iso-8859-1"),"utf-8");
    38             String nickname=new String(request.getParameter("nickname").getBytes("iso-8859-1"),"utf-8");
    39             System.out.println("user:"+user+":nickname:"+nickname);
    40         }
    41 
    42 
    43         String user = request.getParameter("username");
    44         String nickname = request.getParameter("nickname");
    45         System.out.println("user:"+user+":nickname:"+nickname);
    46 
    47         //获取多个参数值,如checkbox
    48         String[] likes = request.getParameterValues("like");
    49         System.out.println(Arrays.toString(likes));
    50 
    51         //返回所有的key value,name包括username,nickname和like
    52         Map<String, String[]> parameterMap = request.getParameterMap();
    53 
    54         //得到全部请求参数
    55         Enumeration<String> parameterNames = request.getParameterNames();
    56         while(parameterNames.hasMoreElements()){
    57             String name=parameterNames.nextElement();//获取参数的名字
    58             String parameter = request.getParameter(name);//这个只能拿到一个参数,如果有多个只能拿一个
    59             System.out.println("name="+name+",value="+parameter);
    60             //获取多个参数
    61             String[] parameters = request.getParameterValues(name);
    62             System.out.println("name="+name+",value="+Arrays.toString(parameters));
    63         }
    64 
    65     }
    66 
    67     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    68         doPost(request, response);
    69     }
    70 }

    准备好后,开始测试。

    (1)POST提交

    可以看到POST提交英文是没有任何问题的,并且注意request.getParameter方法一次只能返回有一个参数,就算这个属性有多个参数也只能返回一个。需要返回多个参数时使用getParameterValues方法。

    如果是提交中文,request的请求body里是有中文显示的,但是到了服务端获取后,中文部分就变成了乱码。 

    web页面正常显示

    查看html代码部分,meta标签里charset属性是utf-8,代表浏览器使用utf-8来打开页面,浏览器使用什么编码格式打开浏览器,再发送数据到服务器(这里是tomcat服务器)的时候就默认使用什么编码格式发送,因此浏览器发送的是utf-8,这个是可以正常携带中文信息的,但是tomcat默认的解码格式是iso-8859-1,因此首先编解码格式不一致会造成乱码,另外一方面因为iso-8859-1因为无法表示中文,也将显示乱码。

    要想解决这个办法,可以使用request.setCharacterEncoding方法来解决,但是这个需要写到获取参数之前,修改后继续提交中文发现编码字符集变成了utf-8,并且可以正常解码中文。

    (2)GET请求

    GET请求的话比较特殊,它的请求参数跟POST请求提交的不太一样,是在请求行里的 ,因此出现乱码解决的方式也有区别,还是在上面代码的基础上进行测试。

    如果提交的是英文,正常提交没问题。

    web页面中请求参数是在请求行里的。

    如果提交的是中文,在注释掉new String部门代码,并保留request.setCharacterEncoding代码,发现依然显示乱码。

    提交显示乱码

    并且web端request里内容不是中文,而是16进制的形式表示。说明request.setCharacterEncoding设置的编码格式,对请求行没有效果,GET请求处理服务端乱码需要使用另外一种方式,即需要上面红色方框的内容,即系统默认是iso-8859-1接受数据那就按照它来编码变成字节数组,然后将字节数组再使用utf-8来解码变成字符。

     

    这样设置后继续提交中文,发现服务端可以正常获得。

    请求转发

    请求转发,是使用RequestDispatcher资源调度,将请求从当前资源交给下一个资源处理,下一个资源可以是servlet,也可以是JSP。转发的过程中,只有一次请求和一次响应,并且地址不变。下面使用三个servlet,来感受以下请求转发的特点。

    准备了RequestDemo4~6,具体代码如下,在使用的过程中部分代码需要修改。

    RequestDemo4

     1 package com.boe.request;
     2 
     3 import javax.servlet.RequestDispatcher;
     4 import javax.servlet.ServletException;
     5 import javax.servlet.annotation.WebServlet;
     6 import javax.servlet.http.HttpServlet;
     7 import javax.servlet.http.HttpServletRequest;
     8 import javax.servlet.http.HttpServletResponse;
     9 import java.io.IOException;
    10 
    11 /**
    12  * 重定转发,和RequestDemo5一组
    13  */
    14 @WebServlet("/RequestDemo4")
    15 public class RequestDemo4 extends HttpServlet {
    16     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    17         //创建调度器
    18         RequestDispatcher dispatcher = request.getRequestDispatcher("/RequestDemo5");
    19         response.getWriter().write("this is demo4");//请求转发前,向response缓冲区中写入数据,请求转发时,会将response缓冲区清空一次
    20 
    21         //response.flushBuffer();//会报错,提示IllegalStateException: Cannot forward after response has been committed,默认提交
    22         /**
    23          * public void flushBuffer() throws java.io.IOException
    24          * 强行将缓冲区中的所有内容写入客户端。调用此方法会自动提交响应,这意味着将编写状态代码和头。后面再次转发会失败
    25          */
    26 
    27         //利用调度器完成转发
    28         //不允许多次转发,但是可以多重转发,可以转发到demo5,接着demo6这种
    29         System.out.println("这是demo4");
    30         dispatcher.forward(request,response);
    31         //request.getRequestDispatcher("index.jsp").forward(request,response);
    32         System.out.println("demo4转发完成");
    33     }
    34 
    35     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    36         doPost(request, response);
    37     }
    38 }
    View Code

    RequestDemo5

     1 package com.boe.request;
     2 
     3 import javax.servlet.RequestDispatcher;
     4 import javax.servlet.ServletException;
     5 import javax.servlet.annotation.WebServlet;
     6 import javax.servlet.http.HttpServlet;
     7 import javax.servlet.http.HttpServletRequest;
     8 import javax.servlet.http.HttpServletResponse;
     9 import java.io.IOException;
    10 
    11 /**
    12  * 重定转发,和RequestDemo4一组
    13  */
    14 @WebServlet("/RequestDemo5")
    15 public class RequestDemo5 extends HttpServlet {
    16     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    17         //response.getWriter().write("this is demo5");
    18         RequestDispatcher dispatcher = request.getRequestDispatcher("RequestDemo6");
    19         System.out.println("这是demo5");
    20         dispatcher.forward(request,response);
    21         System.out.println("demo5转发完成");
    22     }
    23 
    24     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    25         doPost(request, response);
    26     }
    27 }
    View Code

    RequestDemo6

     1 package com.boe.request;
     2 
     3 import javax.servlet.ServletException;
     4 import javax.servlet.annotation.WebServlet;
     5 import javax.servlet.http.HttpServlet;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 import java.io.IOException;
     9 
    10 @WebServlet("/RequestDemo6")
    11 public class RequestDemo6 extends HttpServlet {
    12     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    13         System.out.println("这是demo6");
    14         response.getWriter().write("<h1 style='font:微软雅黑;color:blue'>this is demo6</h1>");
    15         System.out.println("demo6完成输出");
    16     }
    17 
    18     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    19         doPost(request, response);
    20     }
    21 }
    View Code

    (1)正常转发,将response.flushBuffer先注释掉,控制台和web端显示如下。

    可以看到可以多重转发,请求链可以在多个资源上传递,并且从控制台输出顺序,可以看到转发代码部分执行完成之后,才执行转发代码之后的代码,因此''demo04转发完成''最后输出。

    最后输出'this is demo6',而刚开始RequestDemo4中的输出被覆盖了。说明在转发前往response缓存中写入的数据,在转发后会被清空

     

    (2) response.flushBuffer取消注释,继续测试,发现控制台会报错。提示IllegalStateException: Cannot forward after response has been committed,并且提示在第30行出现问题,第30行是转发的代码,为啥这里不能转发了呢?其实就是flushBuffer的原因,它会在转发前将写入response中的缓存强行提交发送给浏览器,因此下面再次转发就不可以了。因此如果在转发前response缓冲区中就有内容提交了给了浏览器,转发会失败

    (3)测试demo4中转发给demo05后又转发给jsp,即测试多次转发,发现报错内容跟上面一样,也是提示IllegalStateException: Cannot forward after response has been committed,因此一个请求也不能多次转发

    域对象

    request可以作用域对象使用,所谓域对象就是有一个可以看到的范围,并且在这个范围内通过map可以共享资源。request就是一种域对象,此外还有其他几种域对象,如servletContext、session和pageContext。通过往域对象中设置值,可以在域对象的范围内都能被访问到,这里使用request,就能在整条访问链上都能得到存入的数据。

    RequestDemo08的代码,用于发送数据。

     1 package com.boe.request;
     2 
     3 import javax.servlet.ServletException;
     4 import javax.servlet.annotation.WebServlet;
     5 import javax.servlet.http.HttpServlet;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 import java.io.IOException;
     9 
    10 /**
    11  * 作为域对象使用-在一个范围内共享数据,这里使用的域对象就是request
    12  */
    13 @WebServlet("/RequestDemo8")
    14 public class RequestDemo8 extends HttpServlet {
    15     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    16         //向域中设置数据
    17         request.setAttribute("name","clyang");
    18         request.getRequestDispatcher("/RequestDemo9").forward(request,response);
    19     }
    20 
    21     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    22         doPost(request, response);
    23     }
    24 }

    RequestDemo09的代码,用于接收数据。

     1 package com.boe.request;
     2 
     3 import javax.servlet.ServletException;
     4 import javax.servlet.annotation.WebServlet;
     5 import javax.servlet.http.HttpServlet;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 import java.io.IOException;
     9 import java.util.Enumeration;
    10 
    11 /**
    12  * 获得域数据
    13  */
    14 @WebServlet("/RequestDemo9")
    15 public class RequestDemo9 extends HttpServlet {
    16     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    17         //获取域属性
    18         String name= (String) request.getAttribute("name");
    19         System.out.println("name="+name);
    20         //获取域属性名字
    21         Enumeration<String> attributeNames = request.getAttributeNames();
    22         while(attributeNames.hasMoreElements()){
    23             String s = attributeNames.nextElement();
    24             System.out.println("域属性的名字为:"+s);
    25         }
    26         response.getWriter().write("<h1 style='font:微软雅黑;color:blue'>"+name+"</h1>");
    27     }
    28 
    29     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    30         doPost(request, response);
    31     }
    32 }

    控制台和web输出情况,可以看到转发后还可以通过request获取name的属性值,因为还在域的范围内,所以可以获取。

     request作用域的范围:一个请求链。

     request作用域的生命周期:一次请求开始到请求结束。

    请求包含

    请求包含指的是服务器内部实现资源合并的效果。如果浏览器请求ServletA,在A的内部可以通过request.getRequestDispatcher("B的虚拟路径").include(request, response)将ServletB包含进来,B处理的结果将会并入A处理的结果一起响应给浏览器,准备两个servlet,将数据合并后发送给浏览器。
     
    RequestDemo11的代码
     1 package com.boe.request;
     2 
     3 import javax.servlet.RequestDispatcher;
     4 import javax.servlet.ServletException;
     5 import javax.servlet.annotation.WebServlet;
     6 import javax.servlet.http.HttpServlet;
     7 import javax.servlet.http.HttpServletRequest;
     8 import javax.servlet.http.HttpServletResponse;
     9 import java.io.IOException;
    10 
    11 /**
    12  * 请求包含
    13  */
    14 @WebServlet("/RequestDemo11")
    15 public class RequestDemo11 extends HttpServlet {
    16     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    17         //创建调度器
    18         RequestDispatcher dispatcher = request.getRequestDispatcher("/RequestDemo12");
    19         response.getWriter().write("9999 from demo11 ");
    20         //利用调度器完成请求包含
    21         dispatcher.include(request,response);
    22     }
    23 
    24     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    25         doPost(request, response);
    26     }
    27 }
    RequestDemo12的代码
     1 package com.boe.request;
     2 
     3 import javax.servlet.ServletException;
     4 import javax.servlet.annotation.WebServlet;
     5 import javax.servlet.http.HttpServlet;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 import java.io.IOException;
     9 
    10 @WebServlet("/RequestDemo12")
    11 public class RequestDemo12 extends HttpServlet {
    12     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    13         response.getWriter().write(" 1 from demo12");
    14     }
    15 
    16     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    17         doPost(request, response);
    18     }
    19 }

    测试结果,可以看到两次请求的内容会并到一起,发送给浏览器。

    参考博文:

    (1)https://www.cnblogs.com/logsharing/p/8448446.html

  • 相关阅读:
    江苏高考的程序题
    visio使用小记
    debian+postfix+dovecot+squirrelmail安装配置笔记
    System.Net.Mail
    DBHelper
    朝发白帝城
    《计算机网络》复习题2010
    mvc3在view中获取是否有验证错误
    Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
    ASP.NET MVC3 Model验证总结
  • 原文地址:https://www.cnblogs.com/youngchaolin/p/11526858.html
Copyright © 2020-2023  润新知