如何写一个简单的TomCat服务器

简介: 1)提供服务,接收请求(Socket通信)2)请求信息封装成Request对象(Response对象)3)客户端请求资源,资源分为静态资源(html)和动态资源(Servlet) 4)资源返回给客户端浏览器

如何写一个简单的TomCat服务器

1. 目标

1)提供服务,接收请求(Socket通信)

2)请求信息封装成Request对象(Response对象)

3)客户端请求资源,资源分为静态资源(html)和动态资源(Servlet)

4)资源返回给客户端浏览器

idea64_nO8ZJMKT92

2.流程图

TomCat-导出

3.pom文件配置

<?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>org.example</groupId>
    <artifactId>SimpleTomCat</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>

        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>jaxen</groupId>
            <artifactId>jaxen</artifactId>
            <version>1.1.6</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

4.资源配置

4.1 h1.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>h1页面测试</title>
</head>
<body>

<h1>
    手写TomCat静态页面1
</h1>

</body>
</html>

4.2 web.xml

<?xml version="1.0" encoding="UTF-8" ?>
<web-app>
    <servlet>
        <servlet-name>myServlet</servlet-name>
        <servlet-class>com.tomcat.servlet.MyServlet</servlet-class>
    </servlet>


    <servlet-mapping>
        <servlet-name>myServlet</servlet-name>
        <url-pattern>/my</url-pattern>
    </servlet-mapping>
</web-app>

5. Response 与 Request 对象

package com.tomcat.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.Properties;

/**
 * @author sz
 * @DATE 2022/5/1  15:32
 */
@Data
public class Request {

    /**
     * 请求方法
     */
    private String method;

    /**
     * 请求路径
     */
    private String url;

    private InputStream inputStream;
    
    public  Request(InputStream inputStream) throws IOException {
        this.inputStream=inputStream;

        byte[] bytes = new byte[1024];

        int start;

        String str = "";

        while (-1 != (start = inputStream.read(bytes))) {
            str += new String(bytes,0,start);
            if (start<1024){
                break;
            }
        }

        String[] split = str.split("\\n");


        //请求头第一行
        try {
            method = split[0].split(" ")[0];
        } catch (Exception e) {
            method="GET";
        }

        try {
            url=split[0].split(" ")[1];
        } catch (Exception e) {
            url="/";
        }
    };

    
}
package com.tomcat.pojo;

import com.tomcat.util.HttpUtils;
import com.tomcat.util.ResponseUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * @author sz
 * @DATE 2022/5/1  15:32
 */
@Data
public class Response {

    private OutputStream outputStream;

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

    /**
     * 根据url 返回静态资源
     * @param str 静态资源url
     */
    public void outputHtml(String str) throws IOException {
        //获取资源的绝对路径
        String absPath = ResponseUtils.getAbsPath(str);

        File file = new File(absPath);

        if (file.exists() && file.isFile()){
            //输出资源
            ResponseUtils.writeStaticHtml(new FileInputStream(file),outputStream);
        }else {
            //返回404
            outputStream.write(HttpUtils.writeNotFound().getBytes(StandardCharsets.UTF_8));
            outputStream.close();
         }
    }


    public void output(String str) throws IOException {
        outputStream.write(str.getBytes(StandardCharsets.UTF_8));
        outputStream.close();
    }
}

6. HttpUtils 与 ResponseUtils 工具类

package com.tomcat.util;

/**
 * @author sz
 * @DATE 2022/5/1  15:32
 */
public class HttpUtils {

    private HttpUtils(){};

    //输出成功的内容信息
    public static String writeSuccess(){
        String str = "HTTP/1.1 200 OK"+"\n"
                +"Content-Type: text/html;charset=utf-8"+"\n"
                +"\r\n";
        return str;
    }

    //输出404的内容信息
    public static String writeNotFound(){
        String str = "HTTP/1.1 404 NotFound"+"\n"
                +"Content-Type: text/html;charset=utf-8"+"\n"
                +"\r\n"
                +"<h1> HTTP/1.1 404 NotFound </h1>";

        return str;
    }

}
package com.tomcat.util;

import lombok.Data;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

/**
 * @author sz
 * @DATE 2022/5/1  16:11
 */
@Data
public class ResponseUtils {

    private ResponseUtils() {
    }

    ;


    /**
     * 获取静态资源的绝对路径
     *
     * @param path
     * @return
     */
    public static String getAbsPath(String path) {

        return  (ResponseUtils.class.getResource("/") + path.substring(1)).split("file:/")[1];
    }

