欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HttpServletRequest和HttpServletResponse

程序员文章站 2022-06-19 11:22:52
...

HttpServletRequest和HttpServletResponse

在前几篇博客中介绍了servlet,也详细描述了自定义的类继承HttpServlet作为一个标准类的原因。

这篇来分析一下doGet和doPost方法中的参数

doGet/Post方法,见名知意,表示的是对get/post请求的处理

因为post的请求方式太过于少见,只用于表单提交数据的请求当中

最常用的是get方式的请求。

因为一个标准servlet类中存在着doPost和doGet方法

所以提供一种小技巧:在doPost方法中调用doGet方法,一劳永逸。

另外需要进行补充的是:在Tomcat8及其之后的版本中,对于get的请求方式,Tomcat使用的是utf-8进行解析的;对于post请求方式,Tomcat采用的是ISO-8859-1的方式来进行解析,所以,如果要是使用表单的请求方法是post进行请求的,那么在接收请求参数之前,需要先指定解析方式,然后再去进行获取参数。否则乱码

获取请求行中的信息

思想良久:还是将请求方式的总结写在前面

我将请求方式分为两种:

  • 第一种:超链接

    http://www.baidu.com?username=guang&password=guang
    http://localhost:8080/guang/login?username=guang&password=guang
    

    如果请求参数有多个,那么使用&来进行分隔

    在请求地址后面加上?参数1=参数值1&参数2=参数2&....
    

    表单方式的get方式提交

    <form action="/xxx" method="get">
    	姓名:<input type="text name="username"/><br>
    	密码:<input type="password" name="password"/><br>
    	性别:<input type="radio" name="sex" value="man"/><input name="radio" name="sex" value="famale"/><br>
    	
         爱好:<input type="checkbox" name="hobby" value="sing"><input type="checkbox" name="hobby" value="skip"><input type="checkbox" name="bobby" value="rap">rap<br>
    		<input type="submit" value="提交" />
    </form>
    

    总结:对于get方式作为请求参数需要满足的条件:

    在请求地址后面加上?参数1=参数值1&参数2=参数2&....
    

    参数在请求行中

  • 第二种:表单

    表单形式的post方式进行提交

    <form action="/xxx" method="get">
    	姓名:<input type="text name="username"/><br>
    	密码:<input type="password" name="password"/><br>
    	性别:<input type="radio" name="sex" value="man"/><input type="radio" name="sex" value="famale"/><br>
    	
         爱好:<input type="checkbox" name="hobby" value="sing"><input type="checkbox" name="hobby" value="skip"><input type="checkbox" name="bobby" value="rap">rap<br>
    		<input type="submit" value="提交" />
    </form>
    

总结:对于post方式提交表单来说,满足的参数是:

①在表单中;②必须拥有name和value值;③请求地址

需要进行解释的三点:

  • 对于text和password,value就是我们输入的内容

  • 对于radio和checkbox,需要保证上面的三个条件之外,还需要保证name都是一样的,不然

    对于radio来说,不再是单选,而是可以进行多选的;对于checkbox来说,提交的name不一致了,那么参数的名称也就不同了。

  • 如果在action中仍然携带了参数,那么这个参数是无效的,不会发送这样的参数

    <form aciton="www.baidu.com?name=guang>
    

    在发送参数的时候,不会写在name=guang这个参数信息过去的。

正式开始进行讲解:

对于一个请求协议包而言,分为了三大部分:

HttpServletRequest和HttpServletResponse

通过对比可以发现,post方式有请求体,而get方式没有请求体。

那么对于post方式的请求体是什么?放的是请求的参数信息,可以放的比较多的请求数据。

对于post请求来说,放的参数信息都在请求行中

先来看下请求协议包中都有着哪些东西:

HttpServletRequest和HttpServletResponse

  • 在请求行中的信息:
Request URL: https://www.baidu.com/?username=guang&password=guang
request Method: GET
Remote Address: 14.215.177.39:443
  • 请求URI和URL
  • 请求参数
  • 请求方式
  • 请求时候本机地址

