Servlet(二):初识Servlet
在手动写完一个Servlet小例子后,是不是有很多疑问,接下来会为大家详细介绍Servlet的知识。
1、什么是Servlet
是在服务器上运行的小程序。一个servlet就是一个Java类,并且可以通过“请求-响应”编程模型来访问驻留在服务器内存里的servlet程序。
2、为什么要用Servlet
web服务器只能处理静态资源的请求,需要事先将静态页面写好,不能处理动态资源请求(动态资源请求主要是一些需要计算或数据操作而生产的页面),在早期为了解决这一问题,使用了CGI程序(Common Gateway Interface通用网关接口)来扩展web服务器的功能,但是其性能较差,可移植性差,慢慢被弃用。
Servlet的出现很好的解决使用CGI出现的问题。第一,Servlet可移植性强,Servlet是用Java语言实现的,具备一处编写处处运行的特点。第二,Servlet可扩展性强,可使用Java的所有类库,并且可以通过sockets和RMI机制(Remote Method Invocation远程方法调用,是允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法,这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中。)与数据库或其他软件进行交互。第三,Servlet性能更好,Servlet只需web服务器加载一次,而且可以在不同请求之间保持服务;相反,每一次对CGI脚本的请求,都会使Web服务器加载并执行该脚本。一旦这个CGI脚本运行结束,它就会被从内存中清除,然后将结果返回到客户端。CGI脚本的每一次使用都会造成程序初始化过程的重复执行。
3、编写Servlet的步骤
A.编写一个Java类,继承HttpServlet,重写doGet()方法和doPost()方法。
B.配置web.xml文件。
C.编写jsp页面。
D.启动容器,访问servlet,在浏览器验证。
4、Servlet的执行流程
5、Servlet的生命周期
Servlet的生命周期是指Servlet容器如何创建Servlet对象,如何对其进行初始化,如何调用Servlet对象处理请求,如何销毁Servlet对象的整个过程。
主要分为四个阶段:(1)实例化;(2)初始化;(3)调用;(4)销毁。
A.实例化阶段。Servlet实例会在以下两种情况下创建:一是在Servlet容器收到request请求后创建;二是在Servlet容器启动时创建,需要在web.xml中配置<load-on-startup>1</load-on-startup>标签,中间的值是一个大于0的整数,值越小优先级越高。
B.初始化阶段。Servlet实例化后,会调用init(ServletConfig config)方法,其中ServletConfig对象是一个成员变量,是Servlet容器传递进来的,init方法只会执行一次。
C.调用阶段。servlet容器收到请求后,调用servlet对象的service()方法,再将处理结果返回给浏览器。
D.销毁阶段。对server执行stop操作或将服务关闭时,调用servlet对象的destroy方法,且只会执行一次。
6、实操验证
新建一个Maven web项目,写好servlet,配置好web.xml,写一个简单的jsp页面,可以来实际验证刚才的分析。
A.新建两个Java类,继承HttpServlet
/** * servlet的生命周期 * @author 小川94 * @date 2018年6月4日 */ public class LifeServlet extends HttpServlet { private static final long serialVersionUID = 1L; public LifeServlet() { System.out.println("LifeServlet:执行构造方法..."); } @Override public void init() throws ServletException { System.out.println("LifeServlet:执行init方法..."); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 打印日志 System.out.println("LifeServlet:处理Get请求..."); // 设置服务器返回的数据类型 response.setContentType("text/html"); // 获取一个输出流 PrintWriter out = response.getWriter(); // 输出数据,将数据发送到浏览器 out.println("<h1>Hello Servlet!</h1>"); // 关闭流 out.close(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 打印日志 System.out.println("LifeServlet:处理Post请求..."); // 对从浏览器获取的数据设置编码格式 request.setCharacterEncoding("UTF-8"); // 获取页面传入的数据 String name = request.getParameter("name"); System.out.println(name); // 设置服务器返回的数据类型 response.setContentType("text/html;charset=UTF-8"); // 获取一个输出流 PrintWriter out = response.getWriter(); // 输出数据,将数据发送到浏览器 out.println("<h1>Hello "+name+"!</h1>"); // 关闭流 out.close(); } @Override public void destroy() { System.out.println("LifeServlet:执行destroy方法..."); } }
public class LifeServlet2 extends HttpServlet { private static final long serialVersionUID = 1L; public LifeServlet2() { System.out.println("LifeServlet2:执行构造方法..."); } @Override public void init() throws ServletException { System.out.println("LifeServlet2:执行init方法..."); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 打印日志 System.out.println("LifeServlet2:处理Get请求..."); // 设置服务器返回的数据类型 response.setContentType("text/html"); // 获取一个输出流 PrintWriter out = response.getWriter(); // 输出数据,将数据发送到浏览器 out.println("<h1>Hello Servlet!</h1>"); // 关闭流 out.close(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 打印日志 System.out.println("LifeServlet2:处理Post请求..."); // 对从浏览器获取的数据设置编码格式 request.setCharacterEncoding("UTF-8"); // 获取页面传入的数据 String name = request.getParameter("name"); System.out.println(name); // 设置服务器返回的数据类型 response.setContentType("text/html;charset=UTF-8"); // 获取一个输出流 PrintWriter out = response.getWriter(); // 输出数据,将数据发送到浏览器 out.println("<h1>Hello "+name+"!</h1>"); // 关闭流 out.close(); } @Override public void destroy() { System.out.println("LifeServlet2:执行destroy方法..."); } }
B.配置web.xml文件
<servlet> <servlet-name>LifeServlet2</servlet-name> <servlet-class>servlet.LifeServlet2</servlet-class> <!-- 设置装载优先级 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>LifeServlet2</servlet-name> <url-pattern>/LifeServlet2</url-pattern> </servlet-mapping> <servlet> <servlet-name>LifeServlet</servlet-name> <servlet-class>servlet.LifeServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LifeServlet</servlet-name> <url-pattern>/LifeServlet</url-pattern> </servlet-mapping>
C.编写jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>第一个servlet例子</title> </head> <body style="margin:50px;"> <!-- 演示get请求 --> <a href="LifeServlet">Get请求</a> <!-- 演示post请求 --> <form action="LifeServlet" method="post"> <label>姓名</label> <input type="text" name="name"/> <br/> <input type="submit" value="提交"/> </form> <br/> <br/> <!-- 演示get请求 --> <a href="LifeServlet2">Get请求</a> <!-- 演示post请求 --> <form action="LifeServlet2" method="post"> <label>姓名</label> <input type="text" name="name"/> <br/> <input type="submit" value="提交"/> </form> </body> </html>
我们进行了两次实验,一次是没有在web.xml文件里添加<load-on-startup>1</load-on-startup>,处理页面请求时,是调用哪个servlet才会去装载哪个servlet,然后进行一系列的操作。
第二次是为LifeServlet2添加了<load-on-startup>1</load-on-startup>标签,在Tomcat启动的时候,Servlet容器就装载了LifeServlet2并初始化,然后根据浏览器的请求来执行对应的方法,最后再销毁。
文章首发于我的个人公众号:悦乐书。喜欢分享一路上听过的歌,看过的电影,读过的书,敲过的代码,深夜的沉思。期待你的关注!
公众号后台输入关键字“Java学习电子书”,即可获得12本Java学习相关的电子书资源,如果经济能力允许,还请支持图书作者的纸质正版书籍,创作不易。