Servlet3.x新特性

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章