Java for the Web With Servlets, JSP, and EJB(Part1-Chapter3)jakarta.servlet.http

上一篇Java for the Web With Servlets, JSP, and EJB(Part1-Chapter2)javax.servelt和jakarta.servlet

软件版本:

  • jakarta.servlet/jakarta.servlet-api/6.0.0
  • tomcat 10.1.19
  • jdk-11.0.20

一、HttpServlet

HttpServlet文档

1.1 7个doXxx方法

  • doHead,doPost, doPut, doGet, doDelete, doOptions and doTrace

  • GET在HTTP请求中是默认的方法

  • (在上一篇中,浏览器输入网址访问某个servlet时没有指定方法,按f12打开DevTools,可以看到默认方法就是GET)
    在这里插入图片描述

1.2 HttpServlet源码片段

1.2.1 类定义使用abstract class

抽象类——不能进行实例化(new)的类。想要用abstract class里面的变量和函数,就需要自定义一个继承该类的子类。

package http;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;
public class PostHttpServlet extends HttpServlet {
    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter out = resp.getWriter();
        out.println("doPost");
    }
}

1.2.2 重写了servlet的service函数

在service函数中对request报文头method进行判断。

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        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);
        }

    }

    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }

        this.service(request, response);
    }

1.2.3 除了HEAD/OPTIONS/TRACE,其他method默认是不允许使用的

GET/POST/PUT/DELETE默认状态都是调用sendMethodNotAllowed。如果HttpServlet的子类没有重写对应的doXxx方法,则默认返回的都是“sendMethodNotAllowed——该方法不允许访问”。
所以如果需要这个servlet能处理该方法,就得在HttpServlet的子类中重写,否则就会报“该方法不允许访问”。


public abstract class HttpServlet extends GenericServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = lStrings.getString("http.method_get_not_supported");
        this.sendMethodNotAllowed(req, resp, msg);
    }


    protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (!DispatcherType.INCLUDE.equals(req.getDispatcherType()) && this.cachedUseLegacyDoHead) {
            NoBodyResponse response = new NoBodyResponse(resp);
            this.doGet(req, response);
            if (req.isAsyncStarted()) {
                req.getAsyncContext().addListener(new NoBodyAsyncContextListener(response));
            } else {
                response.setContentLength();
            }
        } else {
            this.doGet(req, resp);
        }

    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = lStrings.getString("http.method_post_not_supported");
        this.sendMethodNotAllowed(req, resp, msg);
    }

    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = lStrings.getString("http.method_put_not_supported");
        this.sendMethodNotAllowed(req, resp, msg);
    }

    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = lStrings.getString("http.method_delete_not_supported");
        this.sendMethodNotAllowed(req, resp, msg);
    }

    private void sendMethodNotAllowed(HttpServletRequest req, HttpServletResponse resp, String msg) throws IOException {
        String protocol = req.getProtocol();
        if (protocol.length() != 0 && !protocol.endsWith("0.9") && !protocol.endsWith("1.0")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }
    protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String allow = this.getCachedAllowHeaderValue();
        if (HttpServlet.TomcatHack.getAllowTrace(req)) {
            if (allow.length() == 0) {
                allow = "TRACE";
            } else {
                allow = allow + ", TRACE";
            }
        }

        resp.setHeader("Allow", allow);
    }

    protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String CRLF = "\r\n";
        StringBuilder buffer = (new StringBuilder("TRACE ")).append(req.getRequestURI()).append(' ').append(req.getProtocol());
        Enumeration<String> reqHeaderNames = req.getHeaderNames();

        while(true) {
            String headerName;
            do {
                if (!reqHeaderNames.hasMoreElements()) {
                    buffer.append(CRLF);
                    int responseLength = buffer.length();
                    resp.setContentType("message/http");
                    resp.setContentLength(responseLength);
                    ServletOutputStream out = resp.getOutputStream();
                    out.print(buffer.toString());
                    out.close();
                    return;
                }

                headerName = (String)reqHeaderNames.nextElement();
            } while(this.isSensitiveHeader(headerName));

            Enumeration<String> headerValues = req.getHeaders(headerName);

            while(headerValues.hasMoreElements()) {
                String headerValue = (String)headerValues.nextElement();
                buffer.append(CRLF).append(headerName).append(": ").append(headerValue);
            }
        }
    }
}

1.3 HttpServletRequest

https://javadoc.io/doc/jakarta.servlet/jakarta.servlet-api/6.0.0/jakarta.servlet/jakarta/servlet/http/HttpServletRequest.html

就是说,Http 请求报文里面的数据都能通过这个类获取到。

1.4 HttpServletResponse

https://javadoc.io/doc/jakarta.servlet/jakarta.servlet-api/6.0.0/jakarta.servlet/jakarta/servlet/http/HttpServletResponse.html

就是说,Http 返回报文所有的可能性都在这里可以进行设置。

1.4.1 重定向sendRedirect

通知浏览器,重定向到另一个页面(如用户登录后需要重定向到首页)。

1.4.2 Buffering the Response

先把返回数据放在response缓冲区中,只有缓冲区满了或者request被处理完成了,才开始向客户端(浏览器)返回数据。

1.4.3 关于返回的数据中特殊字符

浏览器接收到返回数据时,会自动当成html文本解析,要注意html中的特殊字符,如果不需要被浏览器解析成html,那么需要进行转编码。

    /**
     * Encode an HTML tag so it will be displayed
     * as it is on the browser.
     * Particularly, this method searches the
     * passed in String and replace every occurrence
     * of the following character:
     * '<' with "&lt;"
     * '>' with "&gt;"
     * '&' with "&amp;"
     * //'"' with "&quot;"
     * ' ' with "&nbsp;"
     */

1.4.4 RequestDispatcher 一个servlet需要使用另一个servlet的功能

RequestDispatcher部分源码:

package jakarta.servlet;

import java.io.IOException;

public interface RequestDispatcher {
    void forward(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    void include(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
}

  • forward
    把request 转发到另一个servlet进行处理
  • include
    使用另一个servlet产生的数据

1.4.5 重定向sendRedirect和RequestDispatcher.forward

  • 重定向sendRedirect
    servlet1号通知浏览器:“你的诉求俺这里的部分搞定了,接下来你直接去找servlet2号吧!”
    这时候servlet2号是拿不到浏览器给servlet1号的request数据的。
  • RequestDispatcher.forward
    servlet1号内心os:“oh,这事儿还得麻烦我的好兄弟servlet2号,直接把request打包给我的好兄弟”。
    这时候servlet2号是直接拿到了servlet1号的request数据。
  • 28
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值