javaweb学习(day07-手动实现tomcat)

一、引入案例

1 小案例

引出对 Tomcat 底层实现思考

1.1 完成小案例

1.1.1 运行效果

1.2 maven简要介绍 

我们准备使用 Maven 创建一个 WEB 项目 , 简单给小伙伴介绍一下 Maven
, 更加详细的使用,我们还会细讲 , 现在先使用一把

 

1.3 创建maven的web项目

 完成后,如果目录没有出现src,不要慌,自行百度搜索解决方案

1.4 配置阿里 maven 镜像

 

1.5 修改 pom.xml 

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.hspedu</groupId>
  <artifactId>tomcat02</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>tomcat02 Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  <!--  引入servlet的依赖
        1. dependency 表示依赖, 也就是我们这个项目需要依赖的 jar 包
    2. groupId 和 artifactId 被统称为坐标, 是为了去定位这个项目/jar
    3. groupId: 一般是公司 比如 com.baidu , 这里是 avax.servlet
    4. artifactId 一般是项目名, 这里是 javax.servlet-api
    5. 这样的化就可以定位一个 jar 包
    6. version 表示你引入到我们项目的 jar 包的版本是 3.1.0
    7. scope: 表示作用域,也就是你引入的 jar 包的作用范围
    8. provided 表示在 tomcat 本身是有这个 jar 的,因此在编译,测试使用,但是在打包
    发布就不用要带上
    9. 在默认情况下, 引入的 jar 会到 中央仓库去下载 https://mvnrepository.com/
    10. 会下载到哪里到你指定的目录 C:\Users\Administrator\.m2\repository
    11. 有时为了下载更快, 往往配置镜像,
    12. 在 默 认 的 路 径 下 拷 贝 一 份 setting.xml 到
    C:\Users\Administrator\.m2\settings.xml
    13. 指定默认的阿里云镜像

  -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>tomcat02</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

 1.7 cal.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算器</title>
</head>
<body>
<h1>计算器</h1>
<form action="/calServlet" method="get">
    num1:<input type="text" name="num1"><br/>
    num2:<input type="text" name="num2"><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>

1.8 创建 java 目录,存放 java 源文件

1.9 创建 CalServlet.java 

package com.hspedu.servlet;

import com.hspedu.utils.WebUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class CalServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //接收提交的数据进行计算
        String strnum1 = request.getParameter("num1");
        String strnum2 = request.getParameter("num2");
        //把strnum1和strnum2转成int
        int num1= WebUtils.parseIt(strnum1,0);
        int num2=WebUtils.parseIt(strnum2,0);
        int result=num1+num2;
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>"+num1+" + "+num2+" = "+result+"<h1>");
        writer.flush();
        writer.close();



    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}

 1.10 修改 web.xml , 配置 Servlet

 1.11 具类

package com.hspedu.utils;

public class WebUtils {
    public static int parseIt (String strNum,int defaultVal){
        try {
            return Integer.parseInt(strNum);
        } catch (NumberFormatException e) {
           System.out.println(strNum+" 格式不对,转换失败");
           return defaultVal;
        }
    }
}

没有配置tomcat记得配置哦,

我们的目标 : 不用 Tomcat, 不用系统提供的 Servlet, 模拟 Tomcat 底层实现并能调用我
们自己设计的 Servle, 也能完成相同的功能

二、 Tomcat 整体架构分析

