当前位置: 首页 > news >正文

深入理解 Java Servlet:从基础到实战

目录

一、引言

二、Servlet 概述

2.1 JavaWeb 的三大组件

2.2 Servlet 的作用

三、Servlet 初识

3.1 第一个 Servlet

3.1.1 Servlet 说明

3.1.2 Servlet 接口

3.1.3 创建 Servlet

3.1.4 JavaWeb 请求响应流程

3.2 Servlet 生命周期

四、HttpServlet

4.1 HttpServlet 介绍

4.2 Http 请求方法

4.3 创建 HttpServlet

4.3.1 第一种方法

4.3.2 第二种方法

4.3.3 Servlet 创建顺序

五、ServletConfig

六、Servlet 路径映射

6.1 Url-Pattern 的配置类型

6.2 优先级

6.3 示例分析

七、相对路径和绝对路径

7.1 相对路径

7.2 绝对路径

八、ServletContext

8.1 ServletContext 介绍

8.2 ServletContext API

8.3 ServletContext 使用

8.3.1 常规应用


一、引言

在 Java Web 开发领域,Servlet 是至关重要的基础组件。它如同一个勤劳的小助手,负责处理来自客户端的各种请求。本文将全面深入地介绍 Servlet 的相关知识,包括其概念、生命周期、创建方式、路径映射等内容,同时会结合实际代码示例,帮助大家更好地掌握 Servlet 的使用。

二、Servlet 概述

2.1 JavaWeb 的三大组件

Servlet 是 JavaWeb 三大组件之一,另外两个组件是 Filter(过滤器)和 Listener(观察者模式)。Servlet 是我们学习 JavaWeb 的基石,必须熟练掌握。

2.2 Servlet 的作用

Servlet 即 Server Let,其主要作用是处理用户请求。当客户端发出请求后,Tomcat 会找到合适的 Servlet 来处理该请求。例如,用户发出登录请求,就会由处理登录的 Servlet 进行处理。

三、Servlet 初识

3.1 第一个 Servlet

3.1.1 Servlet 说明

Servlet 是运行在 Web 服务器中的小型 Java 程序,通常通过 HTTP 接收和响应来自 Web 客户端的请求。我们自己编写的 Servlet 必须实现 javax.servlet.Servlet 接口,并且要在 web.xml 文件中进行部署,否则 Tomcat 无法找到该 Servlet。

3.1.2 Servlet 接口

javax.servlet.Servlet 接口包含以下几个重要方法:

  • void init(ServletConfig servletConfig):Tomcat 创建 Servlet 实例后,马上调用该方法进行初始化,且只调用一次。
  • void service(ServletRequest request, ServletResponse response):每次处理请求时都会调用该方法。
  • void destroy():Tomcat 销毁 Servlet 实例前会先调用该方法。
  • ServletConfig getServletConfig():返回 ServletConfig 对象,通常在 init() 方法中保存参数并在此返回。
  • String getServletInfo():返回一个说明当前 Servlet 的字符串,基本无用。
3.1.3 创建 Servlet

init 初始化

当Tomcat创建Servlet实例后,马上调用init()方法。这个方法只在创建后调用一次!用来做Servlet初始化工作!一个Servlet实例只被创建一次,所以init()方法也只被调用一次!

getServletConfig

  • 这个方法返回ServletConfig对象,但我们不能自己去创建ServletConfig对象,所以一般我们会在init()方法中把init()方法的参数保存起来,然后再在本方法中返回它。ServletConfig对象对应web.xml中当前Servlet实例的配置信息。

 service 

  • void service(ServletRequest request, ServletResponse response):Servlet实例在每次处理请求时都调用service()方法。

destory

  • void destroy()当Tomcat要销毁Servlet实例时,会先调用destroy()方法,再销毁它。所谓销毁Servlet,其实就是在Servlet缓存池中把Servlet移除!一般只有Tomcat关闭时,才会销毁Servlet实例!

getServletInfo

  • String getServletInfo():这个方法只是返回一个字符串,用来说明当前Servlet。基本没用!

同时,需要在 web.xml 文件中配置 Servlet 的访问路径:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>cn.tx.servlet.Servlet1</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>
3.1.4 JavaWeb 请求响应流程

