【Servlet06】请求与响应对象

1 HttpServletResponse接口

API介绍:

Extends the ServletResponse interface to provide HTTP-specific functionality in sending a response. For example, it has methods to access HTTP headers and cookies.

The servlet container creates an HttpServletResponse object and passes it as an argument to the servlet's service methods (doGet, doPost, etc).

HttpServletResponse 接口来自于 Servlet 规范下一个接口,HttpServletResponse 接口的实现类由 Http 服务器厂商提供。习惯上,将HttpServletResponse 接口修饰的对象称为响应对象

1.1 手动发送响应状态码

响应状态码表示服务器的运行状态,常见的响应状态码有:

  • 404:表示路径有问题;

  • 500: 表示服务器端程序发生了异常;

  • 200:表示服务器运行一切正常;

HttpServletResponse对象可以通过sendError方法手动发送响应状态码(和手动抛异常类似):

@WebServlet("/response")
public class ResponseServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Before sendError......");
        response.sendError(HttpServletResponse.SC_NOT_FOUND,"自定义响应状态码");
        System.out.println("After sendError......");
    }
}

重启服务器,访问:

1.2 响应对象中的打印流

响应对象中存在一个打印流PrintWriter,通过这个流可以向浏览器输出信息,并且在流中可以使用前端代码:

例如:

@WebServlet("/response")
public class ResponseServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter writer = response.getWriter();
        writer.write("Hello World");
    }
}

重启服务器,访问查看结果:

如果是中文的话则需要加入以下来设置编码:

response.setContentType("text/html;charset=UTF-8");

以下展示了如何通过打印流在浏览器输出html及中文:

@WebServlet("/response")
public class ResponseServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        writer.write("<html>");
        writer.write("<header>");
        writer.write("</header>");
        writer.write("<body>");
        writer.write("<h2>Hello World</h2><br>");
        writer.write("<a href='http://www.baidu.com'>百度一下</a>");
        writer.write("</body");
        writer.write("</html>");
    }
}

2 HttpServletRequest接口

API介绍

Extends the ServletRequest interface to provide request information for HTTP servlets.

The servlet container creates an HttpServletRequest object and passes it as an argument to the servlet's service methods (doGet, doPost, etc).

HttpServletRequest来自与 Servlet 规范中一个接口,HttpServletRequest接口实现类由Http服务器厂商负责提供,习惯上将 HttpServeltRequest 接口修饰的对象称为请求对象

2.1 基本方法

可以通过请求对象获取浏览器或服务器的一些信息,演示如下:

@WebServlet("/request")
public class RequestServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String remoteAddr = request.getRemoteAddr();//浏览器的IP地址
        int remotePort = request.getRemotePort();//浏览器的端口号
        String method = request.getMethod();//请求方式
        String scheme = request.getScheme();//协议名称
        String serverName = request.getServerName();//服务器所在的域名(没有域名使用ip地址)
        int serverPort = request.getServerPort();//服务器端口号
        String requestURI = request.getRequestURI();//请求的uri地址
        StringBuffer requestURL = request.getRequestURL();//请求的完成url路径

        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.write("浏览器的IP地址"+remoteAddr+"<br>");
        out.write("浏览器的端口号"+remotePort+"<br>");
        out.write("请求方式"+method+"<br>");
        out.write("协议名称"+scheme+"<br>");
        out.write("服务器所在的域名"+serverName+"<br>");
        out.write("服务器端口号"+serverPort+"<br>");
        out.write("请求的uri地址"+requestURI+"<br>");
        out.write("请求的完成url路径"+requestURL+"<br>");
    }
}

重启服务器,访问查看结果:

2.2 获取请求参数数据

此处的请求参数需要和前面提到的初始化参数数据以及作用域数据作区分:

  • 初始化参数数据:在服务器端以配置的方式完成的键值对数据,分为局部和全局;

  • 作用域数据:在编写代码的过程中通过对象调用固定的方法完成的数据,例如servletContext.setAttributeservletContext.getAttribute

  • 请求参数数据:通过浏览器端的一些组件发出的请求中包含的数据(例如:表单中的数据、超连接和地址栏拼接的数据等);

请求参数数据是从浏览器发送过来的数据,而初始化参数数据和作用域数据都是服务器内部的数据。