    /**
     * 输出静态资源
     *
     * @param inputStream
     * @param outputStream
     */
    public static void writeStaticHtml(InputStream inputStream, OutputStream outputStream) throws IOException {
        //首先输出请求头
        outputStream.write(HttpUtils.writeSuccess().getBytes(StandardCharsets.UTF_8));
        //再输出请求体
        byte[] bytes = new byte[1024];

        int len;

        if (-1 != (len = inputStream.read(bytes))) {
            outputStream.write(bytes,0,len);
        }

        outputStream.close();
    }
}

7. Serlvet 处理动态资源

image-20220501215359989

package com.tomcat.inter;

import com.tomcat.pojo.Request;
import com.tomcat.pojo.Response;

public interface Servlet {

    void init();

    void destory();

    void service(Request request, Response response);

}
package com.tomcat.abs;

import com.tomcat.inter.Servlet;
import com.tomcat.pojo.Request;
import com.tomcat.pojo.Response;

/**
 * @author sz
 * @DATE 2022/5/1  20:16
 */
public abstract class HttpServlet implements Servlet {

    public abstract void doGet(Request request, Response response);

    public abstract void doPost(Request request, Response response);

    @Override
    public void service(Request request, Response response) {
        if ("GET".equals(request.getMethod())) {
            doGet(request, response);
        } else {
            doPost(request, response);
        }
    }
}
package com.tomcat.servlet;

import com.tomcat.abs.HttpServlet;
import com.tomcat.pojo.Request;
import com.tomcat.pojo.Response;
import com.tomcat.util.HttpUtils;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * @author sz
 * @DATE 2022/5/1  20:20
 */
public class MyServlet extends HttpServlet {

