Tomcat & Servlet

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Tomcat & Servlet

一、What is “Tomcat”?

Tomcat 本质上是一个基于 TCP 协议的 HTTP 服务器。我们知道HTTP是一种应用层协议,是 HTTP 客户端和 HTTP 服务器之间的交互数据的格式。Tomcat 就是基于 Java 实现的一个开源免费,也是被广泛使用的 HTTP 服务器。


以下是 Tomcat 安装完成后的文件目录:

运行Tomcat我们可以使用cmd命令查看Tomcat的端口号的进程ID:

二、 What is “Servlet”?

对于网站的后端开发,我们总是围绕着 HTTP 服务器展开相关工作,当然我们也可以重 0 开始写一个服务器,一步步的实现服务器的功能,包括根据 HTTP 协议解析请求报文、根据HTTP构造响应报文等等……对于服务器来说,很多功能都是千篇一律的,如果我们把中心放到整个服务器的开发上,这对于业务逻辑的开发来说,显然是非常不友好的。因此我们可以借助现成的 HTTP 服务器进行开发,例如 Tomcat 就为我们省去了这些不必要的环节,为我们提供了一些列的 API ,让我们能够更专注于业务逻辑。


Servlet 就是一组 Tomcat 提供的 API,让程序猿自己写的代码能很好的和 Tomcat 配合起来,从而更简单的实现一个 webapp,而不必关注 Socket、HTTP协议格式、多线程并发等技术细节,降低了 webapp 的开发门槛,提高了开发效率。


Servlet 中提供的 API 有很多,这里我们重点掌握 3 个类:HttpServletHttpServletRequestHttpServletResponse,下面我们逐一介绍👇:

1、HttpServlet

我们写 Servlet 代码的时候,首先第一步就是先创建类,继承自 HttpServlet,并重写其中的某些方法。

HttpServlet 核心方法展示:

方法名称 调用时机
init 在 HttpServlet 实例化之后被调用一次
destroy 在 HttpServlet 实例不再使用的时候调用一次
service 收到 HTTP 请求的时候调用
doGet 收到 GET 请求的时候调用 (由 service 方法调用)
doPost 收到 POST 请求的时候调用 (由 service 方法调用)
doPut/doDelete/doOptions/… 收到其他请求的时候调用(由 service 方法调用)

其中 init、destroy、service 这 3 个方法的调用时机,就称为 “Servlet 生命周期”:

  1. init方法,只会在初始情况下调用1次,也就是HttpServlet实例化时调用,一般使用这个方法做一些初始化的相关工作。(HttpServlet 的实例只是在程序启动时创建一次,而不是每次收到 HTTP 请求都重新创建实例。)
  2. destroy方法,用于该webapp被销毁之前执行1次,用来做一些首尾工作。但是并不建议使用这个方法,因为通常采用直接杀死进程的方式停止服务器,此时destroy执行不了。
  3. service方法,每次收到路径匹配的请求都会执行,例如上述doGet、doPost方法其实都是在service方法中被调用,一般不会重写service方法。

在实际开发中,我们往往重写 doXXX 方法,很少会重写 init / destory / service:

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
    throws ServletException, IOException {
      resp.getWriter().write("hello world");
    }
}

代码说明:

  1. 在这个类上方加上 @WebServlet("/hello") 注解, 表示 Tomcat 收到的请求中, 路径为 /hello的请求才会调用HelloServlet 这个类的代码
  1. HttpServletRequest 表示 HTTP 请求。Tomcat 按照 HTTP 请求的格式把 字符串 格式的请求转成了一个 HttpServletRequest 对象。后续想获取请求中的信息(方法、url、 header、body 等) 都是通过这个对象来获取。
  2. HttpServletResponse 表示 HTTP 响应。我们可以根据resp响应对象提供的方法,构造响应的状态码, header, body 等。Tomcat 会把整个响应转成字符串,通过 socket 写回给浏览器。

2、HttpServletRequest

当 Tomcat 通过 Socket API 读取到 HTTP 请求(字符串)后,就会按照 HTTP 协议的格式把字符串解析成 HttpServletRequest 对象。

HttpServletRequest 提供了一些方法,可以获取到一个请求中的各个方面的信息:

