首页 > 其他分享 >Servlet 详解!

Servlet 详解!

时间:2025-01-19 11:44:03浏览次数:1  
标签:xml resp req HttpServlet 详解 子项目 Servlet

一、Servlet简介

Servlet是Sun公司开发动态Web的一门技术。Sun公司在这些API中提供了一个Servlet接口,如果你想开发一个Servlet程序只需要完成如下两个步骤:

1、编写一个Java类实现Servlet接口。

2、把开发好的Java类部署到Web服务器中。

我们把实现了Servlet接口的Java程序叫做Servlet。

注:

  • 一个Servlet就是一个实现了Servlet接口的Java类。
    
  • 一个Servlet对应一个URL。
    

二、父项目与子项目

关于父子项目的理解:

(1)父项目的pom.xml配置文件中存在……标签,记录了子项目的信息:

<modules>
    <module>servlet-01</module>
</modules>

(2)相对应的,子项目(即:Module模块)中存在……标签,记录了父项目的信息:

<parent>
    <artifactId>javaWeb-Servlet</artifactId>
    <groupId>com.atangbiji</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>

(3)父项目中的依赖包,子项目可以直接使用。(类似于Java中的继承)

这样我们把所有项目的依赖都添加到父项目的pom.xml配置文件中后,那么所有的子项目就不用每次再重复导入依赖包了。

(4)Servlet接口在子项目中实现。

三、Hello Servlet

3.1 创建父项目

(1)创建一个普通的Maven项目(具体步骤参考《Maven详解》),项目名称为javaWeb-Servlet。

(2)删除项目中的src目录,所得到的空项目就是我们的Maven父项目,我们可以在其中创建多个子项目(即:Module)。

(3)在父项目的pom.xml文件中导入父/子工程需要的依赖,根据需求查询有哪些依赖需要导入。

以Servlet项目为例,需要在父项目的pom.xml文件中导入如下依赖:

<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>
</dependencies>

注:若在父项目的pom.xml文件中已经添加了某个依赖后,则子项目的pom.xml文件中不要再重复添加该依赖了,否则Maven项目编译会出错。

至此,父项目创建完毕。

3.2 创建子项目

(1)在父项目中新建一个模块(子项目)。

(2)使用Maven模板创建一个MavenWeb子项目。

(3)填写子项目名称和Maven项目GAV。

(4)配置子项目Maven。点击Finish按钮完成子项目创建,等待Maven依赖包导入完毕。

(5)由于使用Maven模板创建的MavenWeb项目的版本较低(“web-app_2_3”)。为了避免以后出现兼容性问题,建议我们先将该子项目中的web.xml文件替换成“web-app_4_0”版本。具体可以参考Tomcat安装目录下的(D:\Environment\apache-tomcat-9.0.65\webapps\examples\WEB-INF)web.xml文件。

web.xml文件:

<?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_4_0.xsd"
         version="4.0"
         metadata-complete="true">

</web-app>

注:Web.xml是Java Web项目的一个核心配置文件,主要用于配置首页、Servlet、Filter、Listener等。

(6)在子项目的main文件夹下新建一个java文件夹和一个resource文件夹,并将它们分别标记为“源码根目录”和“资源根目录”。(具体步骤参考《Maven详解》)

(7)至此,子项目创建完毕。编译父项目或子项目,此时父项目与子项目的目录结构如下图所示。

3.3 编写一个Java类实现Servlet接口(重点)

(1)在子项目的java目录下新建一个com.atangbiji.servlet包,并在该包下新建一个HelloServlet类,用于实现Servlet接口。

(2)让HelloServlet类继承(extends)HttpServlet类。(此时,Maven会通过父项目中的依赖自动导入依赖包。)

HelloServlet.java文件:

public class HelloServlet extends HttpServlet {

}

注:

  • Servlet是一个接口程序,也就是一个java程序,其存放于main-java文件夹中。

  • 由于sun公司为我们提供了两个默认的Servlet接口实现类:①HttpServlet,②GenericServlet。因此,我们只需继承HttpServlet类便可实现Servlet接口。

