梦想还是要有的,万一忘了咋办?

0%

Servlet介绍

  • Servlet是什么
  • Servlet与tomcat关系

是什么

实现动态网站的技术早期的Web服务器,只能响应浏览器发来的HTTP静态资源的请求,并将存储在服务器中的静态资源返回给浏览器。随着Web技术的发展,逐渐出现了动态技术,为了解决web服务器不能够直接运行脚本的问题诞生了:CGI、Servlet等技术。

Java Servlet API 是Java EE技术的一部分。

方案对比:

Tomcat跟Servlet直间关系

Tomcat是应用(java)服务器,它只是一个servlet容器,是Apache的扩展,处理动态网页部分。

Servlet容器用来来管理和运行servlet,但是为什么要这样做呢?使用servlet容器的原因有:

  • 通信支持
    利用容器提供的方法,你能轻松的让servlet与web服务器对话,而不用自己建立serversocket、监听某个端口、创建流等 等。容器知道自己与web服务器之间的协议,所以你的servlet不用担心web服务器(如Apache)和你自己的web代码之间的API,只需要考 虑如何在servlet中实现业务逻辑(如处理一个订单)。
  • 生命周期管理:
    servlet容器控制着servlet的生与死,它负责加载类、实例化和初始化servlet,调用servlet方法,以及使servlet实例被垃圾回收,有了servlet容器,你不需要太多的考虑资源管理。
  • 多线程支持:
    容器会自动为它所接收的每个servlet请求创建一个新的java线程。针对用户的请求,如果servlet已经运行完相应的http服务方法,这个线程就会结束。这并不是说你不需要考虑线程安全性,其实你还会遇到同步问题,不过这样能使你少做很多工作。
  • 声明方式实现安全:
    利用servlet容器,你可以使用xml部署描述文件来配置和修改安全性,而不必将其硬编码写到servlet类代码中。
  • JSP支持:
    servlet容器负责将jsp代码翻译为真正的java代码。

常见容器对比

Servlet4.0

  • 支持服务器推送(HTTP/2 强化功能)
  • 运行时发现servlet的URL映射

PushBuilder

1
2
3
4
5
6
7
8
9
10
11
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
PushBuilder pushBuilder = request.newPushBuilder();
if (pushBuilder != null) {
pushBuilder.path("images/hero-banner.jpg").push();
pushBuilder.path("css/menu.css").push();
pushBuilder.path("js/marquee.js").push();
}
}
  • newPushBuilder() 返回一个全新对象
  • newPushBuilder 可能会返回Null,当客户端不接收时
  • 只支持GET方法类型
  • 请求头不包含:
    • 条件标头
    • Range标头
    • Expect 标头
    • Authorization 标头
    • Referrer 标头

HttpServletMapping接口

