Java Webサーブレット(パートC)-HttpServletRequest&HttpServletResponse

「オファーが届きました。友達を探して受け取りましょう。私は2022年春の採用チェックインイベントに参加しています。クリックしてイベントの詳細を表示してください。」

一、HttpServletRequest

リクエストがTomcatに入るたびに、TomcatサーバーはリクエストされたHTTPプロトコル情報を解析してHttpServletRequestオブジェクトにカプセル化し、それをサービスメソッドに渡します。クライアントから送信されたリクエストの情報は、HttpServletRequestオブジェクトを介して取得できます。

HttpServletRequestの一般的なメソッド

  • getRequestURI()、要求されたリソースパスを取得します
  • gerRequestURL()、要求されたユニフォームリソースロケーターを取得します
  • getRemoteHost()、クライアントIPを取得します
  • getHeader()、リクエストヘッダーを取得します
  • getParameter()、リクエストのパラメータを取得します
  • getParameterValues()、リクエスト内の複数のパラメーターの値を取得します
  • getMethod()、リクエストメソッドを取得、GETまたはPOST
  • setAttribute(key、value)、ドメインデータを設定します
  • getAttribute(key)、ドメインデータを取得
  • getRequestDispatcher()、リクエスト転送オブジェクトを取得します

コントローラパッケージにHiServletを追加する

public class HiServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 1. 获取请求的资源路径
        System.out.println("请求资源路径为:" + req.getRequestURI());
        // 2. 获取请求的URL地址
        System.out.println("请求的URL地址为:" + req.getRequestURL());
        // 3. 获取请求的客户端IP地址
        System.out.println("客户端IP地址为:" + req.getRemoteHost());
        // 4. 获取请求头
        System.out.println("请求头为:" + req.getHeader("User-Agent"));
        // 5. 获取请求方式
        System.out.println("请求方式为:" + req.getMethod());
    }
}
复制代码

web.xmlでサーブレットのアクセスパスを構成します

<servlet>
    <servlet-name>HiServlet</servlet-name>
    <servlet-class>com.lilith.servlet.HiServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>HiServlet</servlet-name>
    <url-pattern>/hi</url-pattern>
</servlet-mapping>
复制代码

Tomcatを再起動すると、ブラウザはhttp:// localhost:8080/hiにアクセスします

image.png

form.htmlページをWebディレクトリに追加し、新しいフォームを追加します

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Form</title>
</head>
<body>
<form action="/param" method="get">
    用户名:<input type="text" name="username"> <br>
    密码: <input type="password" name="password"> <br>
    兴趣爱好:<input type="checkbox" name="hobby" value="cpp"> C++
    <input type="checkbox" name="hobby" value="java"> Java
    <input type="checkbox" name="hobby" value="python"> Python <br>
    <input type="submit" value="提交">
</form>
</body>
</html>
复制代码

フォームによって送信されたデータを取得するためのParamServletクラスが追加されました

public class ParamServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求中的参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String hobby = req.getParameter("hobby");
        System.out.println("请求中username参数的值为:" + username);
        System.out.println("请求中password参数的值为:" + password);
        System.out.println("请求中hobby参数的值为:" + hobby);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}
复制代码

web.xmlにParamServletのアクセス構成を追加します

<servlet>
    <servlet-name>ParamServlet</servlet-name>
    <servlet-class>com.lilith.servlet.ParamServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>ParamServlet</servlet-name>
    <url-pattern>/param</url-pattern>
</servlet-mapping>
复制代码

Tomcatを再起動し、ブラウザにhttp:// localhost:8080 / form.htmlと入力し、フォームにデータを入力してから[送信]をクリックします

image.png

当参数有多个值时,需要使用getParameterValues来获取,getParameter只能获取参数的第一个值

// 获取请求中的参数(有多个值)
String[] hobbies = req.getParameterValues("hobby");
System.out.println("请求中hobby参数的所有值:" + Arrays.asList(hobbies));
复制代码

中文乱码问题

表单中输入中文,点击提交

image.png

当请求方式为GET请求时,中文可以正常显示

更改form.html中请求方式为post,将goGet方法中的代码拷贝至doPost方法中,在表单中再次提交中文信息

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("doPost方法被调用!");
    // 获取请求中的参数
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    String hobby = req.getParameter("hobby");
    System.out.println("请求中username参数的值为:" + username);
    System.out.println("请求中password参数的值为:" + password);
    System.out.println("请求中hobby参数的值为:" + hobby);

    // 获取请求中的参数(有多个值)
    String[] hobbies = req.getParameterValues("hobby");
    System.out.println("请求中hobby参数的所有值:" + Arrays.asList(hobbies));
}
复制代码

