Servlet是Java EE的核心。基于xml配置的方式已经过时,现在是基于注解注入。过时的方法不在细说
Servlet是Web容器的组件,其不直接处理Http请求,而是由容器创建后转发给Servlet

什么是Servlet

他就是一个 Java 编程语言中的一个class,用于扩展服务器的功能。
servlet 可以响应任何类型的请求,但它们通常用于扩展由 Web 服务器托管的应用程序。对于这样的应用程序,Java Servlet 技术定义了特定于 HTTP 的 servlet 类。
image.png
换言之Java EE封装了Http请求的Servlet,并且定义了http通用的方法,其他类型的Servlet也可以基于其他协议用Servlet实现

Web容器的作用

Servlet是运行在Web容器中,当HTTP请求转发给Web时,Web容器会创建一个HttpServletRequest和HttpServletResponse对象,根据配置信息去查找相应的Servlet,同时将对象传递给Servlet
换言之,Web容器已经帮我们做了很多的事情,我们需要做的只是定义业务逻辑,即Servlet中的service()方法。觉得牛逼可以研究tomcat源码...
image.png
在专门的Http实现abstract类HttpServlet定义了Http的请求方式post、get、delete等7种请求方法,由service方法判断逻辑

protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            
        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            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);
        }
    }

怎么使用servlet

Servlet是JavaEE的体系框架标准规范SPI,根本在于JavaSE。是SE的拓展。
Servelt规范可以单独升级,但是因为基于SE的基础,所以低版本的SE可能不支持高版本的Servlet规范。

引入servlet规范jar

在使用springboot的时候我们无需引入单独的servlet规范,因为springboot内置的tomcat中已经含有servlet规范不需要单独引入
image.png

在没有springboot的单独体系中则需要引入EE相关规范
下面基本涵盖了所有的ee规范标准,当然也可以单独引入servlet4.0

 <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>8.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.mvc</groupId>
            <artifactId>javax.mvc-api</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.ws</groupId>
            <artifactId>jaxws-api</artifactId>
            <version>2.3.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.jws</groupId>
            <artifactId>javax.jws-api</artifactId>
            <version>1.1</version>
            <scope>provided</scope>
        </dependency>

serlvet功能

  • 对客户端发送的数据进行拦截
    url参数、Ajax表单提交Servlet可以对请求进行拦截进行预处理(访问权限、字符集等),称之为拦截器
  • 读取客户端请求的隐含数据
    例如请求IP、缓存Cookie、客户端类型
  • 运行结果或产生数据
  • 发送响应数据
    对客户端发送响应数据,让客户端获取请求结果

servlet生命周期

image.png
**servlet 的生命周期由部署了 servlet 的容器控制。**当请求映射到 servlet 时,容器将执行以下步骤。
1.如果 servlet 的实例不存在,则 Web 容器:
2.加载 servlet 类
3.创建 servlet 类的实例
4.通过调用方法初始化 Servlet 实例(创建和初始化 Servlet中介绍了初始化init)
5.容器调用该方法,传递请求和响应对象。
6.如果需要删除 servlet,容器将通过调用 servlet 的方法完成
所有的所有是容器主导,servlet只是组件!!!
image.png

  • 编写一个最简单的servlet
@WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet extends HttpServlet {
    private String message;

    @Override
    public void init() {
        message = "Hello World!";
        System.out.println("init");
    }

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html");

        // Hello
        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("<h1>" + message + "</h1>");
        out.println("</body></html>");
    }

    @Override
    public void destroy() {
        System.out.println("destory");
    }
}

由servlet直接渲染返回页面,
image.png

创建和初始化

使用注释在 Web 应用程序中定义 servlet 组件。此注解是在类上指定的,并且包含有关所声明的 servlet 的元数据。带注释的 servlet 必须至少指定一个 URL 模式。

HttpServletRequest

HttpServletRequest从何而来?由Web容器为我们生成
image.png
我们只需要关注其有哪些方法供我们使用
image.png
我们无需关注所有方法,有的放矢,需要时再去查找

image.png

ServletRequest及常用API

ServletRequest是一个对象以向 servlet 提供客户端请求信息。 servlet 容器创建一个ServletRequest对象并将其作为参数传递给 servlet 的service方法。
ServletRequest对象提供的数据包括参数名称和值、属性和输入流。 扩展ServletRequest接口可以提供额外的特定于协议的数据

获取字符

  • BufferedReader getReader()
    以字符流读取body 适用于获取字符串等

获取文件

  • ServletInputStream getInputStream() 获取文件
    以二进制字节流读取body 适用于获取字节文件等
  • Part getPart(String name)。 获取multipart/form-data 文件
    获取指定名称的Part
  • Collection getParts() 获取multipart/form-data 文件
    获取此请求的所有Part组件,前提是它的类型为multipart/form-data
    image.png
    使用这2个注解的前提是需要有
    @MultipartConfig(location="",maxFileSize=)注解配置限制位置和文件大小

tomcat容器默认实现ApplicationHttpRequest

image.png

RequestDispatcher

该对象接收来自客户端的请求并将它们发送到服务器上的任何资源(例如 servlet、HTML 文件或 JSP 文件)。
servlet 容器创建RequestDispatcher对象,该对象用作位于特定路径或由特定名称指定的服务器资源的包装器。
因为是由Servlet创建的RequestDispatcher对象 Java EE并没有做具体实现
image.png
其包含2个方法

  • void forward(ServletRequest request, ServletResponse response)
    将该Aservlet转发给其他Bservlet,最终由B返回(转发是在一个servlet资源内部)
  • void include(ServletRequest request, ServletResponse response)
    在该Aservlet中调用其他Bservlet,最终由A返回

tomcat中的RequestDispatcher实现类

ApplicationDispatcher
image.png
RequestDispatcher标准实现,它允许将请求转发到不同的资源以创建最终响应,或者在来自该资源的响应中包含另一个资源的输出。

HttpServletResponse

容器将ServletResponse、ServletRequest传递给servlet执行,servlet执行之后返回给容器,容器再将ServletResponse返回给调用请求的客户端
image.png

  • void sendError(int sc)
    使用指定的状态代码向客户端发送错误响应并清除缓冲区。 服务器将保留 cookie
  • void sendRedirect(String location)
    使用指定的重定向位置 URL 向客户端发送临时重定向响应并清除缓冲区。 缓冲区将被此方法设置的数据替换。 重定向,浏览器参与其中

ServletResponse及其常用API

image.png

  • ServletOutputStream getOutputStream()
    获得二进制数据的ServletOutputStream 。 servlet 容器不对二进制数据进行编码。再调用flush() 提交response。
  • PrintWriter getWriter()
    返回一个可以向客户端发送字符文本的PrintWriter对象。 PrintWriter使用getCharacterEncoding返回的字符编码。
  • setCharacterEncoding(String charset)
    将发送到客户端的响应的字符编码(MIME 字符集)设置为 UTF-8。 如果响应字符编码已由ServletContext.setResponseCharacterEncoding 、部署描述符或使用 setContentType() 或 setLocale() 方法设置,则此方法中设置的值将覆盖这些值中的任何一个。 用text/html的String调用setContentType用UTF-8的String调用这个方法等价于用text/html; charset=UTF-8的String调用setContentType text/html; charset=UTF-8 text/html; charset=UTF-8
  • void setContentType(String type)
    如果响应尚未提交,则设置发送到客户端的响应的内容类型。 给定的内容类型可能包括字符编码规范,例如text/html;charset=UTF-8 。





这个家伙很懒,啥也没有留下😋