Servlet4.0


Servlet4.0

 

參考文章:

https://developer.ibm.com/zh/tutorials/j-javaee8-servlet4/

 

 

概述

使用Servlet4.0

服務器推送

HttpServletMapping

Servlet4.0的細微變化

題外話

ServletRequest和HttpServletRequest區別

ServletRequest

HttpServletRequest

 

 

 

概述

Servlet API是Java開發人員最熟悉的API之一,Servlet在1999年所發布的J2SE1.2版本中首次面世,Servlet在JavaWEB的開發中發揮着重要的作用。JavaEE8對Servlet4.0進行了重要的更新。其中服務器推送是最主要的更新,如果要使用服務器推送的功能,則我們必須使用HTTP/2.0版本的協議。JavaEE8提供了對Servlet映射的運行時發現,在運行時我們可以獲取Servlet的名稱,Servlet的映射路徑。JavaEE8簡化了對Filter的開發。

IDEA 2017.3版本才開始提供對JAVAEE8的支持,本文使用的是IDEA 2018.3版本,默認只支持Servlet4.0。

開發環境:jdk8,tomcat9,tomcat-native,openssl

 

 

使用Servlet4.0

Servlet4.0是使用HTTP/2協議,而Tomcat9下載后,默認使用的是HTTP/1.1,所以我們要先修改server.xml配置文件:

1、注釋原有的默認使用HTTP/1.1方式

<!-- 
      <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
               -->

  

2、開啟HTTP2的注釋,並刪除certificateChainFile這一行HTTP2使用的端口不在是8080,而是8443,使用HTTP2需要配置一個私鑰文件和一個證書文件。

 <Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
               maxThreads="150" SSLEnabled="true" >
        <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
        <SSLHostConfig>
            <Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
                         certificateFile="conf/localhost-rsa-cert.pem"
                         certificateChainFile="conf/localhost-rsa-chain.pem"
                         type="RSA" />
        </SSLHostConfig>
    </Connector>

  

關於上面Certificate標簽有關說明:當你申請證書時或獲取一個證書crt和一個私鑰key文件,certificateKeyFile放的就是你的證書key文件,certificateFile則是私鑰cert文件,默認放在Tomcat9的conf目錄下。

certificateChainFile:一般操作系統/瀏覽器會內置一些CA(證書頒發機構)的證書,如果你的證書是直接由這些內置CA頒發的,那么就不需要Chain文件,瀏覽器可以直接識別你的證書。如果你的證書是由二級CA頒發的,即內置CA頒發給另一個二級CA,然后二級CA在頒發給你,那么就需要Chain文件,否則瀏覽器就不知道你的證書和內置CA的關系。如果你將自記得CA設置成了內置CA,那么直接由你的CA頒發的證書自然不需要Chain文件。

 

 

3、現在我們需要生成server.xml配置中的證書和私鑰文件,在這里我是使用openssl生成的,openssl windows版本網盤下載地址,提取碼:0sra ,網盤分享的openssl是win32版本的,由於windows64是兼容windows32的,所以不必擔心不能使用的問題。解壓開后,進入bin目錄,啟動openssl.exe

生成私鑰:

OpenSSL> genrsa -out localhost-rsa-key.pem 1024

  

使用配置文件生成證書(一路回撤即可):

OpenSSL> req -new -x509 -key localhost-rsa-key.pem -out localhost-rsa-cert.pem -days 3650 -config D:\soft\openssl\openssl-0.9.8k_WIN32\bin\openssl.cnf

  

4、將第三步生成了兩個文件,放入tomcat9的conf目錄下。

 

5、下載tomcat-nativate文件並解壓,如果你是win32系統直接將bin目錄下tcnative-1.dll和tcnative-1-src.pdb文件復制到jdk的bin目錄下,如果你是win64則將x64文件下的這兩個文件復制到jdk目錄下。

至此我們已經完成了Tomcat9的HTTP協議的升級,現在你可以啟動Tomcat9,然后訪問https://localhost:8443/即可看到tomcat頁面。

 

 

服務器推送

將用戶所需的WEB資源提前推送到用戶的瀏覽器緩存中,當用戶使用瀏覽器訪問所需WEB資源時,用戶不需要再次下載所需的資源,因為用戶所需的WEB資源已經存在與用戶的瀏覽器緩存中。

如下內容摘自這里

Servlet4.0通過PushBuilder接口公開服務器推送。為了能夠進行訪問,你需要通過調用newPushBuilder()方法,從HttpServletRequest獲取PushBuilder實例。

@Override
protected void doGet(HttpServletRequest request,
                     HttpServletResponse response)
                     throws ServletException, IOException {

   PushBuilder pushBuilder = request.newPushBuilder();

}

  

每次調用newPushBuilder()方法時,都將返回PushBuilder的新實例。如果服務器推送不可用,newPushBuilder()將返回null。在某些情況下,客戶端可能會為請求事務拒絕服務器推送。如果客戶端沒有使用安全連接,服務器推送也不會起作用。因此,務必要在對PushBuilder實例調用方法前,針對null返回值進行測試。

顧名思義,PushBuilder實現Builder模式。在這一實現過程中,通過鏈接賦值方法構建推送請求。這些賦值方法通過設置請求HTTP標頭、方法類型(GET是唯一的可接受值)、查詢字符串、會話ID和資源路徑(即,將要推出的資源的路徑),來配置PushBuilder實例。

大多數來自原始HtpServletRequest實例的請求標頭,只添加到PushBuilder實例中。由於正確運行服務器推送並不需要某些標頭,因此不包括以下標頭:

 條件標頭

 Ranfe標頭

 Authorization標頭

 Referrer標頭