当 Tomcat 接收到请求(如 http://localhost:8080/servlet_pro/logon)后,会按以下步骤处理:

  1. 找到 servlet_pro 项目中的 web.xml 文件。
  2. 通过请求路径查找处理该请求的 Servlet 类型。
  3. 根据匹配的 url-pattern 找到对应的 servlet-name
  4. 再通过 servlet-name 找到 servlet-class
  5. Tomcat 检查内存中是否存在该 Servlet 对象,若存在则直接调用其 service() 方法;若不存在则通过反射创建实例并调用 service() 方法。

 

3.2 Servlet 生命周期

javax.servlet.Servlet 接口中的三个方法说明了 Servlet 的生命周期:

  • void init(ServletConfig):创建后马上调用进行初始化。
  • void service(ServletRequest,ServletResponse):每次处理请求时调用。
  • void destroy():销毁 Servlet 实例前调用。

默认情况下,Servlet 对象的实例在浏览器第一次调用时被创建,也可以通过配置修改创建时机。需要注意的是,只有这三个方法是生命周期方法,由 Tomcat 在不同时间点调用,其他自定义方法不会被 Tomcat 调用,但可以在生命周期方法中调用。

四、HttpServlet

4.1 HttpServlet 介绍

由于现在的请求大多基于 HTTP 协议,因此我们可以专门为 HTTP 请求编写一个通用的父类 HttpServletHttpServlet 是 GenericServlet 的子类,而 GenericServlet 又是 Servlet 接口的子类。

4.2 Http 请求方法

HTTP 请求方法除了常见的 GET 和 POST 外,还有 PUT、DELETE、CONNECT 等,但大部分使用场景较少。

  • GET:通过请求 URI 得到资源。
  • POST:用于添加新的内容。
  • PUT:用于修改某个内容。
  • DELETE:删除某个内容。
  • CONNECT:用于代理进行传输,如使用 SSL。
  • OPTIONS:询问可以执行哪些方法。
  • PATCH:部分文档更改。
  • TRACE:用于远程诊断服务器。
  • HEAD:类似于 GET,但不返回 body 信息,用于检查对象是否存在及获取元数据。

4.3 创建 HttpServlet

4.3.1 第一种方法

创建一个类继承 HttpServlet,并在 web.xml 中配置映射路径:

 

4.3.2 第二种方法

在 IDEA 中可以直接创建 Servlet,创建完成后自行填写映射路径。这种也是注释方法。直接在参数添加路径

4.3.3 Servlet 创建顺序

有些 Servlet 需要在 Tomcat 启动时就被创建,可以在 web.xml 文件的 <servlet> 元素中添加 <load-on-startup> 元素:

<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>cn.tx.servlet.Servlet1</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

当 <load-on-startup> 的值为 0 或者大于 0 时,表示容器在应用启动时就加载这个 Servlet,并且该值是一个序号,Tomcat 会按此顺序创建 Servlet 实例。

重写init方法

五、ServletConfig

ServletConfig 对象对应 web.xml 文件中的 <servlet> 元素。我们不能自己创建 ServletConfig 对象,它会作为 init() 方法的参数由 Tomcat 传递。可以通过它获取当前 Servlet 在 web.xml 文件中的配置信息,例如配置名、初始化参数等。

<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>cn.tx.servlet.Servlet1</servlet-class>
    <init-param>
        <param-name>username</param-name>
        <param-value>123456</param-value>
    </init-param>
    <init-param>
        <param-name>password</param-name>
        <param-value>abcd</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
public class Servlet1 implements Servlet {
    private ServletConfig servletConfig;

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        this.servletConfig = servletConfig;
        String username = servletConfig.getInitParameter("username");
        System.out.println("username:" + username);

        Enumeration<String> parameterNames = servletConfig.getInitParameterNames();
        while (parameterNames.hasMoreElements()) {
            String element = parameterNames.nextElement();
            System.out.println(element + ":" + servletConfig.getInitParameter(element));
        }
    }

    // 其他方法...
}

 打印输出

六、Servlet 路径映射

