【JavaWeb】Servlet 系列——响应 HTML 代码、Servlet 连接数据库、IDEA 开发 Servlet 程序、Servlet 对象的生命周期、Generic
10 向浏览器响应一段 HTML 代码
11 在 Servlet 中连接数据库,怎么做?
Servlet 是 Java 程序,所以在 Servlet 中完全可以编写 JDBC 代码连接数据库。
在一个 webapp 中去连接数据库,需要将驱动 jar 包放到 WEB-INF/lib 目录下。(com.mysql.cj.jdbc.Driver 这个类就在驱动 jar 包当中。)
12 在集成开发环境当中开发 Servlet 程序
12.1 集成开发工具很多,其中目前使用比较多的是:
IntelliJ IDEA(这个居多,IDEA 在提示功能方面要强于 Eclipse,也就是说 IDEA 使用起来比 Eclipse 更加智能,更好用。JetBrain 公司开发的。收费的。)
Eclipse(这个少一些),Eclipse 目前还是有团队使用,只不过处于减少的趋势,自己从事工作之后,可能会遇到。Eclipse 是 IBM 团队开发的。Eclipse 寓意是“日食”。“日食”表示将太阳吃掉。太阳是 SUN。IBM 团队开发 Eclipse 的寓意是吞并 SUN 公司,但是 2009 年的时候 SUN 公司被 Oracle 公司并购了。IBM 并没有成功并购 SUN 公司。
12.2 使用 IDEA 集成开发工具开发 Servlet
第一步:New Project(我比较习惯先创建一个 Empty Project【空工程】,然后在空工程下新建 Module【模块】,这不是必须的,只是一种习惯,你可以直接新建非空的 Project),这个 Empty Project 起名为:javaweb(不是必须的,只是一个名字而已。一般情况下新建的 Project 的名字最好和目录的名字一致。)
第二步:新建模块(File --> new --> Module...)
这里新建的是一个普通的 JavaSE 模块(这里先不要新建 Java Enterprise 模块)
这个 Module 自动会被放在 javaweb 的 project 下面。
这个 Module 起名:servlet01
第三步:让 Module 变成 JavaEE 的模块。(让 Module 变成 webapp 的模块。符合 webapp 规范。符合 Servlet 规范的 Module)
在 Module 上点击右键:Add Framework Support...(添加框架支持)
在弹出的窗口中,选择 Web Application(选择的是 webapp 的支持)
选择了这个 webapp 的支持之后,IDEA 会自动给你生成一个符合 Servlet 规范的 webpp 目录结构。
重点,需要注意的:在 IDEA 工具中根据 Web Application 模板生成的目录中有一个 web 目录,这个目录就代表 webapp 的根
第四步(非必须):根据 Web Application 生成的资源中有 index.jsp 文件,这里我选择删除这个 index.jsp 文件。
第五步:编写 Servlet(StudentServlet)
class StudentServlet implements Servlet
这个时候发现 Servlet.class 文件没有。怎么办?将 CATALINA_HOME/lib/servlet-api.jar 和 jsp-api.jar 添加到 classpath 当中(这里的 classpath 说的是 IDEA 的 classpath)
File --> Project Structrue --> Modules --> + 加号 --> Add JARS....
实现 jakarta.servlet.Servlet 接口中的 5 个方法。
第六步:在 Servlet 当中的 service 方法中编写业务代码(我们这里连接数据库了。)
第七步:在 WEB-INF 目录下新建了一个子目录:lib(这个目录名可不能随意,必须是全部小写的 lib),并且将连接数据库的驱动 jar 包放到 lib 目录下。
第八步:在 web.xml 文件中完成 StudentServlet 类的注册。(请求路径和 Servlet 之间对应起来)
第九步:给一个 html 页面,在 HTML 页面中编写一个超链接,用户点击这个超链接,发送请求,Tomcat 执行后台的 StudentServlet。
student.html
这个文件不能放到 WEB-INF 目录里面,只能放到 WEB-INF 目录外面。
student.html 文件的内容
13.4 Servlet 对象生命周期
默认情况下服务器启动的时候 AServlet 对象并没有被实例化
13.4.1 关于 Servlet 中的 init、service、destroy 方法
用户发送第一次请求的时候,控制台输出了以下内容:
根据以上输出内容得出结论:
用户在发送第一次请求的时候 Servlet 对象被实例化(AServlet 的构造方法被执行了。并且执行的是无参数构造方法。)
AServlet 对象被创建出来之后,Tomcat 服务器马上调用了 AServlet 对象的 init 方法。(init 方法在执行的时候,AServlet 对象已经存在了。已经被创建出来了。)
用户发送第一次请求的时候,init 方法执行之后,Tomcat 服务器马上调用 AServlet 对象的 service 方法。
用户继续发送第二次请求,控制台输出了以下内容:
根据以上输出结果得知,用户在发送第二次,或者第三次,或者第四次请求的时候,Servlet 对象并没有新建,还是使用之前创建好的 Servlet 对象,直接调用该 Servlet 对象的 service 方法,这说明:
第一:Servlet 对象是单例的(单实例的。但是要注意:Servlet 对象是单实例的,但是 Servlet 类并不符合单例模式。我们称之为假单例。之所以单例是因为 Servlet 对象的创建我们 javaweb 程序员管不着,这个对象的创建只能是 Tomcat 来说了算,Tomcat 只创建了一个,所以导致了单例,但是属于假单例。真单例模式,构造方法是私有化的。)
第二:无参数构造方法、init 方法只在第一次用户发送请求的时候执行。也就是说无参数构造方法只执行一次。init 方法也只被 Tomcat 服务器调用一次。
第三:只要用户发送一次请求:service 方法必然会被 Tomcat 服务器调用一次。发送 100 次请求,service 方法会被调用 100 次。
关闭服务器的时候,控制台输出了以下内容:
通过以上输出内容,可以得出以下结论:
Servlet 的 destroy 方法只被 Tomcat 服务器调用一次。
destroy 方法是在什么时候被调用的?
在服务器关闭的时候。
因为服务器关闭的时候要销毁 AServlet 对象的内存。
服务器在销毁 AServlet 对象内存之前,Tomcat 服务器会自动调用 AServlet 对象的 destroy 方法。
请问:destroy 方法调用的时候,对象销毁了还是没有销毁呢?
destroy 方法执行的时候 AServlet 对象还在,没有被销毁。destroy 方法执行结束之后,AServlet 对象的内存才会被 Tomcat 释放。
13.4.2 Servlet 对象更像一个人的一生:
Servlet 的无参数构造方法执行:标志着你出生了。
Servlet 对象的 init 方法的执行:标志着你正在接受教育。
Servlet 对象的 service 方法的执行:标志着你已经开始工作了,已经开始为人类提供服务了。
Servlet 对象的 destroy 方法的执行:标志着临终。有什么遗言,抓紧的。要不然,来不及了。
13.4.3 关于 Servlet 类中方法的调用次数?
构造方法只执行一次。
init 方法只执行一次。
service 方法:用户发送一次请求则执行一次,发送 N 次请求则执行 N 次。
destroy 方法只执行一次。
13.4.4 当我们 Servlet 类中编写一个有参数的构造方法,如果没有手动编写无参数构造方法会出现什么问题?
报错了:500 错误。
注意:500 是一个 HTTP 协议的错误状态码。
500 一般情况下是因为服务器端的 Java 程序出现了异常。(服务器端的错误都是 500 错误:服务器内部错误。)
如果没有无参数的构造方法,会导致出现 500 错误,无法实例化 Servlet 对象。
所以,一定要注意:在 Servlet 开发当中,不建议程序员来定义构造方法,因为定义不当,一不小心就会导致无法实例化 Servlet 对象。
13.4.5 思考:Servlet 的无参数构造方法是在对象第一次创建的时候执行,并且只执行一次。init 方法也是在对象第一次创建的时候执行,并且只执行一次。那么这个无参数构造方法可以代替掉 init 方法吗?
不能。
Servlet 规范中有要求,作为 javaweb 程序员,编写 Servlet 类的时候,不建议手动编写构造方法,因为编写构造方法,很容易让无参数构造方法消失,这个操作可能会导致 Servlet 对象无法实例化。所以 init 方法是有存在的必要的。
13.4.6 init、service、destroy 方法中使用最多的是哪个方法?
使用最多就是 service 方法,service 方法是一定要实现的,因为 service 方法是处理用户请求的核心方法。
什么时候使用 init 方法呢?
init 方法很少用。
通常在 init 方法当中做初始化操作,并且这个初始化操作只需要执行一次。例如:初始化数据库连接池,初始化线程池....
13.4.7 什么时候使用 destroy 方法呢?
destroy 方法也很少用。
通常在 destroy 方法当中,进行资源的关闭。马上对象要被销毁了,还有什么没有关闭的,抓紧时间关闭资源。还有什么资源没保存的,抓紧时间保存一下。
14 GenericServlet
14.1 我们编写一个 Servlet 类直接实现 Servlet 接口有什么缺点?
我们只需要 service 方法,其他方法大部分情况下是不需要使用的。代码很丑陋。
14.2 适配器设计模式 Adapter
手机直接插到 220V 的电压上,手机直接就报废了。怎么办?可以找一个充电器。这个充电器就是一个适配器。手机连接适配器。适配器连接 220V 的电压。这样问题就解决了。
14.3 编写一个 GenericServlet 类,这个类是一个抽象类,其中有一个抽象方法 service。
GenericServlet 实现 Servlet 接口。
GenericServlet 是一个适配器。
以后编写的所有 Servlet 类继承 GenericServlet,重写 service 方法即可。
14.4 思考:GenericServlet 类是否需要改造一下?怎么改造?更利于子类程序的编写?
思考第一个问题:我提供了一个 GenericServlet 之后,init 方法还会执行吗?
还会执行。会执行 GenericServlet 类中的 init 方法。
思考第二个问题:init 方法是谁调用的?
Tomcat 服务器调用的。
思考第三个问题:init 方法中的 ServletConfig 对象是谁创建的?是谁传过来的?
都是 Tomcat 干的。
Tomcat 服务器先创建了 ServletConfig 对象,然后调用 init 方法,将 ServletConfig 对象传给了 init 方法。
思考一下 Tomcat 服务器伪代码:
版权声明: 本文为 InfoQ 作者【胖虎不秃头】的原创文章。
原文链接:【http://xie.infoq.cn/article/24a9f8560634f46108f5fe101】。文章转载请联系作者。
评论