設置推送資源路徑需要調用path()方法。該方法只能被調用一次,因為它會改變PushBuilder對象的路徑值。該路徑可能會以正斜杠(”/“)開頭,指示資源路徑是絕對路徑;否則,該資源會被認為是相對於關聯請求的上下文路徑。該路徑可以包含一個查詢字符串,該查詢字符串將與queryString()方法設置的任何字符串合並。

 

測試:

准備:使用一張圖片,復制一份並改名。如下代碼hello.jpg和hey.jpg使用的是同一張圖片,保證大小一致。清空瀏覽器緩存

不使用服務器推送:

@WebServlet("/NoPushServlet")
public class NoPushServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getRequestDispatcher("nopush.jsp").forward(req, resp);
    }
}

 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
Hello
<p><img src="./hello.jpg" alt=""></p>
</body>
</html>

 

 

 

 

不使用服務器推送,瀏覽器渲染hello.jsp頁面時會再次請求后台下載hello.jpg圖片,這會再次創建一個HTTP鏈接,發送請求耗時0.16ms,等待響應耗時6.49ms,最后下載圖片Content Download耗時1.13ms。

 

使用服務器推送:

/**
 * 將用戶所需的WEB資源提前推送到用戶的瀏覽器緩存中,當用戶使用瀏覽器訪問所需WEB資源時,
 * 用戶不需要再次下載所需的資源,因為用戶所需的WEB資源已經存在與用戶的瀏覽器緩存中。
 */
@WebServlet("/PushServlet")
public class PushServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PushBuilder pushBuilder = req.newPushBuilder();
        if (pushBuilder != null) {
            PushBuilder path = pushBuilder.path("./hey.jpg");
            path.push();

            // 只推送最后一個path里的資源
//        PushBuilder path = pushBuilder.path("./hey.jpg").path("./hello.jpg");
//        path.push();

            // 推送多個資源的寫法
//        pushBuilder.path("./hey.jpg").push();
//        pushBuilder.path("./hello.jpg").push();
        }


        req.getRequestDispatcher("push.jsp").forward(req, resp);
    }
}

 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
Hello
<p><img src="./hey.jpg" alt=""></p>
</body>
</html>

 

 

 

 

使用服務器推送,效果很明顯,不需要向服務器二次請求建立連接,因為圖片在建立Servlet鏈接請求的時候,服務器端就已經推送過來了,所以在PushServlet時可以看到,這張圖比NoPushServlet中Content Download多耗了一點時間,因為要多下載一張圖。總體上相當於省下了hey.jpg建立鏈接的時間。

如果一個頁面上有很多張圖時候,使用服務器推送技術可以省下的時間也會是一個可觀的數字。

 

 

HttpServletMapping

用於在運行時獲取Servlet的映射信息,它是Servlet4.0新增的接口,含有四個方法:

 getMappingMatch():返回匹配的類型(如果沒有則返回null)

 

 getMatchValue():返回匹配的值(如果沒有返回空字符串)

 getPattern():與此請求匹配的url模式,如果未知則為空String。

 getServletName():映射到請求的servlet的名稱(在web.xml,WebServlet.name(),ServletContext.addServlet(String,Class)或其他addServlet()指定的方法之一)

 

@WebServlet(value = "/myServletMapping", name = "my-servlet-mapping")
public class MyServletMapping extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // HttpServletMapping用於在運行時獲取Servlet的映射信息
        HttpServletMapping httpServletMapping = req.getHttpServletMapping();

        // getMappingMatch返回匹配的值(如果沒有返回空字符串)
        MappingMatch mappingMatch = httpServletMapping.getMappingMatch(); // EXACT

        // 返回匹配的值(如果沒有返回空字符串)
        String matchValue = httpServletMapping.getMatchValue(); // myServletMapping

        // 與此請求匹配的url,如果未知則為空String。
        String pattern = httpServletMapping.getPattern(); // /myServletMapping

        // 映射到請求的servlet的名稱,如果沒寫默認是全路徑名稱
        String servletName = httpServletMapping.getServletName(); // my-servlet-mapping

    }
}

 

 

Servlet4.0的細微變化

 Servlet4.0添加了GenericFilter和HttpFilter抽象類,這些抽象類通過提供最低限度地實現生命周期方法init()和destory(),簡化了編寫過濾器。

 ServletContext 接口采用了一些新方法:

 addJspFile() 可將帶有給定 JSP 文件的 servlet 添加到 servlet 上下文中。

 getSessionTimeout() 和 setSessionTimeout() 可提供對會話超時的訪問權限。

 getRequestCharacterEncoding() 和 setRequestCharacterEncoding() 可為當前的 servlet 上下文提供訪問權限,並改變默認的請求字符編碼。

 HttpServletRequest 接口上的 isRequestedSessionIdFromUrl() 方法已被棄用。

 由於升級到 Java SE 8,默認方法已被添加到偵聽器接口中。

 

 

題外話

ServletRequest和HttpServletRequest區別

 

 

ServletRequest

定義一個對象以向servlet提供客戶端請求信息。servlet容器創建一個ServletRequest對象,並將其作為參數傳遞給servlet的服務方法。

ServletRequest對象提供數據,包括參數名和值、屬性和輸入流。擴展ServletRequest的接口可以提供額外的協議特定的數據(例如,HTTP數據是由HttpServletRequest提供的。

 

HttpServletRequest

擴展ServletRequest接口,為HTTP servlet提供請求信息。

servlet容器創建一個HttpServletRequest對象,並將其作為參數傳遞給servlet的服務方法(doGet,doPost等)。

 

ServletRequest只是提供了基礎通信的行為,如:

設置字符集,獲取參數,獲取端口、地址等。

HttpServletRequest處理提供了上面的這些行為,還支持

獲取cookie、session信息,關於servlet的請求映射、方法,文件上傳Part等。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM