SpringMVC学习之HttpServlet 阅读笔记

简要说明

HttpServlet 抽象类是GenericServlet的子类,HttpServlet类为servlet接口提供了与HTTP协议相关的通用实现,也就是说HttpServlet对象适合运行在与客户端采用HTTP协议通信的servlet容器或web服务器中。

请求类型

(仅包含HttpServlet里面默认实现):
GET: 请求指定的文档的内容。
POST: 请求服务器接受所指定的文档作为对所标识的URI的新的从属实体。
PUT: 从客户端向服务器传送的数据取代指定的文档的内容。
DELETE: 请求服务器删除指定的页面。
HEAD: 仅返回头部信息。
OPTIONS: 返回服务器的请求类型列表。
TRACE: 用作调试,返回请求 URL, 版本信息以及请求的头信息。

解析service()方法

  1. 作用:被Servlet容器调用,完成请求
    1) 把请求转发到具体的方法上,通过调用重载的service(HttpServletRequest,HttpServletResponse)
    2) 完成这个方法做的事情就是把request和response转换成HttpServerRequest,HttpServletResponse,
    3) 具体的转发工作由重载的service方法完成(通过method类型,转发请求给不同的方法处理,如:doGet、doPut等)
  2. GET方式的缓存逻辑(图见底部)
    1)首先通过getLastModified(req)获得修改时间lastModified
    2)如果修改时间为-1直接调用doGet方法处理请求
    3)如果不是-1,则获取请求中的Modified_Since的值ifModifiedSince,
    3.1) ifModifiedSince 大于lastModified,缓存未过期,返回304通知浏览器,直接使用缓存
    3.2) ifModifiedSince小于lastModified,缓存失效,调用doGet,同时ifModifiedSince = lastModified

init()方法

  1. 谁来调用
    由servlet容器调用,以指示将servlet放入服务中的servlet。
  2. ServletConfig 是什么
    servlet容器在初始化期间将信息传递给servlet的servlet配置对象。
  3. init方法能做什么
    在servlet的生命周期中,init()方法仅会被执行一次,可以被覆盖;因此,可用来初始化一些配置信息信息,如:http数据库的连接,spring容器初始化配置信息等等

    destory()方法

    当Servlet对象退出声明周期时,负责释放占有的资源

源码解析

  1. doGet、doPost、doPut、doDelete默认实现(相同)
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{

   String protocol = req.getProtocol(); //返回请求协议

   String msg = lStrings.getString("http.method_get_not_supported"); 
    //由于是默认实现,根据不同的协议,直接报错if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);

    } else {
      resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
    }   
   } 
  1. doHead()方法解析
//仅返回头部信息,不返回实体
 protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    //申明一个空实体

    NoBodyResponse response = new NoBodyResponse(resp);
    //调用doGet方法

    doGet(req, response);
    //将实体长度为空

    response.setContentLength();

        }
  1. doTrace()方法解析
//这个方法返回一个字符串到 HTTP 响应体里面,这个字符串包含请求 URL, 版本信息以及请求的头信息,主要是用来调试 
   protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


   int responseLength;

   //回车换行符

   String CRLF = "\r\n";
    //链接URI字符串和版本协议信息

    String responseString = "TRACE "+ req.getRequestURI()+ " " + req.getProtocol();


    Enumeration reqHeaderEnum = req.getHeaderNames();

    //遍历所有请求头信息while( reqHeaderEnum.hasMoreElements() ) {

        String headerName = (String)reqHeaderEnum.nextElement();
        // 拼接所有的请求头到字符串中,并且使用:分割名值对,每对头信息之间使用回车换行进行分隔
        responseString += CRLF + headerName + ": " + req.getHeader(headerName); 
   }

        // 附着回车换行符到字符串结尾

        responseString += CRLF;

        // 取得字符串字节长度信息

        responseLength = responseString.length();

        // 设置响应类型为 message/http
        resp.setContentType("message/http");    
       // 设置响应体的长度
       resp.setContentLength(responseLength);

       ServletOutputStream out = resp.getOutputStream();
       // 输出字符串消息到响应中 out.print(responseString);   
       // 关闭相应流,结束操作 out.close();

       return;

    }
  1. service()方法解析
