Servlet3.0新特性全解



tomcat 7以上的版本都支持Servlet 3.0

Servlet 3.0 新增特性

  1. 註解支持;Servlet、Filter、Listener無需在web.xml中進行配置,可以通過對應註解進行配置;
  2. 支持Web模塊;
  3. Servlet異步處理;
  4. 文件上傳API簡化;

Servlet3.0的註解

  1. @WebServlet :修飾Servlet類,用於部署該Servlet類。
  2. @WebFilter:修飾Filter類,用於部署該Filter類
  3. @WebInitParam:與@WebServlet或@WebFilter註解連用,爲它們配置參數
  4. @MultipartConfig:修飾Servlet類,指定該Servlet類負責處理multipart/form-data類型的請求(主要用於處理上傳文件)
  5. @ServletSecurity:修飾Servlet類,與JAAS(Java驗證和授權API)有關的註解
  6. @HttpConstrait:與@ServletSecurity連用
  7. @HttpMethodConstrait:與@ServletSecurity連用

示例代碼片
修飾過濾器Filter:

@WebFilter(
        filterName="log",
        urlPatterns={"/*"},
        initParams={
        @WebInitParam(name="encoding",value="GBK"),
        @WebInitParam(name="loginPage",value="/login.jsp")
        })
public class MyFilter implements Filter {
    //內容省略......
}

修飾servlet:

@WebServlet(name="test",
    urlPatterns={"/basic.do"},
    initParams={
        @WebInitParam(name="userName",value="peter"),
        @WebInitParam(name="age",value="100")
        })
public class TestServlet extends HttpServlet{
    //內容省略....
}

修飾監聽器Listener:

@WebListener
public class MyRequestListener implements ServletRequestListener{
    //內容省略...
}

  • Servlet3.0的Web模塊支持
  1. 原來一個web應用的任何配置都需要在web.xml中進行,因此會使得web.xml變得很混亂,而且靈活性差。現在可通過Web模塊來部署管理它們。
  2. Web模塊對應一個Jar包,即Servlet 3.0可以將每個Servlet、Filter、Listener打成jar包,然後放在WEB-INF\lib中。
  3. 每個模塊都有自己的配置文件,這個配置文件的名稱爲 web-fragment.xml 。
  4. 製作一個Servlet模塊的步驟:

    1. 正常編寫Servlet,並編譯;
    2. 將此編譯class文件及所在包通過jar包命令打成jar包;
    3. 將此jar包用winrar打開,將META-INF中的manifest刪除後添加 web-fragment.xml;
    4. 將此jar包放入WEB-INF\lib中即可;
  5. 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
    7. 值得注意的是,web.xml中用<absolute-ordering>標籤指定的模塊加載順序將會覆蓋web模塊的web-fragment.xml文件中指定的加載順序。
  6. 如何用myEclipse打jar包(有些人不知道)
    右鍵你web項目裏的編寫的servlet(或filter或listener)類——>Export…——>JAR file——>NEXT——>(Browse)填寫導出名字和存放位置——>finish
    這樣就生成了我們需要的jar包了

  7. 示例
    servlet類代碼片:
@WebServlet(name="test",urlPatterns={"/basic.do"})
public class TestServlet extends HttpServlet{

    //使用該方法可響應客戶端的所有請求
    public void service(HttpServletRequest req, HttpServletResponse resp)throws IOException{
        System.out.println("進servlet了");
        PrintStream out = new PrintStream(resp.getOutputStream());
        //向頁面輸入下面字符串
        out.print("1234567890");
    }

}

web-fragment.xml代碼片

<web-fragment version="3.0" 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 http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd">  

   <!-- 指定模塊名稱 :唯一標識-->  
   <name>mySerModule</name>  
   <!-- 加載順序 -->  
   <ordering>  
      <!-- 在其它模塊之前加載 -->  
      <before>  
         <others/>  
      </before>  
   </ordering>      
</web-fragment> 

在web-fragment.xml裏的配置和之前的web.xml裏類似,如果是註解實現的servlet的配置,則在web-fragment.xml裏就將不再寫配置了,如果不是,則還需要寫配置。
打成jar包放在一個項目裏面啓動後,就可通過上面servlet註解配置的/basic.do路徑訪問上面的servle了。

servlet3.0提供的異步處理

* 提供異步原因*

在以前的servlet中,如果作爲控制器的servlet調用了一個較爲耗時的業務方法,則servlet必須等到業務執行完後纔會生成響應,這使得這次調用成了阻塞式調用,效率比較差

實現異步原理

重新開一個線程單獨去調用耗時的業務方法。

配置servlet類成爲異步的servlet類

  1. 通過註解asyncSupported=true實現
  2. 通過web.xml配置
