深度理解Tomcat底层机制

大家好呀,我是小笙,我和大家分享下我学习Javaweb的笔记

Tomcat

概述

BS 与 CS 开发介绍

image-20220421193359742

(1) 兼容性 , 浏览器的种类很多
(2) 安全性, 通常情况下,BS 安全性不如 CS 好控制
(3) 易用性, BS 好于 CS, 浏览器方便在线使用
(4) 扩展性, BS 相对统一,只需要写 Server

常用服务器

  1. Tomcat:由 Apache 组织提供的一种 Web 服务器,提供对 jsp 和 Servlet 的支持。它 是一种轻量级的 javaWeb 容器(服务器),也是当前应用最广的 JavaWeb 服务器(免费),Tomcat 本质就是一个 Java 程序, 但是这个 Java 程序可以处理来自浏览器的 HTTP 请求

    Tomcat下载网址

  2. Jboss:是一个遵从 JavaEE 规范的、它支持所有的 JavaEE 规范(免费)

  3. GlassFish: 由 Oracle 公司开发的一款 JavaWeb 服务器,是一款商业服务器,达到产品级质量(应用很少)

  4. Resin:是 CAUCHO 公司的产品,是一个非常流行的服务器,对 servlet 和 JSP 提供了 良好的支持, 性能也比较优良(收费)

  5. WebLogic:是 Oracle 公司的产品,支持 JavaEE 规范, 而且不断的完善以适 应新的开发要求,适合大型项目(收费,用的不多,适合大公司)

Tomcat 目录结构

image-20220422164147589

image-20220422164414505

Web应用

Tomcat 服务中部署 WEB 应用

概念:Web应用通常也称之为web应用程序(网站),WEB应用是多个web资源的集合

组成

image-20220422172300345