对于使用java方法来进行操作

  • getMethod();获取请求方式
  • getRemoteAddr():是哪台计算机发起请求的,IP地址是多少
  • **getContextPath()????*获得部署到服务器上的项目名称
  • **getRequestURI()????*获得请求地址,不带项目名
  • **getRequestURL():**获得请求地址,带项目名字

再次进行提醒的是前端发送多来的参数都是字符串。如果需要解析,请使用对应的方式来进行解析

最常见的是两种:整数和日期

对于请求头来说:

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9

Accept-Encoding: gzip, deflate, br

Accept-Language: zh-CN,zh;q=0.9

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/84.0.4147.135 Safari/537.36
  • Accept:告知服务器,我能就收什么样的数据格式,也就是传输过来的数据进行解码的格式
  • Accept-Encoding:压缩算法,不常用
  • Accept-Language:浏览器接收的语言是中文
  • User-Agent:客户端的信息全部暴露出来了。使用的操作系统版本号,多少位操作系统,什么浏览器等等

因为这里的数据还没有使用到,所以在这里就不再过多的进行解释!

对于post方式提交的数据来说,请求参数在请求体中,我用的是谷歌浏览器,这种看不到,所以这里无法进行展示,但是,可以猜测出来这里的数据

username=liguang&password=guang

综合比较而言,我们更常用的是获取得到请求的参数!!!

所以下面着重来讲解这个地方。

来啦老弟!

HttpServletRequest

见名知意,http协议的servlet的请求处理,我们着重分析的是获取得到参数,这里有各种各样的方法来进行操作。

我觉得在这里有必要对HttpServletRequest和HttpServletResponse做一个生命周期的介绍。

HttpServletRequest和HttpServletResponse

HttpServletRequest继承体系

HttpServletRequest和HttpServletResponse

在servlet的继承体系中,Servlet接口、GenericServlet类

void service(ServletRequest var1, ServletResponse var2)

但是在HttpServlet的doGet和doPost方法中

void doGet(HttpServletRequest req, HttpServletResponse resp)
void doPost(HttpServletRequest req, HttpServletResponse resp) 

我的理解是更好的处理HTTP请求和响应

获取参数

查看HttpServletRequest中的常用的方法:

法名 描述
String getParameter(String name) 获得指定参数名对应的值。如果没有则返回null,如果有多个获得第一个。 例如:username=jack。(有弊端存在,比如说checkbox中的数据)_
String[] getParameterValues(String name) 获得指定参数名对应的所有的值。此方法专业为复选框提供的。 例如:hobby=抽烟&hobby=喝酒&hobby=敲代码
Map<String,String[]> getParameterMap() 获得所有的请求参数。key为参数名,value为key对应的所有的值。(常用)
String getQueryString() 直接获取得到所有的请求参数的字符串(post请求为null)

创建一个新的servlet来进行测试:

public class OneServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 先将解析方式改还成utf-8来进行解析
        // 获取得到请求参数
        String queryString = req.getQueryString();
        System.out.println(queryString);
    }
}

在web.xml中进行配置

    <servlet>
        <servlet-name>oneservlet</servlet-name>
        <servlet-class>guang.servlet.OneServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>oneservlet</servlet-name>
        <url-pattern>/one</url-pattern>
    </servlet-mapping>

第一种:

String getQueryString()方法(做做测试玩玩还是可以的)

测试一:在浏览器的地址栏中输入:

http://localhost:8080/test/one

在控制台中显示的信息:

null

因为没有什么参数

测试二:在浏览器中的地址栏中输入:

http://localhost:8080/test/one?username=guang

在控制台显示的是:

username=guang

测试三:使用表单来进行提交

使用get方式

  <p>使用get方式提交</p>
  <form action="./one" method="get">
    姓名:<input type="text name="username"/><br>
    密码:<input type="password" name="password"/><br>
    性别:<input type="radio" name="sex" value="man"/><input type="radio" name="sex" value="famale"/><br>

    爱好:<input type="checkbox" name="hobby" value="sing"><input type="checkbox" name="hobby" value="skip"><input type="checkbox" name="bobby" value="rap">rap<br>
    <input type="submit" value="提交" />
  </form>

