Servlet 3 0 新特性詳解
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
Servlet 3.0 新特性概覽
1.Servlet、Filter、Listener無需在web.xml中進行配置,可以通過Annotation進行配置;
2.模組化程式設計,即將各個Servlet模組化,將配置檔案也分開配置。
3.Servlet非同步處理,應對複雜業務處理;
4.非同步Listener,對於非同步處理的建立、完成等進行監聽;
5. 檔案上傳API簡化;
tomcat 7.0.X 支援Servlet 3.0
一、Annotation支援
1.Servlet
原本Servlet開發完後,必須在web.xml中配置如下程式碼:
<servlet> <servlet-name> </servlet-name> <servler-class></servlet-class> <load-on-startup></load-on-startup> <init-param> <param-name></param-name> <param-value ></param-value> </init-param></servlet><servlet-mapping> <servlet-name></servlet-name> <url-pattern></url-pattern></servlet-mapping>
現在只需要在java原始檔的Servlet類前面加上:
@WebServlet(name="",urlPatterns={""},initParams={@WebInitParam(name="",value=""),loadOnStartup=1})
public class FirstServlet extends HttpServlet{}
程式碼示例:
實現一個最簡單的Servlet。
package org.servlet;import java.io.*;import javax.servlet.*;import javax.servlet.http.*;import javax.servlet.annotation.*;/* name == <servlet-name> urlPatterns == <url-pattern>, loadOnStartup == <load-on-startup> initParam == <init-param> name == <param-name> value == <param-value>*/@WebServlet(name="HelloServlet" ,urlPatterns={"/HelloServlet"},loadOnStartup=1, initParams={ @WebInitParam(name="name",value="xiazdong"), @WebInitParam(name="age",value="20") })public class HelloServlet extends HttpServlet{ public void init(ServletConfig config)throws ServletException{ super.init(config); } public void service(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{ request.setCharacterEncoding("GBK"); ServletConfig config = getServletConfig(); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<body>"); out.println("Hello world"+"<br />"); out.println(config.getInitParameter("name")); out.println("</body>"); out.println("</html>"); }}
這樣的話只需要將class檔案放入WEB-INF\classes 中,不需要再web.xml中作任何改動就完成部署;
2.Filter
原本Filter的配置如下:
<filter> <filter-name></filter-name> <filter-class></filter-class><filter><filter-mapping> <filter-name></filter-name> <url-pattern></url-pattern></filter-mapping>
現在只需要在java原始檔的Filter類前面加上
@WebFilter(filterName="",urlPattern={"/"});
3.Listener
原本在web.xml中配置如下:
<listener> <listener-class></listener-class></listener>
現在只需要在java原始檔的Listener類前面加上@WebListener即可;
二、web模組化
原本一個web應用的任何配置都需要在web.xml中進行,因此會使得web.xml變得很混亂,而且靈活性差,因此Servlet 3.0可以將每個Servlet、Filter、Listener打成jar包,然後放在WEB-INF\lib中;注意各自的模組都有各自的配置檔案,這個配置檔案的名稱為 web-fragment.xml ;
製作一個Servlet模組的步驟:
1.編寫Servlet,並編譯;
2.將此編譯class檔案及所在包通過jar包命令打成jar包;
3.將此jar包用winrar開啟,並將其中的META-INF中的manifest刪除並新增 web-fragment.xml;
4.將此jar包放入WEB-INF\lib中即可;
web-fragment.xml注意點:
1.根元素為<web-fragment>;
2.<name></name>表示模組名稱;
3.<ordering></ordering>是此模組的載入順序;
4.<before><others/></before>表示第一個載入;
5.<after><name>A</name></after>表示比A後面載入;
6.可以在裡面部署listener、filter、servlet
當然可以不設定任何的模組載入順序;
程式碼示例:
配置兩個listener模組;
FirstListener.java
package org.listener;import javax.servlet.annotation.*;import javax.servlet.http.*;import javax.servlet.*;import java.util.*;import java.sql.*;import javax.naming.*;public class FirstListener implements ServletRequestListener{ public void requestInitialized(ServletRequestEvent event){ System.out.println("FirstListener created"); } public void requestDestroyed(ServletRequestEvent event){ System.out.println("FirstListener destroyed"); }}
FirstListener 的 web-fragment.xml內容:
<?xml version="1.0" encoding="ISO-8859-1"?><web-fragment xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee <A href="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"">http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <name>FirstListener</name> <listener> <listener-class>org.listener.FirstListener</listener-class> </listener> <ordering> <before> <others/> </before> </ordering></web-fragment>
SecondListener.java
package org.listener;import javax.servlet.annotation.*;import javax.servlet.http.*;import javax.servlet.*;import java.util.*;import java.sql.*;import javax.naming.*;public class SecondListener implements ServletRequestListener{ public void requestInitialized(ServletRequestEvent event){ System.out.println("SecondListener created");
} public void requestDestroyed(ServletRequestEvent event){ System.out.println("SecondListener destroyed"); }}
SecondListener的 web-fragment.xml內容是:
<?xml version="1.0" encoding="ISO-8859-1"?><web-fragment xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee <A href="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"">http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <name>SecondListener</name> <listener>
<listener-class>org.listener.SecondListener</listener-class> </listener> <ordering> <after> <name>FirstListener</name> </after> </ordering></web-fragment>
然後分別打成jar包,放入 WEB-INF\lib中即可;
隨便訪問一個web應用,然後發現 tomcat控制檯輸出:
看出先載入FirstListener,再載入SecondListener;
三、Servlet 非同步處理
Servlet在MVC中作為控制器,控制器負責分發任務給MODEL完成,然後把結果交給JSP顯示;
而如果有許多MODEL,其中有一個MODEL處理時間很長,則會導致整個頁面的顯示很慢;
非同步處理關鍵點:將複雜業務處理另外開一個執行緒,而Servlet將執行好的業務先送往jsp輸出,等到耗時業務做完後再送往JSP頁面;
一句話:先顯示一部分,再顯示一部分;
非同步處理Servlet的注意點是:
1.需要在Annotation中註明 asyncSupported=true;
package org.sync;import javax.servlet.*;import javax.servlet.http.*;import javax.servlet.annotation.*;import java.io.*;@WebServlet(name="AsyncServlet",urlPatterns={"/AsyncServlet"},asyncSupported=true)public class AsyncServlet extends HttpServlet{ public void service(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{ request.setCharacterEncoding("GBK"); response.setContentType("text/html;charset=GBK"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<body>"); out.println("====頁面開始====<hr />"); AsyncContext actx = request.startAsync(); actx.setTimeout(30*3000); actx.start(new MyThread(actx)); out.println("====頁面結束====<hr />"); out.println("</body>"); out.println("</html>"); out.flush(); }}class MyThread implements Runnable{ private AsyncContext actx; public MyThread(AsyncContext actx){ this.actx = actx; } public void run(){ try{ Thread.sleep(5*1000); //消耗5秒 actx.dispatch("/1.jsp"); } catch(Exception e){} }}
1.jsp
<%@ page contentType="text/html;charset=GBK" pageEncoding="GBK" session="false"%><html> <body> <% out.println("======複雜業務方法===="); %> </body></html>
四、非同步監聽器
非同步監聽器用來監聽非同步處理事件;即“三”中講到的知識點;
此監聽器類似於ServletContextListener的機制;
只需要實現AsyncListener介面即可;
此介面有4個方法:
public void onStartAsync(AsyncEvent event)throws IOException;
public void onComplete(AsyncEvent event);
public void onTimeout(AsyncEvent event);
public void onError(AsyncEvent event);
以下是監聽器實現的程式碼:
package org.listener;import javax.servlet.annotation.*;import javax.servlet.http.*;import javax.servlet.*;import java.util.*;import java.sql.*;import javax.naming.*;import java.io.*;public class MyListener implements AsyncListener{ public void onStartAsync(AsyncEvent event)throws IOException{} public void onComplete(AsyncEvent event){ System.out.println("-----------------------Complete"); } public void onTimeout(AsyncEvent event){ } public void onError(AsyncEvent event){}}
在Servlet非同步處理處新增:
actx.addListener(new MyListener());就可以新增監聽器,每當非同步處理完成時就會觸發onComplete()事件,輸出Complete;
五、檔案上傳改進API
原本檔案上傳時通過 common-fileupload或者SmartUpload,上傳比較麻煩,在Servlet 3.0 中不需要匯入任何第三方jar包,並且提供了很方便進行檔案上傳的功能;
注意點:
1. html中 <input type="file">表示檔案上傳控制元件;
2. form的 enctype="multipart/form-data";
3.在Servlet類前加上 @MultipartConfig
4.request.getPart()獲得;
下面是一個檔案上傳的例子:
upload.html
<html> <body> <form method="post" enctype="multipart/form-data" action="upload"> <input type="file" id="file" name="file"/> <input type="text" id="name" name="name"/> <input type="submit" value="提交"/> </form> </body></html>
UploadServlet.java
package org.servlet;import java.io.*;import javax.servlet.*;import javax.servlet.http.*;import javax.servlet.annotation.*; @WebServlet(name="UploadServlet" ,urlPatterns={"/upload"})@MultipartConfigpublic class UploadServlet extends HttpServlet{ public void init(ServletConfig config)throws ServletException{ super.init(config); } public void service(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{ Part part = request.getPart("file"); PrintWriter out = response.getWriter(); out.println("此檔案的大小:"+part.getSize()+"<br />"); out.println("此檔案型別:"+part.getContentType()+"<br />"); out.println("文字框內容:"+request.getParameter("name")+"<br />"); out.println(UploadUtil.getFileName(part)+"<br />"); part.write("F:\\1."+UploadUtil.getFileType(part)); }}
UploadUtil.java
由於在Servlet 3.0中很難獲取上傳檔案的型別,因此我寫了兩個工具類,可以方便開發;
/** * 此工具類只適用於Servlet 3.0 * 為了彌補 Servlet 3.0 檔案上傳時獲取檔案型別的困難問題 * * @author xiazdong */import javax.servlet.http.*;public class UploadUtil{ public static String getFileType(Part p){ String name = p.getHeader("content-disposition"); String fileNameTmp = name.substring(name.indexOf("filename=")+10); String type = fileNameTmp.substring(fileNameTmp.indexOf(".")+1,fileNameTmp.indexOf("\"")); return type; } public static String getFileName(Part p){ String name = p.getHeader("content-disposition"); String fileNameTmp = name.substring(name.indexOf("filename=")+10); String fileName = fileNameTmp.substring(0,fileNameTmp.indexOf("\"")); return fileName; }}