Http响应协议&Servlet入门

309 阅读12分钟

什么是HTTP响应

服务器端数据发送回浏览器,称为响应,在浏览器端就可以看到服务器处理的结果,:如下订单成功,预约成功等.

请求:request 响应:response

响应信息的三个组成

响应行、响应头、响应体的格式

目标

  1. 响应行的格式
  2. 响应头的格式
  3. 响应体的格式

响应行

请求行三个部分:请求方式 URI HTTP/1.1

响应行三个部分:协议和版本 状态码 状态描述

HTTP/1.1 200 OK
HTTP/1.1 302 Found

响应头

左边是键,右边是值,中间是冒号

响应头信息 说明
Location: www.baidu.com 下一个要跳转的页面
Server:Apache Tomcat 访问的服务器名字
Content-Encoding: gzip 服务器数据的压缩格式,服务器的数据压缩过的
Content-Length: 80 服务器发送回来的数据长度
Content-Type: text/html; charset=utf-8 服务器返回的数据类型,MIME类型
Refresh: 1;url=/hello.html 过1秒以后跳转到另一个页面
Content-Disposition:
attachment; filename=文件名.扩展名
文件下载,以附件的方式打开文件

响应体

从服务器端发送回来的数据主要有两种:字节数据和字符数据

文本:字符数据,比如:HTML,JS,CSS

图片,音乐,视频,可执行文件,压缩包:字节数据

小结:响应的组成

常见的状态码

目标

  1. 响应行中常见状态码的含义
  2. 404与405出现的原因

常见状态码的含义

200

服务器正常响应

HTTP/1.1 200 OK

302

表示页面进行了跳转

HTTP/1.1 302 Found

304

表示浏览器使用了缓存

403

请求服务器,被服务器禁止访问

404

  1. 页面地址输入错误,注意在tomcat中地址区分大小写

  2. 不能直接访问WEB-INF下面资源,这下面的资源是受保护,如果直接访问也会出现404错误

  3. 重定向或转发地址不正确,页面跳转的时候那个跳转到的地址不存在

405

doGet或doPost方法没有重写

500

服务器端代码出现异常

小结

状态码 含义
200 正确响应
302 页面进行了跳转
304 页面使用了缓存
404 服务器上指定的资源不存在
405 没有重写doGet或doPost方法
500 服务器代码出现异常

XML配置方式:创建Servlet

目标

使用web.xml配置方式编写第1个Servlet

什么是Servlet

Servlet与普通的Java程序的区别

  1. 本质上就是一个Java类
  2. 所有的类必须直接或间接的实现javax.servlet.Servlet接口
  3. 必须运行在Tomcat等Web容器中,由Web容器来调用Servlet程序
  4. 处理浏览器发送的请求,并且将服务器的处理结果响应给浏览器

Tomcat与Servlet的关系

  1. 用户发送请求请求Tomcat的8080端口
  2. 由Tomcat去调用我们写的Servlet,我们的任务就是编写Servlet
  3. Servlet接受用户的请求,并且处理结果,将结果通过响应发送回浏览器
  4. 浏览器看到服务器返回的结果,这个网页其实就是Servlet运行的结果

编写Servlet的步骤

  1. 创建一个类,继承于HttpServlet抽象类(实现了Servlet接口)
  2. 重写doGet或者doPost方法,分别处理浏览器发送的get或者post请求
  3. 在web.xml中配置servlet的信息,浏览器才能访问这个Servlet
    1. 配置类完全限定名(包名,类名)
    2. 配置Servlet的访问地址,必须以/开头

代码实现步骤

/*
1. 创建一个类,继承于HttpServlet抽象类(实现了Servlet接口)
2. 重写doGet或doPost方法,分别处理浏览器发送的get或post请求
3. 在web.xml中配置servlet的信息,浏览器才能访问这个Servlet
   1. 配置类完全限定名(包名.类名)
   2. 配置Servlet的访问地址,必须以/开头
 */