控制台显示信息:

username=%E5%B9%BF%E5%9C%BA%E8%88%9E&password=guangchangwu&sex=famale&hobby=sing&hobby=skip

这里的username我输入的是一个中文。在这边是无法进行显示中文。

使用post方式

  <p>使用post方式提交</p>
  <form action="./one" method="post">
    姓名:<input type="text name="username"/><br>
    密码:<input type="password" name="password"/><br>
    性别:<input type="radio" name="sex" value="man"/><input type="radio" name="sex" value="famale"/><br>

    爱好:<input type="checkbox" name="hobby" value="sing"><input type="checkbox" name="hobby" value="skip"><input type="checkbox" name="bobby" value="rap">rap<br>
    <input type="submit" value="提交" />
  </form>

控制台信息:

null

小结:对于getQueryString方法来说,如果是get的请求方式,可以获取得到请求参数;如果是post的请求方式,那么获取得到的结果是null。

第二种

  • String getParameter(String name)

    测试代码如下:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 先设置解析数据的方式
        request.setCharacterEncoding("utf-8");
        // 根据参数名字来获取得到参数
        String value = request.getParameter("username");
        System.out.println(value);
    }
    

    在地址栏中输入的信息:

    http://localhost:8080/test/two?username=guang
    

    在控制台中的信息显示:

    guang
    

第三种

  • String[] getParameterValues(String name)

    根据参数和方法名称发现,这里应该使用表单中的数据来进行提交的

    测试代码:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取得到参数值
        String[] hobbies = request.getParameterValues("hobby");
        for (String hobby : hobbies) {
            System.out.println(hobby);
        }
    }
    

    表单方式提交:

      <form action="./three" method="get">
        姓名:<input type="text"  name="username" /><br>
        密码:<input type="password" name="password"/><br>
        性别:<input type="radio" name="sex" value="man"/><input type="radio" name="sex" value="famale"/><br>
    
        爱好:<input type="checkbox" name="hobby" value="sing"><input type="checkbox" name="hobby" value="skip"><input type="checkbox" name="hobby" value="rap">rap<br>
        <input type="submit" value="提交" />
      </form>
      </body>
    

    控制台信息:

    sing
    skip
    rap
    

第四种

  • Map<String,String[]> getParameterMap()

同上,这里采用的是map集合而已

测试代码:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 根据参数名字来获取得到参数值
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
        for (Map.Entry<String, String[]> entry : entries) {
            String key = entry.getKey();
            // 获取得到的是一个数组
            String[] value = entry.getValue();
            System.out.print(key+"=");
            // 循环遍历数组中的内容
            for (int i = 0; i < value.length; i++) {
                System.out.print(" "+value[i]);
            }
            System.out.println();
        }
    }

表单方式提交:

  <p>使用get方式提交</p>
  <form action="./four" method="get">
    姓名:<input type="text"  name="username" /><br>
    密码:<input type="password" name="password"/><br>
    性别:<input type="radio" name="sex" value="man"/><input type="radio" name="sex" value="famale"/><br>

    爱好:<input type="checkbox" name="hobby" value="sing"><input type="checkbox" name="hobby" value="skip"><input type="checkbox" name="hobby" value="rap">rap<br>
    <input type="submit" value="提交" />
  </form>

控制台信息:

username= 光
password= fdsafds
sex= man
hobby= sing skip rap

使用post方式进行测试:

username= 光
password= guang
sex= man
hobby= sing skip rap

其他方法:

  • String getContextPath():获取得到当前的项目路径
  • Cookie[] getCookie():获取所有的cookie,可以实现循环遍历
  • String getMethod():获取得到请求的方式
  • StringBuffer getRequestURL():获取得到URL。【返回值类型是StringBuffer】
  • String getRequestURI():获取得到的是URI。获取的是请求的资源路径
  • String getServletPath(); 得到servlet的路径
  • Session getSession():获取得到session