HttpServletRequest 提供的方法都只是“读”方法,而不是“写”方法。其实这也很容易理解,请求对象是服务器收到的内容,不应该被修改。

方法 描述
String getProtocol() 返回请求协议的名称和版本。
String getMethod() 返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。
StringBuffer getRequestURL() 它用于获取请求的URL,不包含 query string
String getRequestURI() 它用于获取请求的统一资源标识符(URI)的部分,即资源路径。
String getContextPath() 获取请求的ContextPath,ContextPath标识一个webapp,即webapp的目录名
String getServlettPath() 获取请求的ServletPath,ServletPath标识一个类
String getQueryString() 返回包含在路径后的请求 URL 中的查询字符串。
Enumeration getHeaderNames() 返回一个枚举,包含该请求中包含的所有请求头名。
String getHeader(String name) 以字符串形式返回指定请求头的值。
String getCharacterEncoding() 返回请求主体中使用的字符编码的名称。
String getContentType() 返回请求主体的类型,如果不知道类型则返回 null。
int getContentLength() 以字节为单位返回请求主体的长度,如果长度未知则返回 -1。
InputStream getInputStream() 返回一个 InputStream 对象,用于读取请求的 body 内容。

上面这些方法只要对HTTP协议足够了解,简单看一下就能够使用。这里主要介绍有关getParameter相关的方法:

方法 描述
Enumeration getParameterNames() 返回一个枚举,表示在该请求中包含的参数的名称。
String getParameter(String name) 返回请求参数的值,以字符串形式返回,如果参数不存在则返回 null。
String[] getParameterValues(String name) 返回一个字符串数组,表示给定请求参数的所有值,如果参数不存在则返回 null。

这些方法主要是获取请求中的请求信息的,下面以getParameter()为例:

1. 获取GET请求中的参数值

@WebServlet("/getParameter")
public class Test extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // 前端通过 url 的 query string 传递 username 和 password 两个属性.
        String userName = req.getParameter("username");
        String passWord = req.getParameter("password");

        resp.setContentType("text/html; charset=utf-8");
        resp.getWriter().write("username="+userName+"<br/>"+"password="+passWord);
    }
}

2. 获取POST请求中的参数值

(1)请求参数通过body传递,采用 form 表单格式提交,即 Content-Type 是 application/x-www-form-urlencoded

此时同样可以使用getParameter直接获取参数值:

注意:需要显示地告诉后端请求的编码方式,防止解析请求时出现中文乱码情况。

@WebServlet("/postParameter")
public class Test extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
    // 显示地告诉后端请求的编码方式,防止中文乱码
        req.setCharacterEncoding("utf8");
    
        // 前端通过 url 的 query string 传递 username 和 password 两个属性.
        String userName = req.getParameter("username");
        String passWord = req.getParameter("password");

        resp.setContentType("text/html; charset=utf-8");
        resp.getWriter().write("username="+userName+"<br/>"+"password="+passWord);
    }
}

(2)请求参数通过body传递,Content-Type 是 application/json

对于Servlet,其没有内置 json 的解析功能,此时想要获取这种格式的参数就需要借助第三方库 jackson,首先我们在中央仓库找到 jackson 依赖引入到 pom.xml 中,然后就可以编写解析 json 格式请求参数的代码了。


使用 jackson,最核心的对象就是 ObjectMapper,通过这个对象里面的两个方法,就可以把 json 字符串解析成 java 对象;也可以把一个 java 对象转成一个 json 格式字符串,具体如下:writeValueAsString 方法把一个 Java 对象转成 JSON 格式字符串。

readValue方法, 第一个参数为输入流对象,或Json字符串,的第二个参数为 JsonData 的 类对象,通过这个类对象,在 readValue 的内部就可以借助反射机制来构造出 Java 对象。

