带你着手「Servlet」

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 有了前边文章为我们奠定下的网络基础,我们就可以开始学习Servlet的知识了,在部署一个Java的Servlet程序时,必须要有的开发工具是Tomcat,需要自行完成Tomcat的配置,并掌握maven仓库的配置方法,下边我们也会进行演示,这些具体的流程该如何来进行。

1.第一个Servlet程序


我们首先通过idea来完成一个最简单的Servlet程序,共需要以下七步来完成,在该部分最后也会介绍较为简单的插件配置方法。


1.1 操作流程


第一步:

创建一个maven项目。


1)新建项目


微信图片_20230111164352.png

2)选择maven项目


微信图片_20230111164348.png

3)编辑信息

微信图片_20230111164344.png

第二步:

引入依赖


1)在maven中央仓库找到Servlet的依赖


微信图片_20230111164341.png

2)找到3.1版本,复制maven依赖


微信图片_20230111164338.png

微信图片_20230111164332.png

3)将依赖引入pom.xml文件中

微信图片_20230111164328.png

第三步:

创建目录结构


1)在main目录创建webapp目录


微信图片_20230111164324.png

2)在webapp目录创建WEB-INF目录


微信图片_20230111164321.png

3)在WEB-INF目录新建web.xml文件


微信图片_20230111164316.png

4)在web.xml文件中写入下面的代码段:


<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>

微信图片_20230111164312.png

第四步:

编写Servlet代码


在main-java目录下新建类,开始编写servlet代码


微信图片_20230111164309.png

继承HttpServlet类

重写doGet方法

在方法里写执行的代码

加上WebServlet注解+路径,将该类与http请求中的URL关联起来


微信图片_20230111164305.png

第五步:

打包


当前的代码是不能单独运行的(没有main方法),需要把当前的代码打包,然后部署到Tomcat上,由Tomcat来进行调用。


1)先进行准备工作,修改pom.xml


微信图片_20230111164301.png

2)双击package,进行打包


微信图片_20230111164258.png

打包完成


微信图片_20230111164254.png

第六步:

部署


1)打开war包所在路径


微信图片_20230111164247.png

2)把war包拷贝到tomcat的webapps目录里


微信图片_20230111164243.png

微信图片_20230111164238.png


3)启动tomcat


微信图片_20230111164235.png

微信图片_20230111164231.png



第七步:

验证程序


在网页访问路径127.0.0.1:8080/hello/test


微信图片_20230111164226.png

此处的路径共有三部分组成


微信图片_20230111164222.png

1.2 插件简化


在我们每次修改Servlet类代码后,都需要重复进行1.1中5-6步操作,较为繁琐,可以利用idea中内嵌的smart tomcat插件来简化开发流程。


微信图片_20230111164218.png

完成上图插件的安装后,按下图流程操作。


微信图片_20230111164214.png

注意,利用插件时,五六步操作完全不再需要手动进行了,不需要再进行第五步的准备工作——在pom.xml文件中加代码,直接在下图中定义Context Path即可。


微信图片_20230111164210.png

点击小三角一次性完成打包、部署工作:


微信图片_20230111164204.png

2.常见的访问出错


初学Servlet,肯定会遇到很多的问题,我们不仅要学习Servlet代码的基本写法,还需要认识常见的错误,在出现错误时能够解决。


2.1 出现404


404表示用户访问的资源不存在,大概率是URL路径写的不正确。


微信图片_20230111164159.png

还有可能是因为web.xml文件写错了,需要写正确web.xml中内容,并重新启动tomact


web.xml文件代码片段:


<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>


2.2 出现405


405表示对应的HTTP请求方法没有实现

微信图片_20230111164154.png

在地址栏输入URL路径进行访问,浏览器默认构造的是GET请求,如果在服务器中的代码没有实现doGet方法,就会报这个错误。


微信图片_20230111164151.png

在什么时候浏览器发的是GET请求呢?

1.直接在地址栏里输入URL

2.通过a标签跳转

3.通过img/link/script...

4.通过form表单,method指定为GET

5.通过ajax,type指定为GET


那在什么时候浏览器发的是POST请求呢?

1.通过form表单,method指定为POST

2.通过ajax,type指定为POST


2.3 出现500


500意味着服务器代码抛出异常了,并且代码没有处理异常,异常向上传递到了Tomcat这里了。


微信图片_20230111164147.png

微信图片_20230111164144.png

