第一章:Request

1.1 概述

1.1.1 Request的概念

  • 在Servlet的API中,定义了一个HttpServletRequest接口,该接口继承于ServletRequest接口,专门用来封装HTTP的请求消息。由于HTTP请求消息分为请求行、请求头和请求体三部分,所以,HttpServletRequest接口中定义了获取请求行、请求头和请求体的相关方法。
  • 换言之,Request就是服务器中的一个对象,该对象中封装了HTTP请求的请求行、请求头和请求体的内容。

Request的概念.png

1.1.2 Request的组成

  • 请求行:包含请求方式、请求的URL地址、所使用的HTTP协议的版本。
  • 请求头:一个个的键值对,每一个键值对中都表示一种含义,用于客户端传递相关的信息给服务器。
  • 请求体:POST请求有请求体,里面携带着POST请求的参数;而GET请求没有请求体。

1.1.3 Request的作用

  • ① 获取HTTP请求的请求行、请求头和请求体。
  • ② 进行请求转发跳转。
  • ③ 作为域对象进行存取数据。

1.2 Request获取HTTP请求的内容

1.2.1 获取HTTP的请求行

  • 获取请求方式:
  1. public String getMethod();
  • 获得当前应用上下文路径 :
  1. public String getContextPath();
  • 获取请求地址,不带主机名:
  1. public String getRequestURI();
  • 获取请求地址,带主机名:
  1. public StringBuffer getRequestURL();
  • 示例:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <a href="/app/demo1Servlet">Demo1Servlet</a>
  9. </body>
  10. </html>
package com.example.javaweb.demo2;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo1Servlet", value = "/demo1Servlet")
public class Demo1Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        // 获取请求方式
        String method = request.getMethod();
        System.out.println("method = " + method); // method = GET
        // 获取应用上下文
        String contextPath = request.getContextPath();
        System.out.println("contextPath = " + contextPath); // contextPath = /app
        // 获取请求地址,带主机名
        StringBuffer requestURL = request.getRequestURL();
        System.out.println("requestURL = " + requestURL); // requestURL = http://localhost:8080/app/demo1Servlet
        // 获取请求地址,不带主机名
        String requestURI = request.getRequestURI();
        System.out.println("requestURI = " + requestURI); // requestURI = /app/demo1Servlet
    }
}

1.2.2 获取HTTP的请求头

  • 根据请求头名称获取对应的值是long类型:
public long getDateHeader(String name);
  • 根据请求头名称获取对应的值(常用):
public String getHeader(String name);
  • 根据请求头名称获取对应多个的值:
public Enumeration<String> getHeaders(String name);
  • 返回所有的请求头名称:
public Enumeration<String> getHeaderNames();
  • 根据请求头名称获取对应的值是int类型:
public int getIntHeader(String name);
  • 示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/demo2Servlet">Demo2Servlet</a>
</body>
</html>
package com.example.javaweb.demo2;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo2Servlet", value = "/demo2Servlet")
public class Demo2Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        // 获取所有的请求头
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            System.out.println("headerName = " + headerName);
        }
        // 根据请求头名称获取对应的值
        String host = request.getHeader("host");
        // host = localhost:8080
        System.out.println("host = " + host);

        // 根据请求头名称获取对应的多个值
        Enumeration<String> headers = request.getHeaders("Accept-Language");
        while (headers.hasMoreElements()) {
            String header = headers.nextElement();
            // header = zh-CN,zh;q=0.9
            System.out.println("header = " + header);
        }

    }
}

1.2.3 获取请求参数

  • 请求参数:客户端携带给服务器的由键值对组成的数据。如:username=xiaogou&password=123456
  • 客户端携带请求参数的格式:
    • ① URL地址后面携带参数。
    • ② 表单携带参数。
    • ③ Ajax请求携带参数。
  • 请求参数的相关方法:

    • 获取当前请求的所有参数,以键值对的方式存储到Map中:

      public Map<String, String[]> getParameterMap();
      
    • 根据参数名获取一个参数值:

      public String getParameter(String name);
      
    • 根据参数名获取多个参数值:

      public String[] getParameterValues(String name);
      
    • 获取当前请求中的所有参数名:

      public Enumeration<String> getParameterNames();
      
  • 示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/app/demo3Servlet" method="post">
        姓名: <input name="username" type="text"/> <br>
        密码:<input name="password" type="password"> <br>
        爱好:
        <input name="hobbies" type="checkbox" value="basketball">打篮球
        <input name="hobbies" type="checkbox" value="football">踢足球
        <input name="hobbies" type="checkbox" value="games">玩游戏 <br>
        <input type="submit" value="提交">
    </form>
</body>
</html>
package com.example.javaweb.demo2;

import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo3Servlet", value = "/demo3Servlet")
public class Demo3Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        // 获取当前请求的所有参数,以键值对的方式存储到Map中
        Map<String, String[]> parameterMap = request.getParameterMap();
        System.out.println("parameterMap = " + parameterMap);
        // 根据参数名获取一个参数值
        String parameter = request.getParameter("username");
        System.out.println("parameter = " + parameter);
        // 根据参数名获取多个参数值
        String[] parameterValues = request.getParameterValues("hobbies");
        System.out.println("parameterValues = " + Arrays.toString(parameterValues));
        // 获取所有的参数名
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String name = parameterNames.nextElement();
            System.out.println("name = " + name);
        }

    }
}

1.3 解决请求参数乱码

1.3.1 为什么会发生请求参数乱码?

  • 因为客户端发送给请求参数给服务器的时候需要进行编码,将字符串编码成二进制才能够在网络中传输,而服务器在接收到二进制之后需要进行解码才能够获取真正的请求参数;在这个过程中如果保证客户端编码使用的字符集和服务器解码使用的字符集相同的话,基本上(只要采用正确的够用的字符集)就不会发生乱码了;而发生乱码的原因是因为使用了错误的字符集,或者是客户端与服务器端所采用的字符集不一致。

1.3.2 解决请求参数乱码

  • 当前使用的Tomcat的版本是Tomcat8,不需要考虑GET请求参数乱码问题,因为Tomcat8及其以上版本默认已经在配置中解决了GET请求参数乱码问题了,我们只需要解决POST请求参数乱码即可。
  • 解决POST请求参数乱码,只需要在获取请求参数前调用下面的代码即可:
request.setCharacterEncoding("UTF-8")
  • 示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/app/demo4Servlet" method="post">
        姓名: <input name="username" type="text"/> <br>
        密码:<input name="password" type="password"> <br>
        爱好:
        <input name="hobbies" type="checkbox" value="打篮球">打篮球
        <input name="hobbies" type="checkbox" value="踢足球">踢足球
        <input name="hobbies" type="checkbox" value="玩游戏">玩游戏 <br>
        <input type="submit" value="提交">
    </form>
</body>
</html>
package com.example.javaweb.demo2;

import java.io.IOException;
import java.util.Arrays;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo4Servlet", value = "/demo4Servlet")
public class Demo4Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        // 解决POST请求参数乱码
        request.setCharacterEncoding("utf-8");
        Map<String, String[]> parameterMap = request.getParameterMap();
        parameterMap.forEach((k, v) -> {
            System.out.println(k + "\t" + Arrays.toString(v));
        });
    }
}

1.4 请求转发

  • 请求转发是从一个资源跳转到另外一个资源,在这个过程中客户端不会产生新的请求,换言之,请求转发是服务器内部的行为,对客户端来说是透明的,无感知的。

请求转发.png

  • 请求转发的特点:
    • ① 请求转发的跳转是由服务器发起的,在这个过程中浏览器只会发送一次请求。
    • ② 请求转发只会跳转到本项目的资源,甚至可以跳转到WEB-INF中的资源。
    • ③ 请求转发不会改变地址栏中的地址。
  • 请求转发的方法:
public RequestDispatcher getRequestDispatcher(String path);
  • 示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/demo5Servlet">Demo5Servlet</a>
</body>
</html>
package com.example.javaweb.demo2;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo5Servlet", value = "/demo5Servlet")
public class Demo5Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        System.out.println("Demo5Servlet");
        // 请求转发不需要写"/应用项目名称"
        request.getRequestDispatcher("/demo6Servlet").forward(request, response);
    }
}
package com.example.javaweb.demo2;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo6Servlet", value = "/demo6Servlet")
public class Demo6Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        System.out.println("Demo6Servlet");
    }
}

1.5 请求域对象

  • 请求域对象只能在一次请求范围中共享数据,所以请求域对象需要配合请求转发一起使用。
  • 向请求域中添加数据:
public void setAttribute(String name, Object o);
  • 获取请求域中的数据:
public Object getAttribute(String name);
  • 删除请求域中的数据:
public void removeAttribute(String name);
  • 示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/demo5Servlet">Demo5Servlet</a>