class User {
    public String username;
    public String password;

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

@WebServlet("/jsonParameter")
public class Test extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
     throws ServletException, IOException {
      // 设置响应格式
        resp.setContentType("text/html;charset=utf-8");
        // 通过 post 请求的 body 传递过来一个 json 格式的字符串.
        // 1.使用objectMapper将json字符串解析成java对象
        User user = objectMapper.readValue(req.getInputStream(), User.class);
        resp.getWriter().write("1.使用objectMapper将json字符串解析成java对象:<br/>"+user.toString()+"<br/>");

        // 2.使用objectMapper将java对象解析成json字符串
        String jsonString = objectMapper.writeValueAsString(user);
        resp.getWriter().write("2.使用objectMapper将java对象解析成json字符串:<br/>"+jsonString);
    }
}

3、HttpServletResponse

Servlet 中的 doXXX 方法的目的就是根据请求计算得到响应,然后把响应的数据设置到 HttpServletResponse 对象中,Tomcat 内壁就会把这个 HttpServletResponse 对象按照 HTTP 协议的格式,转成一个字符串,并通过 Socket 写回给浏览器。

响应对象是服务器要返回给浏览器的内容,这里的重要信息都是程序员根据请求设置到响应中的,因此下面的方法都是 “写” 方法。

下面是在设置响应时常用到的方法:

方法 描述
void setStatus(int sc) 为该响应设置状态码。
void setHeader(String name, String value` 设置一个带有给定的名称和值的 header。如果 name 已经存在,则覆盖旧的值。
void addHeader(String name, String value) 添加一个带有给定的名称和值的 header。如果 name 已经存在,不覆盖旧的值,并列添加新的键值对。
void setContentType(String type) 设置被发送到客户端的响应的内容类型。
void setCharacterEncoding(String charset) 设置被发送到客户端的响应的字符编码(MIME 字符集),例如 UTF-8。
void sendRedirect(String location) 使用指定的重定向位置 URL 发送临时重定向响应到客户端。
PrintWriter getWriter() 用于往 body 中写入文本格式数据。
OutputStream getOutputStream() 用于往 body 中写入二进制格式数据。

其实上面这些方法和同样只要对HTTP协议足够了解,简单看一下就能够使用,下面就简单演示几个方法,体会一下设置响应的过程:

(1)设置自动刷新

@WebServlet("/Refresh")
public class Refresh extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
     throws ServletException, IOException {
        // 设置自动刷新,刷新频率:每隔1秒自动刷新一次
        resp.setHeader("Refresh","1");
        resp.getWriter().write("time = "+System.currentTimeMillis());
    }
}

(2)设置重定向

方式1:使用 sendRedirect 方法

@WebServlet("/Redirect")
public class Redirect extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
     throws ServletException, IOException {
      // 设置重定向:
        resp.sendRedirect("https://www.baidu.com");
    }
}

方式1:使用 setStatus + setHeader方法

@WebServlet("/Redirect")
public class Redirect extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
     throws ServletException, IOException {
        // 设置重定向:
        resp.setStatus(302);
        resp.setHeader("Location","https://www.baidu.com");
    }
}


相关文章
|
2月前
|
Java 应用服务中间件 Maven
JavaWeb基础5——HTTP,Tomcat&Servlet
JavaWeb技术栈、HTTP、get和post区别、响应状态码、请求响应格数据式、IDEA使用Tomcat、报错解决、Servlet的体系结构、IDEA使用模板创建Servlet
JavaWeb基础5——HTTP,Tomcat&Servlet
|
5月前
|
Java 应用服务中间件 Maven
|
5月前
|
前端开发 应用服务中间件
|
5月前
|
XML 数据格式
|
5月前
|
XML Java 应用服务中间件
|
5月前
|
前端开发 Java 应用服务中间件
|
6月前
|
XML 前端开发 Java
Tomcat和Servlet
Tomcat和Servlet
44 0
|
6月前
|
前端开发 Java 应用服务中间件
HTTP&Tomcat&Servlet
HTTP&Tomcat&Servlet
82 0
|
Java 应用服务中间件 Linux
HTTPS && Tomcat && Servlet && 博客系统 && 软件测试的概念 && Linux
HTTPS && Tomcat && Servlet && 博客系统 && 软件测试的概念 && Linux
57 0
|
存储 XML 安全
Tomcat+Servlet面试题都在这里(修订版)(二)
下面是我整理下来的Servlet知识点:
107 0
Tomcat+Servlet面试题都在这里(修订版)(二)