这种错误是最好解决的,因为异常的调用栈,会直接打印在页面上,可以直接找到问题的所在。


2.4 出现空白页面


没有resp.getWritter().write() 操作。


微信图片_20230111164141.png

2.5 出现“无法访问此网站”


最大可能性是因为Tomcat没有正确启动(比如Tomcat的8080端口被占用,启动失败)


微信图片_20230111164137.png

3.Servlet运行原理


3.1 Servlet运行原理


Servlet是位于应用层的上层建筑,下面的传输层、网络层、和数据链路层属于经济基础,经济基础决定上层建筑。


Tomcat其实就是一个运行在用户态的应用程序(普通的Java进程)。

微信图片_20230111164134.png

当用户操作浏览器,发送请求给服务器的时候,Tomcat作为HTTP Servlet会调用Servlet API,然后执行我们所写的Servlet程序来处理请求。


微信图片_20230111164130.png

更详细的交互过程见下图:


微信图片_20230111164125.png

用户浏览器发出请求后,客户端主机会将请求数据包一层层封装,最后到物理层转换成光电信号传输给服务器;到达服务器后再将数据包进行一层层分用,最后到服务器的应用层处理请求并计算响应。


3.2 Tomcat的执行逻辑


我们通过用伪代码的方式来演示Tomcat在Servlet程序运行中起到的作用。


1)Tomcat初始化流程


class Tomcat {
    // 用来存储所有的 Servlet 对象
    private List<Servlet> instanceList = new ArrayList<>();
    public void start() {
        // 根据约定,读取 WEB-INF/web.xml 配置文件;
        // 并解析被 @WebServlet 注解修饰的类
        // 假定这个数组里就包含了我们解析到的所有被 @WebServlet 注解修饰的类. 
        Class<Servlet>[] allServletClasses = ...;
        // 这里要做的的是实例化出所有的 Servlet 对象出来;
        for (Class<Servlet> cls : allServletClasses) {
            // 这里是利用 java 中的反射特性做的
            // 实际上还得涉及一个类的加载问题,因为我们的类字节码文件,是按照约定的
            // 方式(全部在 WEB-INF/classes 文件夹下)存放的,所以 tomcat 内部是
            // 实现了一个自定义的类加载器(ClassLoader)用来负责这部分工作。
            Servlet ins = cls.newInstance();
            instanceList.add(ins);
        }
        // 调用每个 Servlet 对象的 init() 方法,这个方法在对象的生命中只会被调用这一次;
        for (Servlet ins : instanceList) {
            ins.init();
        }
        // 利用我们之前学过的知识,启动一个 HTTP 服务器
        // 并用线程池的方式分别处理每一个 Request
        ServerSocket serverSocket = new ServerSocket(8080);
        // 实际上 tomcat 不是用的固定线程池,这里只是为了说明情况
        ExecuteService pool = Executors.newFixedThreadPool(100);
        while (true) {
            Socket socket = ServerSocket.accept();
            // 每个请求都是用一个线程独立支持,这里体现了我们 Servlet 是运行在多线程环境下的
            pool.execute(new Runnable() {
                doHttpRequest(socket);//处理请求
            });
        }
        // 调用每个 Servlet 对象的 destroy() 方法,这个方法在对象的生命中只会被调用这一次;
        for (Servlet ins : instanceList) {
            ins.destroy();
        }
    }
    public static void main(String[] args) {
        new Tomcat().start();
    }
}


小结:


Tomcat的代码中内置了main方法。当我们启动Tomcat的时候,就是从Tomcat的main方法开始执行的。

被@WebServlet注解修饰的类会在Tomcat启动的时候被获取到,并集中管理。

Tomcat通过反射机制来创建被@WebServlet注解修饰的类的实例。

这些实例被创建完了之后,会调用其中的init方法进行初始化(该方法是HttpServlet自带的,我们自己写的类可以重写init)

这些实例被销毁之前,会调用其中的destory方法进行收尾工作(只有正常退出Tomcat才会触发该方法,而通过直接杀死进程的方法是来不及调用该方法的)

Tomcat内部也是通过Socket API进行网络通信

Tomcat为了能同时响应多个HTTP请求,采取了多线程的方式实现。因此Servlet是运行在多线程环境下的


2)Tomcat处理请求流程