Servlet 4.0 的全新 servlet 映射发现 API 使服务器能够对 URL(可调用 servlet)执行运行时检查。例如,对 file.ext, /path 和 /path/file.ext 的请求将通过 URL 模式 /path/* 和 *.ext 激活 servlet。

HttpServletMapping 接口支持运行时发现 servlet 的映射 URL。您可以在 HttpServletRequest 实例上调用 getHttpServletMapping() ,获取接口的实例。您可以使用以下方法获取有关 servlet 映射 URL 的信息:

  • getMatchValue() 返回部分 URI 路径,该路径会导致请求匹配。
  • getPattern() 返回 URL 模式的 String 表示形式。
  • getServletName() 返回 servlet 名称的 String 表示形式。
  • getMappingMatch() 返回匹配的类型,表示为 MappingMatch 枚举值,该枚举值将为以下值之一: CONTEXT_ROOT 、 DEFAULT 、 EXACT 、 EXTENSION 或 PATH 。

其他变化

除了服务器推送和全新 HttpServletMapping 接口,Servlet 4.0 还包括少量值得注意的新增功能和变更。

  • Trailer 响应标头支持发送方在分块消息的末尾包含额外字段。这用于提供在发送消息主体时可能会动态生成的元数据,例如,消息完整性检查、数字签名或后期处理状态。

  • Servlet 4.0 添加了 GenericFilter 和 HttpFilter 抽象类,这些抽象类通过最低限度地实现生命周期方法 init() 和 destroy() ,简化了编写过滤器。

  • Servlet 4.0 还集成了全新的 HTTP Trailer ,支持发送方在分块消息的末尾包含额外的字段。

  • ServletContext 接口采用了一些新方法:

    • addJspFile() 可将带有给定 JSP 文件的 servlet 添加到 servlet 上下文中。
    • getSessionTimeout() 和 setSessionTimeout() 可提供对会话超时的访问权限。
    • getRequestCharacterEncoding() 和 setRequestCharacterEncoding() 可为当前的 servlet 上下文提供访问权限,并改变默认的请求字符编码。
  • HttpServletRequest 接口上的 * isRequestedSessionIdFromUrl() 方法已被弃用。

  • 由于升级到 Java SE 8,默认方法已被添加到侦听器接口中。

Servlet3.0

Servlet 3.0 作为 Java EE 6 规范体系中一员,随着 Java EE 6 规范一起发布。该版本在前一版本(Servlet 2.5)的基础上提供了若干新特性用于简化 Web 应用的开发和部署。

  • 异步处理支持:
  • 新增的注解支持
  • 可插性支持

异步处理支持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<servlet>
<servlet-name>DemoServlet</servlet-name>
<servlet-class>footmark.servlet.Demo Servlet</servlet-class>
<async-supported>true</async-supported>
</servlet>
------OR------
@WebFilter(urlPatterns = "/demo",asyncSupported = true)
public class DemoFilter implements Filter{...}

//异步处理器提供一个监听器
AsyncContext ctx = req.startAsync();
ctx.addListener(new AsyncListener() {
public void onComplete(AsyncEvent asyncEvent) throws IOException {
// 做一些清理工作或者其他
}
...
});
//异步线程开始时,调用 AsyncListener 的 onStartAsync(AsyncEvent event) 方法;
//异步线程出错时,调用 AsyncListener 的 onError(AsyncEvent event) 方法;
//异步线程执行超时,则调用 AsyncListener 的 //onTimeout(AsyncEvent event) 方法;
//异步执行完毕时,调用 AsyncListener 的 onComplete(AsyncEvent event) 方法;

新增的注解支持

@WebServlet
@WebServlet 用于将一个类声明为 Servlet,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为 Servlet。该注解具有下表给出的一些常用属性(以下所有属性均为可选属性,但是 vlaue 或者 urlPatterns 通常是必需的,且二者不能共存,如果同时指定,通常是忽略 value 的取值):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@WebServlet(urlPatterns = {"/simple"}, asyncSupported = true,
loadOnStartup = -1, name = "SimpleServlet", displayName = "ss",
initParams = {@WebInitParam(name = "username", value = "tom")}
)
public class SimpleServlet extends HttpServlet{... }

------------

<servlet>
<display-name>ss</display-name>
<servlet-name>SimpleServlet</servlet-name>
<servlet-class>footmark.servlet.SimpleServlet</servlet-class>
<load-on-startup>-1</load-on-startup>
<async-supported>true</async-supported>
<init-param>
<param-name>username</param-name>
<param-value>tom</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SimpleServlet</servlet-name>
<url-pattern>/simple</url-pattern>
</servlet-mapping>

@WebInitParam
该注解通常不单独使用,而是配合 @WebServlet 或者 @WebFilter 使用。它的作用是为 Servlet 或者过滤器指定初始化参数,这等价于 web.xml 中 和 的 子标签。@WebInitParam 具有下表给出的一些常用属性:

@WebFilter
@WebFilter 用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。该注解具有下表给出的一些常用属性 ( 以下所有属性均为可选属性,但是 value、urlPatterns、servletNames 三者必需至少包含一个,且 value 和 urlPatterns 不能共存,如果同时指定,通常忽略 value 的取值 ):

1
2
3
4
5
6
7
8
9
10
11
@WebFilter(servletNames = {"SimpleServlet"},filterName="SimpleFilter")
public class LessThanSixFilter implements Filter{...}
---------
<filter>
<filter-name>SimpleFilter</filter-name>
<filter-class>xxx</filter-class>
</filter>
<filter-mapping>
<filter-name>SimpleFilter</filter-name>
<servlet-name>SimpleServlet</servlet-name>
</filter-mapping>

@WebListener

该注解用于将类声明为监听器,被 @WebListener 标注的类必须实现以下至少一个接口:

  • ServletContextListener
  • ServletContextAttributeListener
  • ServletRequestListener
  • ServletRequestAttributeListener
  • HttpSessionListener
  • HttpSessionAttributeListener
1
2
3
4
5
6
@WebListener("This is only a demo listener")
public class SimpleListener implements ServletContextListener{...}
----------
<listener>
<listener-class>footmark.servlet.SimpleListener</listener-class>
</listener>

@MultipartConfig
该注解标注在 Servlet 上面,以表示该 Servlet 希望处理的请求的 MIME 类型是 multipart/form-data。

可插性支持

Servlet 3.0 引入了称之为”Web 模块部署描述符片段”的 web-fragment.xml 部署描述文件,该文件必须存放在 JAR 文件的 META-INF 目录下,该部署描述文件可以包含一切可以在 web.xml 中定义的内容。JAR 包通常放在 WEB-INF/lib 目录下,除此之外,所有该模块使用的资源,包括 class 文件、配置文件等,只需要能够被容器的类加载器链加载的路径上,比如 classes 目录等。

三种方式增加一个(过滤器、监听器、Servlet):

  • 编写一个类继承自 HttpServlet,将该类放在 classes 目录下的对应包结构中,修改 web.xml,在其中增加一个 Servlet 声明。这是最原始的方式;
  • 编写一个类继承自 HttpServlet,并且在该类上使用 @WebServlet 注解将该类声明为 Servlet,将该类放在 classes 目录下的对应包结构中,无需修改 web.xml 文件。
  • 编写一个类继承自 HttpServlet,将该类打成 JAR 包,并且在 JAR 包的 META-INF 目录下放置一个 web-fragment.xml 文件,该文件中声明了相应的 Servlet 配置。web-fragment.xml 文件示例如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?xml version="1.0" encoding="UTF-8"?>
    <web-fragment
    xmlns=http://java.sun.com/xml/ns/javaee
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"
    metadata-complete="true">
    <servlet>
    <servlet-name>fragment</servlet-name>
    <servlet-class>footmark.servlet.FragmentServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>fragment</servlet-name>
    <url-pattern>/fragment</url-pattern>
    </servlet-mapping>
    </web-fragment>

ServletContext 的性能增强

ServletContext支持在运行时动态部署 Servlet、过滤器、监听器,以及为 Servlet 和过滤器增加 URL 映射等。

1、通过createServlet方法创建Servlet

  • T createServlet(Class clazz)

2、通过addServlet动态注册Servlet:

  • ServletRegistration.Dynamic addServlet(String servletName, String className)
  • ServletRegistration.Dynamic addServlet(String servletName,Class<? extends Servlet> servletClass)
  • ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet)

*3、为Servlet配置映射信息 *

  • ServletRegistration getServletRegistration(String servletName)
  • Map<string,? extends servletregistration> getServletRegistrations()

以上 ServletContext 新增的方法要么是在 ServletContextListener 的 contexInitialized 方法中调用,要么是在 ServletContainerInitializer 的 onStartup() 方法中调用。

ServletContainerInitializer也是Servlet3.0新增的一个接口,容器在启动时使用 JAR 服务 API(JAR Service API) 来发现 ServletContainerInitializer 的实现类,并且容器将 WEB-INF/lib 目录下 JAR 包中的类都交给该类的 onStartup() 方法处理,我们通常需要在该实现类上使用 @HandlesTypes 注解来指定希望被处理的类,过滤掉不希望给 onStartup() 处理的类。

HttpServletRequest 对文件上传的支持

此前对于文件上传需要依赖三方框架实现。Servlet3.0 提供了优雅的解决方案,在HttpServletRequest提供2个方法用于从请求中解析出上传的文件。

  • Part getPart(String name)
  • Collection getParts()
1
2
3
Part photo = request.getPart("photo");
photo.write("/tmp/photo.jpg");
// 可以将两行代码简化为 request.getPart("photo").write("/tmp/photo.jpg")
  • 通过@MultipartConfig注解对上传操作做一些配置,大小、保存路径等。
  • MIME类型一定是 multipart/form-data,否则会抛出异常。