手写tomcat

发布于:2025-07-22 ⋅ 阅读:(12) ⋅ 点赞:(0)

package com.qcby.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)// 表示该注解只能用于类上
@Retention(RetentionPolicy.RUNTIME)// 表示该注解在运行时存在
public @interface ZFLServlet {
    String url()default "";
}

package com.qcby.config;

import com.qcby.annotation.ZFLServlet;
import com.qcby.servlet.HttpServlet;
import com.qcby.util.SearchClassUtil;


import java.util.HashMap;
import java.util.List;

public class TomcatRoute {
    public static HashMap<String, HttpServlet> routes = new HashMap<>();

        static {
            List<String> paths = SearchClassUtil.searchClass();//获取全路径名
            //根据全路径生成对象
            for (String path : paths) {
                try {
                    Class clazz = Class.forName(path);//生成类对象
                    ZFLServlet webServlet = (ZFLServlet) clazz.getDeclaredAnnotation(ZFLServlet.class);
                    System.out.println(webServlet.url());
                    routes.put(webServlet.url(), (HttpServlet) clazz.getDeclaredConstructor().newInstance());

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

}

package com.qcby.myweb;

import com.qcby.annotation.ZFLServlet;
import com.qcby.requset.HttpServletRequest;
import com.qcby.response.HttpServletResponse;
import com.qcby.servlet.HttpServlet;

import java.io.IOException;

@ZFLServlet(url = "/delete")
public class DeleteServlet extends HttpServlet {
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        super.doPost(request, response);
    }

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        super.doGet(request, response);
    }
}

package com.qcby.myweb;

import com.qcby.annotation.ZFLServlet;
import com.qcby.requset.HttpServletRequest;
import com.qcby.response.HttpServletResponse;
import com.qcby.servlet.HttpServlet;

import java.io.IOException;
@ZFLServlet(url = "/insert")
public class InsertServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("我是insert......");
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        super.doPost(request, response);
    }
}

package com.qcby.servlet;

import com.qcby.requset.HttpServletRequest;
import com.qcby.response.HttpServletResponse;

import java.io.IOException;

public abstract class HttpServlet implements servlet{

    public void doPost(HttpServletRequest request, HttpServletResponse response) {}

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {

    }

    @Override
    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
        if (request.getMethod().equals("GET")){
            doGet(request,response);
        } else if (request.getMethod().equals("POST")) {
            doPost(request,response);
        }

    }


}

package com.qcby.requset;

public class HttpServletRequest {
    private String url;
    private String method;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }
}
package com.qcby.response;

import com.qcby.util.FileUtil;
import com.qcby.util.ResponseUtil;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

public class HttpServletResponse {
    //输出流
    private OutputStream outputStream;
    public HttpServletResponse(OutputStream outputStream) {
        this.outputStream = outputStream;
    }
    /**
     * 返回动态资源
     * @param context
     */
    public void write(String context) throws IOException {
        outputStream.write(context.getBytes());
    }
    /**
     * 返回静态资源
     */
    public void writeHtml(String path) throws Exception {
        String resourcesPath = FileUtil.getResoucePath(path);
        File file = new File(resourcesPath);
        if(file.exists()){
            //静态文件存在
            System.out.println("静态文件存在");
            FileUtil.writeFile(file,outputStream);
        }else {
            System.out.println("静态文件不存在");
            write(ResponseUtil.getResponseHeader404());
        }
    }
}

package com.qcby.servlet;

import com.qcby.requset.HttpServletRequest;
import com.qcby.response.HttpServletResponse;

import java.io.IOException;

public abstract class HttpServlet implements servlet{

    public void doPost(HttpServletRequest request, HttpServletResponse response) {}

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {

    }

    @Override
    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
        if (request.getMethod().equals("GET")){
            doGet(request,response);
        } else if (request.getMethod().equals("POST")) {
            doPost(request,response);
        }

    }


}
package com.qcby.servlet;

import com.qcby.requset.HttpServletRequest;
import com.qcby.response.HttpServletResponse;

import java.io.IOException;

public interface servlet {
    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException;
}

package com.qcby.util;

import java.io.*;

