Servlet3.x新特性
介紹
Servlet標準一直在推進,Servlet3.0相比之前的版本有很多特性和改進。
學習Java Web開發,Servlet絕對是最重要也是最應該好好掌握和深入理解的部分。
一、註解式開發支持
Servlet3.x之前開發Servlet需要在web.xml中配置對應的映射地址,但是從3.x之後這樣的配置將不再是必須的了。
常用註解:@WebServlet、@WebListener、@WebFilter、@WebInitParam
Servlet3.x支持的註解都在javax.servlet.annotation包下.
案例
/**
* <h3>Servlet3.x註解式開發案例</h3>
*
* @author xuyi3
* @2016年9月8日 @上午10:27:53
* @GetController
* @功能說明:<br>
* @春風十里不如你
* @備註
*/
@WebServlet(urlPatterns = "/getController",
initParams = { @WebInitParam(name = "key1", value = "value1"),
@WebInitParam(name = "key2", value = "value2") })
//配置單個servlet初始化參數
//@WebInitParam(name="key",value="xxx")
public class GetController extends HttpServlet
{
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(GetController.class);
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
logger.info("doGet...");
}
}
二、異步處理支持
Servlet3.x之前的針對每個請求都是阻塞的,只要服務器沒有處理完任務時不會響應客戶端的,這樣的體驗並不好。
解決方法可以是借組消息中間件來異步處理,Servlet3.x開始支持開啓新線程異步處理,無需等待新線程處理完成即可響應客戶端。
案例
/**
* <h3>Servlet3.x異步處理簡單案列</h3>
*
* @author xuyi3
* @2016年9月8日 @上午10:21:08
* @AsyncController
* @功能說明:<br>
* @春風十里不如你
* @備註
*/
@WebServlet(urlPatterns = "/asyncController", asyncSupported = true)
public class AsyncController extends HttpServlet
{
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(AsyncController.class);
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
//處理耗時任務...
AsyncContext asyncContext = request.startAsync();//啓動異步處理線程
asyncContext.setTimeout(5000);//設置異步處理超時時間
asyncContext.start(new Runnable()//異步處理的新線程處理的任務
{
public void run()
{
for (int i = 0; i < 4; i++)
{
try
{
Thread.sleep(1000);
logger.info("=====處理耗時任務{}=====", (i + 1));
} catch (InterruptedException e)
{
logger.error("", e);
}
}
}
});
//響應前端
response.setContentType("application/json;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println(JsonUtils.getDefaultJsonString());
writer.flush();
writer.close();
}
}
備註:要深入學習Servelt3.x的異步處理的話,請查看AsyncContext源碼實現。
備註:是否採用這種方式還是要看公司已有的技術架構,個人推薦使用消息中間件來達到異步處理任務。
異步處理支持:有了該特性,Servlet線程不再需要一直阻塞,直到業務處理完畢才能再輸出響應,最後才結束該Servlet線程。
在接收到請求之後,Servlet線程可以將耗時的操作委派給另一個線程來完成,自己在不生成響應的情況下返回至容器。
針對業務處理較耗時的情況,這將大大減少服務器資源的佔用,並且提高併發處理速度。
三、文件上傳下載新方式支持
Servlet3.x之前對於文件上傳並不友好,編寫相對麻煩。Servlet3.x之後提供了Part類來表示上傳文件對象,完全可以藉助該對象實現上傳功能。
備註:可以去查看Part的源碼和其中的方法
案例
/**
* <h3>使用Servlet3.x新特性,實現單個和多個文件上傳</h3>
*
* @author xuyi3
* @2016年9月8日 @下午1:57:24
* @UploadController
* @功能說明:<br>
* @春風十里不如你
* @備註
*/
@WebServlet(urlPatterns = "/uploadController")
@MultipartConfig//備註上傳不要忘記配置
public class UploadController extends HttpServlet
{
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(UploadController.class);
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
Collection<Part> parts = request.getParts();
logger.info("=====上傳文件數:{}=====", parts.size());
for (Part part : parts)
{
if (part != null && part.getSize() > 0)
{
//獲得文件名
String fileName = getFileName(part);
//獲得文件後綴
String suffix = getSuffix(part);
InputStream inputStream = part.getInputStream();
FileOutputStream outputStream = new FileOutputStream(new File("e:/" + fileName + "." + suffix));
//備註:通常上傳的文件名字由我們服務端自己定義,只要和用戶關聯就行,至於命名規則我們定義(比如對用戶id、用戶名計算MD5等)
//上傳文件操作
IOUtils.copy(inputStream, outputStream);
}
}
}
/**
* 獲得上傳文件的後綴
* @param part
* @return
*/
private String getSuffix(Part part)
{
//上傳文件名
String submitFileName = part.getSubmittedFileName();
int beginIndex = submitFileName.lastIndexOf(".");
int endIndex = submitFileName.length();
String suffix = submitFileName.substring(beginIndex + 1, endIndex);
return suffix;
}
/**
* 獲得上傳文件名字
* @param part
* @return
*/
private String getFileName(Part part)
{
//上傳文件名
String submitFileName = part.getSubmittedFileName();
int endIndex = submitFileName.lastIndexOf(".");
String suffix = submitFileName.substring(0, endIndex);
return suffix;
}
}
需要注意點:
1、配置MIME 類型是 multipart/form-data
2、配置MultipartConfig
//備註:通常想要實現文件上傳功能都不會由我們自己寫,大部分web mvc框架都會提供更簡便方式來實現。
比如spring mvc、struct2.x框架
參考
1、https://www.ibm.com/developerworks/cn/java/j-lo-servlet30/
2、https://en.wikipedia.org/wiki/Servlets
3、http://www.journaldev.com/2015/servlet-interview-questions-and-answers
4、http://www.journaldev.com/2114/servlet-jsp-tutorial