image.png 根据控制台的输出,POST提方式提交时中文乱码了。

doPost方法中增加编码设置

req.setCharacterEncoding("UTF-8");
复制代码

再次提交表单

image.png

中文乱码问题已解决

Servlet的请求转发

请求转发是指服务器收到请求后,从一个资源跳转到另一个资源的操作。

在controller包中新建两个Servlet类AlphaServlet和BravoServlet,用作实现请求转发

public class AlphaServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求参数
        String username = req.getParameter("username");
        System.out.println("alpha请求中参数username的值为:" + username);

        // 要转发到BravoServlet的地址
        // 请求转发的地址必须要以/开头
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/bravo");
        // 转发到BravoServlet
        requestDispatcher.forward(req,resp);
    }
}
复制代码
public class BravoServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String username = req.getParameter("username");
        System.out.println("bravo请求中参数username的值为:" + username);

        System.out.println("BravoServlet业务处理");
    }
}
复制代码

在web.xml中配置AlphaServlet和BravoServlet的访问路径

<servlet>
    <servlet-name>AlphaServlet</servlet-name>
    <servlet-class>com.lilith.servlet.AlphaServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>AlphaServlet</servlet-name>
    <url-pattern>/alpha</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>BravoServlet</servlet-name>
    <servlet-class>com.lilith.servlet.BravoServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>BravoServlet</servlet-name>
    <url-pattern>/barvo</url-pattern>
</servlet-mapping>
复制代码

重新启动Tomcat,在浏览器中输入 http://localhost:8080/alpha?username=peter, 点击回车 image.png

F12打开浏览器的检查页面,查看网络可以确定从请求AlphaServlet然后转发到BravoServlet只发了一次请求,也就是说请求AlphaServlet和AlphaServlet转发到BravoServlet是同一个请求,所以在两个Servlet中都可以获取到username参数的值 image.png 并且浏览器的地址栏没有变化。

请求转发可以访问WEB-INF下的文件

在WEB-INF下新建success.html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>SUCCESS</title>
</head>
<body>
<h1>成功转发到WEB-INF目录下</h1>
</body>
</html>
复制代码

修改AlphaServlet,使其转发到success.html页面

RequestDispatcher requestDispatcher = req.getRequestDispatcher("/WEB-INF/success.html");
复制代码

重新启动应用

image.png 浏览器输出了success页面的内容,转发可以访问WEB-INF下的文件

请求转发的特点

  • 浏览器地址栏没有变化
  • 是同一次请求
  • 共享Request域中的数据
  • 可以转发到WEB-INF目录下
  • 不可以访问工程以外的资源

Web中的相对路径和绝对路径

在JavaWeb中,路径分为相对路径和绝对路径 相对路径

  • .:表示当前目录
  • ..:表示上一级目录
  • 资源名:表示当前目录/资源

绝对路径

Web中 “/” 的不同意义

在Web中 “/” 是一种绝对路径

二、HttpServletResponse

HttpServletResponse和HttpServletRequest类一样,每次请求进来Tomcat都会创建一个Response对象传递给Servlet程序使用,HttpServletRequest表示请求传过来的信息,HttpServletResponse表示所有响应的信息;如果需要返回给客户端消息,可以使用HttpServletResponse对象来进行设置

HttpServletResponse使用输出流来给客户端发送消息

  • 字节流,getOutputStream(); 常用于下载(传递二进制数据)
  • 字符流,getWriter();常用与回传字符串(常用)

另个流只能同时使用一个。

在controller包中创建一个SteamServlet类,同时使用字符流和字节流

public class StreamServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.getWriter();
        resp.getOutputStream();
    }
}
复制代码

在web.xml中配置Servlet的访问路径

<servlet>
    <servlet-name>SteamServlet</servlet-name>
    <servlet-class>com.lilith.servlet.StreamServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>SteamServlet</servlet-name>
    <url-pattern>/stream</url-pattern>
</servlet-mapping>
复制代码

重启Tomcat,浏览器输入 http://localhost:8080/stream

image.png 页面出现报错

修改StreamServlet,只使用字符流

public class StreamServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        PrintWriter writer = resp.getWriter();
        // resp.getOutputStream();
        writer.write("Response Content");
    }
}
复制代码

重启Tomcat,浏览器输入 http://localhost:8080/stream image.png 浏览器返回response信息

