zoukankan      html  css  js  c++  java
  • 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:softopensslopenssl-0.9.8k_WIN32inopenssl.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等。

     

     

    前进时,请别遗忘了身后的脚印。
  • 相关阅读:
    Oracle 查看一个表对应的主键和外键的约束关系,查看的语句:
    openssl 生成p12文件错误
    XP SP3远程桌面无法连接Windows Server 2008/Vista
    windows 7 正确禁用 IPv6
    用正则表达式替换换行符
    Eclipse插件开发之定制向导(各方法说明)
    oepnvpn 配置自启动
    TNS12547: TNS:lost contact 错误解决
    redhat 5.5 U盘安装
    Hibernat 使用Criteria查询多对多关系(SET集合)条件
  • 原文地址:https://www.cnblogs.com/liudaihuablogs/p/14169475.html
Copyright © 2011-2022 走看看