1 一图胜千言

  • 说明: Tomcat 有三种运行模式(BIO, NIO, APR, 因为核心讲解的是 Tomcat 如何接收客户端请求,解析请求, 调用 Servlet , 并返回结果的机制流程, 采用 BIO 线程模型来模.[绘图]

 

三、实现 

1 实现任务阶段 1 

编写自己 Tomcat, 能给浏览器返回 Hi, Hspedu 

1.1 基于 socket 开发服务端-流程 

 1.2 需求分析/图解

需求分析如图, 浏览器请求 http://localhost:8080/??, 服务端返回 hi , hspedu

1.3 分析+代码实现 

1.3.1 分析示意图 
 1.3.2 代码实现
package com.hspedu.tomcat;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/*
这是第一个版本的tomcat,可以完成接收浏览器的请求,并返回信息
 */
public class LinranTomcatV1 {
    public static void main(String[] args) throws IOException {
        //1.创建
        ServerSocket serverSocket=new ServerSocket(8080);
        System.out.println("服务器正在8080端口监听");
        while (!serverSocket.isClosed()){
            //等待浏览器/客户端的链接
            //如果有连接,就创建一个socket
            //这个socket就是服务器和浏览器的连接通道
            Socket socket=serverSocket.accept();

            //先接收浏览器发送的数据
            //inputStream是字节流=》BufferedReader(字符流)
            InputStream inputStream = socket.getInputStream();
            BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
            //接收到浏览器发送的数据
            System.out.println("==============接收到浏览器发送的数据==============");
            String mes=null;
            //循环读取
            while ((mes=bufferedReader.readLine())!=null){
                if(mes.length()==0){
                    break;//退出
                }
                System.out.println(mes);
            }

            //我们的tomcat回送数据
            OutputStream outputStream = socket.getOutputStream();
            //构建一个 http 响应的头
            //\r\n 表示换行
            //http 响应体,需要前面有两个换行 \r\n\r\n
            String respHeader = "HTTP/1.1 200 OK\r\n" +
                    "Content-Type: text/html;charset=utf-8\r\n\r\n";
            String resp = respHeader + "hi, hspedu 韩顺平教育";
            System.out.println("========我们的 tomcat 给浏览器会送的数据 ======");
            System.out.println(resp);
            outputStream.write(resp.getBytes());//将 resp 字符串以 byte[] 方式返回

            //关闭
            outputStream.flush();
            outputStream.close();
            inputStream.close();
            socket.close();
        }
    }
}

 问题分析:没有使用 BIO 线程模型,没有实现多线程,性能差

实现任务阶段 2 

使用 BIO 线程模型,支持多线程

2.1 BIO 线程模型介绍 

2.2 需求分析/图解 

浏览器请求 http://localhost:8080, 服务端返回 hi , hspedu, 后台 hsptomcat 使用 BIO 线程模型 , 支持多线程 => 对前面的开发模式进行改造

 2.3 分析+代码实现

2.3.1 分析示意图 

2.3.2 代码实现 

新建一个线程类

package com.hspedu.tomcat.handler;
/*
    HspRequestHandler对象是一个线程对象
    处理http请求的
 */

import java.io.*;
import java.net.Socket;

public class HspRequestHandler implements Runnable {
    //定义一个socket
    private Socket socket=null;

    public HspRequestHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        //这里我们可以对客户端/浏览器进行通信

        try {
            InputStream inputStream = socket.getInputStream();

            //把inputStream->bufferedReader
            BufferedReader bufferedReader =
                    new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
            String mes;
            System.out.println("=============HspRequestHandler接收的信息如下=================");
            while ((mes=bufferedReader.readLine())!=null){
                if(mes.length()==0)
                {
                    break;
                }
                System.out.println(mes);
            }
            //返回数据给我们的浏览器->封装成http响应
            OutputStream outputStream = socket.getOutputStream();
            //构建http响应
            String respHeader = "HTTP/1.1 200 OK\r\n" +
                    "Content-Type: text/html;charset=utf-8\r\n\r\n";
            String resp = respHeader + "hi, hspedu 韩顺平教育";
            System.out.println("========我们的 tomcat 给浏览器会送的数据 ======");
            System.out.println(resp);
            outputStream.write(resp.getBytes());//将 resp 字符串以 byte[] 方式返回
            outputStream.flush();
            outputStream.close();
            inputStream.close();
            socket.close();



        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //最后一定确保socket要关闭
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }
}

 主程序

package com.hspedu.tomcat;

import com.hspedu.tomcat.handler.HspRequestHandler;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class LinranTomcatV2 {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket=new ServerSocket(8080);
        System.out.println("============LinranTomcatV2在8080监听===============");

        while (!serverSocket.isClosed()){
            //只要serverSocket没有关闭,就一直等待连接
            Socket socket = serverSocket.accept();
            //这个socket就是一个通信
            //创建一个线程对象,并把socket给该线程
            new Thread( new HspRequestHandler(socket)).start();


        }
    }
}

3 实现任务阶段

处理 Servlet

3.1 Servlet 生命周期-回顾

3.2 需求分析/图解 

 3.3 分析

 代码实现参考视频和项目源码

很心塞的一点,在跟着学习的过程中,最终 报错了,很烦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜菜小林然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值