• JavaWeb之组件Servlet详解


    目录

    一.Servlet简介:

    二.Servlet接口:

    三.Servlet的抽象实现类:


    一.Servlet简介:

     1.1 什么是Servlet:

    Servlet全称Java Servlet 是用Java编写在服务端程序,主要是动态生成Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。

        Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

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

            下图:

    1.2.Servlet的主要任务:

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

    二.Servlet接口:

      2.1 Servlet简介:

    我们讲的Servlet就是一个所有的Servlet类直接或者间接必须实现的接口。而实现Servlet有三种方式:

    • 实现javax.servlet.Servlet接口;

    • 继承javax.servlet.GenericServlet类;

    • 继承javax.servlet.http.HttpServlet类;(这个是我们主要用的)

    当我们实现Servlet时,Servlet容器(服务器,现阶段Tomcat)会将Servlet类加载,并且产生一个Servlet实例以及调用具体的方法,Servlet实现类不需要程序员自己创建对象,在Servlet容器就已经创建好对象了。

      注意点:

               1.每一个Servlet类只能有一个实例对象(由容器创建)。 

     2.2 Servlet的工作流程:

    当客户端发送请求到服务端时,服务器都会创建一个request对象,response对象,并把请求数据封装到request中,response对象用来对客户端进行响应,然后在调用Servlet.service()方法时传递给service()方法 ,调用sevice()方法之后把进行数据处理,形成动态数据,之后通过response对象对客户端进行响应。          

       request的主要功能:

    • 封装了请求头数据;

    • 封装了请求正文数据,如果是GET请求,那么就没有正文;

    • request是一个域对象,可以把它当成Map来添加获取数据;

    • request提供了请求转发和请求包含功能。

     

     response的主要功能:

    • 设置响应头信息;

    • 发送状态码;

    • 设置响应正文;

    • 重定向;

    2.3 Servlet接口的方法:

    Servlet接口定义了五种方法:

    1. * 实现Servlet的第一种方式
    2. * 实现javax.servlet.Servlet接口
    3. public class AServlet implements Servlet {
    4. private ServletConfig servletConfig; //默认null
    5. /**
    6. * 初始化方法 生命周期方法, 由Tomcat调用 做初始化操作
    7. * 在Servlet创建之后调用, 调用一次
    8. * @param servletConfig
    9. * @throws ServletException
    10. */
    11. @Override
    12. public void init(ServletConfig servletConfig) throws ServletException {
    13. System.out.println("555~~555,我出生了...");
    14. this.servletConfig = servletConfig;
    15. }
    16. /**
    17. * 得到ServletConfig对象 (Servlet的配置)
    18. *
    19. * @return
    20. */
    21. @Override
    22. public ServletConfig getServletConfig() {
    23. return servletConfig;
    24. }
    25. /**
    26. * 最重要的方法, 接收用户请求,处理用户请求, 响应结果
    27. * Tomcat调用: 生命周期方法 , 每请求一次,执行一次
    28. * @param servletRequest
    29. * @param servletResponse
    30. * @throws ServletException
    31. * @throws IOException
    32. */
    33. @Override
    34. public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    35. System.out.println("AServlet 正在服务...");
    36. //获取Servlet配置
    37. //System.out.println("Servlet的名字:"+servletConfig.getServletName());
    38. //获取初始化参数
    39. //根据初始化参数名获取值
    40. String name = servletConfig.getInitParameter("name");
    41. System.out.println("name:"+name);
    42. //获取所有的初始化参数名
    43. Enumeration names = servletConfig.getInitParameterNames();
    44. //遍历
    45. while(names.hasMoreElements()){
    46. String key = names.nextElement(); //参数名
    47. String value = servletConfig.getInitParameter(key);
    48. System.out.println("key:"+key+"--value:"+value);
    49. }
    50. }
    51. /**
    52. * 没什么意义
    53. * 得到Servlet的描述
    54. * @return
    55. */
    56. @Override
    57. public String getServletInfo() {
    58. return null;
    59. }
    60. /**
    61. * 销毁方法, 释放资源
    62. * 生命周期方法, Tomcat调用,
    63. * 在Servlet销毁之前调用, 只执行一次
    64. */
    65. @Override
    66. public void destroy() {
    67. System.out.println("555~555~我走了...");
    68. }
    69. }

     这五个方法描述了Servlet的生命周期,从生到死的过程:

      出生:默认情况下,第一次请求时,由Tomcat创建。

                调用init方法。

       运行:用户每请求一次这个Servlet, tomcat调用一次service()方法。

       死亡:当Tomcat服务器关闭之前, 销毁它创建的所有对象,包含创建Servlet, 在Servlet销毁之前, 调用destroy()

     

    2.4 ServletConfig接口:

    当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init( )方式传入一个ServletConfig对象。 ServletConfig对象,由服务器创建。

      主要方法:

    • String getServletName():获取Servlet在web.xml文件中的配置名称,即指定的名称;

    • ServletContext getServletContext():用来获取ServletContext对象,

    • String getInitParameter(String name):用来获取在web.xml中配置的初始化参数,通过参数名来获取参数值;

    • Enumeration getInitParameterNames():用来获取在web.xml中配置的所有初始化参数名称;

     

    2.5 ServletContext对象:

    ServletContext对象表示Servlet应用程序。每个Web应用程序都只有一个ServletContext对象。在将一个应用程序同时部署到多个容器的分布式环境中,每台Java虚拟机上的Web应用都会有一个ServletContext对象。

     ServletContext对象的作用是在整个Web应用的动态资源之间共享数据!例如在AServlet中向ServletContext对象中保存一个值,然后在BServlet中就可以获取这个值,这就是共享数据了。

                    通过在ServletConfig中调用getServletContext方法,也可以获得ServletContext对象。

    在HttpServlet中可以直接调用 getServletConfig()方法,因为HttpServlet继承了GenericServlet,而GenericServlet实现了ServletConfig,并且GenericServlet有 getServletConfig(),所以在HttpServlet中可以直接调用得到ServletContext对象。

        ServletContext servletContext = getServletConfig().getServletContext();

    三.Servlet的抽象实现类:

    3.1 GenericServlet抽象类 :

    我们编写Servlet一直是通过实现Servlet接口来编写的,但是,使用这种方法,则必须要实现Servlet接口中定义的所有的方法,即使有一些方法中没有任何东西也要去实现,并且还需要自己手动的维护ServletConfig这个对象的引用。因此,这样去实现Servlet是比较麻烦的。
       而GenericServlet抽象类则有三个好处:

    1.为Servlet接口中的所有方法提供了默认的实现,则程序员需要什么就直接改什么,不再需要把所有的方法都自己实现了。

    2.并且提供方法,包围ServletConfig对象中的方法。

    3.将init( )方法中的ServletConfig参数赋给了一个内部的ServletConfig引用从而来保存ServletConfig对象,不需要程序员自己去维护ServletConfig了。

    注:但是我们很少用 GenericServlet抽象类,因为主要使用HttpServlet

    以下是 GenericServlet抽象类代码:

    1. //
    2. // Source code recreated from a .class file by IntelliJ IDEA
    3. // (powered by Fernflower decompiler)
    4. //
    5. package javax.servlet;
    6. import java.io.IOException;
    7. import java.io.Serializable;
    8. import java.util.Enumeration;
    9. public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
    10. private static final long serialVersionUID = 1L;
    11. private transient ServletConfig config;
    12. public GenericServlet() {
    13. }
    14. public void destroy() {
    15. }
    16. public String getInitParameter(String name) {
    17. return this.getServletConfig().getInitParameter(name);
    18. }
    19. public Enumeration getInitParameterNames() {
    20. return this.getServletConfig().getInitParameterNames();
    21. }
    22. public ServletConfig getServletConfig() {
    23. return this.config;
    24. }
    25. public ServletContext getServletContext() {
    26. return this.getServletConfig().getServletContext();
    27. }
    28. public String getServletInfo() {
    29. return "";
    30. }
    31. public void init(ServletConfig config) throws ServletException {
    32. this.config = config;
    33. this.init();
    34. }
    35. public void init() throws ServletException {
    36. }
    37. public void log(String message) {
    38. this.getServletContext().log(this.getServletName() + ": " + message);
    39. }
    40. public void log(String message, Throwable t) {
    41. this.getServletContext().log(this.getServletName() + ": " + message, t);
    42. }
    43. public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    44. public String getServletName() {
    45. return this.config.getServletName();
    46. }
    47. }

     3.2  HttpServlet抽象类:

    HttpServlet类是GenericServlet的子类,它提供了对HTTP请求的特殊支持,所以HttpServlet抽象类覆盖了GenericServlet抽象类中的Service( )方法,并且添加了一个自己独有的Service(HttpServletRequest request,HttpServletResponse方法。

     

    HttpServlet中的service方法把接收到的ServletRequsest类型的对象转换成了HttpServletRequest类型的对象,把ServletResponse类型的对象转换成了HttpServletResponse类型的对象。之所以能够这样强制的转换,是因为在调用Servlet的Service方法时,Servlet容器总会传入一个HttpServletRequest对象和HttpServletResponse对象,预备使用HTTP。因此,转换类型当然不会出错了。

        转换之后,service方法把两个转换后的对象传入了另一个service方法,那么我们再来看看这个方法是如何实现的:
     

    1. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    2. String method = req.getMethod();
    3. long lastModified;
    4. if (method.equals("GET")) {
    5. lastModified = this.getLastModified(req);
    6. if (lastModified == -1L) {
    7. this.doGet(req, resp);
    8. } else {
    9. long ifModifiedSince;
    10. try {
    11. ifModifiedSince = req.getDateHeader("If-Modified-Since");
    12. } catch (IllegalArgumentException var9) {
    13. ifModifiedSince = -1L;
    14. }
    15. if (ifModifiedSince < lastModified / 1000L * 1000L) {
    16. this.maybeSetLastModified(resp, lastModified);
    17. this.doGet(req, resp);
    18. } else {
    19. resp.setStatus(304);
    20. }
    21. }
    22. } else if (method.equals("HEAD")) {
    23. lastModified = this.getLastModified(req);
    24. this.maybeSetLastModified(resp, lastModified);
    25. this.doHead(req, resp);
    26. } else if (method.equals("POST")) {
    27. this.doPost(req, resp);
    28. } else if (method.equals("PUT")) {
    29. this.doPut(req, resp);
    30. } else if (method.equals("DELETE")) {
    31. this.doDelete(req, resp);
    32. } else if (method.equals("OPTIONS")) {
    33. this.doOptions(req, resp);
    34. } else if (method.equals("TRACE")) {
    35. this.doTrace(req, resp);
    36. } else {
    37. String errMsg = lStrings.getString("http.method_not_implemented");
    38. Object[] errArgs = new Object[]{method};
    39. errMsg = MessageFormat.format(errMsg, errArgs);
    40. resp.sendError(501, errMsg);
    41. }
    42. }

    这个service方法的参数是HttpServletRequest对象和HttpServletResponse对象,刚好接收了上一个service方法传过来的两个对象。我们会发现在service方法中还是没有任何的服务逻辑,但是却在解析HttpServletRequest中的方法参数,并调用以下方法doGet,doPost,doHead,doPut,doTrace,doOptions和doDelete。这7种方法中,每一种方法都表示一个Http方法。doGet和doPost是最常用的。所以,如果我们需要实现具体的服务逻辑,不再需要覆盖service方法了,只需要覆盖doGet或者doPost就好了。所以我们只需要写doget和doPost方法了。这样使代码更加简洁。

    1. public class aServlet extends HttpServlet {
    2. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    3. }
    4. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    5. }
    6. }

     

  • 相关阅读:
    spring笔记-ioc容器 大概流程
    服务器存储面临的两大难题
    【网络安全 --- PHP基础】学网安PHP语言所涉及到的知识,来看看吧,看着一篇文章就够了,建议收藏学习!!!
    Vue v-for、v-if、v-show常见问题
    物联网的应用——工业自动化
    基于Java毕业设计弹幕视频网站源码+系统+mysql+lw文档+部署软件
    Spring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)
    @Builder使用遇到的坑
    UI布局:Margin和absolute的区别
    数据库概论 - MySQL的简单介绍
  • 原文地址:https://blog.csdn.net/qq_50692350/article/details/127417513