- Servlet
Sun在 其api 中定义了servlet 接口,不要去到 jdk 中找, 而要去 javaee的api 找。
Servlet是sun公司提供的一门用于开发动态web资源的技术。
servlet 基于request - response 请求模型 (http协议)
Sun公司在其API中提供了一个servlet接口,用户若想开发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
编写一个Java类,实现servlet接口。
把开发好的Java类部署到web服务器中。
4.1 快速入门(编写servlet步骤)
- 继承 javax.servlet.http.HttpServlet
- 覆盖doGet、doPost
- web.xml配置Servlet的虚拟路径
- 启动服务器, 发布web应用,去访问http://localhost:8080/day08_servlet/hello
web.xml配置Servlet访问虚拟路径:
GET方式请求提交映射关系:
4.2 为什么要去继承HttpSerlvet
4.3 servlet的生命周期
servlet的生命周期方法执行顺序:
Init : 第一次访问, 创建serlvet的时候会执行, 用来 初始化 serlvet
Service: 每次 请求的时候, 都会执行
Destroy: 当servlet销毁, 不再服务客户端请求的时候销毁
小结: 一个servlet第一次被访问的时候,会创建出来,调用init 初始化,然后这个servlet类的一个实例对象就驻留在内存中,后续再去访问这个servlet的时候, 就会拿 内存中servlet实例来响应请求. 直至 服务器 停止…
- Servlet是一个供其他Java程序(Servlet引擎,服务器)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。
- 针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁。
- 在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法。
4.4 自定义的servlet 的doGet,doPost方法是如何被调用到的
Servlet程序不是 咱们自己调用的, 是服务器调用的.
Servlet在每次访问的时候都会调用service方法, 但是 我们在访问自定义的sevlet的时候, 发现没有service方法, 只写了doGet和doPost, 但是 这个doGet ,doPost方法在每次请求的时候 也都相应的执行了. 那么这里的 doGet,doPost方法是如何被调用到的呢?
生命周期的service方法, 调用了 httpservlet 自定义的那个 service方法, 而自定义的service 方法中,又 根据当前的请求方式, 调用 了具体的doXxx方法
原来, doGet,doPost方法 实际上还是 通过调用了生命周期的service , 再根据请求方式 调用过来的.
4.5 覆盖servlet时,几个注意点
第一个:
覆盖init方法时, 不要覆盖 有参数的 init方法
第二个:
根据Http请求的方式,覆盖相应的doGet或者doPost方法,无需覆盖Service方法
第三个:
当doGet和doPost代码逻辑相同时,可以相互调用,简化编程
观察 doGet和doPost,两个方法 接收的参数 是一模一样的, 只是 方法名字不一样.
那么 如果在开发过程中. doGet和doPost里的代码逻辑完全一致, 那么 就可以在 其中一方调用下 对方,这样可以简化编程.
4.6 映射servlet的对外访问路径
通过 url-pattern 来实现映射.
这个 路径有三种写法:
第一种:
绝对路径 匹配, 必须要以 / 开始 -------- 例如: /aaa/bbb
第二种:
目录匹配, 必须要以 / 开始, 以 * 结束 ----- 例如: /mmm/nnn/* , /aaa/bbb/*
第三种:
扩展名匹配, 必须要以 * 开始. 扩展名结束 ---- 例如: *.do , .xxx
当出现 多个servlet 都对访问 的目标路径都 匹配时, 那么 会有优先级顺序.
http://localhost/day08/aaa/bbb
优先级顺序: 第一种> 第二种> 第三种
经典的错误: /.do —
4.7 Servlet的启动配置
默认的情况下, 一个serlvet类 只有在访问的时候才会创建实例. 然后驻留在内存中
但是 实现上, 对与一些 servlet ,如果 这个servlet 要完成一些特殊功能, 比方说 读取web工程中比较大的资源配置 文件,
那么在这种场景下, 你可能就需要在 web应用一启动的时候 就去 启动的serlvet, 实例化, 去读取 大的资源配置文件.
就需要将 servlet 配置为 web应用启动时就加载 .
4.8 ServletConfig对象
ServletConfig---- 代表 着 一次请求的时候, 关于servlet的 配置信息. 这个对象中封装的就是 针对于 某个具体的servlet的 启动配置信息…
Serlvet生命周期方法中 :
这个对象是服务器 在调用init 方法时 ,传递进来的.
在web.xml文件中,你 注册 serlvet的时候, 是可以通过 init-param 来 配置 servlet的具体的参数信息的.
Tomcat服务器 会将 这些参数信息封装到一个叫做 serlvetConfig的对象中,并且将这个对象在 调用 init方法的时候传递进来 . 那么你就可以拿到 对这个对象的引用.
注意点 : 每个serlvet的都有其独占的 servletConfig对象, 用来封装各自的初始化参数 信息.
例如: A serlvet的配置, 是不能 够通过 B servlet的 serlvetConfig 来获得的.
4.9 使用servletContext对象
ServletContext对象就代表着 一个web应用, 那么只要拿到一个SerlvetContext对象, 就 代表着一个web应用…
每个web应用,都有 与其相对应的唯一的servletContext对象.
- 常识 :
Context — 上下文 , 贯穿始终的 玩意 … 一般就是一个工具类 . 可以让你去获得 一些 文件, 配置信息, 读取一些资源等等功能.
ServletContext – 代表着web应用
Context — 代表着 你的那个 app
4.9.1 获得全局的配置信息
在web.xml文件中, 可以配置web应用的全局的初始化参数信息.
- 如何获得对servletContext对象的引用呢?
在任何一个servlet中 通过 getServletContext() 方法 获得 对当前web应用的 serlvetContext的 引用
4.9.2 实现数据共享
对于每个web应用,都有一个唯一的sevletContext对应与其 对应, 那么 如果你在servlet1 拿到了 对serlvetContext对象引用, 向 serlvetContext 存入了一些值, 然后 现在去 servlet2, 那么 也可以获得 对serlvetContext 引用,这个时候 ,那么拿到的同一个 对象, 都是代表着 当前的web应用, 由于 拿到的是 同一个对象, 那么就可以实现数据的 共享.
- 域对象:
1.域对象是一个容器,
2.域对象容器就会有大小(范围)
3.域对象都有实现数据共享的方法
setAttribute(name,value) — String , Object
getAttribute(name) , 返回值是 Object ---- String
removeAttribute(name) ------- String
SerlvetContext 对象是一个域对象
类加载器 : 负责 将 classpath 路径下的 资源 文件 加载到 虚拟机中去, .class文件 一旦被加载到虚拟机中, 那么 就 完成了类加载的过程,
- 使用serlvetContext实现统计网站的访问次数
- 在init 方法中 搞个计数器的初始值 是 0, 并且存到 servletContext域 中去
- 在doGet 方法中,取出 原有的值, 然后 +1 ,然后再 放回去 .
- 取出 存在 servletContext 的次数, 显示一下.
- 使用serlvetContext去获得web应用下文件的路径
ServletContext context = getServletContext();
String realPath2 = context.getRealPath("/2.txt");
String path3 =context.getRealPath("/WEB-INF/3.txt");
String path4 = context.getRealPath("/WEB-INF/classes/4.txt");
readContent(path4);
public static void readContent(String path) {
try {
InputStream in = new FileInputStream(path);
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) > 0) {
System.out.println(new String(buf, 0, len));
}
} catch (Exception e) {
e.printStackTrace();
}
}
-
使用 类加载器 去获得 4.txt 的 路径
由于 4.txt 在src 目录下, 那么 这里4.txt 又 多了一种 使用 类加载器 去 获得 路径的方式//类加载 Class clazz = Class.forName("com.A"); // 使用这种方式 的时候 要 加 个 / URL url = ReadContentServlet.class.getResource("/4.txt"); String realpath = url.getFile(); readContent(realpath);
4.10 缺省的Servlet
- 如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。
- 凡是在web.xml文件中找不到匹配的元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。
- 在<tomcat的安装目录>\conf\web.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为了缺省Servlet。
- 当访问Tomcat服务器中的某个静态HTML文件和图片时,实际上是在访问这个缺省Servlet。
当没有任何一个servlet 程序可以 响应客户端的请求时 ,默认的serlvet 就出来干活了.
你每次向服务器发送的时候, 都是由 一个serlvet 来处理你的请求的, 包括你访问的是
静态的html 页面的时候也是 由 一个servlet来响应你的请求的.
在tomcat服务器的 conf目录下的 web.xml 文件中
这里 由于 默认的servlet的 对外访问路径是 / , 那么就表示配置成了默认的serlvet . 用于响应 当找不到对应的servlet的时候, 来响应客户端的请求.
你以后在配置 serlvet的对外访问路径, 不要 将你的servlet 的对外访问路径 弄成 / , 如果弄成/ , 那么就会将你自己 写的那个servlet 弄成默认的. 那样的话, 就 看不到 之前的 访问 资源不存在的时候404, 500 等等错误友好提示信息了.