Servlet

1. Servlet概述

1.1 什么是Servlet

  1. Servlet是Java EE规范之一。规范就是接口
  2. Servlet是JavaWeb三大组件之一。三大组件分别是:
    • Servlet程序
    • Filter过滤器
    • Listener监听器
  3. Servlet是运行在服务器上的一个java小程序,它可以接收客户端发送过来的请求,并响应数据给客户端。

1.2 如何实现Servlet程序

  1. 编写一个类去实现Servlet接口
  2. 实现service方法,处理请求,并响应数据
  3. 到web.xml中去配置servlet程序的访问地址

2. Servlet的使用

2.1 获取依赖

<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

2.2 实现Servlet接口

package com.example.Servletdemo;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;

public class HelloServlet implements Servlet {

    public HelloServlet() {
        System.out.println("1. 构造器方法");
    }

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("2. 初始化方法");
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
     * @author      YanceyGao
     * @createTime  2021/4/3 10:22
     * @methodName  service
     * @description 专门用来处理请求和响应的
     * @param1		servletRequest: 
     * @param2		servletResponse: 
     * @return: 	void
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("3. service方法");
        //强转为HttpServletRequest类型,因为service方法同时支持get和post,为了区分两种方式的不同操作,需要通过getMethod方法
        //来获取请求类型,而ServletRequest并没有这个方法,因此强转为ServletRequest的子类HttpServletRequest。
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        //获取请求方式
        String method = httpServletRequest.getMethod();

        System.out.println(method);

        if ("GET".equals(method)) {
            System.out.println("我是GET!");
        } else if ("POST".equals(method)) {
            System.out.println("我是POST!");
        }

    }

    @Override
    public String getServletInfo() {
        return null;
    }

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

2.3 配置Servlet类

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- Servlet标签给Tomcat配置Servlet程序 -->
    <servlet>
        <!-- servlet-name标签给servlet程序起一个别名(一般是类名) -->
        <servlet-name>HelloServlet</servlet-name>
        <!-- servlet-class标签是servlet程序的全类名 -->
        <servlet-class>com.example.Servletdemo.HelloServlet</servlet-class>
    </servlet>
    <!-- servlet-mapping标签给servlet程序配置访问地址 -->
    <servlet-mapping>
        <!-- servlet-name标签的作用是告诉服务器,当前配置的地址给哪个servlet程序使用 -->
        <servlet-name>HelloServlet</servlet-name>
        <!-- url-pattern标签配置访问地址
            /               :斜杠在服务器解析的时候,表示地址为:http://ip:port/工程路径
            /HelloServlet   :表示地址为:http://ip:port/工程路径/HelloServlet
        -->
        <url-pattern>/HelloServlet</url-pattern>
    </servlet-mapping>

</web-app>

2.4 具体访问流程

全流程

image-20210403110930212

工程流程

image-20210403105123359

3. Servlet理论

3.1 Servlet的生命周期

  1. 执行Servlet构造器方法
  2. 执行init初始化方法
    • 第一二步会在初次访问创建Servlet的时候调用
  3. 执行service方法
    • 每次访问都会调用
  4. 执行destory方法
    • 在web工程停止的时候执行

3.2 GET和POST请求的分发处理

一般在实际项目开发中,都是使用继承HttpServlet类的方式去实现Servlet程序。

  1. 编写一个类去继承HttpServlet类
  2. 根据业务需要重写doGet方法和doPost方法(HttpServlet类自己实现了doGet和doPost方法,直接重写即可)
  3. 到web.xml中的配置Servlet程序的访问地址

3.3 通过继承HttpServlet实现Servlet分发处理

@WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet extends HttpServlet {
    private String message;

    @Override
    public void init() {
        //获取Servlet程序的别名servlet-name的值
        System.out.println(servletConfig.getServletName());
        //获取ServletContext对象
        System.out.println(servletConfig.getServletContext());
        //获取初始化参数init-param
        System.out.println(servletConfig.getInitParameter("user"));
        message = "Hello World!";
        
    }

    @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 doPost(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() {
    }
}

3.4 Servlet类的继承体系

image-20210403124643354

3.5 ServletConfig类

概念:

  • ServletConfig:Servlet程序配置信息类。
  • Servlet程序和ServletConfig对象都是由Tomcat负责创建,我们负责使用。
  • Servlet程序默认是第一次访问的时候创建,ServletConfig是每个Servlet程序创建时,就创建一个对应的ServletConfig对象。
  • servletConfig对象除了可以在init()中使用外,也可以在其他地方使用,但是只能获取自己的servlet程序的初始化参数等信息。

ServletConfig的三大作用:

  • 可以获取Servlet程序的别名servlet-name的值

    servletConfig.getServletName();
    
  • 获取初始化参数init-param

    初始化参数可以有多组,是键值对的形式

    <!-- web.xml -->
    <servlet>
    	<!-- init-param是初始化参数 -->
            <init-param>
                <!-- 参数名 -->
                <param-name>username</param-name>
                 <!-- 参数值 -->
                <param-value>root</param-value>
            </init-param>
    </servlet>
    
    <!-- java -->
    servletConfig.getInitParameter([参数名]);
    
  • 获取ServletContext对象

    servletConfig.getServletContext();
    

3.6 ServletContext类

概念:

  • ServletContext是一个接口,他表示Servlet上下文对象。

  • 一个web工程只会有一个ServletContext对象。

  • ServletContext是在web工程部署启动的时候创建,在web工程停止的时候销毁(注意ServletContext是一个全局的对象,因此可以跨Servlet操作)。

  • ServletContext对象是一个域对象。

    • 域对象:是一个像Map一样存取数据的对象。域指的是存取数据的操作范围(整个Web工程)。

    • Map和域对象的区别:

      存数据取数据删除数据
      Mapput()get()remove()
      域对象setAttribute()getAttribute()removeAttribute()
  • ServletContext类的四个常见作用:

    1. 获取web.xml中配置的上下文参数context-param

      <!-- web.xml -->
      <!-- context-param是上下文参数,可以配置多组(它属于整个web工程) -->
          <context-param>
              <param-name>username</param-name>
              <param-value>context</param-value>
          </context-param>
      
      <!-- java -->
      ServletContext context = getServletConfig().getServletContext();
              context.getInitParameter("username");
      
    2. 获取当前的工程路径,格式:/工程路径

      context.getContextPath();
      
    3. 获取工程部署后在服务器硬盘上的绝对路径

      //获取当前工程在服务器中的真实路径,斜杠被服务器解析问:http:ip:port/projectname/
      //实际上也就是映射到工程代码的web目录(Tomcat服务器目类),如果需要映射到其他目录下,改变参数即可(例如web目录下的img目类为"/img")
      context.getRealPath("/");
      
    4. 像Map一样存取数据

      //存取数据
              ServletContext servletContext = getServletConfig().getServletContext();
              servletContext.setAttribute("testData1", 1);
              servletContext.setAttribute("testData2", true);
      

3.7 HttpServletRequest类

类作用:

每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到Request对象中。然后传递到service()方法(doGet和doPost)中给我们使用。我们可以通过HttpServletRequest对象,获取到所有的请求信息。

类常用方法:

  • getRequestURI()
    • 获取请求的资源路径(URI地址)
  • getRequestURL()
    • 获取请求的统一资源定位符(绝对路径)
    • URL=协议+主机+端口号+URI
  • getRemoteHost()
    • 获取客户端的IP地址
  • getHeader()
    • 获取请求头
  • getParameter()
    • 获取请求的参数
  • getParameterValues()
    • 获取请求的参数(多个参数的时候使用)
  • getMethod()
    • 获取请求的坊市(get或post)
  • setAttribute(key, value)
    • 设置域数据
  • getAttribute(key)
    • 获取域数据
  • getRequestDispatcher()
    • 获取请求转发对象

3.8 HttpServletResponse类

类作用:

HttpServletResponse类和HttpServletRequest类一样,每次收到请求后,Tomcat服务器会创建一个Response对象传递给Servlet程序去使用。HttpServletRequest表示请求信息,HttpServletResponse表示响应信息。

两个输出流的说明:

  • 字节流(getOutputStream();)

    • 常用于下载(传递二进制数据)
  • 字符流(getWriter();)

    • 常用于回传字符串(常用方式)

    两个流只能使用一个,不能同时使用。

往客户端回传数据:

//字符串数据
PrintWriter writer = resp.getWriter();
writer.write("response's content!");

中文字符乱码问题:

​ 在实际应用过程中往往会出现因为客户端和浏览器字符集不同而导致乱码的问题。解决方式是通过response返回字符集。

// 在前面的响应格式中有说明,字符集在响应头中设置
resp.setHeader("Content-type", "text/html; charset=UTF-8");
// 这种方式会同时设置服务器和客户端同时使用UTF-8的字符集,还设置了响应头
// 另外,此方法一定要在获取流之前使用!!!否则无效
resp.setContentType("text/html; charset=UTF-8");

4. HTTP协议

4.1 什么是HTTP协议

  • 什么是协议?

    协议是指双方或多方相互约定好,大家都需要遵守的规则。

  • 所谓HTTP协议,就是指客户端和服务器之间通信时发送的数据需要遵守的规则,叫HTTP协议。

  • HTTP协议中的数据又叫报文。

4.2 请求的HTTP协议格式

什么是请求?

  • 客户端给服务器发送数据叫请求;服务器回应客服端请求叫响应。
  • 请求分为GET请求和 POST请求两种。

GET请求:

  • 请求行
    • 请求方式 GET
    • 请求资源路径[ + ? + 请求参数]
    • 请求协议和版本号 HTTP/1.1
  • 请求头
    • key:value组成 不同的键值对表示不同的含义
    • image-20210404103114493

POST请求:

  • 请求行:
    • 请求方式 POST
    • 请求资源路径[ + ? + 请求参数]
    • 请求协议和版本号 HTTP/1.1
  • 请求头
    • key:value组成 不同的键值对表示不同的含义
    • image-20210404230913107
  • 空行(往往在请求头和请求体之间有一个空行二者隔开)
  • 请求体
    • key:value键值对组成 内容为参数

如何判断哪些是GET请求,哪些是POST请求?

GET请求:

  1. form标签:method="GET"
  2. a标签
  3. link标签引入css请求
  4. Script标签引入js文件
  5. img标签引入图片
  6. iframe引入html标签
  7. 在浏览器地址栏中输入地址后回车

POST请求:

  1. form标签:method="POST"

4.3 响应的HTTP协议格式

  1. 响应行
    • 响应的协议和版本号
    • 响应状态码
    • 响应状态描述符
  2. 响应头
    • key:value键值对,不同的响应头有不同的含义
  3. 空行
  4. 响应体
    • 回传给客户的数据

image-20210406103803076

4.4 常见的响应码说明

  • 200 表示请求成功
  • 302 表示请求重定向
  • 400 表示发送的请求语法错误,服务器无法正常读取。
  • 404 表示请求服务器已经收到,但是请求内容不存在(或者请求地址错误)
  • 500 表示服务器已经收到请求,但是服务器内部错误(代码错误)

4.5 MIME类型说明

MIME是HTTP协议中数据类型。

MIME的英文全称是“Multipurpose Internet Mail Extensions”(多功能Internet邮件扩充服务)。MIME类型的格式是“大类型/小类型”,并与某一种文件的扩展名相对应。

常见的MIME类型:

文件MIME类型
超文本标记文本.html, .htm———text/html
普通文本.txt———text/plain
RTF文本.rtf———application/rtf
GIF文本.gif———image/gif
JPEG文本.jpeg, .jpg———image/jpeg
au声音文件.au———audio/basic
MIDI音乐文件mid, midi———audio/midi, audio/x-midi
RealAudio音乐文件.ra, .ram———audio/x-pn-realaudio
MPEG文件.mpg, .mpeg———video/mpeg
AVI文件.avi———video/x-msvideo
GZIP文件.gz———application/x-gzip
TAR文件.tar———application/x-tar

4.6 请求转发

请求转发是指,服务器收到请求后,从一个资源跳转到另一个资源的操作。

image-20210420102944108

请求转发的特点:

  1. 浏览器地址栏没有变化
  2. 他们是一次请求
  3. 他们共享Request域中的数据
  4. 可以访问到WEB-INF目录下
  5. 不能访问工程以外的资源

4.7 base标签的作用

在a标签跳转时:

  • 在使用a标签重定向的时候,浏览器地址栏中的地址是:http://ip:port/protject_name/a/b/c.html,往回跳转的a标签路径是:../../index.html。也就是说在使用a标签都是使用的相对路径。参照后使用的路径即:http://ip:port/protject_name/a/b/c.html/../../index.html,最后的跳转路径为:http://ip:port/protject_name/index.html
  • 相对路径中使用../产生的效果为返回上层目录

在请求转发时进行跳转时:

base标签的作用:

可以设置当前页面中所有相对路径工作时,参照哪个相对路径来进行跳转。

<head>
    <title>Title</title>
    <!-- base标签设置页面相对路径工作时参照的地址,
    	 href属性就是参照的地址
		 另外在base标签中最后一个资源名可以省略,在示例中,href即为:"http://ip:port/project_name/a/b/c.html"
	-->
    <base href="http://ip:port/project_name/a/b/">
</head>
<body>
    <a href="../../index.html">跳回首页</a>
</body>

4.8 Web中的相对路径和绝对路径

在java-web中,路径分为相对路径和绝对路径:

4.9web中斜杠的不同意义

在web中/斜杠是一种绝对路径。

  • 在浏览器中,/解析得到的地址为:http://ip:port/
  • 在服务器中,/解析得到的地址为:http://ip:port/project_name/
    • /servlet
    • servletContext.getRealPath("/");
  • 特殊情况
    • response.sendRediect("/"); 这个方法(请求重定向)的作用是把参数发给浏览器解析,因此得到的结果为:http://ip:port/

4.10 请求重定向

请求重定向是指,客户端给服务器发请求,服务器返回新地址,使客户端去新地址访问。

image-20210422112149490

重定向的特点:

  1. 浏览器地址栏发生变化
  2. 两次请求
  3. 不共享Request域中的数据
  4. 不能跳转到WEB-INF下
  5. 可以访问工程外的资源

请求重定向的两种方法:

//第一种方法
//设置响应状态码表示重定向
resp.setStatus(302);
//设置响应头,说明新的地址在哪里
resp.setHeader("Location", "http://localhost:8080/Servletdemo/redirectServlet2");
//第二种方法(推荐)
resp.sendRedirect("https://www.yanceygao.cn");

Q.E.D.


If you don't come, I will snow.