//实际处理请求类,可以被重写
 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {

 HttpServletRequest request;

 HttpServletResponse    response;


 try {

     request = (HttpServletRequest) req;

     response = (HttpServletResponse) res;

     } catch (ClassCastException e) {

     throw new ServletException("non-HTTP request or response");

     }

     service(request, response);
}

//默认实现
protected void service(HttpServletRequest req, HttpServletResponse resp)   throws ServletException, IOException   {   
    // 从 HTTP 请求中取得这次请求所使用的 HTTT 方法   
    String method = req.getMethod();   
    if (method.equals(METHOD_GET)) {   
        // 如果这次请求使用 GET 方法   
        // 取得这个 Servlet 的最后修改的时间   
        long lastModified = getLastModified(req);   
        if (lastModified == -1) {   
            //-1 代表这个 Servlet 不支持最后修改操作,直接调用 doGet() 进行处理 HTTP GET 请求   
            doGet(req, resp);   
        } else {   
            // 如果这个 Servlet 支持最后修改操作,取得请求头中包含的请求的最后修改时间   
            long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);   

            if (ifModifiedSince < (lastModified / 1000 * 1000)) {   
            // 如果请求头中包含的修改时间早于这个 Servlet 的最后修改时间,说明这个 Servlet 自从客户上一次 HTTP 请求已经被修改了 , 设置最新修改时间到响应头中   
              maybeSetLastModified(resp, lastModified);    
              // 调用 doGet 进行进行处理 HTTP GET 请求   
              doGet(req, resp);   
             } else {   
                // 如果请求头中包含修改时间晚于这个 Servlet 的最后修改时间,说明这个 Servlet 自从请求的最后修改时间后没有更改过,这种情况下,仅仅返回一个 HTTP 响应状态 SC_NOT_MODIFIED
                     resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);   
             }   
        }   

    } else if (method.equals(METHOD_HEAD)) {   
       ………
    } else {   
       // 如果这次请求是其他未知方法,返回错误代码 SC_NOT_IMPLEMENTED 给 HTTP 响应,并且显示一个错误消息,说明这个操作是没有实现的   
        String errMsg = lStrings.getString( "http.method_not_implemented" );   
        Object[] errArgs = new Object[1];   
        errArgs[0] = method;   
        errMsg = MessageFormat.format(errMsg, errArgs);   

        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);   
    }   
}  
  1. doOptions()方法解析
//返回服务器的请求类型列表
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

   //取得当前这个 Servlet 以及父类 Servlet 声明的所有方法,这些方法不包括本类 HTTP Servlet 所生命的方法
    Method[] methods = getAllDeclaredMethods(this.getClass());


    boolean ALLOW_GET = false;

    boolean ALLOW_HEAD = false;

    boolean ALLOW_POST = false;

    boolean ALLOW_DELETE = false;

    boolean ALLOW_OPTIONS = true;


    for (int i=0; i<methods.length; i++) {

        Method m = methods[i];
        if (m.getName().equals("doGet")) {

            ALLOW_GET = true;

            ALLOW_HEAD = true;

            }

        if (m.getName().equals("doPost"))
            ALLOW_POST = true;
        if (m.getName().equals("doPut"))

            ALLOW_PUT = true;
        if (m.getName().equals("doDelete"))

            ALLOW_DELETE = true;

    }


    String allow = null;
    if (ALLOW_GET)
        if (allow==null) allow=METHOD_GET;
    if (ALLOW_HEAD)

        if (allow==null) allow=METHOD_HEAD;

     else
         allow += ", " + METHOD_HEAD;

    if (ALLOW_POST)
        if (allow==null) allow=METHOD_POST;
    else 
        allow += ", " + METHOD_POST;
    if (ALLOW_PUT)
        if (allow==null) allow=METHOD_PUT;

    else 
        allow += ", " + METHOD_PUT;

    if (ALLOW_DELETE)

        if (allow==null) allow=METHOD_DELETE;
    else 
        allow += ", " + METHOD_DELETE;

    if (ALLOW_TRACE)

        if (allow==null) allow=METHOD_TRACE;

    else allow += ", " + METHOD_TRACE;

        if (allow==null) allow=METHOD_OPTIONS;

    else allow += ", " + METHOD_OPTIONS;

    //返回投信息

    resp.setHeader("Allow", allow);

    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值