Servlet3.0规范是Servlet规范史上最重要的变革,它的许多特性都极大的简化了Java Web应用的开发。
Servlet 3.0新特性:
1.Servlet 3.0(规范在javax.servlet.annotation包下提供的)注解:
——@WebServlet
——@WebInitParame
——@WebListener
——@WebFilter
——@MultipartConfig :用于修饰Servlet,指定该Servlet讲负责处理 multipart/form-data类型处理(多用于文件上传)
——@ServletSecurity :与JAAS有关的注解,修饰Servlet指定该Servlet的安全与授权控制
——@HttpConstrant :与@WebSecurity 一起使用,用于指定该Servlet的安全与授权控制
——@HtppMethodConstraint: :与@WebSecurity 一起使用,用于指定该Servlet的安全与授权控制
2.Servlet 3.0的Web模块支持
注:没接触过(各位可以分享这方面经验,谢谢)
3. Servlet 3.0提供的异步处理
在以前的Servlet作为控制器调用一个耗时的业务,那么Servlet必须等待到业务方法完全返回时才会生成响应,这将使得Servlet变成一种阻塞式的调用,故效率低下。
Servlet3.0 引入异步处理,允许Servlet重新发起一条新线程去调用方法。
通过AsyncContext 类来处理的,Servlet通过ServletRequest 开启异步调用、创建AsyncContext对象
进行异步处理的Servlet类:
@WebServlet(urlPatterns = "/async", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html;charset=GBK");
PrintWriter out = response.getWriter();
out.println("<title>异步调用示例</title>");
out.println("进入Servlet的时间:" + new java.util.Date() + ".<br/>");
// 创建AsyncContext,开始异步调用
AsyncContext actx = request.startAsync();
// 设置异步调用的超时时长
actx.setTimeout(60 * 1000);
// 启动异步调用的线程,该线程以异步方式执行
actx.start(new GetBooksTarget(actx));
out.println("结束Servlet的时间:" + new java.util.Date() + ".<br/>");
out.flush();
}
}
该线程模拟调用业务方法耗时(通过睡眠):
public class GetBooksTarget implements Runnable {
private AsyncContext actx = null;
public GetBooksTarget(AsyncContext actx) {
this.actx = actx;
}
public void run() {
try {
// 等待5秒钟,以模拟业务方法的执行
Thread.sleep(5 * 1000);
ServletRequest request = actx.getRequest();
List<String> books = new ArrayList<String>();
books.add("疯狂Java讲义");
books.add("轻量级Java EE企业应用实战");
books.add("疯狂Ajax讲义");
request.setAttribute("books", books);
actx.dispatch("/async.jsp");
} catch (Exception e) {
e.printStackTrace();
}
}
}
让线程暂停5s来模拟调用业务耗时方法,最后调用AsyncContext的dispatch方法将请求dispatch到该页面。
注:被异步请求的页面需要指定 Session="false",表明该页面不会创建新的会话
<%@ page contentType="text/html; charset=GBK" language="java"
session="false"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<ul>
<c:forEach items="${books}" var="book">
<li>${book}</li>
</c:forEach>
</ul>
<%out.println("业务调用结束的时间:" + new java.util.Date());
if (request.isAsyncStarted()) {
// 完成异步调用
request.getAsyncContext().complete();
}%>
当Servlet启动异步调用的线程之后,该过程对开发者是透明的。
让我们来了解下一步处理的执行细节并对执行的结果进行针对性的处理,可借助于Servlet提供的异步监听器来实现。
需要实现AsyncListener接口,实现该接口的监听器类需要实现的方法:
——onStartAsync(AsyncEvent event)
——onComplete(AsyncEvent event)
——onError(AsyncEvent event)
——onTimeout(AsyncEvent event)
为上面的异步调用定义如下的监听器类:
public class MyAsyncListener
implements AsyncListener
{
public void onComplete(AsyncEvent event)
throws IOException
{
System.out.println("------异步调用完成------" + new Date());
}
public void onError(AsyncEvent event)
throws IOException
{}
public void onStartAsync(AsyncEvent event)
throws IOException
{
System.out.println("------异步调用开始------" + new Date());
}
public void onTimeout(AsyncEvent event)
throws IOException
{}
}
在上面的Servlet增加如下代码:
AsyncContext actx = request.startAsync();
actx.addListener(new MyAyncListener());
注:上面的应用基于servlet,但由于Filter与Servlet具有很大的相似性,3.0的规范完全支持Filter中使用异步调用,进行的效果完全相似。
4. 改进的Servlet API
Servlet 3.0其中的两个较大的改进是:
——httpServletRequest 增加对文件上传的支持
——ServletContext允许通过编程的方式动态注册Servlet、Filter。
HttpServletRequest提供两个方法来支持文件上传:
——part getPart(String name)
——Collection<Part> getParts():获取所有文件上传域
为了向服务器上传文件,需要在表单使用<inout type="file".../>;上传文件一定要表单设置enctype(数据编码)属性:
该属性有三个值:
——application/x-www-form-urlencoded: 默认方式,只处理表单域带有value属性值,将表单域的值处理成URL编码方式
——multipart/form-data: 以二进制流的方式来表单数据,会把文件域指定的文件内容也封装到请求参数里
——text/plain : 当表单的action属性值为mailto:URL的形式时比较方便,主要适用于直接通过表单发送邮件的方式
定义一个文件上传的页面:
<%@ page contentType="text/html; charset=utf-8" language="java" errorPage="" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title> 文件上传 </title>
</head>
<body>
<form method="post" action="upload" enctype="multipart/form-data">
文件名:<input type="text" id="name" name="name" /><br/>
选择文件:<input type="file" id="file" name="file" /><br/>
<input type="submit" value="上传" /><br/>
</form>
</body>
</html>
Servlet 类代码:
@WebServlet(name = "upload", urlPatterns = { "/upload" })
@MultipartConfig
public class UploadServlet extends HttpServlet {
public void service(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html;charset=GBK");
PrintWriter out = response.getWriter();
request.setCharacterEncoding("utf-8");
// 获取普通请求参数
String name = request.getParameter("name");
out.println("普通的name参数为:" + name + "<br/>");
// 获取文件上传域
Part part = request.getPart("file");
// 获取上传文件的文件类型
out.println("上传文件的的类型为:" + part.getContentType() + "<br/>");
// 获取上传文件的大小。
out.println("上传文件的的大小为:" + part.getSize() + "<br/>");
// 获取该文件上传域的Header Name
Collection<String> headerNames = part.getHeaderNames();
// 遍历文件上传域的Header Name、Value
for (String headerName : headerNames) {
out.println(headerName + "--->" + part.getHeader(headerName)
+ "<br/>");
}
// 获取包含原始文件名的字符串
String fileNameInfo = part.getHeader("content-disposition");
// 提取上传文件的原始文件名
String fileName = fileNameInfo.substring(
fileNameInfo.indexOf("filename=\"") + 10,
fileNameInfo.length() - 1);
// 将上传的文件写入服务器
part.write(getServletContext().getRealPath("/uploadFiles") + "/"
+ fileName); // ①
}
}
注:part.write(getServletContext().getRealPath("/uploadFiles") + "/" ,服务器目录已存在/uploadFiles
May-Good-Luck-Be-With-You