tomcat 7以上的版本都支持Servlet 3.0
Servlet 3.0 新增特性
- 註解支持;Servlet、Filter、Listener無需在web.xml中進行配置,可以通過對應註解進行配置;
- 支持Web模塊;
- Servlet異步處理;
- 文件上傳API簡化;
Servlet3.0的註解
- @WebServlet :修飾Servlet類,用於部署該Servlet類。
- @WebFilter:修飾Filter類,用於部署該Filter類
- @WebInitParam:與@WebServlet或@WebFilter註解連用,爲它們配置參數
- @MultipartConfig:修飾Servlet類,指定該Servlet類負責處理multipart/form-data類型的請求(主要用於處理上傳文件)
- @ServletSecurity:修飾Servlet類,與JAAS(Java驗證和授權API)有關的註解
- @HttpConstrait:與@ServletSecurity連用
- @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模塊支持
- 原來一個web應用的任何配置都需要在web.xml中進行,因此會使得web.xml變得很混亂,而且靈活性差。現在可通過Web模塊來部署管理它們。
- Web模塊對應一個Jar包,即Servlet 3.0可以將每個Servlet、Filter、Listener打成jar包,然後放在WEB-INF\lib中。
- 每個模塊都有自己的配置文件,這個配置文件的名稱爲 web-fragment.xml 。
製作一個Servlet模塊的步驟:
- 正常編寫Servlet,並編譯;
- 將此編譯class文件及所在包通過jar包命令打成jar包;
- 將此jar包用winrar打開,將META-INF中的manifest刪除後添加 web-fragment.xml;
- 將此jar包放入WEB-INF\lib中即可;
web-fragment.xml說明:
<web-fragment>
爲根元素;<name></name>
表示模塊名稱(模塊的唯一標識);<ordering></ordering>
定義模塊加載順序的標籤,當然可以不設置模塊加載順序;<before><others/></before>
表示在所有模塊前面加載(第一個加載);<after><name>A</name></after>
表示在A模塊後面加載;- 可以在裏面部署listener、filter、servlet
- 值得注意的是,web.xml中用
<absolute-ordering>
標籤指定的模塊加載順序將會覆蓋web模塊的web-fragment.xml文件中指定的加載順序。
如何用myEclipse打jar包(有些人不知道)
右鍵你web項目裏的編寫的servlet(或filter或listener)類——>Export…——>JAR file——>NEXT——>(Browse)填寫導出名字和存放位置——>finish
這樣就生成了我們需要的jar包了- 示例
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類
- 通過註解asyncSupported=true實現
- 通過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(上傳文件)
- 改進內容
- HttpServletRequest增加了對上傳文件的支持
- ServletContext允許通過編程的方式動態註冊Servlet、Filter
- HttpServletRequest提供瞭如下兩個方法處理文件的上傳
Part getPart(String name)
根據名稱獲取文件上傳域Collection<Part> getParts()
獲取所有文件上傳域
- 上傳文件時一定要爲表單域設置enctype屬性,它表示表單數據的編碼方式,有如下三個值:
- application/x-www-form-urlencoded (默認),它只處理表單裏的value屬性值,它會將value值處理成URL編碼方式。如果此時表單域裏有上傳文件的域(type=”file”),則只會獲取該文件在上傳者電腦裏的絕對路徑串,該串沒什麼實際意義。
- multipart/form-data 此處編碼方式會以二制流的方式來處理表單數據,此時會將文件內容也封裝到請求參數裏。
- texst/plain 當表單的action屬性爲mailto:URL的形式時比較方便,主要適用於直接通過表單發送郵件的方式
- 上傳文件的Servlet需要加上@MultipartConfig註解
- 通過request獲取的Part對象就可以操作文件域了
- 示例
@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);
}
}