Java Web Application——servlet

概述

是一个部署于web服务器中的实现了servlet接口的Java类,用于响应web请求

Web容器(也称为servlet容器)本质上是与servlet交互的Web服务器的组件。Web容器负责管理servlet的生命周期,将URL映射到特定的servlet,并确保URL请求者具有正确的访问权限。

和CGI相比更有性能优势

流程

  1. 假设用户请求访问URL
    1. 浏览器为此URL生成HTTP请求。
    2. 将此请求发送到适当的服务器。
  2. HTTP请求由Web服务器接收并转发到servlet容器。
    1. 容器将此请求映射到特定的servlet。
    2. 动态检索servlet并将其加载到容器的地址空间中。
  3. 容器调用servlet 的init()方法。
    1. 仅当servlet首次加载到内存中时才会调用此方法。
    2. 可以将初始化参数传递给servlet,以便它可以自行配置。
  4. 容器调用servlet 的service()方法。
    1. 调用此方法来处理HTTP请求。
    2. servlet可以读取HTTP请求中提供的数据。
    3. servlet还可以为客户端制定HTTP响应。
  5. servlet保留在容器的地址空间中,可用于处理从客户端收到的任何其他HTTP请求。
    1. 每个HTTP请求都会调用service()方法。
    2. 每个请求都在自己独立的线程中提供服务。
    3. Web容器为每个请求调用servlet 的service()方法。该service()方法确定正在进行的请求的类型,并将其分派给适当的方法来处理请求。servlet的开发人员必须为这些方法提供实现。如果对servlet未实现的方法发出请求,则调用父类的方法,通常会导致将错误返回给请求者。
    4. service()方法有参数:
      1. ServletRequest req:从容器接收的请求数据
      2. ServletResponse res:返回给容器的响应数据
  6. 在某些时候,容器可能决定从其内存中卸载servlet。
    1. 做出此决定的算法特定于每个容器。
  7. 容器调用servlet的destroy()方法来放弃任何资源,例如为servlet分配的文件句柄; 重要数据可以保存到持久性存储中。
  8. 然后可以对为servlet及其对象分配的内存进行垃圾回收。

两个已经实现好的servlet抽象类

GenericServlet

  • 实现了Servlet接口
  • GenericServlet是独立于协议的,可以在J2EE应用程序中用于实现从其他Java类访问的服务

HttpServlet

  • 继承自GenericServlet
  • 用于实现适用于web站点的HTTP servlet
  • 其子类必须实现至少一种以下方法:
    • doGet, if the servlet supports HTTP GET requests
    • doPost, for HTTP POST requests
    • doPut, for HTTP PUT requests
    • doDelete, for HTTP DELETE requests
    • init and destroy, to manage resources that are held for the life of the servlet
    • getServletInfo, which the servlet uses to provide information about itself
  • 重写Service方法是没有必要的,因为已经实现的功能是将标准的HTTP请求根据HTTP请求的类型分发给相应的doXXX方法
  • 标准的Servlet的Service方法的参数是ServletRequest/ServletResponse类型。HttpServlet也有这个方法,但是这个方法会将请求发送给另一个protected的service方法,这个方法的参数是HttpServletRequest/HttpServletResponse类型的

将servlet配置为web应用程序的一部分

在Web应用程序部署描述符(Web.xml)中用<servlet>和<servlet-mapping>将servlet部署为应用程序的一部分

<servlet>:

  • <servlet-name>:定义servlet的名字
  • <servlet-class>:定义执行servlet的已编译类
  • <init-param>:定义初始化属性,这些属性的使用将在ServletConfig中描述
    • <param-name>:变量名
    • <param-value>:变量值
  • <load-on-startup>1<load-on-startup>:可选,如果存在,将在应用程序启动的时候加载servlet并调用其inti方法;若不存在,则在该servlet的第一个请求时加载它

<servlet-mapping>:控制访问servlet的方式

  • <servlet-name>:Servlet的注册名称,可以在多个<servlet-mapping>中相同
  • <url-pattern>:Servlet的对外访问路径

配置JSP:将JSP注册为Servlet

  • JSP也是一种servlet
  • 在第一次调用JSP的时候会按照JSP的名称隐式注册JSP
  • 也可以在Web.xml文件中按照servlet的方式注册:
<servlet>
     <servlet-name>myFoo</servlet-name>
     <jsp-file>myJSPfile.jsp</jsp-file>
