都2023年了,Servlet还有必要学习吗?一文带你快速了解Servlet(二)

简介: 都2023年了,Servlet还有必要学习吗?一文带你快速了解Servlet(二)

6. 方法初识


Servlet 是一个接口,其中一共有 5 个方法,当我们的类实现了这个接口以后,必须将这 5 个方法全部实现。这 5 个方法分别是:

  • 初始化方法:void init()
  • 提供服务方法:void service()
  • 销毁方法:void destroy()
  • 获取Servlet信息方法:String getServletInfo()
  • 获取ServletConfig对象方法:servletConfig getServletConfig()


其中,前三个方法我们在之前的生命周期中已经接触过了,在 Servlet 被创建时,会执行 init() 方法进行初始化操作,此方法只会执行一次,每次 Servlet 被访问时都会执行 service() 方法,而 Servlet 被销毁时,则会执行 destroy() 方法,释放对象。

我们看到在进行初始化操作时,会往 init() 方法中传入 ServletConfig 类对象,如下:

@Override
public void init(ServletConfig servletConfig) throws ServletException {
//...
    }


所以在 getServletConfig() 方法中,我们只需要将容器创建的 ServletConfig 对象返回即可,而在 getServletInfo() 方法中先返回一个空字符串处理,如下:

private ServletConfig servletConfig;
public void init(ServletConfig config) throws ServletException {
    this.servletConfig = config;
    System.out.println("init...");
}
public ServletConfig getServletConfig() {
    return servletConfig;
}
public String getServletInfo() {
     return "";
     }


其中最常用的是前面三个方法,这里我们都是只做了解,后面等对整个 Servlet 体系有了认知以后,再深入学习。

小tips:这也是我们学习编程一个很重要的方法论,先广度后深度,前期不用深入的了解其底层的含义,否则容易导致我们钻牛角尖,得不偿失。

7. 体系结构


在我们编写的实现 Servlet 接口的类中,我们更加关注的是 service() 方法,有没有一种方式让我们创建 Servlet 更加简便高效呢?学习完 Servlet 的体系结构之后,这个问题就变得简单了。

我们开发 B / S 架构的 Web 项目时,其实都要对 HTTP 协议进行封装,所以我们自定义的 Servlet 要继承 HttpServlet ,Servlet 的体系结构如下:

3.5.png

我们想要实现的是,在客户端发送 GET 请求给 Servlet 后,执行一种逻辑,当客户端发送 POST 请求给 Servlet 后执行另外一种逻辑…

在 HttpServlet 类中就实现了这样的功能,HttpServlet 类会判断页面发送的请求方式,根据不同的请求方式定义了不同的执行方法,例如 doGet,doPOST 等,

例如下面是部分HttpServlet类的源码:

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        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);
        } 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);
        }
    }

我们自己定义的实现类只需要继承自 HttpServlet 类,并且重写 HttpServlet 类中的 doGet 这样的方法,以此来实现不同的处理逻辑。例如:

@WebServlet("/demo")
public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //TODO GET 请求方式处理逻辑
        System.out.println("get...");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //TODO Post 请求方式处理逻辑
        System.out.println("post...");
    }
}


8. urlPattern 配置


Servlet 编写好以后,要想被浏览器访问,就需要配置其访问路径,例如前面案例中我们就通过 Java 注解的方式,给 Servlet 配置了访问路径,如图:

3.6.png

一个 Servlet 可以配置多个访问路径,urlPattern 的配置有以下几个规则:

  • 精确匹配
  • 目录匹配
  • 扩展名匹配
  • 任意匹配


精确匹配:

当我们配置如下的访问路径:

@WebServlet("/user/demo")


此时我们在浏览器中访问时的 url 为:

3.7.png

目录匹配:

当我们配置如下的访问路径:

@WebServlet("/user/*")


此时我们在浏览器中的访问 url 为:

3.8.png3.9.png

扩展名匹配:

当我们配置如下的访问路径:

@WebServlet("*.do")


此时我们在浏览器中的访问 url 为:

3.10.png

3.11.png

任意匹配:

当我们配置如下的访问路径:

@WebServlet("/")


@WebServlet("/*")


此时我们在浏览器中的访问 url 为:

3.12.png

3.13.png

