带你吃透Servlet核心编程上篇(完整图文教程)

发布于:2022-10-13 ⋅ 阅读:(479) ⋅ 点赞:(0)

在这里插入图片描述
本文被 系统学习JavaWeb 收录点击订阅专栏



1 走进Servlet

1.1 Servlet简介

Servlet是什么?

  • Servlet是JavaEE规范之一,规范就是接口
  • Servlet是JavaWeb的三大组件之一,三大组件分别是:Servlet程序、Filter过滤器、Listener监听器
  • Servlet是运行在服务器上的一个java小程序,可以接收客户端发来的请求,并响应数据给客户端

如何实现Servlet程序呢?

  1. 编写一个类去实现Servlet接口
  2. 实现service方法,处理请求,并响应数据
  3. 到web.xml中配置servlet程序的访问地址

1.2 第一个Servlet程序

下面来完成一个简单的Servlet程序,当访问到则在控制台打印提示信息
HelloServlet.java:

import javax.servlet.*;
import java.io.IOException;

/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class HelloServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
     * service方法是专门用来处理请求和响应的
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Hello Servlet 被访问了");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

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">
    <!--servlet标签给Tomcat配置Servlet程序-->
    <servlet>
        <!--servlet-name标签Servlet程序起别名 一般是类名-->
        <servlet-name>HelloServlet</servlet-name>
        <!--servlet-class是Servlet程序的全类名-->
        <servlet-class>com.example.servlet_test.HelloServlet</servlet-class>
    </servlet>
    <!--servlet-mapping标签给servlet程序配置访问地址-->
    <servlet-mapping>
        <!--servlet_name告诉服务器,当前配置的地址给哪个servlet程序使用-->
        <servlet-name>HelloServlet</servlet-name>
        <!--url-pattern标签配置访问地址     <br/>
            /   斜杠表示在服务器解析的时候,地址为:http://ip:port/工程路径   <br/>
            /hello  表示地址为:http://ip:port/工程路径/hello <br/>
        -->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

配置完成后,可以通过 http://ip:port/工程路径/hello 访问,成功访问后,控制台打印了如下信息:
在这里插入图片描述

1.3 Servlet程序如何定位到url地址

以上面的案例:http://localhost:8080/工程路径/hello为例:
在这里插入图片描述
  先通过ip定位定位到了服务器,而后通过服务器端口找到Tomcat,再通过工程路径确认访问的工程,而后由资源路径访问到 web.xml 配置文件 中的 url,后确认了访问的HelloServlet类。

1.4 Servlet的生命周期方法

Servlet程序的生命周期方法调用顺序如下:

  1. 执行Servlet构造器方法;
  2. 执行init初始化方法;
  3. 执行service方法;
  4. 执行destroy销毁方法。

其中第一、二步,是在第一次访问的时候创建Servlet程序会调用。第三步每次访问都会调用。第四步只有在web工程停止的时候调用。

案例如下:
修改HelloServlet.java如下

import javax.servlet.*;
import java.io.IOException;

/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class HelloServlet implements Servlet {
    public HelloServlet(){
        System.out.println("构造方法被调用");
    }
    
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("init方法被调用");
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
     * service方法是专门用来处理请求和响应的
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("service方法被调用");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {
        System.out.println("destroy方法被调用");
    }
}

当运行程序后,进行一次刷新页面后退出程序时,控制台打印信息如下:
在这里插入图片描述

补充

除了生命周期方法外,Servlet接口还提供了 getServletConfig 方法和 getServletInfo 方法,servlet可使用前一种方法获取任何启动信息,而后一种方法允许 servlet 返回有关其自身的基本信息,比如:作者、版权、版本等。

1.5 Servlet请求的分发处理

表单的提交方式分为POST和GET两种请求方式,但是service方法只有一个,如何实现分发处理呢?
首先在webapp文件夹下创建一个页面,以get方式提交表单给资源文件hello:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="http://localhost:8080/Servlet_Test/hello" method="get">
    <input type="submit"/>
</form>
</body>
</html>

HelloServlet中的service方法修改如下:

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        //向下转型
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String method = httpServletRequest.getMethod();
        //请求分发处理
        String post = "POST";
        String get = "GET";
        if(post.equals(method)){
            System.out.println("POST方式");
        }else if (get.equals(method)){
            System.out.println("GET方式");
        }
    }