public class Demo1Servlet extends HttpServlet {

    /**
     * 只重写了doGet方法,因为我只用get请求
     * @param request 请求对象
     * @param response 响应对象
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.设置服务器响应的数据类型
        response.setContentType("text/html;charset=utf-8");   //表示这是一个网页的内容,编码是utf-8
        //2.得到响应的打印流,向网页上输出内容
        PrintWriter out = response.getWriter();
        //3.输出任何文本
        out.print("<h1>你好,这是第1个Servlet</h1>");
    }
}
  1. 编辑web.xml中配置servlet,设置访问地址为/demo01
<?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
    1. 配置类完全限定名(包名.类名)
    2. 配置Servlet的访问地址,必须以/开头
    -->

    <servlet>
        <!--配置servlet的名字,servlet不能出现相同的名字-->
        <servlet-name>demo1</servlet-name>
        <servlet-class>com.itheima.servlet.Demo1Servlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <!--这个名字与上面的名字相同-->
        <servlet-name>demo1</servlet-name>
        <!--访问地址必须以/开头,否则会导致tomcat加载项目失败,所有的资源都无法访问-->
        <url-pattern>/demo1</url-pattern>
    </servlet-mapping>

</web-app>

注解的方式:开发Servlet

目标

Servlet3.0以后才支持,使用注解的方式创建Servlet

流程

  1. 创建1个类,继承于HttpServlet类
  2. 重写doGet或doPost方法
  3. 使用@WebServlet指定Servlet的访问地址

具体操作

  1. 创建Servlet类,使用注解@WebServlet

    @WebServlet注解属性 说明
    name 可选属性,servlet的名字相当于配置:
    <servlet-name>demo1</servlet-name>
    urlPatterns 访问地址,相当于
    <url-pattern>/demo1</url-pattern>
    value 功能与上面urlPatterns一样,指定当前Servlet访问地址,必须以/开头

  1. 代码:

    package com.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    /*
    1. 创建1个类,继承于HttpServlet类
    2. 重写doGet或doPost方法
    3. 使用@WebServlet指定Servlet的访问地址
     */
    @WebServlet("/demo2")   //demo2就是访问地址,必须以/开头
    public class Demo2Servlet extends HttpServlet {
    
        /**
         * @param request 请求对象
         * @param response 响应对象
         */
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.设置响应的类型和编码
            response.setContentType("text/html;charset=utf-8");
            //2.得到打印流,输出文本
            PrintWriter out = response.getWriter();
            //3.输出文本
            out.print("<h1 style='color:red'>你好,注解的Servlet 3.0</h1>");
        }
    }
    
    

Servlet的生命周期

目标

Servlet生命周期有哪些方法

Servlet接口中的方法

每个servlet在tomcat中执行都会依次执行这3个方法,构成了servlet的生命周期

方法 作用 运行次数
void init(ServletConfig config) 初始化的时候执行 第1次有用户访问的时候执行1次
void service(ServletRequest req,
ServletResponse res)
服务的方法 每次请求和响应都会执行
执行多次
void destroy() 销毁的方法 在服务器关闭的时候执行1次

Servlet的生命周期

注:一个Servlet在tomcat容器中只会实例化一次,只会产生一个对象,而且常驻内存,要等到服务器关闭才会销毁。

代码实现

package com.servlet;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.sql.Timestamp;

/*
1. 创建一个类,实现接口javax.servlet.Servlet
2. 重写接口中所有的方法: init() service() destroy()
3. 使用注解@WebServlet("/访问地址")
 */
@WebServlet("/demo3")
public class Demo3LifeCycleServlet implements Servlet {
    //初始化方法:Servlet第1次实例化的时候执行1次,因为只会有一个对象,所以只会执行1次
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println(new Timestamp(System.currentTimeMillis()) + " " +  this + "被初始化");
    }

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

    /**
     * 每次请求都会执行
     * @param servletRequest 请求
     * @param servletResponse 响应
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println(new Timestamp(System.currentTimeMillis()) + " 执行service方法");
    }

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

    /**
     * 服务器关闭的时候执行1次
     */
    @Override
    public void destroy() {
        System.out.println(new Timestamp(System.currentTimeMillis()) + " " + this + " 被销毁");
    }
}