public class FileUtil {
    public  static  boolean witeFile(InputStream inputStream, OutputStream outputStream){
        boolean success = false ;
        BufferedInputStream bufferedInputStream ;
        BufferedOutputStream bufferedOutputStream;

        try {
            bufferedInputStream = new BufferedInputStream(inputStream);
            bufferedOutputStream = new BufferedOutputStream(outputStream);
            bufferedOutputStream.write(ResponseUtil.responseHeader200.getBytes());

            int count = 0;
            while (count == 0){
                count = inputStream.available();
            }
            int fileSize = inputStream.available();
            long written = 0;
            int beteSize = 1024;
            byte[] bytes = new byte[beteSize];
            while (written < fileSize){
                if(written + beteSize > fileSize){
                    beteSize = (int)(fileSize - written);
                    bytes = new byte[beteSize];
                }
                bufferedInputStream.read(bytes);
                bufferedOutputStream.write(bytes);
                bufferedOutputStream.flush();
                written += beteSize;
            }
            success = true;

        } catch (IOException e) {
            e.printStackTrace();
        }
        return success;
    }

    public static boolean writeFile(File file,OutputStream outputStream) throws Exception{
        return witeFile(new FileInputStream(file),outputStream);
    }


    public static String getResoucePath(String path){
        String resource = FileUtil.class.getResource("/").getPath();
        return resource + "\\" + path;
    }
}

package com.qcby.util;

/**
 * 设置响应头
 */
public class ResponseUtil {
    public  static  final String responseHeader200 = "HTTP/1.1 200 \r\n"+
            "Content-Type:text/html\r\n"+"\r\n";

    public static String getResponseHeader404(){
        return "HTTP/1.1 404 \r\n"+
                "Content-Type:text/html\r\n"+"\r\n" + "404";
    }

    public static String getResponseHeader200(String context){
        return "HTTP/1.1 200\r\n"+
                "Content-Type:text/html\r\n"+"\r\n" + context;
    }

}

package com.qcby.util;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public class SearchClassUtil {
    public static List<String> classPaths = new ArrayList<>();

    public static List<String> searchClass() {
        // 需要扫描的包名
        String basePack = "com.qcby.myweb";
        try {
            // 使用字符串替换
            Enumeration<URL> resources = SearchClassUtil.class.getClassLoader().getResources(basePack.replace(".", "/"));
            while (resources.hasMoreElements()) {
                URL url = resources.nextElement();
                String protocol = url.getProtocol();
                if ("file".equals(protocol)) {
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    doPath(new File(filePath), basePack);
                } else if ("jar".equals(protocol)) {
                    // 处理JAR包情况
                    System.out.println("暂未完整处理JAR包情况");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return classPaths;
    }

    /**
     * 该方法会得到所有的类,将类的绝对路径写入到classPaths中
     *
     * @param file 当前文件或目录
     * @param basePack 基础包名
     */
    private static void doPath(File file, String basePack) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files != null) {
                for (File subFile : files) {
                    doPath(subFile, basePack);
                }
            }
        } else if (file.getName().endsWith(".class")) {
            String classFilePath = file.getAbsolutePath();
            // 使用字符串替换
            classFilePath = classFilePath.substring(classFilePath.indexOf(basePack.replace(".", File.separator)));
            classFilePath = classFilePath.replace(File.separator, ".");
            classFilePath = classFilePath.substring(0, classFilePath.length() - 6);
            classPaths.add(classFilePath);
        }
    }

    public static void main(String[] args) {
        List<String> paths = searchClass();
        for (String path : paths) {
            System.out.println(path);
        }
    }
}

package com.qcby;

import com.qcby.config.TomcatRoute;
import com.qcby.requset.HttpServletRequest;
import com.qcby.response.HttpServletResponse;
import com.qcby.servlet.HttpServlet;

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

public class MyTomcat {
    static HashMap<String, HttpServlet> routes = TomcatRoute.routes; //tomcat路由\


    /**
     * 分发器
     */
    public  void dispatch(HttpServletRequest request ,HttpServletResponse response) throws IOException {
        HttpServlet servlet = routes.get(request.getUrl());  //
        if(servlet!=null){ //说明请求的就是我们的servlet
            servlet.service(request,response);
        }
    }

    /**
     * socket 启动
     * @throws IOException
     */
    public  void start() throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);  //1.指定监听的端口号
        //2.对端口进行监听
        while (true){
            Socket socket = serverSocket.accept();//阻塞监听
            //3.打开输入流,解析客户端发来的内容
            InputStream inputStream = socket.getInputStream(); //输入流
            HttpServletRequest request = new HttpServletRequest();

            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));  //将字节流转换成字符流
            String str = reader.readLine();
            request.setMethod(str.split("\\s")[0]);
            request.setUrl(str.split("\\s")[1]);

            //4.打开输出流
            OutputStream outputStream = socket.getOutputStream();
            HttpServletResponse response = new HttpServletResponse(outputStream);
            dispatch(request,response);
        }

    }

    //socket
    public static void main(String[] args) throws IOException {
        MyTomcat myTomcat = new MyTomcat();
        myTomcat.start();


    }
}


网站公告

今日签到

点亮在社区的每一天
去签到