Servlet3.0中Servlet的使用
目录
1.注解配置
2.异步调用
3.文件上传
相对于之前的版本,Servlet3.0中的Servlet有以下改进:
l 支持注解配置。
l 支持异步调用。
l 直接有对文件上传的支持。
在这篇文章中我将主要讲这三方面的应用示例。
1.注解配置
在以往我们的Servlet都需要在web.xml文件中进行配置(Servlet3.0同样支持),但是在Servlet3.0中引入了注解,我们只需要在对应的Servlet类上使用@WebServlet注解进行标记,我们的应用启动之后就可以访问到该Servlet。对于一个@WebServlet而言,有一个属性是必须要的,那就是它的访问路径。@WebServlet中有两个属性可以用来表示Servlet的访问路径,分别是value和urlPatterns。value和urlPatterns都是数组形式,表示我们可以把一个Servlet映射到多个访问路径,但是value和urlPatterns不能同时使用。如果同时使用了value和urlPatterns,我们的Servlet是无法访问到的。下面是一个使用@WebServlet的简单Servlet示例。
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * * Servlet3.0支持使用注解配置Servlet。我们只需在Servlet对应的类上使用@WebServlet进行标注, * 我们就可以访问到该Servlet了,而不需要再在web.xml文件中进行配置。@WebServlet的urlPatterns * 和value属性都可以用来表示Servlet的部署路径,它们都是对应的一个数组。 */ @WebServlet(name="exampleServlet", urlPatterns="/servlet/example") public class ExampleServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().write("Hello User."); } }
使用@WebServlet时也可以配置初始化参数,它是通过@WebServlet的initParams参数来指定的。initParams是一个@WebInitParam数组,每一个@WebInitParam代表一个初始化参数。
import java.io.IOException; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 带初始化参数的Servlet * WebServlet的属性initParams可以用来指定当前Servlet的初始化参数,它是一个数组, * 里面每一个@WebInitParam表示一个参数。 */ @WebServlet(value="/servlet/init-param", initParams={@WebInitParam(name="param1", value="value1")}) public class WebInitParamServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Enumeration<String> paramNames = this.getServletConfig().getInitParameterNames(); String paramName; while (paramNames.hasMoreElements()) { paramName = paramNames.nextElement(); resp.getWriter().append(paramName + " = " + this.getServletConfig().getInitParameter(paramName)); } resp.getWriter().close(); } }
2.异步调用
在Servlet3.0中,在Servlet内部支持异步处理。它的逻辑是当我们请求一个Servlet时,我们的Servlet可以先返回一部分内容给客户端。然后在Servlet内部异步处理另外一段逻辑,等到异步处理完成之后,再把异步处理的结果返回给客户端。这意味着当我们的Servlet在处理一段比较费时的业务逻辑时,我们可以先返回一部分信息给客户端,然后异步处理费时的业务,而不必让客户端一直等待所有的业务逻辑处理完。等到异步处理完之后,再把对应的处理结果返回给客户端。
异步调用是通过当前HttpServletRequest的startAsync()方法开始的,它返回一个AsyncContext。之后我们可以调用AsyncContext的start()方法来新起一个线程进行异步调用。在新线程内部程序的最后我们最好是调用一下当前AsyncContext的complete()方法,否则异步调用的结果需要等到设置的超时时间过后才会返回到客户端。另外当异步调用超时以后会接着调用异步任务,即新起的线程。
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.AsyncContext; 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 * 对于Servlet的异步返回,首先我们必须指定@WebServlet的asyncSupported属性为true(默认是false),同时在它之前的Filter * 的asyncSupported属性也必须是true,否则传递过来的request就是不支持异步调用的。 * */ @WebServlet(value="/servlet/async", asyncSupported=true) public class AsyncServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/plain;charset=UTF-8"); final PrintWriter writer = resp.getWriter(); writer.println("异步之前输出的内容。"); writer.flush(); //开始异步调用,获取对应的AsyncContext。 final AsyncContext asyncContext = req.startAsync(); //设置超时时间,当超时之后程序会尝试重新执行异步任务,即我们新起的线程。 asyncContext.setTimeout(10*1000L); //新起线程开始异步调用,start方法不是阻塞式的,它会新起一个线程来启动Runnable接口,之后主程序会继续执行 asyncContext.start(new Runnable() { @Override public void run() { try { Thread.sleep(5*1000L); writer.println("异步调用之后输出的内容。"); writer.flush(); //异步调用完成,如果异步调用完成后不调用complete()方法的话,异步调用的结果需要等到设置的超时 //时间过了之后才能返回到客户端。 asyncContext.complete(); } catch (Exception e) { e.printStackTrace(); } } }); writer.println("可能在异步调用前输出,也可能在异步调用之后输出,因为异步调用会新起一个线程。"); writer.flush(); } }
对于一个Servlet如果要支持异步调用的话我们必须指定其asyncSupported属性为true(默认是false)。使用@WebServlet注解标注的Servlet我们可以直接指定其asyncSupported属性的值为true,如:
@WebServlet(value=”/servlet/async”, asyncSupported=true)。而对于在web.xml文件中进行配置的Servlet来说,我们需要在配置的时候指定其asyncSupported属性为true。
<servlet> <servlet-name>xxx</servlet-name> <servlet-class>xxx</servlet-class> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>xxx</servlet-name> <url-pattern>xxx</url-pattern> </servlet-mapping>
Servlet的异步调用程序的关键是要调用当前HttpServletRequest的startAsync()方法。至于利用返回的AsyncContext来新起一个线程进行异步处理就不是那么的必须了,因为在HttpServletRequest startAsync()之后,我们可以自己新起线程进行异步处理。
@WebServlet(value="/servlet/async", asyncSupported=true) public class AsyncServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/plain;charset=UTF-8"); final PrintWriter writer = resp.getWriter(); writer.println("异步之前输出的内容。"); writer.flush(); //开始异步调用,获取对应的AsyncContext。 final AsyncContext asyncContext = req.startAsync(); //设置超时时间,当超时之后程序会尝试重新执行异步任务,即我们新起的线程。 asyncContext.setTimeout(10*1000L); Runnable r = new Runnable() { @Override public void run() { try { Thread.sleep(5*1000L); writer.println("异步调用之后输出的内容。"); writer.flush(); //异步调用完成 asyncContext.complete(); } catch (Exception e) { e.printStackTrace(); } } }; Thread t = new Thread(r); //开启自己的线程进行异步处理 t.start(); writer.println("可能在异步调用前输出,也可能在异步调用之后输出,因为异步调用会新起一个线程。"); writer.flush(); } }
异步调用监听器
当我们需要对异步调用做一个详细的监听的时候,比如监听它是否超时,我们可以通过给AsyncContext设置对应的监听器AsyncListener来实现这一功能。AsyncListener是一个接口,里面定义了四个方法,分别是针对于异步调用开始、结束、出错和超时的。
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; 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 * 对于Servlet的异步返回,首先我们必须指定@WebServlet的asyncSupported属性为true(默认是false),同时在它之前的Filter * 的asyncSupported属性也必须是true,否则传递过来的request就是不支持异步调用的。 * */ @WebServlet(value="/servlet/async2", asyncSupported=true) public class AsyncServlet2 extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/plain;charset=UTF-8"); final PrintWriter writer = resp.getWriter(); writer.println("异步之前输出的内容。"); writer.flush(); //开始异步调用,获取对应的AsyncContext。 final AsyncContext asyncContext = req.startAsync(); //设置当前异步调用对应的监听器 asyncContext.addListener(new MyAsyncListener()); //设置超时时间,当超时之后程序会尝试重新执行异步任务,即我们新起的线程。 asyncContext.setTimeout(10*1000L); //新起线程开始异步调用,start方法不是阻塞式的,它会新起一个线程来启动Runnable接口,之后主程序会继续执行 asyncContext.start(new Runnable() { @Override public void run() { try { Thread.sleep(5*1000L); writer.println("异步调用之后输出的内容。"); writer.flush(); //异步调用完成 asyncContext.complete(); } catch (Exception e) { e.printStackTrace(); } } }); writer.println("可能在异步调用前输出,也可能在异步调用之后输出,因为异步调用会新起一个线程。"); writer.flush(); } /** * 异步调用对应的监听器 * @author Yeelim * @date 2014-2-8 * @mail yeelim-zhang@todaytech.com.cn */ private class MyAsyncListener implements AsyncListener { @Override public void onComplete(AsyncEvent event) throws IOException { System.out.println("异步调用完成……"); event.getSuppliedResponse().getWriter().println("异步调用完成……"); } @Override public void onError(AsyncEvent event) throws IOException { System.out.println("异步调用出错……"); event.getSuppliedResponse().getWriter().println("异步调用出错……"); } @Override public void onStartAsync(AsyncEvent event) throws IOException { System.out.println("异步调用开始……"); event.getSuppliedResponse().getWriter().println("异步调用开始……"); } @Override public void onTimeout(AsyncEvent event) throws IOException { System.out.println("异步调用超时……"); event.getSuppliedResponse().getWriter().println("异步调用超时……"); } } }
注:
对于正常执行的异步调用而言上述代码中开始是没有监听到的,只有在异步调用超时,重新执行异步任务的时候才有监听到异步调用的开始。不过如果需要监听异步第一次开始的话,我们可以在异步调用开始的时候做相应的监听器监听到异步调用开始时需要做的内容。
3.文件上传
在Servlet3.0中上传文件变得非常简单。我们只需通过request的getPart(String partName)获取到上传的对应文件对应的Part或者通过getParts()方法获取到所有上传文件对应的Part。之后我们就可以通过part的write(String fileName)方法把对应文件写入到磁盘。或者通过part的getInputStream()方法获取文件对应的输入流,然后再对该输入流进行操作。要使用request的getPart()或getParts()方法对上传的文件进行操作的话,有两个要注意的地方。首先,用于上传文件的form表单的enctype必须为multipart/form-data;其次,对于使用注解声明的Servlet,我们必须在其对应类上使用@MultipartConfig进行标注,而对于在web.xml文件进行配置的Servlet我们也需要指定其multipart-config属性,如:
<servlet> <servlet-name>xxx</servlet-name> <servlet-class>xxx.xxx</servlet-class> <multipart-config></multipart-config> </servlet> <servlet-mapping> <servlet-name>xxx</servlet-name> <url-pattern>/servlet/xxx</url-pattern> </servlet-mapping>
不管是基于注解的@MultipartConfig,还是基于web.xml文件配置的multipart-config,我们都可以给它们设置几个属性。
l file-size-threshold:数字类型,当文件大小超过指定的大小后将写入到硬盘上。默认是0,表示所有大小的文件上传后都会作为一个临时文件写入到硬盘上。
l location:指定上传文件存放的目录。当我们指定了location后,我们在调用Part的write(String fileName)方法把文件写入到硬盘的时候可以,文件名称可以不用带路径,但是如果fileName带了绝对路径,那将以fileName所带路径为准把文件写入磁盘。
l max-file-size:数值类型,表示单个文件的最大大小。默认为-1,表示不限制。当有单个文件的大小超过了max-file-size指定的值时将抛出IllegalStateException异常。
l max-request-size:数值类型,表示一次上传文件的最大大小。默认为-1,表示不限制。当上传时所有文件的大小超过了max-request-size时也将抛出IllegalStateException异常。
上面的属性是针对于web.xml中配置Servlet而言的,其中的每一个属性都对应了multipart-config元素下的一个子元素。对于基于注解配置的Servlet而言,@MultipartConfig的属性是类型的,我们只需把上述对应属性中间的杠去掉,然后把对应字母大写即可,如maxFileSize。
下面给出Servlet3.0中文件上传的一个示例。
Html:
<form method="post" action="servlet/upload" enctype="multipart/form-data"> <input type="file" name="upload"/> <input type="submit" value="upload"/> </form>
对应Servlet:
@WebServlet("/servlet/upload") @MultipartConfig public class FileUploadServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); Part part = req.getPart("upload"); //格式如:form-data; name="upload"; filename="YNote.exe" String disposition = part.getHeader("content-disposition"); System.out.println(disposition); String fileName = disposition.substring(disposition.lastIndexOf("=")+2, disposition.length()-1); String fileType = part.getContentType(); long fileSize = part.getSize(); System.out.println("fileName: " + fileName); System.out.println("fileType: " + fileType); System.out.println("fileSize: " + fileSize); String uploadPath = req.getServletContext().getRealPath("/upload"); System.out.println("uploadPath" + uploadPath); part.write(uploadPath + File.separator +fileName); } }
对于Servlet3.0中的文件上传还有一个需要注意的地方,当我们把Part写入到硬盘以后,我们原先的Part(也就是之前的临时文件)可能已经删了,这个时候如果我们再次去访问Part的内容的话,那它就是空的,系统会抛出异常说找不到对应的文件。
相关推荐
开发者可以通过这个文件快速查找和理解Servlet3.0中的类、接口、方法以及它们的使用示例,对于学习和使用Servlet3.0非常有帮助。 总的来说,Servlet3.0通过增强的注解配置、异步处理、过滤器改进、上下文参数和监听...
1. **注解驱动的配置**:在Servlet 3.0中,开发者可以使用注解(如`@WebServlet`, `@WebFilter`, `@WebListener`)来声明和配置Servlet、Filter和Listener,而不再需要在web.xml中进行繁琐的手动配置。这使得部署...
下载的`servlet3.0jar综合`压缩包包含了实现这些特性的关键库,对于进行Java EE 3.0开发的程序员来说是必不可少的工具。在实际开发中,结合相关的框架(如Spring MVC)和其他Java EE组件,可以构建出功能强大、易...
Servlet 3.0是Java Servlet规范的一个重要...总的来说,“servlet3.0.zip”包含的资源为开发者提供了使用Servlet 3.0规范进行Web开发的基础,通过学习和实践,开发者可以构建高效、灵活且易于维护的Java Web应用程序。
5. **生命周期管理**:Servlet3.0允许在Servlet中定义自己的初始化和销毁方法,通过`@PostConstruct`和`@PreDestroy`注解标记,这些方法会在Servlet实例化后和销毁前自动调用。 6. **嵌入式容器**:Servlet3.0支持...
文件上传通常涉及到表单提交,HTML中使用`<form>`元素的`enctype`属性设置为`multipart/form-data`来支持文件上传。在Servlet 3.0中,我们可以通过`Part`接口处理这些上传的文件。例如,以下代码展示了如何接收并...
在这个主题中,我们将深入探讨Servlet 3.0的主要特性和功能,以及提供的两个jar包——`javax.servlet-3.0-sources.jar`和`javax.servlet.jar`的作用。 首先,Servlet 3.0作为Servlet API的一个版本,引入了许多新...
在实际开发中,我们可以使用Servlet 3.0的异步特性来处理WebSocket连接的生命周期,例如在接收到新消息时,通过异步上下文将消息分发给所有在线的WebSocket连接。同时,我们还需要一个后台服务来处理聊天室的消息...
在Servlet3.0中,我们可以使用注解(@WebServlet、@WebFilter、@WebListener)来替代web.xml中的XML配置,使得部署更简洁。例如,`@WebServlet("/example")`可以直接在Servlet类上声明URL映射。 2. **异步处理**:...
最后,关于"链接.txt"、"创建MavenWeb项目Servlet3.0的模板"和"Idea安装插件"这三个文件,它们可能是教程的补充资料。"链接.txt"可能包含其他相关资源的URL;"创建MavenWeb项目Servlet3.0的模板"可能是一个详细的...
【标题】"maven servlet 3.0 eclipse config video" 提供的是关于如何在Eclipse集成开发环境中配置Maven和Servlet 3.0的视频教程。这个教程旨在帮助开发者了解和掌握如何有效地利用Maven构建Java Web项目,并利用...
在这个主题中,我们将深入探讨Servlet3.0的三大关键特性:监听器(Listeners)、过滤器(Filters)的新实现方式,以及Servlet的动态注册功能。 **一、Servlet3.0监听器新特性** 在Servlet2.x版本中,监听器主要...
【标题】"Jsp/Servlet3.0 ppt和代码"涉及的是Java服务器页面(JSP)和Servlet 3.0版本的关键技术。JSP是一种动态网页技术,它允许开发者将HTML代码与Java代码混合编写,从而实现服务器端的动态内容生成。而Servlet是...
4. **jstl-impl**: 这是JSTL的实现包,包含了JSTL的具体实现,使得开发者可以在实际项目中使用JSTL的功能。在JSTL1.2版本(与Servlet3.0兼容)中,它提供了对EL(Expression Language)的扩展,使得在JSP页面上进行...
这个规范PDF文件是开发人员深入理解Servlet 3.0的核心资源,同时包含的javadoc为开发者提供了API的详细文档,便于在实际开发中查阅和使用。 1. **异步处理**:Servlet 3.0引入了异步处理能力,允许Servlet在请求...
在之前的版本中,Servlet、过滤器和监听器都需要在 web.xml 文件中进行声明式配置,而在 Servlet 3.0 中,可以利用注解来替代这些配置。这不仅减少了配置文件的复杂度,也使得代码更加简洁易读。 新增的注解包括但...
在Servlet 3.0中,开发者可以通过注解(@WebServlet、@WebFilter、@WebListener)来声明Servlet、Filter和Listener,无需再在web.xml中进行繁琐的XML配置。这简化了部署描述符的编写,提高了代码的可读性和可维护性。...
在这个"Servlet3.0 Demo"项目中,我们可以看到一个典型的使用Servlet3.0特性的示例。以下是关于Servlet3.0的一些关键知识点: 1. **注解配置**: Servlet3.0引入了注解配置,允许开发者无需在web.xml文件中进行...
Servlet 3.0是Java Web开发中的一个重要里程碑,它带来了许多新特性和改进,使得开发者在构建Web应用程序时更加高效和灵活。Apache Tomcat 7.0.61是广泛使用的开源Servlet容器,它实现了Servlet 3.0规范,提供了稳定...
Servlet3.0是Java Servlet API的一个重要版本更新,它带来了许多新特性和改进,极大地提升了Web应用程序的开发效率和灵活性。以下将详细讲解Servlet3.0的关键特性。 1. **注解驱动的配置**: 在Servlet3.0之前,...