Servlet 3.0中引入了若干个重要的新特性,例如新增的注释、异步处理、可插型支持等内容。这些内容的添加是Servlet技术逐渐完善的一个体现。
1、新增注释
Servlet 3.0中的重大革新之一。通过使用注释就无需在web.xml文件中对Servlet或者过滤器进行配置。Servlet 3.0新增的注释有@WebServlets、@WebFilter、@WebListener、@WebInitParam等。
1.1 @WebServlet注释
@WebServlet注释定义在Servlet的类声明之前,用于定义Servlet组件。使用该注释,就无须再 web.xml 文件中对Servlet进行配置。@WebServlet注释包含很多属性。
@WebServlet注释主要属性列表:
属性名 | 类型 | 描述 |
---|---|---|
name | String | 指定Servlet的name属性,等价于<servlet-name>标签。如果没有显示指定,则该Servlet的取值即为类的全限定名。 |
value | String[] | 该属性等价于urlPatterns属性。两个属性不能同时使用。 |
urlPatterns | String[] | 指定一组Servlet的URL匹配模式,等价于<url-pattern>标签。 |
loadOnStartup | int | 指定Servlet的加载顺序,等价于<load-on-startup>标签。 |
initParams | WebInitParam[] | 指定一组Servlet初始化参数,等价于<init-param>标签。 |
asyncSupported | boolean | 声明Servlet是否支持异步操作,等价于<async-supported>标签。 |
smallIcon | String | 此Servlet的小图标。 |
largeIcon | String | 此Servlet的大图标。 |
description | String | 该Servlet的描述信息,等价于<description>标签。 |
displayName | String | 该Servlet的显示名,通常配合工具使用,等价于<display-name>标签。 |
示例:使用Servlet实现用户注册功能。
(1)创建index.jsp页面。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户注册</title>
</head>
<body>
<div>请输入注册信息
<form name="form1" method="post" action="servlet/RegServlet">
<table border="0" >
<tr>
<td>姓名:</td>
<td><input type="text" name="name"/></td>
</tr>
<tr>
<td>年龄:</td>
<td><input type=text name="age"/></td>
</tr>
<tr>
<td>性别:</td>
<td>
<select name = "sex">
<option value="男" selected="selected">男</option>
<option value="女">女</option>
</select>
</td>
</tr>
<!-- 以下是提交、取消按钮 -->
<tr>
<td>
<input type="submit" value="提交" />
</td>
<td>
<input type="reset" value="取消" />
</td>
</tr>
</table>
</form>
</div>
</body>
</html>
(2)创建名为RegServlet的Servlet类。该类继承HttpServlet类,并应用@WebServlet注释,配置Servlet的name属性与urlPatterns属性。
package com.pjb.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 用户注册Servlet类
*
* @author pan_junbiao
*
*/
@WebServlet(name = "RegServlet", urlPatterns = "/servlet/RegServlet")
public class RegServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// 设置request的编码
request.setCharacterEncoding("UTF-8");
// 获取信息
String name = request.getParameter("name");
String age = request.getParameter("age");
String sex = request.getParameter("sex");
// 设置response的编码
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
// 获取PrintWriter对象
PrintWriter out = response.getWriter();
// 输出信息
out.println("<HTML>");
out.println("<HEAD><TITLE>注册信息</TITLE></HEAD>");
out.println("<BODY>");
out.println("姓名:" + name + "<br>");
out.println("年龄:" + age + "<br>");
out.println("性别:" + sex + "<br>");
out.println("</BODY>");
out.println("</HTML>");
// 释放PrintWriter对象
out.flush();
out.close();
}
}
说明:使用@WebServlet注释,配置Servlet的name属性与urlPatterns属性,如下代码:
@WebServlet(name = "RegServlet", urlPatterns = "/servlet/RegServlet")
这样配置完成后,就不必在 web.xml 文件中配置相应的<servlet>和<servlet-mapping>元素了。与上面的代码等价的 web.xml 文件的配置如下:
<servlet>
<servlet-name>RegServlet</servlet-name>
<servlet-class>com.pjb.servlet.RegServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegServlet</servlet-name>
<url-pattern>/servlet/RegServlet</url-pattern>
</servlet-mapping>
执行结果:
(1)注册页面 index.jsp。
(2)提交注册结果信息。
1.2 @WebFilter注释
@WebFilter注释用于声明过滤器,该注释将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。
@WebFilter注释主要属性列表:
属性名 | 类型 | 描述 |
---|---|---|
filterName | String | 指定过滤器的name属性,等价于<filter-name>标签。 |
value | String[] | 该属性等价于urlPatterns属性,但是两者不应该同时使用。 |
urlPatterns | String[] | 指定一组过滤器的URL匹配模式,等价于<url-pattern>标签。 |
servletNames | String[] | 指定过滤器将应用于哪些Servlet,是@WebServlet中的name属性的取值,或者是web.xml文件中的<servlet-name>标签的取值。 |
initParams | WebInitParam[] | 指定一组过滤器初始化参数,等价于<init-param>标签。 |
asyncSupported | boolean | 声明过滤器是否支持异步操作模式,等价于<async-supported>标签。 |
description | String | 该过滤器的描述信息,等价于<description>标签。 |
displayName | String | 该过滤器的显示名,通常配合工具使用,等价于<display-name>标签。 |
dispatcherTypes | DispatcherType[] | 指定过滤器的转发模式。具体取值包括:ASYNC、ERROR、FORWARD、INCLUDE 和 REQUEST。 |
示例:创建过滤器,使用@WebFilter注释进行配置。
@WebFilter(filterName = "char", urlPatterns = "/*")
public class CharFilter implements Filter
{
// 省略了过滤器中间的代码
}
如此配置之后,就不需要在 web.xml 文件中配置相应的<filter>和<filter-mapping>元素了,容器会在部署时根据指定的属性将该类发布为过滤器。使用@WebFilter注释,等价于在 web.xml 文件中进行如下配置:
<filter>
<filter-name>char</filter-name>
<filter-class>CharFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>char</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
1.3 @WebListener注释
@WebListener注释用于声明监听器,该注释用于充当给定web应用上下文中各种web应用事件的监听器的类。可以使用@WebListener来标注一个实现:ServletContextListener、ServletContextAttributeListener、ServletRequestListener、ServletRequestAttributeListener、HttpSessionListener、HttpSessionAttributeListener的类。@WebListener注释有一个value的属性,该属性为可选属性,用于描述监听器信息。使用该注释就不需要在 web.xml 文件中配置<listener>标签了。
示例:使用@WebListener注释,创建监听器。
@WebListener("监听器的描述信息")
public class MyContextListener implements ServletContextListener
{
// 省略了监听器中间的代码
}
这样配置完成后,就不必在 web.xml 文件中配置相应的<listener>元素了。与上面的代码等价的 web.xml 文件的配置如下:
<listener>
<listener-class>MyContextListener</listener-class>
</listener>
1.4 @WebInitParam注释
@WebInitParam注释等价于web.xml文件中的<servlet>和<filter>的<init-param>子标签,该注释通常不单独使用,而是配合@WebServlet或者@WebFilter使用。
@WebInitParam注释主要属性列表:
属性名 | 类型 | 描述 |
---|---|---|
name | String | 指定参数的名字,等价于<param-name>标签,必填项。 |
value | String | 指定参数的值,等价于<param-value>标签,必填项。 |
description | String | 关于参数的描述,等价于<description>标签,非必填项。 |
示例:应用@WebInitParam注释配置初始化参数。
package com.pjb.servlet;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
@WebServlet(urlPatterns = { "/simple" }, name = "SimpleServlet",
initParams = { @WebInitParam(name = "username", value = "pan_junbiao") })
public class SimpleServlet extends HttpServlet
{
// 省略了Servlet中间的代码
}
这样配置完成后,就不必在 web.xml 文件中配置相应的<servlet>和<servlet-mapping>元素了。与上面的代码等价的 web.xml 文件的配置如下:
<servlet>
<servlet-name>SimpleServlet</servlet-name>
<servlet-class>com.pjb.servlet.SimpleServlet</servlet-class>
<init-param>
<param-name>username</param-name>
<param-value>pan_junbiao</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SimpleServlet</servlet-name>
<url-pattern>/simple</url-pattern>
</servlet-mapping>
2、对文件上传的支持
在Servlet3.0出现之前,处理文件上传是一件很麻烦的事情,因为要借助第三方组件,例如commons fileupload等。而Servlet3.0出现以后就摆脱了这一问题。使用Servlet3.0可以十分方便的实现文件的上传。实现文件上传需要以下两项内容:
(1)需要添加@MultipartConfig注释。
(2)从request对象中获取Part文件对象。
@MultipartConfig注释需要标注在@WebServlet注释之上。
@MultipartConfig注释主要属性列表:
属性名 | 类型 | 描述 |
---|---|---|
fileSizeThreshold | int | 当数据量大于该值时,内容将被写入文件。 |
location | String | 存放生成的文件地址。 |
maxFileSize | long | 允许上传的文件最大值。默认值为-1,标识没有限制。 |
maxRequestSize | long | 针对该multipart/form-data请求的最大数量,默认值为-1,表示没有限制。 |
除了要配置@MultipartConfig注释之外,还需要两个重要的方法,即:getPart(String name)与getParts()方法。
Part getPart(String name)
Collection<Part> getParts()
getPart(String name)方法的name参数表示请求的表单的name文件。getParts()方法可获取请求中的所有文件。上传文件用 javax.servlet.http.Part 对象来表示。Part 接口提供了处理文件的简易方法,如:write(String fileName)、delete()等。
示例:应用Servlet实现文件上传。
(1)编写具有上传文件组件的JSP页面。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<form action="UploadServlet" enctype="multipart/form-data" method="post">
选择文件:<input type="file" name="file1" id="file1">
<input type="submit" name="btnUpload" value="上传" />
</form>
</body>
</html>
(2)编写处理上传文件的Servlet,在该Servlet中对上传文件进行控制。
package com.pjb.servlet;
import java.io.File;
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;
/**
* 文件上传Servlet类
*
* @author pan_junbiao
*
*/
@WebServlet("/UploadServlet")
@MultipartConfig
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")) // 仅处理上传的图片文件
{
String fname1 = p.getSubmittedFileName(); // 获取上传文件的名称
String fileName = path + "/upload/" + fname1; // 上传文件的路径和文件名称
File file = new File(fileName);
File parentFile = file.getParentFile();
if (!parentFile.exists()) // 如果文件夹不存在,则创建该文件夹
{
parentFile.mkdir();
}
p.write(fileName); // 写入文件
out.write("文件上传成功");
} else
{
out.write("请选择图片文件!");
}
}
}
执行结果:
运行本程序,选择上传文件后,如果上传文件是图片文件,点击“上传”按钮后,即可实现文件上传。
3、异步处理
异步处理是 Servlet3.0最重要的内容之一。在此之前,一个Servlet的工作流程是:首先,Servlet接收到请求后,需要对请求携带的数据进行一些预处理。接着调用业务接口的某些方法,以完成业务处理。最后,根据处理的结果提交响应,至此,Servlet线程结束。在此过程中,如果任何一个任务没有结束,Servlet线程就处于阻塞转态,直到业务方法执行完毕。对于较大的应用,很容易造成程序性能的降低。
Servlet3.0针对这一问题做了突破性的工作,现在通过使用 Servlet3.0的异步处理机制可以将之前的Servlet处理流程调整为以下过程。首先,Servlet接收到请求之后,可能需要对请求携带的数据进行一些预处理;接着Servlet线程将请求转交给一个异步线程来执行业务处理,线程本身返回至容器,此时Servlet还没有生成响应数据,异步线程处理完业务之后,可以直接生成响应数据,或者将请求继续转发给其它Servlet。这样,Servlet线程不再是一直处于阻塞状态以等待业务逻辑的处理,而是启动异步之后可以立即返回。
异步处理机制可以应用于Servlet和过滤器两种组件,由于异步处理的工作模式与普通工作模式有着本质的区别,在默认情况下,并没有开启异步处理特性,如果希望使用该特性,则必须按如下的方法启用:
3.1 使用asyncSupported属性
@WebServlet和@WebFilter注释提供了asyncSupported属性,默认该属性的取值为false,要启用异步处理支持,只需将该属性设置为true即可。
示例:@WebServlet和@WebFilter注释实现设置异步处理。
@WebFilter(urlPatterns = { "/chFilter" }, asyncSupported = true)
public class DemoFilter implements Filter
{
// 省略了过滤器实现代码
}
3.2 通过在web.xml文件中配置<async-supported>子标签
如果实现选择在web.xml文件中对Servlet或者过滤器进行配置,可以在Servlet 3.0为<servlet>和<filter>标签增加了<async-supported>子标签,该标签的默认取值为false,要启用异步处理支持,则将其设为true即可。
示例:在web.xml文件中配置异步处理。
<servlet>
<servlet-name>CharServlet</servlet-name>
<servlet-class>com.pjb.servlet.CharServlet</servlet-class>
<async-supported>true</async-supported>
</servlet>