初识Servlet(三)🚕

167 阅读7分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第24天,点击查看活动详情

写在前面👀

今天主要讲讲Servlet的体系结构和HttpServletRequest接口获取客户端请求信息的一些方法

一、Servlet体系结构

上回书说到,使用Servlet就必须要实现Servlet接口,重写接口中的5个方法,这是比较麻烦的,我们更关注的其实只有service方法,那有没有更简单方式来创建Servlet呢?

要想解决上面的问题,我们需要先对Servlet的体系结构进行下了解

1️⃣继承关系

image-20220426224218662

a.Servlet根接口

  • 从上图可以看出,Servlet接口的基本目标是提供与Servlet生命周期相关的方法,如:init()、service()和destroy()等

b.GenericServlet抽象类

  • 继承自Servlet,除了重写了五个方法外,还多了其他方法。
  • 不常用

c.HttpServlet类

  • HttpServlet指能够处理HTTP请求的Servlet,它在原有Servlet接口上添加了对HTTP协议的处理,它比Servlet接口的功能更为强大,比前两个Servlet更常用
  • HttpServlet在实现Servlet接口时,重写了service()方法,该方法会自动判断用户的请求方式
    • 若为若为GET请求,则调用HttpServlet的doGet( )方法;若为POST请求,则调用doPost( )方法。当然还有别的请求方式

image-20220426225858605

2️⃣自定义HttpServlet类

HttpServlet类已经为我们封装好了和HTTP有关许多复杂的操作,而B/S架构的web项目,都是针对HTTP协议的。作为程序员,我们选择继承HttpServlet类时,通常只需要重写**doGet( )doPost( )**方法,来处理GET和POST请求,而不需要去重写service方法。

编写格式示例💥

@WebServlet("/demo4")
public class ServletDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //TODO GET 请求方式处理逻辑
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //TODO Post 请求方式处理逻辑
    }
}

二、HttpServletRequest

1️⃣什么是HttpServletRequest?

在 Servlet API 中,定义了一个 HttpServletRequest 接口,它继承自 ServletRequest 接口。HttpServletRequest的实现类RequestFacade对象专门用于封装 HTTP 请求消息,简称 request 对象

2️⃣HttpServletRequest继承体系

我们都知道,HttpServletRequest是一个接口,而接口是不能直接创建对象的,所以tomcat就定义了一个HttpServletRequest接口的实现类——RequestFacade,而这个类的对象也是由tomcat创建的。

验证猜想
  • 编写一个Servlet,把request对象打印下,可以看到,他的类型确实为RequestFacade
/**
 * 验证request的类型
 */
@WebServlet("/demo4")
public class ServletDemo4 extends HttpServlet {

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
}
  • 演示结果如下👇

image-20220427163727412

3️⃣RequestFacade的API

  • Java EE API 官方手册

  • 要想了解RequestFacade中都提供了哪些方法,我们可以直接查看JavaEE的API文档中关于ServletRequest和HttpServletRequest的接口文档,因为RequestFacade实现了其接口就需要重写接口中的方法

三、Request获取请求数据

HTTP请求数据总共分为三部分内容,分别是请求行请求头请求体,下面通过几个实例来演示下如何获取这些请求数据

1️⃣获取请求行数据

请求行包含三块内容,分别是请求方式请求资源路径HTTP协议及版本

image-20220427103307680

a.接口方法
  • HttpServletRequest 接口定义了一系列获取请求行信息的方法,如下表
返回值类型方法声明描述
StringgetMethod()获取 HTTP 请求方式(如 GET、POST 等)。
StringgetContextPath()获取虚拟目录(项目访问路径),如/tomcat
StringgetServletPath()获取 Servlet 所映射的路径,如/req1
StringgetRequestURI()获取URI(统一资源标识符),即位于 URL 的主机和端口之后,参数部分之前的部分,如/tomcat/req1
StringBuffergetRequestURL()获取URL(统一资源定位符),如http://localhost:8080/tomcat/req1
StringgetQueryString()获取请求行的参数(GET方式),也就是 URL 中“?”以后的所有内容,如username=bighorn&&password=123456
StringgetRemoteAddr()获取客户端的 IP 地址。
StringgetRemoteHost()获取客户端的完整主机名,如果无法解析出客户机的完整主机名,则该方法将会返回客户端的 IP 地址。
b.代码示例

下面以获取GET请求行数据为例。

  1. 创建一个HttpServlet的子类:RequestDemo1,Servlet映射路径:/req1
