要求
1. MyEclipse10.0或以上版本!
2. 发布到Tomcat7.0或以上版本!
3. 创建JavaEE6.0应用!
Servlete3.0的主要新特性如下三部分:
l 使用@WebServlet、@WebFilter、@WebListener三个注解来替代web.xml文件中的Servlet、Filter、Listener的配置;
l Servlet异步处理:当Servlet处理比较费时的问题时,这会让客户感觉到很卡。当使用异常处理时可以把已经处理好的内容先一步响应给客户端浏览器,然后使用另一个线程来完成费时的操作,也就是把内容一部分一部分的显示出来;
l 上传组件:不用再使用fileupload等第三方的上传组件,使用Servlet3.0的上传组件会更方便。
@WebServlet( urlPatterns={"/AServlet"}, initParams={@WebInitParam(name="paramName",value="paramValue")}, loadOnStartup=1 ) publicclass AServlet extends HttpServlet { publicvoid init(ServletConfig config) throws ServletException { System.out.println(config.getInitParameter("paramName")); } publicvoid doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); response.getWriter().print("Hello World!"); } } |
@WebFilter(urlPatterns={"/*"}, dispatcherTypes={DispatcherType.REQUEST, DispatcherType.FORWARD}) publicclass AFilter implements Filter { publicvoid destroy() {}
publicvoid doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("start filter"); chain.doFilter(request, response); System.out.println("end filter"); }
publicvoid init(FilterConfig fConfig) throws ServletException {} } |
@WebListener() publicclass AListener implements ServletContextListener { publicvoid contextDestroyed(ServletContextEvent arg0) { System.out.println("服务器关闭了"); }
publicvoid contextInitialized(ServletContextEvent arg0) { System.out.println("服务器启动了"); } } |
Servlet异步处理就是让Servlet在处理费时的请求时不要阻塞,而是一部分一部分的显示。
也就是说,在使用Servlet异步处理之后,页面可以一部分一部分的显示数据,而不是一直卡,等到请求响应结束后一起显示。
在使用异步处理之前,一定要在@WebServlet注解中给出asyncSupported=true,不然默认Servlet是不支持异步处理的。如果存在过滤器,也要设置@WebFilter的asyncSupportedt=true。
@WebServlet(urlPatterns = {"/MyServlet"}, asyncSupported=true ) publicclass MyServlet extends HttpServlet {…} |
注意,响应类型必须是text/html,所以:response.setContentType(“text/html;charset=utf-8”);
使用异步处理大致可以分为两步:
l Servlet正常响应数据;
l Servlet异常响应数据。
在Servlet正常响应数据时,没什么可说的,可通知response.getWriter().print()来向客户端输出,但输出后要使用response.getWriter().flush()刷新,不然数据只是在缓冲区中,不能向客户端发送数据的。
异步响应数据需要使用request.startAsync()方法获取AsyncContext对象。然后调用AsyncContext对象的start()方法启动异步响应,start()方法需要一个Runnable类型的参数。在Runnable的run()方法中给出异步响应的代码。
AsyncContext ac = request.startAsyncContext(request, response); ac.start(new Runnable() {…}); |
注意在异步处理线程中使用response做响应后,要使用response.getWriter().flush()来刷新流,不然数据是不能响应到客户端浏览器的。
asyncContext.start(new Runnable() { publicvoid run() { for(char i = 'a'; i <= 'z'; i++) { try { Thread.sleep(100); asyncContext.getResponse().getWriter().print(i + " "); asyncContext.getResponse().getWriter().flush(); } catch (Exception e) { e.printStackTrace(); } } asyncContext.complete(); } }); |
Tomcat需要知道异步响应是否结束,如果响应不结束,虽然客户端浏览器会看到响应的数据,但是鼠标上只是有个圈圈的不行的转啊转的,表示还没有结束响应。Tomcat会等待到超时为止,这个超时的时间可以通过AsyncContext类的getTimeout()方法获取,Tomcat默认为20000毫秒。当然也可以通过setTimeOut()方法设置,以毫秒为单位。ac.setTimeout(1000*10)。
如果异步线程已经结束了响应,那么可以在异步线程中调用AsyncContext.complete()方法,这样Tomcat就知道异步线程已经完成了工作了。
@WebServlet(urlPatterns = {"/AServlet"}, asyncSupported=true) publicclass AServlet extends HttpServlet { publicvoid doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("Servlet begin <br>"); out.println("Servlet begin <br>"); out.println("Servlet begin <br>"); out.println("Servlet begin <br>"); out.println("Servlet begin <br>"); out.println("Servlet begin <br>"); out.println("Servlet begin <br>"); out.println("Servlet begin <br>"); out.println("Servlet begin <br>"); out.println("Servlet begin <br>"); out.println("Servlet begin <br>"); out.println("Servlet begin <br>"); out.println("Servlet begin <br>"); out.println("Servlet begin <br>"); out.println("Servlet begin <br>");
out.flush(); final AsyncContext asyncContext = request.startAsync(request, response); asyncContext.setTimeout(1000 * 20); asyncContext.start (new Runnable() { publicvoid run() { try { Thread.sleep(1000); asyncContext.getResponse().getWriter().print("马上开始" + "<br/>"); asyncContext.getResponse().getWriter().flush(); Thread.sleep(2000); } catch (Exception e1) { } for(char i = 'a'; i <= 'z'; i++) { try { Thread.sleep(100); asyncContext.getResponse().getWriter().print(i + " "); asyncContext.getResponse().getWriter().flush(); } catch (Exception e) { e.printStackTrace(); } } asyncContext.complete(); } }); // asyncContext.start(businessHandleThread); // 也可以用这种方法启动异步线程 out.println("Servlet end <br>"); } } |
Servlet3.0提供了文件上传的处理方案。只需要在Servlet上添加@MultipartConfig注解即可。
Servlet3.0对上传提供了支持:
* 表单不变
* 在Servlet中不需要再使用commons-fileupload,而是使用Servlet3.0提供的上传组件接口!
==============
上传的步骤:
* 使用request.getPart("字段名"),得到Part实例,
* Part:
> String getContentType():获取上传文件的MIME类型
> String getName():获取表单项的名称,不是文件名称
> String getHeader(String header):获取指定头的值
> long getSize():获取上传文件的大小
> InputStream getInputStream():获取上传文件的内容
> void write(String fileName):把上传文件保存到指定路径下
* 默认Servlet是不支持使用上传组件:需要给Servlet添加一个注解: @MultipartConfig
它没有提供获取上传文件名称的方法:
* 这需要我们自己从Content-Disposition头中截取!
@WebServlet(urlPatterns={"/UploadServlet"}) @MultipartConfig(maxFileSize=1024) publicclass UploadServlet extends HttpServlet { … } |
当然也可以为@MultipartConfig注解指定属性值,它有四个属性:
l int filesizeThreshold:指定缓存的大小,当超出这个大小后,文件会保存到磁盘上;
l long maxFilesize:指定上传单个文件的大小限制,如果上传的谁的超出了这个大小,那么就会抛出异常;
l long maxRequestSize:指定整个表单的大小限制。
当在Servlet上使用了@MultipartConfig注解后,那么就可以使用request.getPart(“fieldName”)来获取<input:file>的内容,其中Part表示一个文件表单项。
<form action="/a1/UploadServlet" method="post" enctype="multipart/form-data"> 用户名:<input type="text" name="username"/><br/> 照 片:<input type="file" name="file1" /><br/> <input type="submit" value="提交"/> </form> |
@WebServlet(urlPatterns={"/UploadServlet"}) @MultipartConfig(maxFileSize=1024 * 1024) publicclass UploadServlet extends HttpServlet { publicvoid doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8");
String username = request.getParameter("username"); response.getWriter().print("size: " + username + "<br/>");
Part part = request.getPart("file1") ;
response.getWriter().print("size: " + part.getSize () + "<br/>"); response.getWriter().print("type: " + part.getContentType () + "<br/>"); response.getWriter().print("name: " + part.getName () + "<br/>");
String name = part.getHeader("content-disposition") ; String fileNameTmp = name.substring(name.indexOf("filename=")+10); String fileName = fileNameTmp.substring(0,fileNameTmp.indexOf("\""));
System.out.println("fileName: " + fileName);
String savepath = this.getServletContext().getRealPath("/uploads"); part.write(savepath + "/" + fileName); } } |
开启异步处理
获取异步处理上下文对象。传递request和response对象给异步上下文,可以使用异步上下文对象的getRequest()和getResponse()方法来获取request和response对象。
启动异步处理线程
给出这么之输出的原因是可爱的IE,如果你的响应内容太少时,IE是不会在浏览器上显示数据的。
要刷新流
获取异步上下文对象
设置超时时间为20秒
启动异步线程
每次响应后都要刷新一次流,这样会看到在浏览器上一个字母一个字母的出现
告诉Tomcat异步线程已经完成。这样Tomcat就会结束响应。
还是用原来方法来获取普通表单项的内容
获取文件表单项的内容,返回值为Part
打印文件的大小
打印文件的类型
打印文件表单项的filedName,而不是fileName。
获取当前文件表单项的指定头信息
获取上传文件的名称!因为Part没有提供获取fileName的方法,所以需要自己来写方法处理这一问题
把文件保存到指定路径