Building a Minimal Tomcat-Like Server in Java

An HTTP request sent by a browser contains a method, path, and headers. To represent this server-side, we define a class that parses the raw input stream.

package tomcat;

import java.io.IOException;
import java.io.InputStream;

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

    public IRequest(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int length = inputStream.read(buffer);
        if (length > 0) {
            String request = new String(buffer, 0, length);
            System.out.println("Request Body:\r\n" + request);
            String[] lines = request.split("\n");
            if (lines.length > 0) {
                String[] parts = lines[0].split("\\s");
                if (parts.length >= 2) {
                    method = parts[0];
                    url = parts[1];
                }
            }
        }
    }

    public String getUrl() { return url; }
    public String getMethod() { return method; }
}

The response must be formatted as HTTP. We create a simple class that writes a HTTP response with HTML content.

package tomcat;

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

public class IResponse {
    private OutputStream outputStream;

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

    public void write(String content) throws IOException {
        StringBuilder sb = new StringBuilder();
        sb.append("HTTP/1.1 200 OK\n");
        sb.append("Content-Type: text/html\n");
        sb.append("\r\n");
        sb.append("<html><body>");
        sb.append(content);
        sb.append("</body></html>");
        outputStream.write(sb.toString().getBytes());
        outputStream.close();
    }
}

Next, we define an abstract servlet with the service method dispatching to doGet or doPost.

package tomcat;

public abstract class IServlet {
    public abstract void doGet(IRequest request, IResponse response);
    public abstract void doPost(IRequest request, IResponse response);

    public void service(IRequest request, IResponse response) {
        if ("POST".equalsIgnoreCase(request.getMethod())) {
            doPost(request, response);
        } else if ("GET".equalsIgnoreCase(request.getMethod())) {
            doGet(request, response);
        }
    }
}

A concrete implementation returns "hello world".

package tomcat.impl;

import tomcat.IRequest;
import tomcat.IResponse;
import tomcat.IServlet;
import java.io.IOException;

public class HelloServletImpl extends IServlet {
    @Override
    public void doGet(IRequest request, IResponse response) {
        try {
            response.write("hello world");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(IRequest request, IResponse response) {
        try {
            response.write("hello post");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

We then map URLs to servlet classes.

package tomcat;

public class ServletMapping {
    private String servletName;
    private String url;
    private Class<?> clazz;

    public ServletMapping(String servletName, String url, Class<?> clazz) {
        this.servletName = servletName;
        this.url = url;
        this.clazz = clazz;
    }

    public String getServletName() { return servletName; }
    public String getUrl() { return url; }
    public Class<?> getClazz() { return clazz; }
}

Configuration holds the list of mappings.

package tomcat;

import tomcat.impl.HelloServletImpl;
import java.util.ArrayList;
import java.util.List;

public class ServletMappingConfig {
    public static List<ServletMapping> servletMappings = new ArrayList<>();
    static {
        servletMappings.add(new ServletMapping("hello", "/hello", HelloServletImpl.class));
        servletMappings.add(new ServletMapping("hello", "/aa", HelloServletImpl.class));
    }
}

Finally, the server listens on a port, accepts connections, and dispatches requests.

package tomcat;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class TomcatServer {
    private int port;
    private Map<String, Class<?>> urlServletMap = new HashMap<>();

    public TomcatServer(int port) {
        this.port = port;
    }

    public void start() {
        initServletMapping();
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            System.out.println("Tomcat running on port " + port);
            while (true) {
                try (Socket socket = serverSocket.accept()) {
                    InputStream is = socket.getInputStream();
                    OutputStream os = socket.getOutputStream();
                    IRequest request = new IRequest(is);
                    IResponse response = new IResponse(os);
                    dispatch(request, response);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void initServletMapping() {
        for (ServletMapping mapping : ServletMappingConfig.servletMappings) {
            urlServletMap.put(mapping.getUrl(), mapping.getClazz());
        }
    }

    private void dispatch(IRequest request, IResponse response) {
        Class<?> clazz = urlServletMap.get(request.getUrl());
        if (clazz != null) {
            try {
                IServlet servlet = (IServlet) clazz.getDeclaredConstructor().newInstance();
                servlet.service(request, response);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        new TomcatServer(8081).start();
    }
}

This implementation handles GET and POST requests for two paths (/hello and /aa). The server reads the raw request, extracts the method and URL, looks up the mapping, and invokes the appropriate servlet method.

Tags: java Tomcat Web Server HTTP servlet

Posted on Tue, 03 Nov 2026 16:54:44 +0000 by Hurklefish