Servlet映射多个路径

目标

如何配置1个Servlet有多个访问地址

配置方式

  1. 写多个url-pattern,每个url-pattern是一个访问地址
<servlet>
    <!--配置servlet的名字,servlet不能出现相同的名字-->
    <servlet-name>demo1</servlet-name>
    <servlet-class>com.itheima.servlet.Demo1Servlet</servlet-class>
</servlet>
<servlet-mapping>
    <!--这个名字与上面的名字相同-->
    <servlet-name>demo1</servlet-name>
    <!--访问地址必须以/开头,否则会导致tomcat加载项目失败,所有的资源都无法访问-->
    <!--可以配置多个访问地址,多个地址不能相同-->
    <url-pattern>/demo1</url-pattern>
    <url-pattern>/demo100</url-pattern>
</servlet-mapping>
  1. 可以配置多个servlet-mapping,对应同一个servlet-name
<servlet>
    <!--配置servlet的名字,servlet不能出现相同的名字-->
    <servlet-name>demo1</servlet-name>
    <servlet-class>com.itheima.servlet.Demo1Servlet</servlet-class>
</servlet>
<servlet-mapping>
    <!--这个名字与上面的名字相同-->
    <servlet-name>demo1</servlet-name>
    <url-pattern>/demo1</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <!--这个名字与上面的名字相同-->
    <servlet-name>demo1</servlet-name>
    <url-pattern>/demo99</url-pattern>
</servlet-mapping>

注解方式

value属性和urlPatterns属性都是一个字符串的数组,可以指定多个访问地址

@WebServlet({"/demo2","/demo200"}) 
@WebServlet(name = "demo2", urlPatterns = {"/demo2","/demo200"})

小结

如何在servlet中配置多个访问地址?

配置文件的方式

  1. 配置多个url-pattern
  2. 一个servlet对应多个servlet-mapping配置

注解的方式

  1. @WebServlet({"/地址","/地址"})
  2. @WebServlet(name="名字", urlPatterns={"/地址","/地址"})

url-pattern的通配符

目标

访问地址不但可以指定多个,还可以使用通配符,可以自动匹配多个地址

介绍

  1. 什么是通配符:
可以匹配多个字符的符号

  1. 两种通配符的格式:
通配符格式 说明
/开头 匹配所有的文件: /*
匹配某个目录下所有的文件:/目录名/*
*.扩展名 匹配某种后缀名结尾的访问地址,如:*.do
  1. 代码

    package com.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    /*
    匹配原则:
    1. Servlet之间最佳匹配原则,如果已经有的servlet访问地址更加精确的匹配,它会执行精确匹配的servlet
    2. 如果某个servlet使用/*的访问地址,会导致所有的静态页面都不能访问,因为所有的静态页面,tomcat都有一个默认的servlet去处理
    3. 不能使用:同时以/开头和以扩展名结尾的地址,这是错误的
    IllegalArgumentException: Invalid <url-pattern> [/*.do] in servlet mapping
    4. 如果既匹配/开头的地址,又匹配扩展名结尾的地址,优先匹配/开头
     */
    //@WebServlet("/*")   //匹配所有的地址
    //@WebServlet("/admin/*")   //匹配某个目录下所有的资源
    //@WebServlet("*.do")   //如果出现了扩展名结尾的通配符,不能以/开头
    //@WebServlet("/*.do")   //同时出现/开头和扩展名结尾,这是一个错误的地址,导致tomcat加载这个servlet失败,所有的资源无法访问
    public class Demo4PathServlet extends HttpServlet {
    
        //重写doGet方法
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.设置响应类型和编码
            response.setContentType("text/html;charset=utf-8");
            //2.得到打印流
            PrintWriter out = response.getWriter();
            //3.输出内容
            out.print("<h2>通配符的使用</h2>");
        }
    }
    
    