附:Servlet接口、GenericServlet类和HttpServlet类详解

a、Servlet接口源码

public interface Servlet {
    void init(ServletConfig var1);
    ServletConfig getServletConfig();
    void service(ServletRequest var1, ServletResponse var2);//核心接口
    String getServletInfo();
    void destroy();
}

b、GenericServlet类源码(部分)

public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
    ……
    public abstract void service(ServletRequest var1, ServletResponse var2);//直接继承,未做任何处理
    ……
}

c、HttpServlet类源码(部分)

public abstract class HttpServlet extends GenericServlet {
    ……
    //重写service方法
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
            HttpServletRequest request = (HttpServletRequest)req;
            HttpServletResponse response = (HttpServletResponse)res;
            this.service(request, response);
        } else {
            throw new ServletException("non-HTTP request or response");
        }
    }

    //重载service方法
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        //若请求方式为get,则调用doGet方法
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader("If-Modified-Since");
                if (ifModifiedSince < lastModified) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);                //若请求方式为post,则调用doPost方法
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        ……
    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp){
        ……
    }
    ……
}

分析源码,我们可以发现:

  • 我们自定义的Servlet类与Servlet接口、GenericServlet类和HttpServlet类的关系如下图所示。

  • HttpServlet类重写的service(ServletRequest,ServletResponse)方法中会把ServletRequest和ServletResponse强转成HttpServletRequest和HttpServletResponse,然后再调用service(HttpServletRequest,HttpServletResponse)方法。

  • HttpServlet类重载了service(HttpServletRequest,HttpServletResponse)方法,该方法是 HttpServlet 自己重载的方法,而不是从Servlet继承来的。

【结论】:HttpServlet类在重载的service(HttpServletRequest,HttpServletResponse)方法中,会根据不同的Http请求方式,调用不同的处理方法。因此,我们需要在我们自己编写的Servlet类中重写相应的Http请求处理方法(重点掌握doGet和doPost方法)。

:我们可以通过IDEA为我们提供的Structure窗口来查看HttpServlet类的成员变量和成员函数。

(3)在HelloServlet类中重写doGet和doPost方法。

HelloServlet.java文件:

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("进入了doGet方法");//在控制台打印调试信息
        PrintWriter writer = resp.getWriter();//响应流
        writer.print("Hello Servlet!");//在浏览器显示Hello Servlet!
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);    //因为`get`和`post`只是不同的Http请求方式,所以它们之间可以相互调用。
    }
}

:因为get和post只是不同的Http请求方式,所以它们之间可以相互调用。

3.4 编写Servlet的映射(重点)

:因为我们写的是一个Java程序,但是如果我们要通过浏览器去访问它,就需要连接web服务器。因此,我们需要在Web配置文件(web.xml)中注册(映射)我们自己编写的Servlet,并为其提供一个浏览器可以访问的路径。

web.xml文件:

<?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_4_0.xsd"
         version="4.0"
         metadata-complete="true">

    <!--  注册Servlet  -->
    <servlet>
        <servlet-name>servlet1</servlet-name>
        <servlet-class>com.atangbiji.servlet.HelloServlet</servlet-class>
    </servlet>
    <!--  Servlet的访问路径  -->
    <servlet-mapping>
        <servlet-name>servlet1</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

</web-app>

3.5 配置Tomcat服务器

(1)配置Tomcat服务器。(具体步骤参考《Tomcat详解》)

(2)deploy(发布)servlet-01:war包,并为该子项目添加虚拟路径映射:/s1。

3.6 启动测试

在IDEA中启动Tomcat。

(1)在浏览器中输入http://localhost:8080/s1/,访问结果如下:

:此时访问的是该Web项目的index.jsp文件。

index.jsp文件:

<html>
<body>
<h2>Hello World!</h2>
</body>
</html>

(2)在浏览器中输入http://localhost:8080/s1/hello,访问结果如下:

:此时访问的是我们自己编写的Servlet类。

原创 阿汤笔迹

标签:xml,resp,req,HttpServlet,详解,子项目,Servlet
From: https://www.cnblogs.com/o-O-oO/p/18679395

