参看《Java Web从入门到精通_明日科技编著》
一、Servlet技术
(一)、Servlet基础
Servlet是运行在Web服务器端的Java应用程序,与Java程序的区别是,Servlet对象主要封装了对HTTP请求的处理,并且它的运行需要Servlet容器的支持。Servlet实质上就是按Servlet规范编写的Java类,但它可以处理Web应用中的相关请求。 Servlet是一个标准,它由Sun公司定义,其具体细节由Servlet容器进行实现,如Tomcat、JBoss等。
1、Servlet结构体系
在J2EE架构中,Servlet结构体系的UML图如下图所示:
上图中,GenericServlet是一个抽象类,实现了三个接口Servlet接口、ServletConfig接口、Serializable接口。该抽象类为Servlet接口及ServletConfig接口提供了部分实现。HttpServlet是GenericServlet的子类,该类为HTTP请求中POST、GET等类型提供了具体的操作方法。通常我们所编写的Servlet对象都继承于HttpServlet。
2、Servlet技术特点
【】功能强大
Servlet采用了Java语言编写,可以调用Java API,此外,Servlet对象对Web应用进行了封装,提供了Servlet对Web应用的编程接口(即Servlet封装的Servlet API编程接口),还可以对HTTP请求进行相应的处理,如处理提交数据、会话跟踪、读取和设置HTTP头信息等。
【】性能高效
Servlet对象在Servlet容器启动时被初始化,当第一次被请求时,Servlet容器将其实例化,此时它驻存于内存中。如果存在多个请求,Servlet不会再被实例化,仍然由此Servlet对其进行处理,每一个请求是一个线程,而不是一个进程,因此,Servlet对请求处理的性能是十分高效的。
【】安全性高
Servlet使用了Java的安全框架,同时Servlet容器还可以为Servlet提供额外的功能,它的安全性是非常高的
3、Servlet与JSP的区别
Servlet是运行在Web应用服务器上的Java程序,JSP是一种在Servlet规范之上的动态网页技术。
【】角色不同
Servlet需要承担客户请求与业务处理的中间角色,JSP更具有显示层的角色;
【】编程方法不同
Servlet遵循Java的标准, JSP遵循一定的脚本语言规范;
【】执行原理不同
Servlet是Java(静态语言)编写的,需要编译后运行在Web容器中,JSP是(脚本语言,动态语言)编写的,由JSP Container管理,运行时编译执行。
【】运行速度不同
Servlet在编译完成后,运行期不需要再编译,可以直接获取及输出动态内容;而JSP有JSP Container管理,在每次执行不同内容的动态JSP页面时,JSP Container都要对其自动编译。因此JSP效率低于Servlet的执行效率。
注:JSP的产生原因:
在JSP产生之前,无论是页面设计还是业务逻辑代码都需要编写于Servlet中,这样操作会过于复杂,而且在页面中,往往还需要用到CSS样式代码、JS脚本代码等,代码量急剧膨胀,难以维护,针对这一问题,Sun公司提出了JSP(Java Server Page)技术,可以将HTML、CSS、JS等相关代码直接写入到JSP页面中,从而减轻了Servlet的职责,简化了程序员对Web程序的开发。
4、Servlet代码结构
HttpServlet类中主要的方法:
// 初始化方法
public void init() throws ServletException {
}
// 处理HTTP Get请求
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
// 处理HTTP Post请求
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
// 处理HTTP Put请求
public void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
// 处理HTTP Delete请求
public void doDelete(HttpServletRequest request, HttpServletResponse)
throws ServletException, IOException {
}
// 销毁方法
public void destroy() {
}
其中,init()方法与destroy()方法为Servlet初始化与生命周期结束所调用的方法,其余的4个方法为Servlet针对处理不同的HTTP请求类型所提供的方法。
(二)、Servlet API编程常用接口和类
1、Servlet接口
Servlet接口中包含5个方法:
【】public void init(ServletConfig config) : Servlet实例化后,Servlet容器调用该方法来完成初始化工作
【】public void service(ServletRequest request, ServletResponse response) : 用于处理客户端的请求
【】public void destroy() : 当Servlet对象从Servlet容器中移除时,容器调用该方法,以便释放资源
【】public ServletConfig getServletConfig() : 用于获取Servlet对象的配置信息,返回ServletConfig对象
【】public String getServletInfo() : 返回有关Servlet的信息,它是纯文本格式的字符串,如作者、版本等。
2、ServletConfig接口
ServletConfig接口封装了Servlet的配置信息,在Servlet初始化期间被传递,每个Servlet都有且只有一个ServletConfig对象。该接口有4个方法:
【】public String getInitParameter(String name) : 返回String类型名称为name的初始化参数值
【】public Enumeration getInitParameterNames() : 获取所有初始化参数名的枚举集合
【】public ServletContext getServletContext() : 用于获取Servlet上下文对象
【】public String getServletName() : 返回Servlet对象的实例名
3、HttpServletRequest接口
HttpServletRequest接口,继承了javax.servlet.ServletRequest接口,其常用方法如下:
【】public String getContextPath() : 返回请求的上下文路径,此路径以“/”开关;
【】public Cookie[] getCookie() : 返回请求中发送的所有cookie对象,返回值为cookie数组;
【】public String getMethod() : 返回请求所使用的HTTP类型,如get、post等;
【】public String getQueryString() : 返回请求中参数的字符串形式,如请求MyServert?username=mr, 则返回username=mr
【】public String getRequestURI() : 返回主机名到请求参数之间的字符串形式;
【】public StringBuffer getRequestURL() : 返回请求的URL,此URL中不包含请求的参数。注意此方法返回的数据类型为StringBuffer
【】public String getServletPath() : 返回请求URI中的Servlet路径的字符串,不包含请求中的参数信息;
【】public HttpSession getSession() : 返回与请求关联的HttpSession对象
4、HttpServletResponse接口
HttpServletResponse接口继承了javax.servlet.ServletResponse接口,常用方法如下:
【】public void addCookie(Cookie cookie) : 向客户端写入cookie信息
【】public void sendError(int sc) : 发送一个错误状态码为sc的错误响应到客户端
【】public void sendError(int sc, String msg) : 发送一个包含错误状态码及错误信息的响应到客户端,参数sc为错误状态码,参数msg为错误信息
【】public void sendRedirect(String location) : 使用客户端重定向到新的URL,参数location为新的地址。
5、GenericServlet类
javax.servlet.GenericServlet类简化了Servlet对象的编写,它是一个抽象类,分别实现了Servlet接口与ServletConfig接口,该类实现了出service()之外的其他方法。
public abstract class GenericServlet extends Object implements Servlet, ServletConfig, Serializable {
...
}
6、HttpServlet类
javax.servlet.http.HttpServlet类对GenericServlet类进行了扩展,为HTTP请求的处理提供了灵活的方法。
public abstract class HttpServlet extends GenericServlet implements Serializable {
...
}
(三)Servlet开发示例
1、在Eclipse中创建Dynamic Web Project项目
2、创建Servlet
在Eclipse的包资源管理器中,右键菜单,选择“新建/Servlet”命令,创建Servlet。(默认已经在web.xml中添加了相关的Servlet配置)。
3、关于Servlet配置
要使Servlet对象正常地运行,需要进行适当的配置,以告知Web容器哪一个请求调用哪一个Servlet对象处理,对Servlet起到一个注册的作用。Servlet的配置包含在web.xml文件中,主要通过以下两步进行设置。
(1)、声明Servlet对象
在web.xml文件中,通过<servlet标签声明一个Servlet对象>。该标签包含两个主要子元素,分别为<servlet-name>与<servlet-class>。其中<servlet-name>元素用于指定Servlet的名称,该名称可以是自动以的名称;<servlet-class>元素用于指定Servlet对象的完整位置,包含Servlet对象的包名与类名。
(2)、映射Servlet
在web.xml文件中国声明Servlet对象后,需要映射访问Servlet的URL。该操作使用<servlet-mapping>标签进行配置。<servlet-mapping>标签包含两个子元素,分别为<servlet-name>与<url-pattern>。其中,<servlet-name>元素与<servlet>标签中的<servlet-name>元素相对应,不可以随意命名。<url-pattern>元素用于映射访问URL。
4、示例
创建名称为FirstServletNew的Servlet之后,重写该类的doGet()方法,该方法用来处理HTTP的get请求,通过PrintWriter对象进行简单输出,如下:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//response.getWriter().append("Served at: ").append(request.getContextPath());
response.setContentType("text/html");
response.setCharacterEncoding("GBK");
PrintWriter out = response.getWriter();
out.println("<HTML>");
out.println(" <HEAD><TITLE>Servlet实例</TITLE></HEAD>");
out.println(" <BODY>");
out.print(" Servlet实例: ");
out.print(this.getClass());
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
然后,在web.xml文件中对FirstServletNew进行配置,如下:
<servlet>
<servlet-name>FirstServletNew</servlet-name>
<display-name>FirstServletNew</display-name>
<description>第一个Servlet</description>
<servlet-class>com.xiaoxiaoyusheng.web.FirstServletNew</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FirstServletNew</servlet-name>
<url-pattern>/FirstServletNew</url-pattern>
</servlet-mapping>
然后,在Eclipse项目右键Run on Server ,选择Tomcat Server,执行。执行成功后,在浏览器中输入“http://localhost:8080/spring-web-test/FirstServletNew”就可以显示如下HTML内容:(注意:spring-web-test是我的测试项目名)
Servlet实例: class com.xiaoxiaoyusheng.web.FirstServletNew
二、Servlet过滤器和监听器
(一)、过滤器
1、过滤器的应用流程
过滤器实质上是在Web应用服务器上的一个Web应用组件,用于拦截客户端(浏览器)与目标资源的请求,并对这些请求进行一定过滤处理再发送给目标资源。当然也可以部署多个过滤器对业务请求进行多次处理,这样做就组成了一个过滤器链。Web容器在处理过滤器链时,将按过滤器的先后顺序对请求进行处理。
注意:目标资源在处理了经过过滤的请求后,器回应信息在从最后一个过滤器依次传递给第一个过滤器,最后传送到客户端。
2、过滤器核心对象
过滤器核心对象包含三个接口:过滤器接口:Filter、过滤器配置接口FilterConfig、过滤器传递工具接口FilterChain;实际开发中,定义的过滤器对象要直接或间接实现Filter接口。
Filter接口:共3个方法
【】public void init(FilterConfig filterConfig) throws ServletException : 过滤器初始化方法,该方法在过滤器初始化时调用
【】public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException : 对请求进行过滤处理
【】public void destroy() : 销毁方法,以便释放资源
FilterConfig接口:(FilterConfig接口由Servlet容器进行实现,主要用于获取过滤器中的配置信息):
【】public String getFilterName() : 用于获取过滤器的名字
【】public ServletContext getServletContext() : 获取Servlet上下文
【】public String getInitParameter(String name) : 获取过滤器的初始化参数值
【】public Enumeration getInitParameterNames() : 获取过滤器的所有初始化参数
FilterChain接口:(FilterChain接口由Servlet容器进行实现)
【】public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException : 该方法用于将过滤后的请求传递给下一个过滤器,如果此过滤器已经是过滤器链中的最后一个过滤器,那么,请求将传送给目标资源。
3、过滤器的创建与配置
示例:实现网站访问计数器的功能,并在web.xml文件中配置。
首先,创建名称为CountFilter的类,如下:
public class CountFilter implements Filter {
// 来访数量
private int count;
public void init(FilterConfig filterConfig) throws ServletException {
String param = filterConfig.getInitParameter("count"); // 获取初始化参数
count = Integer.valueOf(param); // 将字符串转换为int
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
count++;
// 将ServletRequest转换成HttpServletRequest
HttpServletRequest req = (HttpServletRequest)request;
// 获取ServletContext
ServletContext context = req.getSession().getServletContext();
context.setAttribute("count", count);
chain.doFilter(request, response);
}
public void destroy() {
}
}
然后在web.xml中配置CountFilter对象,注意filter配置要放在servlet配置之前:
<filter>
<filter-name>CountFilter</filter-name>
<filter-class>com.xiaoxiaoyusheng.filter.CountFilter</filter-class>
<init-param>
<param-name>count</param-name>
<param-value>5000</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CountFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>
创建index.jsp页面,在该页面中通过JSP内置对象Application获取计数器的值。
<html>
<body>
<h2>hello<br>
[<%=application.getAttribute("count") %>>]
</h2>
</body>
</html>
然后就可以启动程序,运行于Servlet容器中。
4、字符编码过滤器
在Java Web程序开发中,由于Web容器内部所使用的编码格式并不支持中文字符集,所以,处理浏览器请求中的中文数据就会出现乱码现象,通过过滤器来处理字符编码,可以很方便地解决这个问题,在Web应用中部署了字符编码过滤器以后,即使Web容器的编码格式不支持中文,但浏览器的每一次请求都会经过过滤器进行转码,所以可以完全避免中文乱码现象的产生。
字符编码过滤器的示例如下:
public class CharactorFilter implements Filter {
String encoding = null;
public void destroy() {
encoding = null;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (encoding != null) {
request.setCharacterEncoding(encoding); // 设置request的编码格式
response.setContentType("text/xml;charset="+encoding); // 设置response字符编码
}
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
encoding = filterConfig.getInitParameter("encoding"); // 获取初始化参数
}
}
配置如下:
<filter>
<filter-name>CharactorFilter</filter-name>
<filter-class>com.xiaoxiaoyusheng.filter.CharactorFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharactorFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(二)、监听器
在Servlet技术中已经定义了一些事件,并且可以针对这些事件来编写相关的事件监听器,从而对事件做出相应处理。监听器的作用是监听Web容器的有效期事件,因此它是由容器管理的。利用Listener接口监听在容器中的某个执行程序,并且根据其应用程序的需要做出适应的响应。如下是Servlet和JS中的8个Listener接口和6个Event类:
Servlet监听器的原理比较类似Java的GUI程序的监听器,可以监听由于Web应用中状态改变而引起的Servlet容器产生的相应事件,然后接受并处理这些事件。
1、Servlet上下文监听
Servlet上下文监听可以监听ServletContext对象的创建、删除以及属性添加、删除和修改操作,
该监听器需要用到如下两个接口:
(1)、ServletContextListener接口
该接口主要用来监听ServletContext的创建和删除。主要提供了两个方法,被称为“Web应用程序的生命周期方法”,如下:
【】contextInitialized(ServletContextEvent event) : 通知正在收听的对象,应用程序已经被加载和初始化。
【】contextDestroyed(ServletContextEvent event): 通知正在收听的对象,应用程序已经被载出,即关闭。
(2)、ServletAttributeListener接口
该接口主要实现监听ServletContext属性的增加、删除和修改。主要有如下方法:
【】attributeAdded(ServletContextAttributeEvent event):当有对象加入Application的范围时,通知正在收听的对象。
【】attributeReplaced(ServletContextAttributeEvent event) : 当在Application的范围有对象取代另一个对象时,通知正在收听的对象。
【】attributeRemoved(ServletContextAttributeEvent event) : 当有对象从Application的范围移除时,通知正在收听的对象。
示例:先创建监听器,然后在web.xml文件中使用<listener>元素来配置监听器类。
2、HTTP会话监听
HTTP会话监听(HttpSession)信息,有4个接口可以进行监听:
(1)HttpSessionListener接口
该接口监听HTTP会话创建、销毁,有如下方法:
【】sessionCreated(HttpSessionEvent event) : 通知正在收听的对象,session已经被加载及初始化。
【】sessionDestoryed(HttpSessionEvent event): 通知正在收听的对象,session已经被载出。
(2)HttpSessionActivationListener接口
该接口实现监听HTTP会话active和passivate。有如下方法:
【】sessionDidActivate(HttpSessionEvent event) : 通知正在收听的对象,它的Session已经变为有效状态;
【】sessionWillPassivate(HttpSessionEvent event) : 通知正在收听的对象,它的session已经变为无效状态;
(3)HttpBindingListener接口
该接口实现监听HTTP会话中对象的绑定信息。它是唯一不需要在web.xml中设置Listener的,有如下方法:
【】valueBound(HttpSessionBindingEvent event) : 当有对象加入session的范围时会被自动调用;
【】valueUnBound(HttpSessionBindingEvent event) : 当有对象从session的范围内移除时会被自动调用;
(4)HttpSessionAttributeListener接口
该接口实现监听HTTP会话中属性的设置请求,方法如下:
【】attributeAdded(HttpSessionBindingEvent event) : 当有对象加入session的范围时,通知正在收听的对象;
【】attributeReplaced(HttpSessionBindingEvent event) : 当有对象从session的范围移除时,通知正在收听的对象。
3、Servlet请求监听
Servlet2.4规范中新增加了可以监听客户端的请求。
(1)、ServletRequestListener接口
该接口提供两个方法:
【】requestInitalized(ServletRequestEvent event) : 通知正在收听的对象,ServletRequest已经被加载及初始化;
【】requestDestroyed(ServletRequestEvent event) : 通知正在收听的对象,ServletRequest已经被载出,即关闭。
(2)、ServletRequestAttributeListener接口
该接口提供三个方法:
【】attributeAdded(ServletRequestAttributeEvent event) : 当有对象加入request的范围,通知正在收听的对象;
【】attributeReplaced(ServletRequestAttributeEvent event) : 当在request的范围内有对象取代另一个对象时,通知正在收听的对象;
【】attributeRemoved(ServletRequestAttributeEvent event) : 当有对象从request的范围移除时,通知正在收听的对象。
三、Servlet3.0新特性
Servlet3.0引入若干个重要的新特性,这些新内容的添加是Servlet技术逐渐完善的一个体现。
(一)、新增注解
Servlet3.0中,通过使用注解就无须在web.xml文件中对Servlet或者过滤器进行配置。Servlet 3.0 新增的注释有@WebServlet、@WebFilter、@WebListener和@WebInitParam等。
1、@WebServlet
@WebServlet注解定义在Servlet的类声明之前,用于定义Servlet组件。@WebServlet注解包含的主要属性如下:
2、@WebFilter
@WebFilter注解用于声明过滤器,该注解将会在部署时被容器处理,容器根据具体的属性配置将相应的类部署为过滤器。主要属性如下:
3、@WebListener
该注解用于声明监听器,还可以用于充当给定Web应用上下文中各种Web应用事件的监听器的类。可以使用@WebListener来标注一个实现ServletContextListener、ServletContextAttributeListener、ServletRequestListener、ServletRequestAttributeListener、HttpSessionListener和HttpSessionAttributeListener的类。
4、@WebInitParam
该注释等价于web.xml文件中的<servlet>和<filter>的<init-param>子标签,该注解通常不单独使用,而是配合@WebServlet或者@WebFilter使用。它的作用是为Servlet或者过滤器指定初始化参数。其包含的常用属性有:
用法示例:
@WebServlet(urlPatterns={"/simple"}, name="SimpleServlet",
initParams={@WebInitParam(name="username", value="tom")})
public class SimpleServlet extends HttpServlet {
...//
}
(二)、对文件上传的支持
在Servlet3.0之前,处理文件上传需要借助第三方组件,Servlet3.0之后可以很方便地处理文件上传。
实现文件上传需要以下两项内容:需要添加@MultipartConfig注释, 从request对象中获取Part文件对象。
@MultipartConfig注解需要标注在@WebServlet注解之上。其属性如下所示:
此外,需要用到request请求中的两个方法,getPart()与getParts()方法:
【】Part getPart(String name); // 获取请求中的文件,name参数表示请求的name文件
【】Collection<Part> getParts(); // 获取请求中的所有文件。
示例:应用Servlet实现文件上传:
实现上传的jsp页面:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!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=ISO-8859-1">
<title>upload test</title>
</head>
<body>
<form action="UploadServlet" enctype="multipart/form-data" method="post">
select file<input type="file" name="file1" id="file1" />
<input type="submit" name="upload" value="upload" />
</body>
</html>
实现处理上传的Servlet:
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import org.apache.catalina.core.ApplicationPart;
@WebServlet("/UploadServlet")
@MultipartConfig(location="d:/tmp")
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String path = this.getServletContext().getRealPath("/"); // 获取服务器地址
Part p = request.getPart("file1"); // 获取用户选择的上传文件
if (p.getContentType().contains("image")) { // 仅处理上传的图像文件
ApplicationPart ap = (ApplicationPart)p;
String fname1 = ap.getSubmittedFileName(); // 获取上传文件名
int path_idx = fname1.lastIndexOf("\\") + 1; // 对上传文件名进行截取
String fname2 = fname1.substring(path_idx, fname1.length());
p.write(path + "/upload/" + fname2); // 写入Web项目根路径下的upload文件夹中
out.write("文件上传成功");
} else {
out.write("请选择图片文件!!!");
}
}
}
运行程序,上传的文件会被存放在webService中的upload目录下。
(三)、异步处理
在Servlet 3.0之前,一个Servlet的工作流程是:首先,Servlet接收到请求后,需要对请求携带的数据进行一些预处理。接着调用业务接口的某些方法,以完成业务处理,最后,根据处理的结果提交响应,至此,Servlet线程结束。在此过程中,如果任何一个任务没有结束,Servlet线程就处于阻塞状态,直到业务方法执行完毕。对于较大的应用,很容易造成程序性能的降低。
Servlet 3.0之后,异步处理机制可以将之前的Servlet处理流程调整为以下过程,首先,Servlet接收到请求之后,可能需要对请求携带的数据进行一些预处理;接着Servlet线程将请求转交给一个异步线程来执行业务处理,线程本身返回至容器,此时Servlet还没有生成响应数据,异步线程处理完业务之后,可以直接生成响应数据,或者将请求继续转发给其他Servlet。这样,Servlet线程不再是一直处于阻塞状态以等待业务逻辑的处理,而是启动异步之后可以立即返回。
注:异步处理机制可以应用于Servlet和过滤器两种组件,在默认情况下,这两种组件并没有开启异步处理特性,如果希望使用该特性,必须按如下的方法启用:
【】@WebServlet 和@WebFilter注解提供了asyncSupported属性,默认该属性的取值为false,要启用异步处理支持,只需将该属性设置为true即可,例如:
@WebFilter(urlPatterns="/chFilter", asyncSupported=true)
public class DemoFilter implements Filter {
... // 省略了过滤器实现代码
}
【】如果选择在web.xml文件中对Servlet或者过滤器进行配置,可以在 Servlet 3.0 为<servlet>和<filter>标签中增加<async-supported>子标签,该标签的默认取值为false,要启用异步处理支持,则将其设为true即可。例如:
<servlet>
<servlet-name>CharServlet</servlet-name>
<servlet-class>footmark.servlet</servlet-class>
<async-supported>true</async-supported>
</servlet>