获取请求参数主要涉及以下两个方法:

  • java.lang.String getParameter(java.lang.String name):返回请求参数的一个键对应的一个值;若该参数不存在,则返回一个空值;

  • java.lang.String[] getParameterValues(java.lang.String name):返回请求参数的一个键对应的多个值;若该参数不存在,则返回一个空值。

注意:当请求方式为get时中文不会乱码,但请求方式为post时中文会出现会乱码,需要解决的话则要按如下进行设置:

request.setCharacterEncoding("UTF-8");

使用一个form表单进行演示,表单html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>获取请求参数</title>
</head>
<body>
<form action="request" method="post">
    <label>账号:</label>
    <input type="text" placeholder="请输入账号" name="username"/><br/>
    <label>密码:</label>
    <input type="password" placeholder="请求输入密码" name="password"/><br/>
    <label>性别:</label>
    <input type="radio" name="sex" value="男1"/>男
    <input type="radio" name="sex" value="女2" checked/>女
    <br/>
    <label>爱好:</label>
    <input type="checkbox" name="hobby" value="编程1"/>编程
    <input type="checkbox" name="hobby" value="游戏1"/>游戏
    <input type="checkbox" name="hobby" value="读书1"/>读书
    <input type="checkbox" name="hobby" value="旅游1"/>旅游
    <input type="checkbox" name="hobby" value="吃饭1"/>吃饭
    <br/>
    <label>部门:</label>
    <select name="dept">
        <option value="技术部1">技术部</option>
        <option value="财务部2">财务部</option>
        <option value="销售部3">销售部</option>
        <option value="后勤部4">后勤部</option>
    </select> <br/>

    <input type="submit" value="发送一个post请求"/>
    <input type="reset" value="重置"/>
</form>
</body>
</html>

此时的键指的是标签中的name属性,Servlet:

@WebServlet("/request")
public class RequestServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String sex = request.getParameter("sex");
        String dept = request.getParameter("dept");

        String[] hobbies = request.getParameterValues("hobby");

        PrintWriter out = response.getWriter();
        out.write("username:" + username + "<br>");
        out.write("password:" + password + "<br>");
        out.write("sex:" + sex + "<br>");
        out.write("dept:" + dept + "<br>");
        for (String hobby : hobbies) {
            out.write("hobby:" + hobby + "<br>");
        }
    }
    ......

重启服务器,查看结果:

对于超链接及地址栏,需要自己拼接请求参数,在请求名称之后添加:?键1=值1&键2=值2

2.3 请求作用域数据操作

和ServletContext对象的全局作用域数据操作方法一致,请求作用域操作涉及到三个方法:

  • java.lang.Object getAttribute(java.lang.String name)方法:通过键获取Request对象中对应的值;

  • void removeAttribute(java.lang.String name)方法:通过键删除Request对象中某个键值对;

  • void setAttribute(java.lang.String name, java.lang.Object object)方法:向某个Request对象中存储一个键值对,如果存在键相同的情况则覆盖之前存储的值;

不同的是,Request对象的作用域数据可操作的范围仅限于一次请求(Request+Response);

3 页面跳转

页面跳转根据跳转的源的不同,可以分为两大类:

  • 从页面出发跳转:使用超链接、表单、地址栏拼接进行,页面是指html、jsp、模板等;

  • 从类出发跳转:使用请求转发以及响应重定向,类是指Servlet;

    • 如果跳转的目标是页面,则不能是单纯的html页面,因为单纯的html页面可能会出现乱码现象;

3.1 请求转发

进行请求转发的两个关键步骤:

  • 通过当前请求对象获取一个请求转发器对象;request.getRequestDispatcher("");,参数填入需要转发到的Servlet类名称;

  • 通过调用请求转发器对象的forward方法进行跳转;

编写一个html和两个servlet进行请求转发演示:

html,传入username和password两个参数至Servlet1:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>请求转发</title>
</head>
<body>
<form action="requestDisServlet01" method="post">
    <label>账号:</label>
    <input type="text" placeholder="请输入账号" name="username"/><br/>
    <label>密码:</label>
    <input type="password" placeholder="请求输入密码" name="password"/><br/>
    <input type="submit" value="请求转发"/>
    <input type="reset" value="重置"/>
</form>
</body>
</html>

Servlet1,采用请求转发的方式跳转到Servlet2:

@WebServlet("/requestDisServlet01")
public class RequestDisServlet01 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        System.out.println("In RequestDisServlet01, username = " + username);
        System.out.println("In RequestDisServlet01, password = " + password);

        request.setAttribute("gender","male");
        System.out.println("In RequestDisServlet01, gender = "+request.getAttribute("gender"));

        RequestDispatcher requestDispatcher = request.getRequestDispatcher("requestDisServlet02");
        requestDispatcher.forward(request,response);

        System.out.println("doPost in RequestDisServlet01 finished...");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

Servlet2,接收Servlet1的参数:

@WebServlet("/requestDisServlet02")
public class RequestDisServlet02 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        System.out.println("In RequestDisServlet02, username = " + username);
        System.out.println("In RequestDisServlet02, password = " + password);

        System.out.println("In RequestDisServlet02, gender = "+request.getAttribute("gender"));
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

测试结果:

可以观察到,在请求转发过程中,有以下几点现象:

  • 浏览器的url没有改变,显示的还是Servlet1的url;

  • Servlet2中可以接收到Servlet1的请求参数;

  • Servlet1和Servlet2执行的都是doPost方法;

  • Servlet1会优先执行请求转发后Servlet2中的代码,再执行自身类中的后续代码;

  • Servlet1中设置的Request作用域参数可以在Servlet2中被取到;

以上的种种现象的原因都是相同的,那就是:在请求转发的过程中,始终只有一次请求,请求全部都是同一个请求(一个请求执行所有的代码);

3.2 响应重定向

进行响应重定向的关键步骤:response.sendRedirect("");,参数填入要重定向到的Servlet名;

和请求转发一致,编写一个html和两个Servlet进行测试:

html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>响应重定向</title>
</head>
<body>
<form action="responseReDirServlet01" method="post">
    <label>账号:</label>
    <input type="text" placeholder="请输入账号" name="username"/><br/>
    <label>密码:</label>
    <input type="password" placeholder="请求输入密码" name="password"/><br/>
    <input type="submit" value="响应重定向"/>
    <input type="reset" value="重置"/>
</form>
</body>
</html>

Servlet1:

@WebServlet("/responseReDirServlet01")
public class ResponseReDirServlet01 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        System.out.println("In ResponseReDirServlet01, username = " + username);
        System.out.println("In ResponseReDirServlet01, password = " + password);

        request.setAttribute("gender","male");
        System.out.println("In ResponseReDirServlet01, gender = "+request.getAttribute("gender"));

        response.sendRedirect("responseReDirServlet02");

        System.out.println("doPost in ResponseReDirServlet01 finished...");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

Servlet2:

@WebServlet("/responseReDirServlet02")
public class ResponseReDirServlet02 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        System.out.println("In ResponseReDirServlet02, username = " + username);
        System.out.println("In ResponseReDirServlet02, password = " + password);

        System.out.println("In ResponseReDirServlet02, gender = "+request.getAttribute("gender"));
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("execute doGet in ResponseReDirServlet02");
    }
}

测试结果:

可以看到,响应重定向会执行目标Servlet的doGet方法,并没有进行我们书写在doPost方法中的一系列操作,因此Servlet2的doGet方法需要进行如下更新:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    System.out.println("execute doGet in ResponseReDirServlet02");
    this.doPost(request,response);
}

重新进行测试,结果如下:

可以观察到,在响应重定向程中,有以下几点现象:

  • 浏览器的url已经发生了改变,显示的是Servlet2的url;

  • Servlet2中不可以接收到Servlet1的请求参数;

  • Servlet1执行的是doPost方法,而Servlet2执行的都是doGet方法;

  • Servlet1会优先执行自身类中的后续代码,再进行响应重定向,执行Servlet2中的代码;

  • Servlet1中设置的Request作用域参数不可以在Servlet2中被取到;

以上的种种现象的原因都是相同的,那就是:在响应重定向的过程中,会产生两次请求,Servlet类会优先结束自身的代码并向浏览器发出结束的响应,浏览器收到后会自动的再向服务器发送一个新的Get请求,完成响应重定向的后续操作(每跳转一次就会产生一个新的请求);

习惯上如果在跳转的时候需要携带数据,选择请求转发;如果不需要携带数据,选择转发重定向。

版权声明:
作者:jackqiang
链接:http://www.jackqiang.com/javaweb/server/servlet/2133/request_response/
来源:JackQiang's
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录