【Java Web】如何写一个简单的TomCat服务器

【Java Web】如何写一个简单的TomCat服务器,第1张

如何写一个简单的TomCat服务器 1. 目标

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

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

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

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

2.流程图

3.pom文件配置


    4.0.0

    org.example
    SimpleTomCat
    1.0-SNAPSHOT

    
        8
        8
    

    
        
            org.projectlombok
            lombok
            1.18.22
        

        
            dom4j
            dom4j
            1.6.1
        
        
            jaxen
            jaxen
            1.1.6
        
    

    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.8.1
                
                    1.8
                    1.8
                    utf-8
                
            
        
    


4.资源配置 4.1 h1.html



    
    h1页面测试




    手写TomCat静态页面1




4.2 web.xml


    
        myServlet
        com.tomcat.servlet.MyServlet
    


    
        myServlet
        /my
    


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"
                +" HTTP/1.1 404 NotFound ";

        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 处理动态资源

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 = "  MyServlet GET " + "\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 = "  MyServlet POST "+ "\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 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 servletMap = new HashMap();

    /**
     * 加载解析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 selectNodes = rootElement.selectNodes("//servlet");
            for (int i = 0; i < selectNodes.size(); i++) {
                Element element = selectNodes.get(i);
                // myServlet
                Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletnameElement.getStringValue();
                // com.tomcat.servlet.MyServlet
                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;
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/798564.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-06
下一篇 2022-05-06

发表评论

登录后才能评论

评论列表(0条)

保存