「英文时间」:servlet
它是由 server
和applet
两个单词拼接造出来的一个词,表示服务端小程序。
Servlet 实现了 CGI 接口,因此它能够拿到 Tomcat 传递过来的内置对象,实现动态网页应用程序的编写。它是纯 Java 程序编写的一个 web 组件,在 MVC 设计模式中通常充当控制器的角色,Tomcat 会给每一次用户请求都分配一个线程来执行相关的操作,所以它必须被设计成是线程安全的。
要想编写一个 Servlet 类,通常需要遵循以下几个语法点:
- 必须有包声明,web 应用中每个类都必须有包声明,不同于 JavaSE 有一个所谓的默认包
- 因为 JavaWeb 标准类库目前只支持 HTTP 协议,所以自定义的 Servlet 类必须继承 javax.servlet.http.HttpServlet 类,并重 doGet() 和 doPost() 方法
- 导入本 Java 类所需的字节码文件,比如 doGet()/doPost() 方法不处理 IOException 和 ServletException ,所以需要导入 java.io.* 和 javax.servlet.* 以及需要导入 javax.servlet.http.* 包。
如何手工运行有 Servlet 类的 web 应用程序?
首先要明确的大前提是,web 应用程序需要依赖 JavaEE 提供的标准类库和 Tomcat 才能得以运行,但是它们又都依赖于 JVM 。JDK 中是没有 JavaEE 标准类库的,所以 JVM 在运行过程中必须要找到这些类字节码文件,才能运行。
那如何能够让 JVM 找到所需的标准类库呢?有以下三种方式
- 配置系统环境变量 CLASSPATH
- 将所需 jar 包放到
jdk1.8.0_144/jre/lib/ext
目录下 - 如果使用 IDE 工具,则它会在项目的配置文件中自动进行相关环境变量的配置
给 Servlet 类配置映射路径
因为 Servlet 类是一个纯 java 类,它编译后的字节码文件必须放在 WEB-INF/classes 目录下,而 WEB-INF 目录下的内容是不可以被服务端直接访问的,所以需要在 WEB-INF/web.xml 中进行路径的映射,Tomcat 才能够通过 web.xml 中的配置找到所访问的 Servlet 字节码文件。
TestServlet
com.keqi.servlet.TestServlet
0
TestServlet
*.do
以上就是在 web.xml 中进行 Servlet 路径映射的方式,而且一个 Servlet 类可以配置多个映射,也就是说一个
元素可以有多个
元素与之对应。
中如果不向上面一样使用通配符的方式配置映射路径,那配置的路径就一定要添加反斜杠/
。
还可以在
元素中添加
元素设定 Servlet 类的优先级别,优先级别[0,10]
,这和线程的优先级是一样的发现了没有???优先级设置为 0 时,Tomcat 会在启动时就会创建该 Servlet 类的对象。
在编写 web.xml 文件时一定要超级小心,只要有一点错误, web 应用程序将无法运行。配置文件一旦修改,就需要重新启动 Tomcat 。
Servlet 和表单
关于路径还有一个非常重要的问题需要注意,以实例讲解这个过程。
在表单中直接提交信息到 Servlet 中时,会把该页面所在目录也当成是请求 url ,也就是说请求 url 相对于项目的根目录可以分为两个部分,一个是当当前页面所在的路径/jsp
和表单访问的路径/fromServlet
。因此全部访问 url 为http://localhost:8080/wb/jsp/fromServlet1
。Tocmat 拿到请求 url 后,就会到 web.xml 文件中去查找对应的/jsp/formServlet1
路径。因此在配置 Servlet 映射路径的时候,必须考虑到表单所在页面的路径,否则会出现找不到资源的问题。
而且在 Servlet 中使用请求转发时,因为用的同样是相对路径,所以它会把请求所带来得到路径那部分当成是当前的相对路径,在转发页面时需要考虑到这点。比如要转发到success.jsp
页面,那么针对此例该页面必须在/jsp
路径下才行。每次请求如果有新的路径,就会把这个路径当成是这次的相对路径,下次路径改变了,那就跟着改变,Servlet 好奇葩哦。
解决这个问题其实很简单,在配置映射路径是使用通配符*.后缀名
的方式接收所有路径的访问。但是在 Servelt 转发,还是无法避免不同路径带来不同的相对路径啊。真正的解决办法是把项目中用到的所有页面全部放到同一个目录下,比如/jsp
,路径全部相同,就可以完美避开这个陷阱了。
Servlet 生命周期
Servlet 生命周期对应方法,其实这三个方法都是在 Servlet 接口中定义的。
-
init()
或者是init(ServletConfig config)
,在对象创建完成后,立即调用此方法进行初始化操作,如果这两个方法同时存在,会默认调用有参的那个方法,只有有参的方法不存在,才会调用无参的方法。根据此方法的特点一般用它来完成做初始化工作,struts 和 springMVC 中就利用它来完成数据的收集工作。 -
destory()
方法在 Tomcat 决定销毁该对象前,会调用此方法,用来进行资源的关闭等等。 -
service()
方法是在 Tomcat 每次接收请求时都会调用的 Servlet 对象的此方法,进行相应用户的请求。但是一般根据请求方式去调用doGet()
和doPost()
方法完成相关工作。
执行流程如下:
- 创建对象:Servlet 类在 Tomcat 启动或者第一次使用这个类的时候,会通过配置文件中找到该请求 url 对应的类名,然后通过反射的方式创建对象。
- 对象一旦创建,立即会调用 init(ServletConfig config) 方法进行对象的初始化
- 然后每当有一次请求发送过来,就会调用对应请求方式的 doGet() 或者 doPost() 方法,因为 Servlet 是线程安全的,所以它最多的情况下是处于服务和不可服务状态。这就很像线程生命周期中的运行和阻塞状态啊,是一样的道理!
- 当 Tomcat 对象希望销毁 Servlet 对象时,会先调用它的 destory() 方法,它就会在堆区中等待 GC 进行内存回收。
Servlet 中获取内置对象
内置对象是由 Tomcat 负责创建并管理的,不是只有 JSP 中才能使用,Servlet 是一样能够使用的,它获取内置对象有两种方式,一种是依赖注入,另一种则是依赖查找。
其中 request 、response 和 config 对象都是作为参数对象在 Tomcat 调用 Servlet 的方法时传送过来的,这种方式就是依赖注入。而 session 、application 和 out 则是通过 request 的方法得到的,这种依赖于某个对象得到其他对象的方式就叫做依赖查找。使用方式如下:
HttpSession session = request.getSession();
ServletContext application = request.getServletContext();
PrintWriter out = request.getWriter();
其他的 page 、pageContext 和 exception 对象在 Servlet 类中基本用不上。
总结下就是:3 个不用的,3 个通过依赖注入的方式得到,还有 3 个通过 reqeust 对象的依赖查找的方式得到。
通过 config 内置对象得到该 Servlet 类的配置信息
有时可能需要在配置文件中给 Servlet 类添加一些配置信息,添加方式如下,可见它是在
元素中的
元素内添加相关信息的。Servlet 类中只要通过String getInitParam(String name)
方法就可以得到参数值。
Simple
cn.zte.pxb.servlet.SimpleServlet
userName
keqi
web.xml 文件中有两种定义参数的方式,一种是局部初始化参数,定义在
元素中,Tomcat 会给每一个 Servlet 对象创建一个 config 对象,并把对应的局部初始化参数存放到此对象中去,如上就是。
另一种是在
元素中定义的初始化信息属于全局初始化信息,它是被 Tomcat 解析并放到该 web 应用对应的 application 对象中去了。定义方式如下:
name
keqi