HttpServletRequest和HttpServletResponse

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_第1张图片

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

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

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

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

HttpServletRequest和HttpServletResponse_第2张图片

  • 在请求行中的信息:
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_第3张图片

HttpServletRequest继承体系

HttpServletRequest和HttpServletResponse_第4张图片

在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 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>oneservletservlet-name>
        <servlet-class>guang.servlet.OneServletservlet-class>
    servlet>
    <servlet-mapping>
        <servlet-name>oneservletservlet-name>
        <url-pattern>/oneurl-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 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_第5张图片

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

HttpServletRequest和HttpServletResponse_第6张图片

首先说明两点:

  • 第一:

在测试动态资源请求转发的时候,发现了一点!就是在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

对应的文件:

在这里插入图片描述

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

  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("\r\n");
      out.write("\r\n");
      out.write("    首页\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("    
\r\n"); out.write(" 姓名:
\r\n"
); out.write(" 年龄:
\r\n"
); out.write(" 性别:
\r\n"
); out.write(" 爱好: 抽烟
\r\n"
); out.write(" 唱歌
\r\n"
); out.write(" 烫头
\r\n"
); out.write(" 喝酒
\r\n"
); out.write(" \r\n"); out.write(" \r\n"
); out.write("\r\n"); out.write("\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_第7张图片

共享数据的方法:

  • 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");

你可能感兴趣的:(javaweb,java,servlet,http,tomcat)