在Tomcat 下的 conf 目录\Catalina\localhost\ 下,配置文件,比如XXX.xml(提醒:通过Tomcat配置,可以把一个web应用,映射到指定的目录,可以解决磁盘空间分配问题

<?xml version="1.0" encoding="utf-8"?>
<!-- Context 表示一个工程上下文 path表示工程的访问路径:/XXX dosBase表示目标工程位置 -->
<Context path:"/XXX" docBase="E:\Java\Java_software">

浏览器请求资源过程

image-20220422233427103

注意:http://localhost , 默 认 是 访 问 80 端 口 , 即 http://localhost 等 价 http://localhost:80

IDEA 开发 JavaWeb 注意事项

1.热加载选项说明

image-20220423160116209

2.修改端口,只会影响当前的项目,但是不会去修改tomcat文件中server.xml文件的端口

3.当tomcat启动时,会生成out目录,该目录就是原项目资源的映射,我们浏览器访问的资源是 out 目录

Maven

基本介绍

概述:一个项目管理工具,可以对 Java 项目进行构建、依赖管理

image-20220428232713295

IDEA创建Maven项目说明

image-20220428233851277

image-20220428234453569

pom.xml文件说明

image-20220429164418392

<dependencies>
    <!--
      1. dependency 表示依赖, 也就是我们这个项目需要依赖的jar包
      2. groupId 和 artifactId 被统称为坐标, 是为了去定位这个项目/jar
      3. groupId: 一般是公司比如:com.baidu , 这里是 javax.servlet
      4. artifactId 一般是项目名, 这里是javax.servlet-api
      5. version 表示你引入到我们项目的jar包的版本是 3.1.0
      6. scope: 表示作用域,也就是你引入的 jar 包的作用范围
        6.1.provided 表示在tomcat服务器中有这个jar包,因此在编译或者测试使用,但是在打包发布就不用要带上该jar包
    -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

实现Tomcat底层机制

框架图

image-20220430230402155

实现案例

题目要求
  • 可以访问静态资源addSum.html

    image-20220430230514287

  • 可以通过提交按钮,跳转到求和解结果

    image-20220430230635344

文件目录说明

image-20220430231547050

xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<myTomcat>
  <myServlet>
    <Servlet-name>myTomcat</Servlet-name>
    <Servlet-class>com.al_tair.myTomcat.myServlet.CalServlet</Servlet-class>
  </myServlet>
  <myServlet-mapping>
    <Servlet-name>myTomcat</Servlet-name>
    <url-pattern>/myTomcat</url-pattern>
  </myServlet-mapping>
</myTomcat>
静态资源
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="http://localhost:9999/myTomcat" method="get">
    <h1>求和</h1>
    第一个数字:<input type="text" name="firstNum"><br>
    第二个数字:<input type="text" name="secondName"><br>
    <button type="submit">提交</button>
</form>
</body>
</html>
网络监听
public class Connector {
    // 存放<name,Servlet实例>
    public static final ConcurrentHashMap<String, MyHttpServlet>
            nameToServlet = new ConcurrentHashMap<>();

    // 存放<urlPattern,name>
    public static final ConcurrentHashMap<String, String>
            urlToName = new ConcurrentHashMap<>();

    public static void main(String[] args) throws IOException, InterruptedException {

        // 在端口9999监听
        ServerSocket serverSocket = new ServerSocket(9999);

        while(!serverSocket.isClosed()){
            init();
            // 创建套接字 socket
            System.out.println("listening...");
            Socket socket = serverSocket.accept();
            RequestHandler rh = new RequestHandler(socket);
            new Thread(rh).start();
        }
    }
    
    public static void init(){
        String path = Connector.class.getResource("/").getPath();
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(new File(path + "web.xml"));
            // 得到根元素
            Element rootElement = document.getRootElement();
            // 得到根元素下的所有元素
            List<Element> myServlet = rootElement.elements();
            for (Element element: myServlet
                 ) {
                if("myServlet".equalsIgnoreCase(element.getName())){
                    Element element1 = element.element("Servlet-name");
                    Element element2 = element.element("Servlet-class");
                    nameToServlet.put(element1.getText(),(MyHttpServlet)Class.forName(element2.getText()).newInstance());
                }else if("myServlet-mapping".equalsIgnoreCase(element.getName())){
                    Element element1 = element.element("Servlet-name");
                    Element element2 = element.element("url-pattern");
                    urlToName.put(element2.getText(),element1.getText());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
线程处理请求和响应
public class RequestHandler implements Runnable{
    private Socket socket = null;

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

    @Override
    public void run() {
        MyHttpRequest Request = null;
        MyHttpResponse Response = null;
        try {
            Request = new MyHttpRequest(socket.getInputStream());
            Response = new MyHttpResponse(socket.getOutputStream());
            String uri = Request.getUri();
            System.out.println(uri);
            String path = RequestHandler.class.getResource("/").getPath();
            if(Connector.urlToName.containsKey(uri)){
                String name = Connector.urlToName.get(uri);
                if(Connector.nameToServlet.containsKey(name)){
                    MyHttpServlet myHttpServlet = Connector.nameToServlet.get(name);
                    try {
                        myHttpServlet.service(Request,Response);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }else{
                    OutputStream outputStream = Response.getOutputStream();
                    int index = uri.indexOf(".");
                    if(uri.substring(index+1).equalsIgnoreCase("html")){
                        try {
                            FileReader fileReader = new FileReader(path + "/static" + uri);
                            BufferedReader br = new BufferedReader(fileReader);
                            String str = "";
                            outputStream.write(Response.getResponseHeader().getBytes());
                            while((str = br.readLine()) != null){
                                outputStream.write(str.getBytes());
                            }
                            outputStream.flush();
                            outputStream.close();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }else{
                        outputStream.write((Response.responseHeader + "<h1>404,没有找到该资源</h1>").getBytes());
                        outputStream.flush();
                        outputStream.close();
                    }
                }
            }else{
                OutputStream outputStream = Response.getOutputStream();
                int index = uri.indexOf(".");
                if(uri.substring(index+1).equalsIgnoreCase("html")){
                    try {
                        FileReader fileReader = new FileReader(path + "/static" + uri);
                        BufferedReader br = new BufferedReader(fileReader);
                        String str = "";
                        outputStream.write(Response.getResponseHeader().getBytes());
                        while((str = br.readLine()) != null){
                            outputStream.write(str.getBytes());
                        }
                        outputStream.flush();
                        outputStream.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }else{
                    outputStream.write((Response.responseHeader + "<h1>404,没有找到该资源</h1>").getBytes());
                    outputStream.flush();
                    outputStream.close();
                }
            }
            socket.close();
        } catch (IOException e) {
            throw new RuntimeException();
        }
    }
}

请求类和响应类
/**
 * 封装http请求数据简化
 */
public class MyHttpRequest {
    private String uri;
    private String method;
    private HashMap<String,String> parameters = new HashMap<>();
    private InputStream inputStream = null;

    public MyHttpRequest(InputStream inputStream) {
       this.inputStream = inputStream;
       init();
    }

    public String getUri() {
        return uri;
    }

    public String getMethod() {
        return method;
    }

    public void init(){
        try {
            // 将字节流转换成字符流,方便读取数据
            BufferedReader bufferedReader =
                    new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
            String request = bufferedReader.readLine();
            String[] requestLine = request.split(" ");
            // GET /servlet?name=18 HTTP/1.1
            method = requestLine[0];
            int index = requestLine[1].indexOf("?");
            if(index == -1){
                // uri后面没有数据
                uri = requestLine[1];
            }else{
                uri = requestLine[1].substring(0,index);
                String parameter = requestLine[1].substring(index+1);
                String[] params = parameter.split("&");
                if(parameter != null && !params.equals("")){
                    for (String param:params
                    ) {
                        String[] split = param.split("=");
                        if(split.length == 2){
                            parameters.put(split[0],split[1]);
                        }
                    }
                }
            }
        }catch (IOException e){
            throw new RuntimeException();
        }
    }

    public String Parameter(String name){
        if(parameters.containsKey(name)){
            return parameters.get(name);
        }else{
            return null;
        }
    }
}

/**
 * http响应头封装简化
 */
public class MyHttpResponse {
    private OutputStream outputStream = null;
    public String responseHeader = "HTTP/1.1 200OK\r\n" +
            "Content-Type:text/html;charset=utf-8\r\n\r\n";

    public MyHttpResponse(OutputStream outputStream) {
        this.outputStream = outputStream;
    }

    public OutputStream getOutputStream() {
        return outputStream;
    }

    public String getResponseHeader() {
        return responseHeader;
    }
}
Servlet接口实现
// Servlet接口
public interface MyServlet {
    void init() throws Exception;
    void service(MyHttpRequest var1, MyHttpResponse var2) throws Exception;
    void destroy();
}

// 抽象类
public abstract class MyHttpServlet implements MyServlet{
    @Override
    public void service(MyHttpRequest request, MyHttpResponse response) throws Exception {
        if("GET".equals(request.getMethod())){
            this.doGet(request,response);
        }else if("POST".equals(request.getMethod())){
            this.doPost(request,response);
        }
    }

    @Override
    public void init() throws Exception {

    }

    @Override
    public void destroy() {

    }

    public abstract void doGet(MyHttpRequest request, MyHttpResponse response);

    public abstract void doPost(MyHttpRequest request, MyHttpResponse response);
}

// Servlet资源
public class CalServlet extends MyHttpServlet{
    @Override
    public void doGet(MyHttpRequest request, MyHttpResponse response) {
        String num1 = request.Parameter("firstNum");
        String num2 = request.Parameter("secondName");
        int sum = Utils.StringToInteger(num1, num2);
        OutputStream outputStream = response.getOutputStream();
        try {
            outputStream.write((response.responseHeader  + "<h1>求和: " + sum + "</h1>").getBytes());
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(MyHttpRequest request, MyHttpResponse response) {
        doPost(request,response);
    }
}
工具类
public class Utils {
    /**
     * 字符串转成整数求和
     */
    public static int StringToInteger(String var1,String var2){
        try{
            return Integer.parseInt(var1) + Integer.parseInt(var2);
        }catch (Exception e){
            System.out.println("格式输入错误");
        }
        return 0;
    }
}

注意细节

  • 如果想要分割点号必须转义 split(“\\.”)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

罗念笙

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

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

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

打赏作者

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

抵扣说明:

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

余额充值