<servlet>
        <servlet-name>test1</servlet-name>
        <servlet-class>com.zrgk.servlet.AsyncServlet</servlet-class>
        <async-suppored>true</async-suppored>       
    </servlet>
    <servlet-mapping>
        <servlet-name>test1</servlet-name>
        <url-pattern>/basic.do</url-pattern>
    </servlet-mapping>

  • 具體實現

java代碼:

@WebServlet(name="AsyncServlet",urlPatterns={"/testAsyn.do"},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");  
       //通過request獲得AsyncContent對象
       AsyncContext actx = request.startAsync(); //重點方法**
       //設置異步調用超時時長
        actx.setTimeout(30*3000);  
        //啓動異步調用的線程
        actx.start(new MyThread(actx));//重點方法**

       // 直接輸出到頁面的內容(不等異步完成就直接給頁面)
        //但這些內容必須放在標籤內,否則會在頁面輸出錯誤內容,這兒反正我測試是這樣,具體不知對不對??
       PrintWriter out = response.getWriter();
       out.println("<h1>不等異步返回結果就直接返到頁面的內容</h1>");  
       out.flush(); 
   }  
}  

//異步處理業務的線程類
public class MyThread implements Runnable {
     private AsyncContext actx;  
     //構造
     public MyThread(AsyncContext actx){  
            this.actx = actx;  
     }  
     public void run(){  
        try{  
            //等待5秒,模擬處理耗時的業務
           Thread.sleep(4*1000); 
           //獲得request對象,添加數據給頁面
           ServletRequest req = actx.getRequest();
           req.setAttribute("content","異步獲得的數據");
           //將請求dispath到index.jsp頁面,該頁面的session必須設爲false
           actx.dispatch("/index.jsp");  
        }catch(Exception e){
            e.printStackTrace();
        }  
     }   
}

頁面代碼(頁頭裏session設爲false,表時該頁面不會再創建session):

<%@ page language="java" import="java.util.*" pageEncoding="utf-8" session="false"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>  
  <body>
    <a href="<%=basePath%>/testAsyn.do">測試異步調用</a>
    異步結果:${content}
  </body>
</html>
  • 異步監聽器

異步監聽器用來監聽異步Servlet的異步處理事件,通過實現AsyncListener接口實現,代碼如下:

public class MyAsyncListener implements AsyncListener{

    //異步調用完成時觸發
    @Override
    public void onComplete(AsyncEvent event) throws IOException {
        // 省略....       
    }

    //異步調用出錯時觸發
    @Override
    public void onError(AsyncEvent event) throws IOException {
        // 省略....       
    }

    //異步調用開始觸發
    @Override
    public void onStartAsync(AsyncEvent event) throws IOException {
        // 省略....       
    }

    //異步調用超時觸發
    @Override
    public void onTimeout(AsyncEvent event) throws IOException {
        // 省略....       
    }

}

還需要在異步Servlet裏註冊異步監聽器,即添加如下代碼即可:

  actx.addListener(new MyAsyncListener());
  • 1

Filter異步調用與Servlet一樣。

改進的ServletAPI(上傳文件)

  1. 改進內容
    1. HttpServletRequest增加了對上傳文件的支持
    2. ServletContext允許通過編程的方式動態註冊Servlet、Filter
  2. HttpServletRequest提供瞭如下兩個方法處理文件的上傳
    1. Part getPart(String name) 根據名稱獲取文件上傳域
    2. Collection<Part> getParts() 獲取所有文件上傳域
  3. 上傳文件時一定要爲表單域設置enctype屬性,它表示表單數據的編碼方式,有如下三個值:
    1. application/x-www-form-urlencoded (默認),它只處理表單裏的value屬性值,它會將value值處理成URL編碼方式。如果此時表單域裏有上傳文件的域(type=”file”),則只會獲取該文件在上傳者電腦裏的絕對路徑串,該串沒什麼實際意義。
    2. multipart/form-data 此處編碼方式會以二制流的方式來處理表單數據,此時會將文件內容也封裝到請求參數裏。
    3. texst/plain 當表單的action屬性爲mailto:URL的形式時比較方便,主要適用於直接通過表單發送郵件的方式
  4. 上傳文件的Servlet需要加上@MultipartConfig註解
  5. 通過request獲取的Part對象就可以操作文件域了
  6. 示例
@WebServlet(name="uploadServlet",urlPatterns="/upload.do")
@MultipartConfig
public class UploaderServlet extends HttpServlet {

    public void service(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException{
        //獲得Par對象(每個Part對象對應一個文件域)
        Part part = request.getPart("file");
        long size = part.getSize(); //獲取上傳文件大小
        String info = part.getHeader("content-disposition");//獲得包含原始文件名的字符串
        //獲取原始文件名
        String fileName = info.substring(info.indexOf("filename=\"")+10,info.length()-1);
        //將文件上傳到某個位置
        part.write(getServletContext().getRealPath("/uploadFiles")+"/"+fileName);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章