演示一下:

代码:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /**
         * - String getContextPath():获取得到当前的项目路径
         * - Cookie[] getCookie():获取所有的cookie,可以实现循环遍历
         * - String getMethod():获取得到请求的方式
         * - StringBuffer getRequestURL():获取得到URL。【返回值类型是StringBuffer】
         * - String getRequestURI():获取得到的是URI。获取的是请求的资源路径
         * - String getServletPath();  得到servlet的路径
         * - Session getSession():获取得到session
         */
        String contextPath = request.getContextPath();
        System.out.println("contextPath:"+contextPath);
        System.out.println("------------------");
        Cookie[] cookies = request.getCookies();
        for (int i = 0; i < cookies.length; i++) {
            System.out.println("cookie["+i+"]:"+cookies[i]);
        }
        System.out.println("------------------");
        String method = request.getMethod();
        System.out.println("method:"+method);
        System.out.println("------------------");
        StringBuffer requestURL = request.getRequestURL();
        String requestURI = request.getRequestURI();
        System.out.println("requestURL:"+requestURL);

        System.out.println("requestURI:"+requestURI);
        System.out.println("------------------------");
        String servletPath = request.getServletPath();
        System.out.println("servletPath:" + servletPath);
        HttpSession session = request.getSession();
        System.out.println("session:" + session);
    }

演示效果:

contextPath:/test                  // 项目名字,也就是当前context项目的路径
------------------
cookie[0]:javax.servlet.http.Cookie@1302b6a
cookie[1]:javax.servlet.http.Cookie@ff7c53c
cookie[2]:javax.servlet.http.Cookie@bc8401a
------------------
method:GET                        // 请求的方式
------------------
requestURL:http://localhost:8080/test/five //统一资源定位符,计算机中的唯一标志。这里当然不是,在本机
requestURI:/test/five					 // 当前资源在当前计算机中的路径
------------------------
servletPath:/five						  // 也就是我们配置的servlet的别名,这里是servlet的路径
session:org.apache.catalina.session.StandardSessionFacade@4ecacf07

请求转发

首先需要明白的是请求转发是什么意思?

请求:向Tomcat进行申请,想要访问的资源。

转发:将要访问的资源返回到客户端去。

示例:

 requset.getRequestDispatcher("/WEB-INF/register.html").forward(requset,response);

为什么使用的是request来记性请求转发呢?为什么后面又要使用到了request和response?

向Tomcat申请资源,那么申请的动作,根据字面上的理解,当然是由request来进行请求完成的。

对于转发来讲,那么就是需要由response将申请的资源打包(响应协议包),让Tomcat推送到前端去。

请求转发静态资源原理分析:

HttpServletRequest和HttpServletResponse

请求转发动态资源原理分析:

HttpServletRequest和HttpServletResponse

首先说明两点:

  • 第一:

在测试动态资源请求转发的时候,发现了一点!就是在Tomcat接收到请求重新创建了一个对象之后,新的request对象和之前的request中的数据都是一样的(基本类型是数据,引用类型是地址)。所以在一次动态资源的请求转发过程中,多个request对象保留着的有着相同的数据!称之为request对象的数据共享

  • 第二:

发现在进行动态资源的请求转发中,response的的地址值一直没有发生改变!说明了在对于一次请求中,request的对象的值是可以发生变化的,但是对于response来说,是不会发生改变的。非常容易理解!因为在请求转发中,请求中根本没有用到response,只有在转发的时候才用到了response。

相信到了这里也应该明白了重定向和请求转发的区别了。

总结:请求转发共享数据适用在servlet之间!jsp也是servlet!

可以来看一下,我的电脑中

C:\Users\guang\.IntelliJIdea2018.2\system\tomcat\Unnamed_Javaweb\work\Catalina\localhost\test\org\apache\jsp

对应的文件:

HttpServletRequest和HttpServletResponse