面试题

创建2个Servlet,一个Servlet1,一个Servlet2,在下列情况下,访问哪个Servlet

请求URL Servlet1 Servlet2 访问哪个
/abc/a.html /abc/* /* servlet1,最佳匹配
/abc /abc/* /abc servlet2,最佳匹配
/abc/a.do /abc/* *.do servlet1,/的优先级更高
/a.do /* *.do servlet1,/的优先级更高
/xxx/yyy/a.do /* *.do servlet1,/的优先级更高

小结

  • 优先级:/开头的优先级高于扩展名结尾的访问地址优先级
  • 匹配原则:最佳匹配原则,哪个更接近访问地址,就匹配哪个
  • Servlet中不能同时出现/开头和扩展名结尾的访问地址,否则会导致服务器加载异常

Servlet的执行流程

目标

了解tomcat的执行过程

Tomcat的执行过程

1. 每个tomcat中可以部署多个项目的,如:one, two
2. 每个项目中有多个servlet,每个servlet有不同的访问地址
3. 在所有的类对象中找有@WebServlet("/demo1")注解的类对象
4. 对Demo这个Servlet通过反射实例化
5. tomcat创建请求和响应对象
6. 调用service()方法,并且将请求和响应对象传递进去
7. 执行service()方法,并且调用子类中doGet或doPost方法
8. 最后执行我们的doGet或doPost方法,并且处理数据
9. 数据处理完毕以后发送响应回到浏览器

小结

  1. Servlet对象是通过什么技术实例化的?

    servlet对象是tomcat通过反射来实例化的
    
  2. request和response对象从哪里来?

    由tomcat创建,并且通过service()方法传递进来
    
  3. service方法做了什么?

    调用子类中doGet或doPost方法
    

load-on-startup参数

目标

学习load-on-startup参数使用

作用

  1. 为什么要使用这个配置?
在默认的情况下,Servlet是用户第一次请求的时候实例化
有时我们希望tomcat启动的时候就实例化这个servlet,而不是等到有人访问的时候才实例化。
使用load-on-startup参数

  1. 参数的使用说明:

    如果没有这个参数或这个参数是负数,由web容器自由加载
    如果这个参数是正整数或0,小的数在前面加载
    
    数字就是加载的先后顺序
    

案例

需求

在一个Servlet中的init方法中直接输出一句话到控制台上,比较加不加的<load-on-startup>的区别

代码

使用配置的方式:web.xml

<servlet>
    <servlet-name>demo6</servlet-name>
    <servlet-class>com.itheima.servlet.Demo6HttpServlet</servlet-class>
    <!--tomcat启动时候就初始化这个servlet-->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>demo6</servlet-name>
    <url-pattern>/demo6</url-pattern>
</servlet-mapping>

使用注解的方式:servlet

@WebServlet(name = "demo6", urlPatterns = "/demo6", loadOnStartup = 1)

代码

/*
loadOnStartup 表示tomcat启动就加载这个servlet
 */
//@WebServlet(name = "demo6", urlPatterns = "/demo6", loadOnStartup = 1)
public class Demo6HttpServlet extends HttpServlet {

    //重写了生命周期中方法,在servlet第1次实例化的时候
    @Override
    public void init() throws ServletException {
        System.out.println(new Timestamp(System.currentTimeMillis()) + " 这是第一次");
    }

    /**
     * 如果直接在浏览器上输入地址访问的方式:doGet方法
     * 只有表单提交使用post方式的时候,才会执行doPost方法,除此之外所有的都是doGet方法
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置响应类型和编码
        response.setContentType("text/html;charset=utf-8");
        //得到打印流
        PrintWriter out = response.getWriter();
        out.print("你好,我是servlet");
    }
}

小结

这个参数的使用是什么?

在tomcat启动的时候加载当前的这个servlet