</body>
</html>
package com.example.javaweb.demo2;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo5Servlet", value = "/demo5Servlet")
public class Demo5Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        System.out.println("Demo5Servlet");
        // 向请求域中设置数据
        request.setAttribute("name", "许大仙");
        // 请求转发不需要写"/应用项目名称"
        request.getRequestDispatcher("/demo6Servlet").forward(request, response);
    }
}
package com.example.javaweb.demo2;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo6Servlet", value = "/demo6Servlet")
public class Demo6Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        System.out.println("Demo6Servlet");
        // 获取请求域中的数据
        Object name = request.getAttribute("name");
        System.out.println("name = " + name);
    }
}

1.6 JavaBean

  • JavaBean是Java语言编写的可重用的组件,在项目中JavaBean主要用于存储内存中的数据以及提供方法以便使用者获取数据。
  • JavaBean的要求:

    • ① 类必须是公开的(public)。
    • ② 必须有无参构造器。
    • ③ 属性私有,使用private修饰。
    • ④ 针对所有的私有属性,提供Setter和Getter方法。
    • ⑤ 建议重写toString(),便于打印对象。
    • ⑥ 基本类型需要使用包装类型代替。
  • 示例:

package com.example.javaweb.demo2;

import java.io.Serializable;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2021-10-21 13:25
 */
public class User implements Serializable {

    private Integer id;

    private String name;

    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" + "id=" + this.id + ", name='" + this.name + '\'' + '}';
    }
}

1.7 BeanUtils的使用

  • BeanUtils可以将Map中的数据填充到JavaBean对象之中,其实底层用的就是内省技术。
  • 方法:
public static void populate(Object bean, Map<String, ? extends Object> properties) throws IllegalAccessException, InvocationTargetException{}
  • 示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/app/demo7Servlet" method="post">
        姓名: <input name="username" type="text"/> <br>
        密码:<input name="password" type="password"> <br>
        性别:<input name="gender" type="radio" value="男">男
        <input name="gender" type="radio" value="女">女 <br>
        爱好:
        <input name="hobbies" type="checkbox" value="打篮球">打篮球
        <input name="hobbies" type="checkbox" value="踢足球">踢足球
        <input name="hobbies" type="checkbox" value="玩游戏">玩游戏 <br>
        <input type="submit" value="提交">
    </form>
</body>
</html>
package com.example.javaweb.bean;

import java.io.Serializable;
import java.util.Arrays;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2021-10-21 13:25
 */
public class User implements Serializable {

    private Integer id;

    private String username;

    private String password;

    private String gender;

    private String[] hobbies;

    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return this.username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return this.password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getGender() {
        return this.gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String[] getHobbies() {
        return this.hobbies;
    }

    public void setHobbies(String[] hobbies) {
        this.hobbies = hobbies;
    }

    @Override
    public String toString() {
        return "User{" + "id=" + this.id + ", username='" + this.username + '\'' + ", password='" + this.password + '\''
            + ", gender='" + this.gender + '\'' + ", hobbies=" + Arrays.toString(this.hobbies) + '}';
    }
}
package com.example.javaweb.demo2;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;

import com.example.javaweb.bean.User;

@WebServlet(name = "Demo7Servlet", value = "/demo7Servlet")
public class Demo7Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");

        Map<String, String[]> parameterMap = request.getParameterMap();
        try {
            User user = new User();
            BeanUtils.populate(user, parameterMap);
            System.out.println("user = " + user);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

第二章:Response

2.1 概述

2.1.1 Response的概念

  • 在Servlet API中,定义了一个HttpServletResponse接口(doGet,doPost方法的参数),它继承自ServletResponse接口,专门用来封装HTTP响应消息。由于HTTP响应消息分为响应行、响应头、响应体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码、响应头、响应体的方法。
  • 换言之,Response就是服务器端的一个对象,该对象封装了响应给客户端的响应行、响应头和响应体信息。

Response的概念.png

2.1.2 Response的组成

  • 响应行:包含HTTP协议版本、响应状态码和响应状态的说明文字。
  • 响应头:一个个的键值对,每一个键值对中都表示一种含义,用于服务器传递相关的信息给客户端。
  • 响应体:用于展示在客户端的文本、图片,或者供客户端下载或播放的内容。

2.1.3 Response的作用

  • ① 设置响应行的信息,主要是设置响应状态码。
  • ② 设置响应头的信息。
  • ③ 设置响应体的信息。

2.2 设置HTTP的响应行

  • 设置响应状态码:
public void setStatus(int sc);
  • 示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/demo8Servlet">Demo8Servlet</a>
</body>
</html>
package com.example.javaweb.demo2;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo8Servlet", value = "/demo8Servlet")
public class Demo8Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        // 设置响应状态码,一般情况下,不需要设置状态码,因为服务器会自动设置状态码
        response.setStatus(200);
    }
}