    @Override
    public void doGet(Request request, Response response) {

//        try {
//            TimeUnit.DAYS.sleep(1);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

        String context = "<h1>  MyServlet GET </h1>" + "\r\n"+Thread.currentThread().getName();
        try {
            response.output(HttpUtils.writeSuccess()+context);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(Request request, Response response) {
        String context = "<h1>  MyServlet POST </h1>"+ "\r\n"+Thread.currentThread().getName();
        try {
            response.output(HttpUtils.writeSuccess()+context);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void init() {

    }

    @Override
    public void destory() {

    }
}

8. RequestProcess 请求处理器

package com.tomcat.process;

import com.tomcat.abs.HttpServlet;
import com.tomcat.pojo.Request;
import com.tomcat.pojo.Response;
import lombok.AllArgsConstructor;

import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;

/**
 * @author sz
 * @DATE 2022/5/1  21:02
 */
@AllArgsConstructor
public class RequestProcess extends Thread{

    private Socket accept;
    private Map<String, HttpServlet> servletMap;

    @Override
    public void run() {
        try {
            //获取Request对象
            Request request = new Request(accept.getInputStream());
            //获取Response对象
            Response response = new Response(accept.getOutputStream());
            //写回资源
            HttpServlet httpServlet = servletMap.get(request.getUrl());
            if (null==httpServlet){
                //为nulll,静态资源
                response.outputHtml(request.getUrl());
            }else {
                //不为null  动态资源
                httpServlet.service(request,response);
            }
        }catch (Exception e){

        }
    }

}

9. Main 方法 服务器启动入口

package com.tomcat.main;


import com.tomcat.abs.HttpServlet;
import com.tomcat.process.RequestProcess;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author sz
 * @DATE 2022/5/1  10:30
 */
public class Main {

    /*设置端口号*/
    private static Integer port = 8080;

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

        Main main = new Main();
        main.start();
    }

    public void start() throws IOException {
        loadServlet();

        //创建线程池
        ThreadPoolExecutor tomcatThreadPool = new ThreadPoolExecutor(
                10,
                100,
                30,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(100)
                , new ThreadFactory() {
            int i = 0;
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "TomCat线程" + "---" + (++i));
            }
        },
                new ThreadPoolExecutor.CallerRunsPolicy()
        );

        //创建连接
        ServerSocket serverSocket = new ServerSocket(port);
        while (true) {
            //获取套接字
            Socket accept = serverSocket.accept();
            RequestProcess requestProcess = new RequestProcess(accept, servletMap);
            tomcatThreadPool.execute(requestProcess);
        }

    }

    private Map<String, HttpServlet> servletMap = new HashMap<String, HttpServlet>();

    /**
     * 加载解析web.xml,初始化Servlet
     */
    private void loadServlet() {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("web.xml");
        SAXReader saxReader = new SAXReader();

        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();

            List<Element> selectNodes = rootElement.selectNodes("//servlet");
            for (int i = 0; i < selectNodes.size(); i++) {
                Element element = selectNodes.get(i);
                // <servlet-name>myServlet</servlet-name>
                Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletnameElement.getStringValue();
                // <servlet-class>com.tomcat.servlet.MyServlet</servlet-class>
                Element servletclassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletclassElement.getStringValue();


                // 根据servlet-name的值找到url-pattern
                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                // /my
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
                servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClass).newInstance());

            }


        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        port = port;
    }
}
相关文章
|
2月前
|
XML 网络协议 Java
JavaWeb -- HTTP -- WEB服务器TOMCAT
JavaWeb -- HTTP -- WEB服务器TOMCAT
|
4天前
|
Java 应用服务中间件 Apache
在 Debian 服务器上安装和配置 Apache Tomcat 的方法
在 Debian 服务器上安装和配置 Apache Tomcat 的方法
7 0
|
2月前
|
Java 关系型数据库 MySQL
杨校老师课堂之Java项目部署到云端服务器之安装MySQL、Jdk、Tomcat
杨校老师课堂之Java项目部署到云端服务器之安装MySQL、Jdk、Tomcat
38 0
杨校老师课堂之Java项目部署到云端服务器之安装MySQL、Jdk、Tomcat
|
2月前
|
Java 应用服务中间件 程序员
JavaWeb基础第四章(SpringBootWeb工程,HTTP协议与Web服务器-Tomcat)
JavaWeb基础第四章(SpringBootWeb工程,HTTP协议与Web服务器-Tomcat)
|
3月前
|
Java 应用服务中间件 Linux
在阿里云服务器上部署Tomcat详细图文详解
本文介绍了在阿里云服务器上安装和配置JDK和Tomcat的步骤。首先,需要注册阿里云账号并进行实名认证,然后购买并设置服务器。接着,通过File Zilla连接服务器,创建Java和Tomcat的安装目录,并将JDK和Tomcat的tar.gz文件上传到服务器,解压并重命名。之后,配置JDK的环境变量,将catalina.sh复制到/etc/init.d/目录下,并修改相关配置。最后,启动Tomcat并配置安全组规则,确保可以通过公网访问。
|
3月前
|
Java 应用服务中间件 Linux
阿里云服务器部署多个tomcat
阿里云服务器部署多个tomcat
|
3月前
|
安全 Java 应用服务中间件
本地部署Tomcat开源服务器并结合内网穿透远程访问
本地部署Tomcat开源服务器并结合内网穿透远程访问
73 0
|
弹性计算 Linux 应用服务中间件
【阿里云ECS】外网无法访问tomcat下部署的项目
问题提出:在ESC实例上部署了jdk和tomcat,启动tomct后,内网可以访问8080端口,外网无法访问8080. 系统环境:Linux version 3.10.0-693.2.2.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC) )  解决方案: 在网上查资料后说是配置安全组策咯,但是没说是在ESC上部署,还是在阿里云网站上部署,这是一个大坑。
3787 0
|
4天前
|
机器学习/深度学习 编解码 人工智能
阿里云gpu云服务器租用价格:最新收费标准与活动价格及热门实例解析
随着人工智能、大数据和深度学习等领域的快速发展,GPU服务器的需求日益增长。阿里云的GPU服务器凭借强大的计算能力和灵活的资源配置,成为众多用户的首选。很多用户比较关心gpu云服务器的收费标准与活动价格情况,目前计算型gn6v实例云服务器一周价格为2138.27元/1周起,月付价格为3830.00元/1个月起;计算型gn7i实例云服务器一周价格为1793.30元/1周起,月付价格为3213.99元/1个月起;计算型 gn6i实例云服务器一周价格为942.11元/1周起,月付价格为1694.00元/1个月起。本文为大家整理汇总了gpu云服务器的最新收费标准与活动价格情况,以供参考。
阿里云gpu云服务器租用价格:最新收费标准与活动价格及热门实例解析
|
7天前
|
云安全 弹性计算 安全
阿里云服务器基础安全防护简介,云服务器基础安全防护及常见安全产品简介
在使用云服务器的过程中,云服务器的安全问题是很多用户非常关心的问题,阿里云服务器不仅提供了一些基础防护,我们也可以选择其他的云安全类产品来确保我们云服务器的安全。本文为大家介绍一下阿里云服务器的基础安全防护有哪些,以及阿里云的一些安全防护类云产品。
阿里云服务器基础安全防护简介,云服务器基础安全防护及常见安全产品简介