• java 之 servlet


    Servlet 是什么?

    Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。

    使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。

    Java Servlet 通常情况下与使用 CGI(Common Gateway Interface,公共网关接口)实现的程序可以达到异曲同工的效果。但是相比于 CGI,Servlet 有以下几点优势:

    • 性能明显更好。
    • Servlet 在 Web 服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。
    • Servlet 是独立于平台的,因为它们是用 Java 编写的。
    • 服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的。
    • Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互。

    Servlet 架构

    下图显示了 Servlet 在 Web 应用程序中的位置。

    Servlet 架构

    Servlet 任务

    Servlet 执行以下主要任务:

    • 读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
    • 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
    • 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
    • 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
    • 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。 

    servlet容器

    Servlet容器(servlet引擎)是Web服务器或应用程序服务器的一部分,用于在发送的请求和响应之上提供网络服务,解码基于 MIME的请求,格式化基于MIME的响应。Servlet容器在servlet生命周期内管理的servlet对象。根据Servlet容器工作模式的不同,可以将Servlet容器分为以下三类:

    (1)       独立的Servlet容器:

    基于java技术的Web服务器:例如tomcat

    (2)       进程内的Servlet容器:

    Servlet容器由Web服务器插件和Java容器两部分的实现组成。Web服务器插件在某个Web服务器内部地址空间中打开一个 JVM(Java虚拟机),使得Java容器可以在此JVM中加载并运行Servlet。如有客户端调用Servlet的请求到来,插件取得对此请求的控 制并将它传递(使用JNI技术)给Java容器,然后由Java容器将此请求交由Servlet进行处理。进程内的Servlet容器对于单进程、多线程 的服务器非常适合,提供了较高的运行速度,但伸缩性有所不足。例如运行在Apache Web服务器内的Tomcat

    (3)       进程外的Servlet容器:

    Servlet容器运行于Web服务器之外的地址空间,它也是由Web服务器插件和Java容器两部分的实现组成的。Web服务器插件和Java容 器(在外部JVM中运行)使用IPC机制(通常是TCP/IP)进行通信。当一个调用Servlet的请求到达时,插件取得对此请求的控制并将其传递(使 用IPC机制)给Java容器。进程外Servlet容器对客户请求的响应速度不如进程内的Servlet容器,但进程外容器具有更好的伸缩性和稳定性。

    Servlet 生命周期

    Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

    • Servlet 通过调用 init () 方法进行初始化。
    • Servlet 调用 service() 方法来处理客户端的请求。
    • Servlet 通过调用 destroy() 方法终止(结束)。
    • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

    现在让我们详细讨论生命周期的方法。

    init() 方法

    init 方法被设计成只调用一次。它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。因此,它是用于一次性初始化,就像 Applet 的 init 方法一样。

    Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,但是您也可以指定 Servlet 在服务器第一次启动时被加载。

    当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。

    init 方法的定义如下:

    public void init() throws ServletException {
      // 初始化代码...
    }
     

    service() 方法

    service() 方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。

    每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。

    下面是该方法的特征:

    public void service(ServletRequest request, 
                        ServletResponse response) 
          throws ServletException, IOException{
    }
    
    

    service() 方法由容器调用,service 方法在适当的时候调用 doGet、doPost、doPut、doDelete 等方法。所以,您不用对 service() 方法做任何动作,您只需要根据来自客户端的请求类型来重写 doGet() 或 doPost() 即可。

    doGet() 和 doPost() 方法是每次服务请求中最常用的方法。下面是这两种方法的特征。

    doGet() 方法

    GET 请求来自于一个 URL 的正常请求,或者来自于一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。

    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
        throws ServletException, IOException {
        // Servlet 代码
    }
    
    

    doPost() 方法

    POST 请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。

    public void doPost(HttpServletRequest request,
                       HttpServletResponse response)
        throws ServletException, IOException {
        // Servlet 代码
    }
    
    

    destroy() 方法

    destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。

    在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。destroy 方法定义如下所示:

    public void destroy() {    // 终止化代码...
      }
    
    

    架构图

    下图显示了一个典型的 Servlet 生命周期方案。

    • 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
    • Servlet 容器在调用 service() 方法之前加载 Servlet。
    • 然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。
    Servlet 生命周期

    创建servlet的三种方式

     

    •     实现servlet接口   implements Servlet
    •    继承GenericServlet 类   extends  GenericServlet 并实现service()方法
    •    继承HttpServlet 方法 extends  HttpServlet

    servlet接口;

     

    package javax.servlet;
    
    import java.io.IOException;
    
    public interface Servlet {
        void init(ServletConfig var1) throws ServletException;//用于servlet初始化
    
        ServletConfig getServletConfig();//返回ServletConfig实例,其中包含Servlet初始化和启动参数
    
        void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;//用于服务处理
    
        String getServletInfo();//返回servlet的作者、版本、版权等信息
    
        void destroy();//销毁servlet
    }  

    GenericServlet类:

    是一个抽象类、实现Servlet接口、ServletConfig接口、Serializable接口,实现了Service()并声明成抽象方法,子类必须实现。

    package javax.servlet;
    
    import java.io.IOException;
    import java.io.Serializable;
    import java.util.Enumeration;
    
    public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
        private static final long serialVersionUID = 1L;
        private transient ServletConfig config;
    
        public GenericServlet() {
        }
    
        public void destroy() {
        }
    
        public String getInitParameter(String name) {
            return this.getServletConfig().getInitParameter(name);
        }
    
        public Enumeration<String> getInitParameterNames() {
            return this.getServletConfig().getInitParameterNames();
        }
    
        public ServletConfig getServletConfig() {
            return this.config;
        }
    
        public ServletContext getServletContext() {
            return this.getServletConfig().getServletContext();
        }
    
        public String getServletInfo() {
            return "";
        }
    
        public void init(ServletConfig config) throws ServletException {
            this.config = config;
            this.init();
        }
    
        public void init() throws ServletException {
        }
    
        public void log(String msg) {
            this.getServletContext().log(this.getServletName() + ": " + msg);
        }
    
        public void log(String message, Throwable t) {
            this.getServletContext().log(this.getServletName() + ": " + message, t);
        }
    
        public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    
        public String getServletName() {
            return this.config.getServletName();
        }
    }

    HttpServlet类:

    是一个抽象类,继承了抽象类GenericServlet,使用了HttpServletRequest 和 HttpServletResponse进行封装

    abstract class HttpServlet extends GenericServlet{
     
       //HttpServlet中的service()
       protected void service(HttpServletRequest httpServletRequest,
                           HttpServletResponse httpServletResponse){
            //该方法通过httpServletRequest.getMethod()判断请求类型调用doGet() doPost()
       }
     // HttpServletRequest接口:提供基于HTTP协议的请求视图。该接口中定义的方法用于获取HTTP请求头信息。Cookie信息等。
    // HttpServletResponse接口:提供基于HTTP协议的响应视图。该接口中定义的方法用于设置HTTP请求头信息。Cookie信息等
       //必须实现父类的service()方法
       public void service(ServletRequest servletRequest,ServletResponse servletResponse){
          HttpServletRequest request;
          HttpServletResponse response;
          try{
             request=(HttpServletRequest)servletRequest;
             response=(HttpServletResponse)servletResponse;
          }catch(ClassCastException){
             throw new ServletException("non-http request or response");
          }
          //调用service()方法
          this.service(request,response);
       }
    }

    Servlet 部署

    通过web.xml来部署:Servlet01

     

    <web-app>
    <servlet>
    <servlet-name>Servlet01</servlet-name>
      #完全限定名=包名+类名
    <servlet-class>cn.xy.servlet.Servlet01</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>Servlet01</servlet-name>
    <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    </web-app> 
     

    通过注解方式来部署Servlet01

    @WebServlet(name = "Servlet01",urlPatterns = {"/hello"})
    或者
    @WebServlet("/hello")

    servlet 浏览器访问路径配置有个小问题:

    1、java 类里的注解 —— @WebServlet("/HelloServlet") 对应浏览器路径:

    http://localhost:8080/TomcatTest/HelloServlet
     

    2、配置文件(web.xml)里对应的浏览器访问路径:

    http://localhost:8080/TomcatTest/TomcatTest/HelloServlet

    这两种配一个就好了,不然路径重名的话反而会让tomcat启动不了。

    例如这样就启动不了:

    修改 web.xml :

    <url-pattern>/HelloServlet</url-pattern>

    修改后,web.xml 和 java 类的注解,对应路径都是:

    http://localhost:8080/TomcatTest/HelloServlet

    导致

    命名的 servlet[HelloServlet]和 [com.runoob.test.HelloServlet] 都被映射到 URL 模式 [/ HelloServlet] 这是不允许的。


     

    解决方法

    注解去掉或者保留注解进入web.xml将映射删除既可以。

    Servlet 映射的类型和顺序:

    1、  精确映射 /test/index.jsp 请求路径必须是/test/index.jsp

    2、  路径映射 /test/*        请求路径可能是/test/index.html或者/test/index.jsp

    3、  扩展映射 *.jsp                    请求路径后缀带.jsp都行

    4、  默认映射 如果无法匹配的Servlet,则将请求转发给默认的Servlet;如果没有默认的Servlet,则返回404

    初始化参数:

    <web-app>
    <context-param>
            <!--全局初始化参数-->
            <param-name>name</param-name>
            <param-value>ayao</param-value>
    </context-param>
    </web-app>
    通过ServletContext的getInitParamter()来获取全局初始化参数
    <web-app>
    <servlet>  
    <servlet-name>Servlet01</servlet-name>
    <servlet-class>cn.xy.servlet.Servlet01</servlet-class>
    <init-param>
         <!--局部servlet初始化参数-->
         <param-name>name</param-name>
         <param-value>ayao</param-value>
     </init-param>
    </servlet>
    <servlet-mapping>
    <servlet-name>Servlet01</servlet-name>  
    <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    </web-app>
    通过ServletConfig接口中的getInitParamter()在init()方法中获取初始化参数

     

     

  • 相关阅读:
    APIO2007 动物园
    SCOI2010 股票交易
    USACO13NOV No Change G
    洛谷 P3694 邦邦的大合唱站队
    洛谷 P6196 3月月赛 ERR1 代价
    洛谷月赛 ERR1 代价
    Splay 学习笔记
    HNOI2009 梦幻布丁
    乘法逆元
    【洛谷】【二分答案+最短路】P1462 通往奥格瑞玛的道路
  • 原文地址:https://www.cnblogs.com/zero-vic/p/10198050.html
Copyright © 2020-2023  润新知