servlet包结构:
- javax.servlet:定义servlet与 servlet容器的交互接口和类(即协议)。
- javax.servlet.http:定义httpservlet 与 servlet容器的交互接口和类(即协议)。
- javax.servlet.annotation:定义相关注解,即被注解的类的元数据
- javax.servlet.descripter:提供程序化登录web容器的配置信息相关类
主要类和接口:
- Servlet <- GenericServlet \ ServletConfig \ ServletInfo
- ServletRequest \ ServletResponse (每次请求)
- Filter
- ServletContext \ RequestDispatcher (全局)
几种概念之间的关系:
- 一个Servlet容器 装载 多个应用程序。
- 一个应用程序 在Servlet容器中 对应一个ServletContext, 多个Servlet类。
- 一个Servlet类 在Servlet容器中 只会有一个Servlet实例,
- 一个Servlet实例 在Servlet容器中 对应一个ServletConfig、ServletInfo
Servlet接口的主要方法:
- init,只在第一次请求这个Servlet时被容器调用,同时容器会创建一个相应的ServletConfig实例作为参数给这个方法
- service,每次请求时都会调用,同时容器会将解析http请求后封装出的一个ServletRequest实例、和一个ServletResponse实例给这个方法
- destroy,在应用程序被卸载或Servlet容器关闭时被调用
- getServletConfig,应该返回容器调用init方法传递的那个ServletConfig实例参数
- getServletInfo,一个描述这个Servlet的字符串或者null
由于一个Servlet实例会被所有请求共享、所有用户共享,因此需要注意线程安全,不建议使用类变量,除非它们是只读的、或者java.util.concurrent.atomic包下的类型。
servlet应用(应用程序)的目录结构:
假如我们的应用程序为app01,则app01目录即应用程序目录,app01目录下有WEB-INF和lib两个子目录,
所有servlet类都必须放在WEB-INF目录下,如果应用程序引用了除了serlet API和java API之外的其它类,需要把类所在jar包放到lib目录下。
通常我们的servlet应用都要引用一些图片和html等,这些资源文件可以放在应用程序目录即app01根目录下,放在应用程序下的任何资源,用户只要在浏览器中直接输入url,都可以直接访问。
通常我们都会在应用程序根目录下另外创建子目录,例如jsp目录、html目录、image目录等,来存放资源文件。但是如果资源文件不想被除Servlet类之外的东西直接访问,则需要放在WEB-INF目录或者其子目录下。
servlet应用(应用程序)的部署
- 方式一:打包成war包,放到webapps目录下。servlet容器会自动部署应用,如果war包有更新,也会自动重新部署。
- 方式二:修改config目录下的server.xml文件,添加应用对应的context元素,设置docBase和path,
- 方式三:直接在conf/catalina/localhost目录下新建一个应用对应的xml文件,设置dobBase和reloadable
访问Servlet:
- 协议名://主机名 or IP:端口号/path/servlet-url
- 如果war包放在了webapps目录下下自动部署,则path就是war文件的文件名
- 如果在server.xml中配置了conext元素来部署,则path就是context元素中path属性的值。
- 如果新建了一个xml文件配置的,则path就是xml文件的文件名
ServletRequest \ ServletResponse
- request.getContentType() \ getContentLength \ getParameter \ getProtocal
- response.getWriter() \ getOutputStream()
ServletConfig
- Servlet::init(ServletConfig servletConfig):当第一次请求某个Servlet类时,容器会调用这个Servlet的 init 方法初始化这个Servlet实例,并将一个ServletConfig实例传递给init方法
- getInitParameter(String paramName) :Servlet容器为一个Servlet创建相应的ServletConfig实例时,会将部署描述符(web.xml文件)中配置在这个servlet下的<initparameter><name>…<value>…<\initparameter>元素、或者注解在这个servlet上的@WebServlet(…initParams={@WebInitParam(name="",value=""), @WebInitParam(…)})中的name和value数据提取,封装到ServletConfig实例中。
- getServletName():同上,容器会将部署描述符中或者@WebServlet注解中的name封装到ServletConfig实例中
- ServletConfig::getServletContext():容器会将Servlet所在应用程序 在容器中对应的ServletContext实例 封装到这个Servlet对应的的ServletConfig实例中
ServletContext
- 容器启动时,会为每个要部署到Servlet容器中的Servlet应用程序创建一个ServletContext实例。这个ServletContext实例的生命周期同对应的应用程序的周期是一致的。
- ServletContext实例封装了应用程序的哪些信息?Servlet容器会读取每个Servlet应用程序部署描述符文件(web.xml)、或者解析注解,解析web.xml文件中的所有Listener、Filter、Servlet以及其initParam\name\urlPattern等配置信息,还有session过期设置等数据,都封装到ServletContext中
- setAttribute \ getAttribute \ removeAttribute :因为ServletContext的生命周期同应用程序的一致,因此当需要记录全局数据时,可以设置数据到ServletContext中,作为一个Attribute。
- getInitParameter(String name):获取部署描述符(web.xml)中配置的应用程序参数<context-param>
- getContextPath():获取web应用的path,即访问servlet时的 协议://主机:端口号/path/servlet-url 中的path
- getSessionCookieConfig():获取部署描述符web.xml中的关于Session超时等的配置。
- getRequestDispatcher(String servletName):返回一个包装了给定的Servlet的RequestDispatcher
- createServlet() \ createFilter() \ createListener():支持动态创建Servlet等实例对象
- addServlet() \ addFilter() \ addListener():支持动态添加Servlet等对象到容器中
- getServletRegistration(String servletName):获取某个Servlet的ServletRegistration实例对象,可以利用这个对象动态地进一步地对Servlet进行配置。
- getResoucesAsStram(String path):读取某个资源文件,可能是一些配置信息
GenericServlet:
- 如果我们开发Servlet应用程序时,直接实现Servlet接口,则每次实现都要实现所有的方法,并且每次都要定义一个实例域servletConfig,来存储容器传递给init方法的servletConfig实例,作为getServletConfig()方法的返回值。这种情况下,就应该提取公共代码,因此又定义了抽象类GenericServlet
- 在GenericServlet类中,对除service方法之外的接口方法都做了默认实现。
- GenericServlet类又实现了ServletConfig接口,并定义了实例域servletConfig,因此可以直接调用getServletContext()方法,来获取应用程序上下文
HttpServlet:
- HttpServlet类继承了GenericServlet类,并扩展出了一个service(HttpServletRequest req, HttpServletResponse res)方法,和doGet \ doPost \ doHead \ doPut \ doTrace() \ doOptions \ doDelete方法
- service(HttpServletRequest req, HttpServletResponse res):会根据req中的HTTP方法来调用相应的doXXX方法
- 开发继承HttpServlet类时,只需实现相应的doXXX方法,而不用实现service方法
- getLastModified(HttpServletRequest req):提供了这样一个方法,可以获取请求最后被修改的时间
HttpServletRequest接口:
- 继承了ServletRequest接口
- 定义了几个代表认证方式的常量:BASIC_AUTH \ FORM_AUTH \ DIGEST_AUTH \ CLIENT_CERT_AUTH \
- getMethod() \ getCookies \ getQueryString \ getSession \ getContextPath
- getHeader \ getHeaders \ getIntHeader(String headerName) \ getDateHeader()
- authenticate(HttpServletResponse res):验证发出此请求的用户,使用ServletContext中保存的用户配置的认证方式
- getAuthType() \ login(String username, String passwrod) \ logout() \ isUserInRole(String roleName)
部署描述符:web.xml
- 部署描述符的文件名必须是web.xml,文件必须位于WEB-INF目录的根目录下
- web.xml中可以配置一些在@WebServlet中没有的元素,比如servlet的子元素load-on-startup,可以设定servlet在容器启动时就实例化并初始化,因为有些初始化可能比较耗时,如果在第一次请求时在初始化,可能会响应慢、影响用户体验
- 相对于@WebServlet注解,在web.xml中修改配置项后,不需要重新编译Servlet类。