class Tomcat {
    void doHttpRequest(Socket socket) {
        // 参照我们之前学习的 HTTP 服务器类似的原理,进行 HTTP 协议的请求解析,和响应构建
        HttpServletRequest req = HttpServletRequest.parse(socket);
        HttpServletRequest resp = HttpServletRequest.build(socket);
        // 判断 URL 对应的文件是否可以直接在我们的根路径上找到对应的文件,如果找到,就是静态
        // 直接使用我们学习过的 IO 进行内容输出
        if (file.exists()) {
            // 返回静态内容
            return;
       }
        // 走到这里的逻辑都是动态内容了
        // 根据我们在配置中说的,按照 URL -> servlet-name -> Servlet 对象的链条
        // 最终找到要处理本次请求的 Servlet 对象
        Servlet ins = findInstance(req.getURL());
        // 调用 Servlet 对象的 service 方法
        // 这里就会最终调用到我们自己写的 HttpServlet 的子类里的方法了
        try {
          ins.service(req, resp); 
       } catch (Exception e) {
            // 返回 500 页面,表示服务器内部错误
       }
   }
}


小结:


Tomcat从Socket中读取到HTTP请求,然后按照HTTP协议的格式解析成一个HttpServletRequest对象。

Tomcat会根据URL中的path判定这个请求是请求一个静态资源还是动态资源;如果是静态资源,直接找到对应的文件把文件的内容通过Socket返回;如果是动态资源,才会执行到Servlet的相关逻辑。

Tomcat会根据URL中的Context Path和Servlet Path确定要调用哪个Servlet实例的service方法(如果没有找到匹配的Servlet类,就会返回404)

通过service方法,就会进一步调用到我们之前写的doGet或者doPost

3)Servlet的service方法的实现


class Servlet {
    public void service(HttpServletRequest req, HttpServletResponse resp) {
        String method = req.getMethod();
        if (method.equals("GET")) {
            doGet(req, resp);
       } else if (method.equals("POST")) {
            doPost(req, resp);
       } else if (method.equals("PUT")) {
            doPut(req, resp);
       } else if (method.equals("DELETE")) {
            doDelete(req, resp);
       } 
       ......
   }
}


小结:


Servlet的service方法内部会根据当前请求的方法,决定调用其中的某个doXXX方法。


在整个流程中,有三个关键的方法:


init方法:在初始化阶段执行,用来初始化每一个Servlet对象,对象创建好之后就会执行到。用户可以重写这个方法,来执行一些初始化逻辑。

service方法:在处理请求阶段来调用,每个请求都要调用一次service

destory方法:退出主循环,tomcat结束之前会调用,用来释放资源。


相关文章
|
11月前
|
小程序 Java 应用服务中间件
【JavaWeb学习】—Servlet(十三)
【JavaWeb学习】—Servlet(十三)
|
2月前
|
Java 应用服务中间件 数据库连接
探索研究Servlet 生命周期
【9月更文挑战第22天】
44 7
|
5月前
|
缓存 小程序 前端开发
Java服务器端技术探秘:Servlet与JSP的核心原理
【6月更文挑战第23天】Java Web开发中的Servlet和JSP详解:Servlet是服务器端的Java小程序,处理HTTP请求并响应。生命周期含初始化、服务和销毁。创建Servlet示例代码展示了`doGet()`方法的覆盖。JSP则侧重视图,动态HTML生成,通过JSP脚本元素、声明和表达式嵌入Java代码。Servlet常作为控制器,JSP处理视图,遵循MVC模式。优化策略涉及缓存、分页和安全措施。这些技术是Java服务器端开发的基础。
59 9
|
设计模式 容器
JavaWeb开发 Servlet技术详解(五)
JavaWeb开发 Servlet技术详解(五)
|
存储 安全 前端开发
JavaWeb开发 Servlet技术详解(四)
JavaWeb开发 Servlet技术详解(四)
|
存储 缓存 Java
JavaWeb开发 Servlet技术详解(二)
JavaWeb开发 Servlet技术详解(二)
|
Java 应用服务中间件 Apache
|
存储 JSON 应用服务中间件
JavaWeb开发 Servlet技术详解(三)
JavaWeb开发 Servlet技术详解(三)
Servlet学习(二):详述servlet的生命周期并动手试验
Servlet学习(二):详述servlet的生命周期并动手试验
115 0
Servlet学习(二):详述servlet的生命周期并动手试验
|
Java 应用服务中间件 API
Web阶段:第十章:Servlet下
Web阶段:第十章:Servlet下
126 0
Web阶段:第十章:Servlet下