Java Web Application——servlet
概述
是一个部署于web服务器中的实现了servlet接口的Java类,用于响应web请求
Web容器(也称为servlet容器)本质上是与servlet交互的Web服务器的组件。Web容器负责管理servlet的生命周期,将URL映射到特定的servlet,并确保URL请求者具有正确的访问权限。
和CGI相比更有性能优势
流程
- 假设用户请求访问URL。
- 浏览器为此URL生成HTTP请求。
- 将此请求发送到适当的服务器。
- HTTP请求由Web服务器接收并转发到servlet容器。
- 容器将此请求映射到特定的servlet。
- 动态检索servlet并将其加载到容器的地址空间中。
- 容器调用servlet 的init()方法。
- 仅当servlet首次加载到内存中时才会调用此方法。
- 可以将初始化参数传递给servlet,以便它可以自行配置。
- 容器调用servlet 的service()方法。
- 调用此方法来处理HTTP请求。
- servlet可以读取HTTP请求中提供的数据。
- servlet还可以为客户端制定HTTP响应。
- servlet保留在容器的地址空间中,可用于处理从客户端收到的任何其他HTTP请求。
- 每个HTTP请求都会调用service()方法。
- 每个请求都在自己独立的线程中提供服务。
- Web容器为每个请求调用servlet 的service()方法。该service()方法确定正在进行的请求的类型,并将其分派给适当的方法来处理请求。servlet的开发人员必须为这些方法提供实现。如果对servlet未实现的方法发出请求,则调用父类的方法,通常会导致将错误返回给请求者。
- service()方法有参数:
- ServletRequest req:从容器接收的请求数据
- ServletResponse res:返回给容器的响应数据
- 在某些时候,容器可能决定从其内存中卸载servlet。
- 做出此决定的算法特定于每个容器。
- 容器调用servlet的destroy()方法来放弃任何资源,例如为servlet分配的文件句柄; 重要数据可以保存到持久性存储中。
- 然后可以对为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映射,则其映射优先于隐式映射