2.3 设置HTTP的响应头信息

  • 设置指定名称和值的响应头:
public void setHeader(String name, String value);
  • 给指定名称的响应头添加值:
public void setHeader(String name, String value);
  • 设置指定名称和日期格式的响应头(不常用):
public void setDateHeader(String name, long date);
  • 给指定名称的响应头添加日期格式的值(不常用):
public void addDateHeader(String name, long date);
  • 设置指定名称和int类型的响应头(不常用):
public void setIntHeader(String name, int value);
  • 给指定名称的响应头添加int类型的值(不常用):
public void addIntHeader(String name, int value);
  • 示例:通过设置响应状态码和响应头实现重定向
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/demo8Servlet">Demo8Servlet</a>
</body>
</html>
package com.example.javaweb.demo2;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo8Servlet", value = "/demo8Servlet")
public class Demo8Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        System.out.println("Demo8Servlet");
        // 设置响应状态码,一般情况下,不需要设置状态码,因为服务器会自动设置状态码
        response.setStatus(302);
        response.setHeader("location", request.getContextPath() + "/demo9Servlet");
    }
}
package com.example.javaweb.demo2;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo9Servlet", value = "/demo9Servlet")
public class Demo9Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        System.out.println("Demo9Servlet");
    }
}

2.4 设置响应体内容

2.4.1 向客户端输出文本内容

  • 通过字符流向客户端输出文本内容:
public PrintWriter getWriter() throws IOException;
  • 由于服务器端在输出内容的时候进行编码使用的字符集和客户端进行解码的时候使用的字符集不一致,所以会发生响应数据乱码问题。
  • 解决响应数据乱码问题只需要在获取字符输出流之前,添加下面的代码:
response.setContentType("text/html;charset=UTF-8");
  • 示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/demo10Servlet">Demo10Servlet</a>
</body>
</html>
package com.example.javaweb.demo2;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo10Servlet", value = "/demo10Servlet")
public class Demo10Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write("你好啊");
    }
}

2.4.2 向客户端输出一个文件

  • 通过字节输出流向客户端输出一个文件:
public ServletOutputStream getOutputStream() throws IOException;
  • 示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/demo11Servlet">Demo11Servlet</a>
</body>
</html>
package com.example.javaweb.demo2;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo11Servlet", value = "/demo11Servlet")
public class Demo11Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        ServletOutputStream outputStream = response.getOutputStream();
        InputStream inputStream = new FileInputStream(request.getServletContext().getRealPath("/images/mm.jpg"));
        byte[] bytes = new byte[1024];
        int len;
        while (-1 != (len = inputStream.read(bytes))) {
            outputStream.write(bytes, 0, len);
        }
        inputStream.close();
        outputStream.close();
    }
}

2.5 重定向

  • 重定向是由项目中的一个资源跳转到另外一个资源,在这个过程中客户端会发起新的请求。

重定向.png

  • 重定向的特点:
    • ① 重定向的跳转是由浏览器发起的,在这个过程中浏览器会发起两次请求。
    • ② 重定向跳转可以跳转到任意服务器的资源,但是无法访问WEB-INF中的资源。
    • ③ 重定向跳转浏览器的地址栏中的地址会变成跳转到的路径。
  • 重定向的方法:
public void sendRedirect(String location) throws IOException;
  • 示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/demo12Servlet">Demo12Servlet</a>
</body>
</html>
package com.example.javaweb.demo2;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Demo12Servlet", value = "/demo12Servlet")
public class Demo12Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

        response.sendRedirect("https://www.baidu.com");
    }
}

2.6 重定向 VS 请求转发

  • ① 重定向会由浏览器发起新的请求,而请求转发不会发起新的请求。
  • ② 重定向可以访问任意互联网资源,而请求转发只能访问本项目资源。
  • ③ 重定向不能访问本项目的WEB-INF内的资源,而请求转发可以访问本项目的WEB-INF内的资源。
  • ④ 发起重定向的资源和跳转到的目标资源没在同一次请求中,所以重定向不能在请求域中使用;而发起请求转发的资源和跳转到的目标资源在同一次请求中,所以请求转发可以在请求域中使用。