响应中文乱码问题解决方案一

设置StreamServlet中返回的内容是中文格式,并重启Tomcat,浏览器输入同一地址 image.png 页面输出的中文出现乱码现象

在代码中获取字符编码,重启Tomcat,访问同一地址 image.png

在代码中设置响应的编码格式

public class StreamServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 设置UTF-8编码
        resp.setCharacterEncoding("UTF-8");
        PrintWriter writer = resp.getWriter();
        // resp.getOutputStream();
        String characterEncoding = resp.getCharacterEncoding();
        System.out.println("字符编码给为:" + characterEncoding);
        
        writer.write("这是响应内容");

    }
}
复制代码

重启Tomcat,访问/stream image.png 还是出现乱码现象

应为还需要通过请求头设置浏览器字符集

public class StreamServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 设置UTF-8编码
        resp.setCharacterEncoding("UTF-8");
        // 响应头设置UTF-8字符集
        resp.setHeader("Content-Type","text/html;charset=UTF-8");
        PrintWriter writer = resp.getWriter();
        // resp.getOutputStream();
        String characterEncoding = resp.getCharacterEncoding();
        System.out.println("字符编码给为:" + characterEncoding);

        writer.write("这是响应内容");

    }
}
复制代码

重启Tomcat,访问/stream image.png 中文可以正常显示

响应中文乱码问题解决方案二

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    // 设置UTF-8编码
    // resp.setCharacterEncoding("UTF-8");
    // 响应头设置UTF-8字符集
    // resp.setHeader("Content-Type","text/html;charset=UTF-8");

    // 一句代码解决
    resp.setContentType("text/html;charset=UTF-8");
    PrintWriter writer = resp.getWriter();
    // resp.getOutputStream();
    String characterEncoding = resp.getCharacterEncoding();
    System.out.println("字符编码给为:" + characterEncoding);

    writer.write("这是响应内容");

}
复制代码

使用resp.setContentType("text/html;charset=UTF-8") 可以同时设置服务器和客户端都是用UTF-8编码,同时设置了响应头,并且该方法一定要在获取流对象之前调用才会生效

重启Tomcat,再次访问/stream image.png

请求重定向

请求重定向,指的是客户端发送给服务器请求后,服务端返回一个新的地址,客户端重新访问这个新的地址,称为请求的重定向。

在controller包中新建两个Servlet,用于实现请求的重定向

public class DeltaServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println(this.getClass().getName());

        resp.setStatus(302);
        resp.setHeader("Location","http://localhost:8080/echo");
    }
}
复制代码
public class EchoServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println(this.getClass().getName());
        resp.getWriter().write(this.getClass().getName());
    }
}
复制代码

在web.xml配置两个Servlet的访问路径

<servlet>
    <servlet-name>DeltaServlet</servlet-name>
    <servlet-class>com.lilith.servlet.DeltaServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>DeltaServlet</servlet-name>
    <url-pattern>/delta</url-pattern>
</servlet-mapping>
<servlet>
    <servlet-name>EchoServlet</servlet-name>
    <servlet-class>com.lilith.servlet.EchoServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>EchoServlet</servlet-name>
    <url-pattern>/echo</url-pattern>
</servlet-mapping>
复制代码

重启Tomcat,并在浏览器中输入http://localhost:8080/delta image.png

根据浏览器的显示的内容可以确定请求重定向的一些特点

  • 请求重定向发生后浏览器地址栏会发生变化
  • 请求重定向实际发生了两次请求
  • 请求重定向不共享Request域中的数据

测试重定向是否能够跳转到WEB-INF下面的页面中

resp.setHeader("Location","http://localhost:8080/WEB-INF/success.html");
复制代码

重新启动应用

image.png 访问失败,重定向不可以访问WEB-INF下的资源,但是重定向可以反问工程外的资源

请求重定向第二种实现方式(推荐使用)

resp.sendRedirect("http://localhost:8080/echo");
复制代码

応答コードとヘッダーを設定する代わりに

public class DeltaServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println(this.getClass().getName());

        // resp.setStatus(302);
        // // resp.setHeader("Location","http://localhost:8080/echo");
        // resp.setHeader("Location","http://localhost:8080/WEB-INF/success.html");
        resp.sendRedirect("http://localhost:8080/echo");
    }
}
复制代码

アプリケーションを再起動します。リダイレクトは引き続き実行できます。2番目の方法をお勧めします

おすすめ

転載: juejin.im/post/7078548826092470309