HTTPServlet源码分析

HTTPServlet源码分析

  • HttpServelt类是专门为HTTP协议准备的。比GenericServlet更加适合HTTP协议下的开发。

  • HttpServlet在哪个包下?

    • jakarta.servlet.http.HttpServlet
  • 到目前为止我们接触了了servlet规范中的那些接口?

    • jakarta.servlet.Servelt 核心接口
    • jakarta.servlet.ServeltConfig Servlet配置信息接口
    • jakarta.servlet.ServeltContext Servlet上下文接口
    • jakarta.servlet.ServeltRequest Servlet请求接口
    • jakarta.servlet.ServeltResponse Servlet响应接口
    • jakarta.servlet.ServeltException Servlet 异常接口
    • jakarta.servlet.GenericServlet Servlet 实现类接口
  • Http包下都有哪些类和接口呢?jakarta.servlet.http.*;

    jakarta.servlet.http.HttpServlet(HTTP协议专用的Servlet类,抽象类)
    jakarta.servlet.http.HttpServletRequest(HTTP协议专用的请求对象)
    jakarta.servlet.http.HttpServletResponse(Http协议专用的响应对象)

  • HttpServletRequest对象中封装了什么信息?

    HttpServletRequest,简称request对象。
    HttpServletRequest中封装了请求协议的全部内容。
    Tomcat服务器(WEB服务器)将“请求协议”中的数据全部解析出来,然后将这些数据全部封装到了request对象当中了。
    也就说,我们要面向HttpServletRequest,就可以获取协议中的数据

  • HttpServletResponse对象是专门用来响应HTTP协议到浏览器的。

  • 回忆Servelt生命周期?

    1. 用户第一次请求

      • Tomcat服务器通过反射机制,创建Servlet对象。(web.xml文件中的配置的Servlet类对应的对象。)
      • Tomcat服务器调用Servlet对象的init方法完成初始化。
      • Tomcat服务器调用Servlet对象的service方法处理请求。
    2. 用户的第二次请求

      • Tomcat服务器调用Servlet对象的service方法处理请求。
        • Tomcat服务器调用Servlet对象的service方法处理请求。
      • …(.Tomcat服务器调用Servlet对象的service方法处理请求。)
      • 服务器关闭
      • Tomcat服务器调用Servlet对象的destroy方法,做销毁之前的准备工作。
  • HttpServlet 源码分析

    public class HelloServlet extends HttpServlet {
        //用户第一次请求,创建HelloServlet对象的时候,会执行这个无参数构造方法。
        public HelloServlet(){}
    }
    public abstract class GenericServlet implements Servlet,ServletConfig,java.io.Serializable{
        //用户第一次请求的时候,HelloServlet对象第一次被创建之后,这个init方法会执行。
        public void init(ServletConfig config) throws ServletException{
            this.config = config;
            this.init()
        }
        //用户第一次请求的时候,带有参数的init(ServletConfig config)执行之后,会执行这个没有参数的init()
        public void init() throws ServletException{
            
        }
    }
    
    //HttpServlet是一个典型的模板类
    public abstract class HttpServlet extends GenericServlet{
        //用户发送第一次请求的时候这个service会执行
        //用户发送第N次请求的时候,这个service方法还是会执行。
        //用户只要发送一次请求,这个service方法就会执行一次。
         public void service(ServletRequest req, ServletResponse res)
             throws ServletException, IOException {
            HttpServletRequest request;
            HttpServletResponse response;
            try {
                //将ServletRequest和ServeltResponse向下转型为带有Http的HttpServletRequest和HttpServletResponse
                request = (HttpServletRequest)req;
                response = (HttpServletResponse)res;
            } catch (ClassCastException var6) {
                throw new ServletException(lStrings.getString("http.non_http"));
            }
    		//调用重载的service方法
            this.service(request, response);
        }
        
        //这个service方法的两个参数都是带有Http的
        //这个service是一个模板方法
        //在该方法中定义核心算法骨架,具体的实现步骤延迟到子类中去完成。
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //获取请求方式
            //这个请求方式最终可能是:""
            //注意:request.getMethod()方法获取的是请求方式,可能是七种之一:
            //GET POST DELETE HEAD OPTIONS OOPTIONS TRACE
            String method = req.getMethod();
            long lastModified;
            if (method.equals("GET")) {
                lastModified = this.getLastModified(req);
                if (lastModified == -1L) {
                    this.doGet(req, resp);
                } else {
                    long ifModifiedSince;
                    try {
                        ifModifiedSince = req.getDateHeader("If-Modified-Since");
                    } catch (IllegalArgumentException var9) {
                        ifModifiedSince = -1L;
                    }
    
                    if (ifModifiedSince < lastModified / 1000L * 1000L) {
                        this.maybeSetLastModified(resp, lastModified);
                        this.doGet(req, resp);
                    } else {
                        resp.setStatus(304);
                    }
                }
            } else if (method.equals("HEAD")) {
                lastModified = this.getLastModified(req);
                this.maybeSetLastModified(resp, lastModified);
                this.doHead(req, resp);
            } else if (method.equals("POST")) {
                this.doPost(req, resp);
            } else if (method.equals("PUT")) {
                this.doPut(req, resp);
            } else if (method.equals("DELETE")) {
                this.doDelete(req, resp);
            } else if (method.equals("OPTIONS")) {
                this.doOptions(req, resp);
            } else if (method.equals("TRACE")) {
                this.doTrace(req, resp);
            } else {
                String errMsg = lStrings.getString("http.method_not_implemented");
                Object[] errArgs = new Object[]{method};
                errMsg = MessageFormat.format(errMsg, errArgs);
                resp.sendError(501, errMsg);
            }
    
        }
    }
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //报405错误
            String msg = lStrings.getString("http.method_get_not_supported");
            this.sendMethodNotAllowed(req, resp, msg);
        }
    
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String msg = lStrings.getString("http.method_post_not_supported");
            this.sendMethodNotAllowed(req, resp, msg);
        }
    
    /*
    通过以上源代码分析:
    	假设前端发送的请求是get请求,后端程序员重写的方法是doPost
    	假设前端发送的请求是Post请求,后端程序员重写的方法是doGet
    	会发生什么呢?
    	发生405这样的一个错误。
    	405表示前端你的错误,发送的请求方式不对。和服务器不一致。不是服务器需要的请求方式。
    	通过以上源代码可以知道:只要HttpServlet类中的doGet方法或doPost方法执行了,必然405.
    	怎么避免405错误呢?
    	后端重写doGet方法,前端一定要发get请求。
    	后端重写doPost方法,前端一定要发Post请求。 
    有的人,你会看到为了避免405错误,在Servlet类当中,将doGet和doPost方法都进行了重写。这样,确实可以避免405的放生,但是不建议,405错误还是有用的,该报错的时候应该让他报错。
    
  • 我们编写的HelloServlet直接继承HttpServlet,直接重写HttpServlet类中的service()方法行吗?

    可以,只不过你享受不到405错误,享受不到HTTP协议专属的东西。

  • 到今天我们终于得到了最终的一个Servlet类的开发步骤:

    • 第一步:编写一个Servlet类,直接继承HttpServlet
    • 第二步:重写doGet方法或者doPost方法,到底重写谁,程序员说了算。
    • 第三步:将Servlet类配置到web.xml文件当中。
    • 第四步:准备前端的页面(from表单),from表单中指定请求路径
posted @   a-tao必须奥利给  阅读(103)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示