JavaWeb学习Day6——HTTP,Tomcat,Servlet

101 阅读10分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第15天,点击查看活动详情

HTTP协议

HyperText Transfer Protocol,超文本传输协议,规定了浏览器和服务器之间==数据传输的规则==。

  • 数据传输的规则指的是请求数据和响应数据需要按照指定的格式进行传输。
  • 如果想知道具体的格式,可以打开浏览器,点击F12打开开发者工具,点击Network来查看某一次请求的请求数据和响应数据具体的格式内容

HTTP协议特点

HTTP协议有它自己的一些特点,分别是:

  • 基于TCP协议: 面向连接,安全

    TCP是一种面向连接的(建立连接之前是需要经过三次握手)、可靠的、基于字节流的传输层通信协议,在数据传输方面更安全。

  • 基于请求-响应模型的:一次请求对应一次响应

    请求和响应是一一对应关系

  • HTTP协议是无状态协议:对于事物处理没有记忆能力。每次请求-响应都是独立的

    无状态指的是客户端发送HTTP请求给服务端之后,服务端根据请求响应数据,响应完后,不会记录任何信息。这种特性有优点也有缺点,

    • 缺点:多次请求间不能共享数据
    • 优点:速度快

    请求之间无法共享数据会引发的问题,如:

    • 京东购物,加入购物车去购物车结算是两次请求,
    • HTTP协议的无状态特性,加入购物车请求响应结束后,并未记录加入购物车是何商品
    • 发起去购物车结算的请求后,因为无法获取哪些商品加入了购物车,会导致此次请求无法正确展示数据

    具体使用的时候,我们发现京东是可以正常展示数据的,原因是Java早已考虑到这个问题,并提出了使用会话技术(Cookie、Session)来解决这个问题。

请求数据格式

请求数据总共分为三部分内容,分别是==请求行==、==请求头==、==请求体==

image.png

  • 请求行:响应数据的第一行,响应行包含三块内容,分别是 HTTP/1.1[HTTP协议及版本] 200[响应状态码] ok[状态码的描述]
  • 请求头:第二行开始,格式为key:value形式
  • 请求体: POST请求的最后一部分,存储请求参数

image.png

响应数据格式

响应数据总共分为三部分内容,分别是==响应行==、==响应头==、==响应体==

  • 响应行:响应数据的第一行,响应行包含三块内容,分别是 HTTP/1.1[HTTP协议及版本] 200[响应状态码] ok[状态码的描述]
  • 响应头:第二行开始,格式为key:value形式
  • 响应体: 最后一部分。存放响应数据

响应状态码

  • 200 ok 客户端请求成功
  • 404 Not Found 请求资源不存在
  • 500 Internal Server Error 服务端发生不可预期的错误 状态码分类 | 说明 | | ----- | ------------------------------------------------------- | | 1xx | 响应中——临时状态码,表示请求已经接受,告诉客户端应该继续请求或者如果它已经完成则忽略它 | | 2xx | 成功——表示请求已经被成功接收,处理已完成 | | 3xx | 重定向——重定向到其它地方:它让客户端再发起一个请求以完成整个处理。 | | 4xx | 客户端错误——处理发生错误,责任在客户端,如:客户端的请求一个不存在的资源,客户端未被授权,禁止访问等 | | 5xx | 服务器端错误——处理发生错误,责任在服务端,如:服务端抛出异常,路由出错,HTTP版本不支持等

Tomcat

Web服务器软件使用步骤

  • 准备静态资源
  • 下载安装Web服务器软件
  • 将静态资源部署到Web服务器上
  • 启动Web服务器使用浏览器访问对应的资源 Tomcat

Tomcat的相关概念:

  • Tomcat是Apache软件基金会一个核心项目,是一个开源免费的轻量级Web服务器,支持Servlet/JSP少量JavaEE规范。

  • 概念中提到了JavaEE规范,那什么又是JavaEE规范呢?

    JavaEE: Java Enterprise Edition,Java企业版。指Java企业级开发的技术规范总和。包含13项技术规范:JDBC、JNDI、EJB、RMI、JSP、Servlet、XML、JMS、Java IDL、JTS、JTA、JavaMail、JAF。

  • 因为Tomcat支持Servlet/JSP规范,所以Tomcat也被称为Web容器、Servlet容器。Servlet需要依赖Tomcat才能运行。

  • Tomcat的官网: tomcat.apache.org/ 从官网上可以下载对应的版本进行使用。

打开apache-tomcat-8.5.68目录就能看到如下目录结构,每个目录中包含的内容需要认识下,

image.png

配置

修改端口

  • Tomcat默认的端口是8080,要想修改Tomcat启动的端口号,需要修改 conf/server.xml

image.png

部署

Tomcat部署项目: 将项目放置到webapps目录下,即部署完成。

一般JavaWeb项目会被打包称==war==包,然后将war包放到Webapps目录下,Tomcat会自动解压缩war文件