6.1 Url-Pattern 的配置类型

  • 完全路径匹配:以 / 开头,如 /aaa/aaa/bbb
  • 目录匹配:以 / 开头,如 /aaa/*/*
  • 扩展名匹配:不能以 / 开头,如 *.do*.action

6.2 优先级

完全路径匹配 > 目录匹配 > 扩展名匹配。需要注意避免出现 /* .do 这样的错误配置。

6.3 示例分析

假设有以下映射关系:

  • Servlet11 映射到 /abc/*
  • Servlet22 映射到 /*
  • Servlet33 映射到 /abc
  • Servlet44 映射到 *.do

对于不同的 URL 请求,Servlet 引擎的响应规则如下:

URL 为 /abc/a.html 时,/abc/* 和 /* 都匹配,由于 /abc/* 限定范围更精确,所以调用 Servlet11 响应。

  • URL 为 /abc 时,/abc/* 和 /abc 都匹配,调用 Servlet33 响应。
  • URL 为 /abc/a.do 时,/abc/* 和 *.do 都匹配,调用 Servlet11 响应。
  • URL 为 /a.do 时,/* 和 *.do 都匹配,调用 Servlet22 响应。
  • URL 为 /xxx/yyy/a.do 时,/* 和 *.do 都匹配,调用 Servlet22 响应。

七、相对路径和绝对路径

7.1 相对路径

相对路径根据当前资源路径与目标资源路径的相对位置关系,通过 .(当前目录)和 ..(上一级目录)访问目标资源。其编写规则会根据当前路径不同而变化。

7.2 绝对路径

绝对路径是指目录下的绝对位置,直接到达目标位置。包括带有协议的完整路径(如 http://localhost/day5/hello)和以 / 开始的路径(如 /day5/hello)。需要注意服务器端和客户端对于 / 的区别,客户端访问路径和服务器内部路径有所不同。

八、ServletContext

8.1 ServletContext 介绍

ServletContext 是一个全局的储存信息的空间,服务器启动时创建,关闭时释放。所有用户共用一个 ServletContext 对象,因此可以在其中存放所有用户需要共享的、线程安全的重要信息。

8.2 ServletContext API

  • Object getAttribute(String name):返回指定名称的属性值,若不存在则返回 null
  • String getContextPath():返回 Web 应用的上下文路径。
  • String getInitParameter(String name):返回指定名称的上下文初始化参数值,若不存在则返回 null
  • String getRealPath(String path):返回给定虚拟路径的真实路径。
  • void setAttribute(String name, Object object):将对象绑定到指定名称的属性上。
  • InputStream getResourceAsStream(String path):返回指定路径的资源作为输入流。

8.3 ServletContext 使用

8.3.1 常规应用
  • 获取 WEB 应用的全局初始化参数
<context-param>
    <param-name>company</param-name>
    <param-value>bbbb</param-value>
</context-param>

init 加入以下内容 

ServletContext servletContext = config.getServletContext();
String company = servletContext.getInitParameter("company");
System.out.println("company:" + company);

 

  • 通过 ServletContext 对象实现数据共享:统计站点访问次数
  • package com.qcby.servlet;
    
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Enumeration;
    
    public class Login1Servlet extends HttpServlet{
        private String username;
        private String password;
        private ServletConfig servletConfig;
        private String company;
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {
            super.init(servletConfig);
            ServletContext servletContext = servletConfig.getServletContext();
            company = servletContext.getInitParameter("company");
            System.out.println("company:" + company);
            this.servletConfig = servletConfig;
            String username = servletConfig.getInitParameter("username");
            System.out.println("username:" + username);
    
            Enumeration<String> parameterNames = servletConfig.getInitParameterNames();
            while (parameterNames.hasMoreElements()) {
                String element = parameterNames.nextElement();
                System.out.println(element + ":" + servletConfig.getInitParameter(element));
            }
            System.out.println("login1init");
        }
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            ServletContext servletContext = getServletContext();
            Integer visitNums = (Integer) (servletContext.getAttribute("visitNums"));
            visitNums = visitNums == null ? 0 : visitNums;
            servletContext.setAttribute("visitNums", ++visitNums);
            req.setCharacterEncoding("UTF-8");
            resp.getWriter().write("当前网站访问人次:" + visitNums);
            System.out.println("当前网站访问人次: " + visitNums);
        }
    }
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Login Form</title>
    </head>
    <body>
    <form action="login1" method="post">
        <input type="submit" value="发送 POST 请求">
    </form>
    </body>
    </html>

相关文章:

  • vue3学习1
  • Spring Boot 应用(官网文档解读)
  • 新能源汽车核心元件揭秘:二极管、三极管结构与工作原理解析(2/2)
  • 算法基础(思想)
  • OSPF | 理论 / 实验
  • 技术成长战略是什么?
  • Windows 主机与安卓设备网线直连配置教程
  • spark
  • RNN中远距离时间步梯度消失问题及解决办法
  • git使用-克隆远程项目、分支管理
  • I2C实践开发 ---【STM32-I2C-HDC1080温湿度采集系统】
  • 期权帮|股指期货中的套期保值如何操作?
  • Redis三剑客解决方案
  • 模板方法模式原理结构以及在Spring源码中的使用。
  • 前端接收后端19位数字参数,精度丢失的问题
  • 二叉树层序遍历的三种情况(总结)
  • ResponseUtil.out 方法分析
  • Golang连接使用SqlCipher
  • android studio 界面启动模拟器无反应——从命令行启动模拟器
  • 一分钟学会JavaScript 变量
  • 商务部回应稀土出口管制问题
  • 长三角首次,在铁三赛事中感受竞技与生态的共鸣
  • 澎湃·镜相第二届非虚构写作大赛初选入围名单公示
  • 沪喀同心|为新疆青少年提供科普大餐,“小小博物家(喀什版)”启动
  • A股午后拉升,沪指收复3400点:大金融发力,两市成交超1.3万亿元
  • 京东一季度净利增长五成,营收增速创近三年新高,称外卖业务取得显著进展