</servlet>
<servlet-mapping>
     <servlet-name>myFoo</servlet-name>
     <url-pattern>/main</url-pattern>
</servlet-mapping>

初始化参数的传递——ServletConfig

  • Servlet config对象是servlet容器用于在servlet的初始化期间向servlet发送信息
  • Web容器将会把配置的初始化参数封装到ServletConfig对象中,servlet接口中的init方法会有ServletConfig参数,Web容器将会把封装好的ServletConfig对象发送给init作为参数,这样servlet就可以获取配置的初始化参数
  • 方法
    • getInitParameterNames:以字符串的枚举方式返回配置的所有初始化参数名
    • getInitParameter(String name):按照参数名name返回参数值

将请求映射到servlet

URL:

使用以下模式构造客户端用于访问Web应用程序的URL(UTF-8解码):

http:// hoststring/ ContextPath/ servletPath/pathInfo

  • Hoststring:是映射到虚拟主机的主机名或hostname:portNumber。
  • pathInfo:URL的剩余部分,比如文件名
  • servletPath:代表一个映射到servletPath 的servlet
  • ContextPath:Web应用程序名称

Web容器在接收到客户端请求后将决定要转发给哪一个Servlet,所选择的Servlet的Context Path具有和URL的最长匹配

所使用的匹配到servlet的路径是URL减去context path和path parameters,即servletPath

将按照以下规则顺序匹配,一旦匹配成功将终止

  • 容器将尝试查找请求路径与servlet路径的完全匹配
  • 容器将递归地尝试匹配最长的路径前缀。 这是通过使用'/'字符作为路径分隔符,一次步进路径树(所有的servlet的路径构成的,叶节点作为一个servlet)的一个目录来完成的。 最长匹配确定所选的servlet。
  • 如果URL路径中的最后一个段包含扩展名(例如.jsp),则servlet容器将尝试匹配可以处理扩展请求的servlet。 扩展名定义为最后一个字符后的最后一个段的一部分。
  • 如果前三个规则都不会导致servlet匹配,则容器将尝试提供适合所请求资源的内容。如果为应用程序定义了默认servlet,则将使用它。许多容器提供用于提供内容的隐式默认servlet。

容器进行匹配时区分大小写

在Web应用程序的部署描述符中(<url-pattern>),下列语法将用于定义匹配

  • 以’/’开头且以’/*’结尾的字符串将用于路径匹配
  • 以’*.’开头的字符串将用于扩展名匹配
  • 空字符串是对应用程序的context root的完全匹配,即匹配到http://host:port/<context-root>/
  • ‘/’字符串表示这是web应用的默认servlet
  • 所有其他类型的字符串将用于完全匹配

如果有效的web.xml(在从片段和注释合并信息之后)包含映射到多个servlet的任何url模式,则部署必将失败。

  • 实验:在将两个servlet配置了部分相同的url pattern之后运行tomcat,在显式的信息中有:
  • x月 xx, 20xx x:xx:x x午 org.apache.catalina.core.ContainerBase addChildInternal
    严重: ContainerBase.addChild: start:
    org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/SpringDemo02]]
            at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:162)
            at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1017)
            at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:993)
            at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
            at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1296)
            at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:2039)
            at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:514)
            at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
            at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1135)
            at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
            at java.base/java.lang.Thread.run(Thread.java:844)
    Caused by: java.lang.IllegalArgumentException: The servlets named [DefaultServlet] and [ControllerServlet] are both mapped to the url-pattern [/product_input] which is not permitted
            at org.apache.catalina.deploy.WebXml.addServletMapping(WebXml.java:293)
            at org.apache.catalina.startup.ContextConfig.processAnnotationWebServlet(ContextConfig.java:2448)
            at org.apache.catalina.startup.ContextConfig.processAnnotationsStream(ContextConfig.java:2123)
            at org.apache.catalina.startup.ContextConfig.processAnnotationsJndi(ContextConfig.java:2039)
            at org.apache.catalina.startup.ContextConfig.processAnnotationsUrl(ContextConfig.java:1934)
            at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1303)
            at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:878)
            at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:388)
            at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
            at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
            at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5566)
            at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
            ... 10 more

隐式映射:如果容器具有内部JSP容器,则* .jsp扩展名将映射到它,从而允许按需执行JSP页面。该映射称为隐式映射。 如果Web应用程序定义了* .jsp映射,则其映射优先于隐式映射

猜你喜欢

转载自blog.csdn.net/qq_40711741/article/details/81115856