查看下里面的关键性代码:

  public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)

    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;


    try {
      response.setContentType("text/html;charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("\r\n");
      out.write("\r\n");
      out.write("<html>\r\n");
      out.write("<head>\r\n");
      out.write("    <title>首页</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("    <form action=\"./myservlet\" method=\"post\">\r\n");
      out.write("        姓名:<input type=\"text\" name=\"name\"><br>\r\n");
      out.write("        年龄:<input type=\"text\" name=\"age\"><br>\r\n");
      out.write("        性别:<input type=\"radio\" name=\"sex\" value=\"man\">男<input type=\"radio\" name=\"sex\" value=\"woman\">女<br>\r\n");
      out.write("        爱好:  <input type=\"checkbox\" name=\"hobby\" value=\"抽烟\">抽烟<br>\r\n");
      out.write("                <input type=\"checkbox\" name=\"hobby\" value=\"唱歌\">唱歌<br>\r\n");
      out.write("                <input type=\"checkbox\" name=\"hobby\" value=\"烫头\">烫头<br>\r\n");
      out.write("                <input type=\"checkbox\" name=\"hobby\" value=\"喝酒\">喝酒<br>\r\n");
      out.write("                <input type=\"submit\" value=\"提交\">\r\n");
      out.write("    </form>\r\n");
      out.write("</body>\r\n");
      out.write("</html>\r\n");
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try {
            if (response.isCommitted()) {
              out.flush();
            } else {
              out.clearBuffer();
            }
          } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
        else throw new ServletException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }

将上面的代码拆分:

    final javax.servlet.jsp.PageContext pageContext;   // 
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;
try中的
	_jspx_page_context = pageContext;

输入数据中就是一个个的将HTML中的语句进行输出,这也是jsp后来不火的原因了!

说明:
这里的推导,是我偶然之间进行测试得到的结果。请教了不少大佬,然后经过自己的猜测,推理出来最后的答案。
如果有问题,请及时联系我

request共享数据域

根据我的理解,我认为是这样的一套流程

HttpServletRequest和HttpServletResponse

共享数据的方法:

  • Object getAttribute(String name) ; 取数据

  • void setAttribute(String name,Object object) ; 存数据

  • void removeAttribute(String name) ; 移除request中的数据

request存值的时候,可以存任何类型的值。

key是String
value是Object

这里就类似于HashMap了

HashMap<String,Object> map = new HashMap<>();
map.put(name1,Object);------------request.setAttribute(String,Ojbect);
Object obj = map.get(name1);  ---------------request.getAttribute(String);

所以这里也就是为什么需要进行强制转换的原因了!!

HttpServletResponse

见名知意,http协议的servlet的响应处理

Response作用

操作的响应行、响应头、响应体

1、操作响应行

状态码。(但是意义不怎么大)

2、操作响应头

重定向问题

response.sendRedirect("重定向的路径")

这里的路径可以是context内部中的资源,也可以是外部的资源。

用的比较的少。

3、操作响应体

告知浏览器用什么方式来进行解析响应包中的二进制数据

​ 第一种:text/html;charset=utf=8【text/html的格式解析】

​ 第二种:application/json 【json格式的数据解析】

response.setContentType("text/html;charset=utf-8");
response.setContentType("application/json");

何类型的值。

key是String
value是Object

这里就类似于HashMap了

HashMap<String,Object> map = new HashMap<>();
map.put(name1,Object);------------request.setAttribute(String,Ojbect);
Object obj = map.get(name1);  ---------------request.getAttribute(String);

所以这里也就是为什么需要进行强制转换的原因了!!

HttpServletResponse

见名知意,http协议的servlet的响应处理

Response作用

操作的响应行、响应头、响应体

1、操作响应行

状态码。(但是意义不怎么大)

2、操作响应头

重定向问题

response.sendRedirect("重定向的路径")

这里的路径可以是context内部中的资源,也可以是外部的资源。

用的比较的少。

3、操作响应体

告知浏览器用什么方式来进行解析响应包中的二进制数据

​ 第一种:text/html;charset=utf=8【text/html的格式解析】

​ 第二种:application/json 【json格式的数据解析】

response.setContentType("text/html;charset=utf-8");
response.setContentType("application/json");