相关文章

  • 以太网详解(五)GMII、RGMII、SGMII接口时序约束(Quartus 平台)
    文章目录接口时序AvalonStreaming接口时序ReceiveTimingTransmitTimingGMII接口时序ReceiveTimingTransmitTimingRGMII接口时序ReceiveTimingTransmitTiming如何创建.sdc约束文件三速以太网系统时钟信号创建set_input_delay,set_output_delay约束set_in......
  • 【模型】Informer模型详解
    Informer是一种针对长时间序列预测任务设计的深度学习模型,特别适用于解决序列数据的高效建模与预测问题。Informer提出了许多创新的机制,尤其是在计算效率方面,能够显著提高长时间序列预测的准确性和速度。以下是对该模型的详细介绍。1.模型架构Informer的核心思想是通......
  • Linux中常用命令详解
        在Linux中,有很多常用命令可以帮助你完成日常操作。以下是一些常用Linux命令的详细介绍:1.ls-列出目录内容语法:ls[选项][目录]常用选项:-l:显示详细信息(权限、文件大小、修改时间等)-a:显示所有文件,包括隐藏文件(以.开头)-h:以可读的方式显示文件......
  • 电子工程师入门-03三极管详解(上)
    以下内容均作为个人学习时遇到问题的学习历程,记在这里也是希望自己能常回顾。另外,文章出现的图片有些是个人手绘不太标准。前言:三极管是流控型器件。一,三极管初识晶体三极管中有两种带有不同极性电荷的载流子参与导电,因此称之为双极性晶体管(BJT),又称半导体三极管。根据不同......
  • objectMapper详解
    objectMapper详解1、主要功能ObjectMapper是Jackson库中的核心类,用于在Java对象和JSON数据之间进行序列化(将Java对象转换为JSON)和反序列化(将JSON转换为Java对象)。ObjectMapper提供了丰富的配置选项和功能,可以帮助开发者处理复杂的JSON数据结构。序列化:......
  • Profibus DP转Modbus TCP协议转换网关模块功能详解
    ProfibusDP和ModbusTCP是两种不同的工业现场总线协议,ProfibusDP常用于制造业自动化领域,而ModbusTCP则在工业自动化和楼宇自动化等领域广泛应用。实现ProfibusDP转ModbusTCP功能,通常需要特定的网关设备,以下为你详细介绍:捷米JM-DPM-TCP网关模块这......
  • ES6新特性详解:var、let、const的区别
    ECMAScript6(简称ES6)是JavaScript语言的一次重大更新,它引入了许多新特性,使得JavaScript编程更加简洁、高效。在ES6中,对变量声明的方式进行了扩展,新增了let和const关键字,与原有的var关键字一起,为开发者提供了更多选择。本文将详细介绍var、let、const三者之间的区别。一、变量......
  • CSS 选择器优先级与继承规则详解
    CSS选择器优先级与继承规则详解在编写CSS时,理解选择器的优先级和继承规则是至关重要的。它们决定了样式如何应用到HTML元素上,尤其是在多个样式规则冲突时。本文将详细介绍CSS选择器的优先级和继承规则,帮助你更好地掌握样式的应用机制。CSS选择器优先级CSS选择器的优......
  • 详解Rust 中 String 和 str 的用途与区别
    文章目录1.基本定义1.1String1.2str2.存储位置与内存模型2.1String2.2str3.用法与区别4.使用场景4.1使用String的场景4.2使用str的场景5.String和str的关系6.代码示例分析6.1从&str创建String6.2从String获取&str6.3拼接字符串6.4静态......
  • 求 n 个数的最小公倍数(详解版)
    你的好朋友小明最近在学习最小公倍数的知识,他妈妈给他出了100题,每一题都有n(2≤n≤20)个数,要小明求出这n个数的最小公倍数。小明现在想快点出去玩,于是想到会编程的你,能否设计一个程序,让他输入题目n个数就可以得到答案?快来帮帮小明吧!输入格式第一行一个整数n (2≤n≤20)。......