Maven创建Web项目

Web项目结构

Web项目的结构分为:开发中的项目和开发完可以部署的Web项目,这两种项目的结构是不一样的:

  • Maven Web项目结构: 开发中的项目

image.png

  • 开发完成部署的Web项目 image.png

创建Maven Web项目

创建方式有两种:使用骨架和不使用骨架

使用骨架

具体的步骤包含:

1.创建Maven项目

2.选择使用Web项目骨架

3.输入Maven项目坐标创建项目

4.确认Maven相关的配置信息后,完成项目创建

5.删除pom.xml中多余内容

6.补齐Maven Web项目缺失的目录结构

image.png

image.png

image.png

image.png

image.png

不使用骨架

具体的步骤包含:

1.创建Maven项目

2.选择不使用Web项目骨架

3.输入Maven项目坐标创建项目

4.在pom.xml设置打包方式为war

5.补齐Maven Web项目缺失webapp的目录结构

6.补齐Maven Web项目缺失WEB-INF/web.xml的目录结构

image.png

image.png

image.png

image.png

image.png

IDEA使用Tomcat

在IDEA中集成使用Tomcat有两种方式,分别是== 集成本地Tomcat ==和==Tomcat Maven插件==

集成本地Tomcat

image.png

image.png

image.png

image.png

image.png

image.png

Tomcat Maven插件

只需要两步,分别是:

1.在pom.xml中添加Tomcat插件

<build>
  <plugins>
    <!--Tomcat插件 -->
    <plugin>
      <groupId>org.apache.tomcat.maven</groupId>
      <artifactId>tomcat7-maven-plugin</artifactId>
      <version>2.2</version>
    </plugin>
  </plugins>
</build>

2.使用Maven Helper插件快速启动项目,选中项目,右键-->Run Maven --> tomcat7:run

image.png

Servlet

  • Servlet是JavaWeb最为核心的内容,它是Java提供的一门==动态==web资源开发技术。
  • 使用Servlet就可以实现,根据不同的登录用户在页面上动态显示不同内容。
  • Servlet是JavaEE规范之一,其实就是一个接口,将来我们需要定义Servlet类实现Servlet接口,并由web服务器运行Servlet

快速入门

具体的实现步骤为:

1.创建Web项目web-demo,导入Servlet依赖坐标

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>3.1.0</version>
  <!--
    此处为什么需要添加该标签?
    provided指的是在编译和测试过程中有效,最后生成的war包时不会加入
     因为Tomcat的lib目录中已经有servlet-api这个jar包,如果在生成war包的时候生效就会和Tomcat中的jar包冲突,导致报错
  -->
  <scope>provided</scope>
</dependency>

2.创建:定义一个类,实现Servlet接口,并重写接口中所有方法,并在service方法中输入一句话

@WebServlet("/demo1")
public class ServletDemo implements Servlet{
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    public ServletConfig getServletConfig() {
        return null;
    }

    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Hello Servlet");

    }

    public String getServletInfo() {
        return null;
    }

    public void destroy() {

    }
}

3.访问:启动Tomcat,浏览器中输入URL地址访问该Servlet

http://localhost:8080/web-demo/demo1

4.访问后,在控制台会打印servlet hello world~ 说明servlet程序已经成功运行。

image.png

执行流程

image.png 浏览器发出http://localhost:8080/web-demo/demo1请求,从请求中可以解析出三部分内容,分别是localhost:8080web-demodemo1

  • 根据localhost:8080可以找到要访问的Tomcat Web服务器
  • 根据web-demo可以找到部署在Tomcat服务器上的web-demo项目
  • 根据demo1可以找到要访问的是项目中的哪个Servlet类,根据@WebServlet后面的值进行匹配

找到ServletDemo1这个类后,Tomcat Web服务器就会为ServletDemo1这个类创建一个对象,然后调用对象中的service方法

  • ServletDemo1实现了Servlet接口,所以类中必然会重写service方法供Tomcat Web服务器进行调用
  • service方法中有ServletRequest和ServletResponse两个参数,ServletRequest封装的是请求数据,ServletResponse封装的是响应数据,后期我们可以通过这两个参数实现前后端的数据交互
  1. Servlet由谁创建?Servlet方法由谁调用?

Servlet由web服务器创建,Servlet方法由web服务器调用

  1. 服务器怎么知道Servlet中一定有service方法?

因为我们自定义的Servlet,必须实现Servlet接口并复写其方法,而Servlet接口中有service方法

生命周期

  • 生命周期: 对象的生命周期指一个对象从被创建到被销毁的整个过程。
  • Servlet运行在Servlet容器(web服务器)中,其生命周期由容器来管理,分为4个阶段:

1.==加载和实例化==:默认情况下,当Servlet第一次被访问时,由容器创建Servlet对象