/**
 * request 获取请求行数据
 */
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1.获取请求方式: GET
        String method = req.getMethod();
        System.out.println("请求方式:" + method);
        // 2.获取虚拟目录(项目访问路径):/tomcat
        String contextPath = req.getContextPath();
        System.out.println("项目访问路径:" + contextPath);
        // 3.获取Servlet映射路径:/req1
        String servletPath = req.getServletPath();
        System.out.println("Servlet映射路径:" + servletPath);
        // 4.获取URI(统一资源标识符):/tomcat/req1
        String uri = req.getRequestURI();
        System.out.println("URI:" + uri);
        // 5.获取URL(统一资源定位符):http://localhost:8080/tomcat/req1
        StringBuffer url = req.getRequestURL();
        System.out.println("URL:" + url.toString());
        // 6.获取请求参数(GET方式): username=bighorn&&password=123456
        String queryString = req.getQueryString();
        System.out.println("请求参数:" + queryString);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}
  1. 启动tomcat服务器

  2. 在浏览器地址栏输入,敲回车

localhost:8080/tomcat/req1?username=bighorn&&password=123456
c.演示结果

image-20220427111701721

2️⃣获取请求头数据

当浏览器发送请求时,需要通过请求头向服务器传递一些附加信息,例如客户端可以接收的数据类型、压缩方式、语言等

  • 请求头的数据,是键值对的形式,例如下图👇

image-20220427145258828

a.接口方法
  • HttpServletRequest 接口定义了一系列获取请求头信息的方法,如下表
返回值类型方法声明描述
StringgetHeader(String name)获取一个指定头字段的值。 如果请求消息中包含多个指定名称的头字段,则该方法返回其中第一个头字段的值。
EnumerationgetHeaders(String name)返回指定头字段的所有值的枚举集合, 在多数情况下,一个头字段名在请求消息中只出现一次,但有时可能会出现多次。
EnumerationgetHeaderNames()返回请求头中所有头字段的枚举集合。
StringgetContentType()获取 Content-Type 头字段的值。
intgetContentLength()获取 Content-Length 头字段的值 。
StringgetCharacterEncoding()返回请求消息的字符集编码 。
b.代码示例

下面以获取GET请求头数据为例。

  1. 创建一个HttpServlet的子类:RequestDemo2,Servlet映射路径:/req2
/**
 * request 获取请求头数据
 */
@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获得所有请求头字段的枚举集合
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            //获得请求头字段的key,即字段名
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName);
            //获得请求头字段的val,即字段值
            System.out.println(headerName + ":" + headerValue);
        }
    }

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

    }
}
  1. 启动tomcat服务器

  2. 在浏览器地址栏输入,敲回车

localhost:8080/tomcat/req2
c.演示结果

image-20220427144646641

3️⃣ 获取请求体数据

众所周知,GET请求的时候是没有请求体的,所以需要把请求方式变更为POST,请求体里大多是客户端传入的参数。

  • 请求体中的数据格式如下👇

image-20220427152917316

a.接口方法
  • HttpServletRequest 接口定义了一系列获取请求头信息的方法,如下表
返回值类型方法声明描述
ServletInputStreamgetInputStream()获取字节输入流,如果前端发送的是字节数据,比如传递的是文件数据,则使用该方法
BufferedReadergetReader()获取字符输入流,如果前端发送的是纯文本数据,则使用该方法
b.代码示例

下面以获取POST请求体纯文本数据为例。

  1. webapp目录下添加一个html文件,名称为:login.html。添加一个表单类型标签,设置请求方式为POST,请求路径为/tomcat/req3
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="/tomcat/req3" method="post">
            账号:<input type="text" name="username">
            <br>
            密码:<input type="password" name="password">
            <br>
            <input type="submit" value="登录">
        </form>
    </body>
</html>
  1. 创建一个HttpServlet的子类:RequestDemo3,Servlet映射路径:/req3
/**
 * 获取请求体数据(POST请求方式)
 */
@WebServlet("/req3")
public class RequestDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.获取请求方式: POST
        String method = request.getMethod();
        System.out.println("请求方式:" + method);
        // 2. 获取字符输入流
        BufferedReader br = request.getReader();
        // 3. 读取数据
        String line = br.readLine();
        System.out.println("请求体数据:"+line);
    }
}
  1. 启动tomcat服务器

  2. 在浏览器地址栏输入,敲回车

localhost:8080/tomcat/login.html
  1. 在表单输入账号和密码

image-20220427154423401

c.演示结果

image-20220427154602825

写在后面🍻

感谢观看啦✨
有什么不足,欢迎指出哦💖
掘金的运营同学审核辛苦了💗