/* 和 / 的区别:当项目中的 Servlet 配置了 / ,会覆盖 tomcat 中的 DefaultServlet 默认访问路径。DefaultSerlet 是用来处理静态资源的,当其他的 urlPattern 都匹配不上时就会访问这个 Servlet,如果我们自己定义了 / 访问路径,则请求静态资源时不会生效而会匹配自己定义的路径,最终导致静态资源无法访问,所以这种方式不建议使用。

当我们的项目中配置了 /*,意味着匹配任意访问路径。

urlPattern 共有四种匹配方式,分别是精确匹配,目录匹配,扩展名匹配和任意匹配。其具有不同的优先级,具体为精确匹配 > 目录匹配 > 扩展名匹配 > 任意匹配,任意匹配中 /* 大于 / 。

9. XML配置


前面对应的 Servlet 访问路径我们都是使用 Java 注解的方式配置,其实在 Servlet 3.0 之前是只支持 XML 配置文件的方式配置 Servlet 的访问路径,这里只对其方法做了解。

使用 XML 配置方法大致分为两步,编写 Servlet 类和配置,下面通过案例的方式讲解。

第一步:编写 Servlet 类。

public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //TODO GET 请求方式处理逻辑
        System.out.println("get...");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //TODO Post 请求方式处理逻辑
        System.out.println("post...");
    }
}


第二步:在 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_4_0.xsd"
         version="4.0">
    <!-- 
        Servlet 全类名
    -->
    <servlet>
        <!-- servlet的名称,名字任意-->
        <servlet-name>demo</servlet-name>
        <!--servlet的类全名-->
        <servlet-class>org.chengzi.web.ServletDemo</servlet-class>
    </servlet>
    <!-- 
        Servlet 访问路径
    -->
    <servlet-mapping>
        <!-- servlet的名称,要和上面的名称一致-->
        <servlet-name>demo</servlet-name>
        <!-- servlet的访问路径-->
        <url-pattern>/demo</url-pattern>
    </servlet-mapping>
</web-app>


10. 总结


不得不说,Servlet 确实是一门古老的技术,现在很少有公司直接使用 Servlet 来写项目了,大家都在用 SpringMVC-Spring-MyBatis / SpringBoot 做开发了,那么 Servlet 还值得学习吗?一个中肯的建议是不要跳过 Servlet 去学习框架,学习完 Servlet ,你将有更好的基础去面对后面的框架的知识,而绝非浪费时间和精力。

本文是 Servlet 的快速入门篇,主要从执行流程,生命周期,方法的介绍,体系结构和访问路径的配置等这几个方面探讨了 Servlet 。后面我们将通过源码更加深入的学习。

目录
相关文章
|
11月前
|
小程序 Java 应用服务中间件
【JavaWeb学习】—Servlet(十三)
【JavaWeb学习】—Servlet(十三)
|
5月前
|
API
servlet研究学习总结--OutputStream和PrintWriter的区别
servlet研究学习总结--OutputStream和PrintWriter的区别
192 1
|
6月前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
|
Java 应用服务中间件 UED
都2023年了,Servlet还有必要学习吗?一文带你快速了解Servlet(一)
都2023年了,Servlet还有必要学习吗?一文带你快速了解Servlet(一)
219 0
|
XML 缓存 前端开发
Java学习之路006——Servlet开发
包括引入servlet的api库、IDEA2022配置servlet有关操作,以及servlet的xml配置与注解使用;以及简单的servlet编程实现。
165 0
Servlet学习(九):请求重定向(例如:页面搬迁后的跳转)
Servlet学习(九):请求重定向(例如:页面搬迁后的跳转)
117 0
Servlet学习(九):请求重定向(例如:页面搬迁后的跳转)
Servlet学习(八):请求转发(两个servlet程序的交互)
Servlet学习(八):请求转发(两个servlet程序的交互)
136 0
Servlet学习(八):请求转发(两个servlet程序的交互)
Servlet学习(七):获取请求的参数值(简单的前后端交互)
Servlet学习(七):获取请求的参数值(简单的前后端交互)
131 0
Servlet学习(七):获取请求的参数值(简单的前后端交互)
Servlet学习(六):ServletContext对象的作用
Servlet学习(六):ServletContext对象的作用
111 0
Servlet学习(六):ServletContext对象的作用
Servlet学习(五):ServletConfig类的作用
ServletConfig的作用: 1、可以获取Servlet程序的别名servlet-name的值 2、获取初始化参数init-param 3、获取ServletContext对象
168 0
Servlet学习(五):ServletConfig类的作用