getMethod方法可以返回一个String值,用于判断是POST请求还是GET请求,运行结果如下:
在这里插入图片描述
该例子中,简单介绍了如何判断请求方式,并打印。实际中,如果分发处理的代码都写在service方法中,会显得过于臃肿。
因此,在实际开发中,分发处理的具体操作会单独写成方法,供service调用。例如:doGet()、doPost()方法。

1.6 通过继承HttpServlet类实现Servlet程序

在实际开发中,我们很少通过实现Servlet方法的方式去实现Servlet程序,更多的是采用继承子类的方式来实现。大致步骤如下:

  1. 编写一个类去继承 HttpServlet 类;
  2. 根据业务需要重写 doGet 和 doPost 方法(分发处理的具体方法);
  3. 到web.xml中配置Servlet程序的访问地址。

需要注意的是,在HttpServlet类中,已经帮我们分发处理完毕了

案例代码如下:

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 * 通过继承的方式实现Servlet
 */
public class HelloServlet2 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("do Get具体操作");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("do Post具体操作");
    }
}

除了自己重写以外,在实际开发中有一种更加便捷的方式:
使用IDEA菜单生成Servlet程序
在这里插入图片描述
创建的时候可以选择取消注解,会自动配置xml文件,只需要手动添加mapping即可:
在这里插入图片描述


2 Servlet体系

2.1 Servlet继承体系

在这里插入图片描述

  • Servlet接口: 负责定义Servlet程序的访问规范;
  • GenericServlet类: 实现了Servlet接口,做了很多空实现。持有一个ServletConfig类的空引用,并对ServletConfig的使用做了些方法;
  • HttpService抽象类: 实现了service方法,并实现了请求的分发处理。GET和POST请求的方式分别对应doGet与doPost方法。
  • 自定Servlet程序: 根据自己的需要去重写doGet与doPost方法即可。

2.2 ServletConfig类的使用

ServletConfig类是Servlet程序的信息类。
Servlet程序和ServletConfig对象都是由Tomcat负责创建,我们只负责使用。
Servlet程序默认第一次访问的时候创建,ServletConfig是每个Servlet程序创建时,就创建一个对应的ServletConfig对象。

ServletConfig的作用简介:

  1. 可以获取Servlet程序的别名servlet-name的值;
  2. 获取初始化参数init-param的值;
  3. 获取ServletContext对象。

下面通过案例来展示基本使用:
修改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">
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.example.servlet_test.HelloServlet</servlet-class>
        <!--配置初始化参数-->
        <init-param>
            <param-name>url</param-name>
            <param-value>jdbc:mysql://localhost:3306/test</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

HelloServlet.java中的init方法:

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("init方法被调用");
        //1.获取Servlet程序的别名 servlet-name 的值
        String servletName = servletConfig.getServletName();
        System.out.println("servlet-name: " + servletName);

        //2.获取初始化参数init-param的值
        String url = servletConfig.getInitParameter("url");
        System.out.println("url的值: " + url);
    }

在这里插入图片描述

2.3 ServletContext类的使用

  • ServletContext是一个接口,表示Servlet上下文。
  • 一个web工程只有一个ServletContext对象实例。
  • ServletContext对象是一个 域对象。

什么是域对象?

域对象是可以像Map一样存取数据的对象。域是指存取数据的操作范围。

Map与域对象横向比较

种类 存数据 取数据 删除数据
Map put() get() remove()
域对象 setAttribute() getAttribute() removeAttribute()

ServletContext的作用

  1. 获取 web.xml 中配置的上下文参数 context-param
  2. 获取当前的工程路径,格式:/工程路径
  3. 获取工程部署后在服务器硬盘上的绝对路径
  4. 像Map一样存取数据

演示案例新建一个ContextServlet类,配置文件如下:

<?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">
    <!--context属于整个web工程-->
    <context-param>
        <param-name>username</param-name>
        <param-value>黄小黄</param-value>
    </context-param>

    <servlet>
        <servlet-name>ContextServlet</servlet-name>
        <servlet-class>com.example.servlet_test.ContextServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ContextServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

ContextServlet.java

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class ContextServlet extends HttpServlet {
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        super.service(req, res);
        //获取context上下文参数
        ServletContext context = getServletConfig().getServletContext();
        String username = context.getInitParameter("username");
        System.out.println("context参数username= " + username);
        //获取当前的工程路径
        System.out.println("当前工程路径= " + context.getContextPath());
        //获取工程部署后在服务器上的绝对路径
        /*
         *  / 被服务器解析地址:http://ip:port/工程名/
         */
        System.out.println("工程部署路径= " + context.getRealPath("/"));
    }
}

在这里插入图片描述