image.png 2. ==初始化==:在Servlet实例化之后,容器将调用Servlet的==init()==方法初始化这个对象,完成一些如加载配置文件、创建连接等初始化的工作。该方法只 调用一次

  1. ==请求处理==:==每次==请求Servlet时,Servlet容器都会调用Servlet的==service()==方法对请求进行处理

  2. ==服务终止==:当需要释放内存或者容器关闭时,容器就会调用Servlet实例的==destroy()==方法完成资源的释放。在destroy()方法调用之后,容器会释放这个Servlet实例,该实例随后会被Java的垃圾收集器所回收

  • 通过案例演示下上述的生命周期
@WebServlet(urlPatterns = "/demo2",loadOnStartup = 1)
public class ServletDemo2 implements Servlet {
    /**
     *  初始化方法
     *  1.调用时机:默认情况下,Servlet被第一次访问时,调用
     *      * loadOnStartup: 默认为-1,修改为0或者正整数,则会在服务器启动的时候,调用
     *  2.调用次数: 1次
     * @param config
     * @throws ServletException
     */
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("init...");
    }
    /**
     * 提供服务
     * 1.调用时机:每一次Servlet被访问时,调用
     * 2.调用次数: 多次
     * @param req
     * @param res
     * @throws ServletException
     * @throws IOException
     */
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Hello Servlet~");
    }
    /**
     * 销毁方法
     * 1.调用时机:内存释放或者服务器关闭的时候,Servlet对象会被销毁,调用
     * 2.调用次数: 1次
     */
    public void destroy() {
        System.out.println("Servlet destroy");

    }
    public ServletConfig getServletConfig() {
        return null;
    }

    public String getServletInfo() {
        return null;
    }
}

体系结构

image.png 因为我们将来开发B/S架构的web项目,都是针对HTTP协议,所以我们自定义Servlet,会通过继承==HttpServlet==

@WebServlet(urlPatterns = "/demo3",loadOnStartup = 1)
public class ServletDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Get...");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Post...");
    }
}

两个问题:

  1. HttpServlet中为什么要根据请求方式的不同,调用不同的方法?
  2. 如何调用?
public class MyHttpServlet implements Servlet {

    public void init(ServletConfig servletConfig) throws ServletException {

    }

    public ServletConfig getServletConfig() {
        return null;
    }

    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String method = ((HttpServletRequest) servletRequest).getMethod();
        if("GET".equals(method)){
            doGet(servletRequest,servletResponse);
        }else if("POST".equals(method)){
            doPost(servletRequest,servletResponse);
        }
    }

    protected void doPost(ServletRequest servletRequest, ServletResponse servletResponse) {
    }

    protected void doGet(ServletRequest servletRequest, ServletResponse servletResponse) {
    }

    public String getServletInfo() {
        return null;
    }

    public void destroy() {

    }
}

有了MyHttpServlet这个类,以后我们再编写Servlet类的时候,只需要继承MyHttpServlet,重写父类中的doGet和doPost方法,就可以用来处理GET和POST请求的业务逻辑。

@WebServlet(urlPatterns = "/demo4",loadOnStartup = 1)
public class ServletDemo4 extends MyHttpServlet{

    @Override
    protected void doGet(ServletRequest servletRequest, ServletResponse servletResponse) {
        System.out.println("GET...");
    }

    @Override
    protected void doPost(ServletRequest servletRequest, ServletResponse servletResponse) {
        System.out.println("POST...");
    }
}

将来页面发送的是GET请求,则会进入到doGet方法中进行执行,如果是POST请求,则进入到doPost方法。这样代码在编写的时候就相对来说更加简单快捷。

urlPattern配置

  • 一个Servlet,可以配置多个urlPattern

image.png

urlPattern配置规则

  • 精确匹配

image.png

  • 目录匹配

image.png

  • 扩展名匹配

image.png

  • 任意匹配

image.png

XML配置

前面对应Servlet的配置,我们都使用的是@WebServlet,这个是Servlet从3.0版本后开始支持注解配置,3.0版本前只支持XML配置文件的配置方法。

对于XML的配置步骤有两步:

  • 编写Servlet类
public class ServletDemo13 extends MyHttpServlet {

    @Override
    protected void doGet(ServletRequest req, ServletResponse res) {

        System.out.println("demo13 get...");
    }
    @Override
    protected void doPost(ServletRequest req, ServletResponse res) {
    }
}
  • 在web.xml中配置该Servlet

<!-- 
    Servlet 全类名
-->
<servlet>
    <!-- servlet的名称,名字任意-->
    <servlet-name>demo13</servlet-name>
    <!--servlet的类全名-->
    <servlet-class>com.itheima.web.ServletDemo13</servlet-class>
</servlet>

<!-- 
    Servlet 访问路径
-->
<servlet-mapping>
    <!-- servlet的名称,要和上面的名称一致-->
    <servlet-name>demo13</servlet-name>
    <!-- servlet的访问路径-->
    <url-pattern>/demo13</url-pattern>
</servlet-mapping>