How to Build a Simple Web Server in Java

Building a simple web server in Java involves creating a server socket to listen on a specific port, accepting client requests, and sending responses back to the client. Below is a basic example of building a simple HTTP server in Java.

Example Code

package org.kodejava.net;

import java.io.*;
import java.net.*;

public class SimpleWebServer {
    public static void main(String[] args) {
        int port = 8080; // Port number the server will listen on

        try (ServerSocket serverSocket = new ServerSocket(port)) {
            System.out.println("Server is listening on port " + port);

            while (true) {
                // Accept incoming client connections
                Socket clientSocket = serverSocket.accept();

                // Create a new thread to handle the request
                new Thread(() -> handleClientRequest(clientSocket)).start();
            }
        } catch (IOException e) {
            System.err.println("Server exception: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private static void handleClientRequest(Socket clientSocket) {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
             PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {

            // Read the HTTP request from the client
            String requestLine = in.readLine();
            System.out.println("Client request: " + requestLine);

            // Read and discard the rest of the request headers
            while (in.ready() && in.readLine() != null);

            // Build a basic HTTP response
            String responseBody = "<html><body><h1>Welcome to Simple Java Web Server</h1></body></html>";
            String response = "HTTP/1.1 200 OK\r\n" +
                              "Content-Type: text/html\r\n" +
                              "Content-Length: " + responseBody.length() + "\r\n" +
                              "\r\n" +
                              responseBody;

            // Send the HTTP response to the client
            out.write(response);
            out.flush();

        } catch (IOException e) {
            System.err.println("Client handling exception: " + e.getMessage());
            e.printStackTrace();
        } finally {
            try {
                clientSocket.close();
            } catch (IOException e) {
                System.err.println("Failed to close client socket: " + e.getMessage());
            }
        }
    }
}

Steps to Run the Server

  1. Compile the Code
    Save the file as SimpleWebServer.java and compile it:

    javac SimpleWebServer.java
    
  2. Run the Server
    Execute the program:

    java SimpleWebServer
    
  3. Access the Server
    Open a web browser and navigate to http://localhost:808. You should see the message:
    Welcome to Simple Java Web Server.

Key Concepts

  1. ServerSocket:
    The ServerSocket class is used to listen on a specific port for incoming connections.
  2. Socket:
    Represents the client’s connection. You can use the Socket object to read the request and send the response.
  3. HTTP Protocol:
    The server follows a basic structure of HTTP responses:

    • First the status line (e.g., HTTP/1.1 200 OK).
    • Then the headers (e.g., Content-Type and Content-Length).
    • Finally, the response body.
  4. Multithreading:
    Each client connection is handled on a separate thread to allow the server to process multiple requests simultaneously.

Notes

  • Error Handling: Additional error handling should be implemented in production-level servers.
  • Performance: For larger servers, consider using established frameworks like Spring Boot or Jakarta EE.
  • Security: This is a basic example and does not address security concerns like HTTPS, request validation, etc.

How to Check If a Date Is Weekend in Java

Here are simple and reliable ways to check whether a date falls on a weekend in Java. Prefer the modern java.time API (Java 8+), which is clearer and thread-safe.

  • Using LocalDate (recommended)
import java.time.DayOfWeek;
import java.time.LocalDate;

public class WeekendChecker {
    public static boolean isWeekend(LocalDate date) {
        DayOfWeek dow = date.getDayOfWeek();
        return dow == DayOfWeek.SATURDAY || dow == DayOfWeek.SUNDAY;
    }

    public static void main(String[] args) {
        System.out.println(isWeekend(LocalDate.now())); // true or false
    }
}
  • With time zones (e.g., when you start from an Instant)
import java.time.*;

public class WeekendCheckerTZ {
    public static boolean isWeekend(Instant instant, ZoneId zone) {
        DayOfWeek dow = instant.atZone(zone).getDayOfWeek();
        return dow == DayOfWeek.SATURDAY || dow == DayOfWeek.SUNDAY;
    }

    public static void main(String[] args) {
        boolean weekendInNY = isWeekend(Instant.now(), ZoneId.of("America/New_York"));
        System.out.println(weekendInNY);
    }
}
  • If you still use the legacy Calendar API
import java.util.Calendar;

public class WeekendCheckerLegacy {
    public static boolean isWeekend(Calendar cal) {
        int dow = cal.get(Calendar.DAY_OF_WEEK);
        return dow == Calendar.SATURDAY || dow == Calendar.SUNDAY;
    }
}
  • Configurable “weekend” definition (some regions consider Friday/Saturday)
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.EnumSet;
import java.util.Set;

public class ConfigurableWeekend {
    private static final Set<DayOfWeek> DEFAULT_WEEKEND = EnumSet.of(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY);

    public static boolean isWeekend(LocalDate date, Set<DayOfWeek> weekendDays) {
        return weekendDays.contains(date.getDayOfWeek());
    }

    public static void main(String[] args) {
        System.out.println(isWeekend(LocalDate.now(), DEFAULT_WEEKEND));
        // Example for Fri/Sat weekend:
        Set<DayOfWeek> friSatWeekend = EnumSet.of(DayOfWeek.FRIDAY, DayOfWeek.SATURDAY);
        System.out.println(isWeekend(LocalDate.now(), friSatWeekend));
    }
}

Notes:

  • Use java.time classes (LocalDate, ZonedDateTime, DayOfWeek) for new code.
  • If you have a timestamp without a zone (Instant), convert with a ZoneId before checking the day of the week.

How to Convert Between Date and LocalDateTime

In Java, you can convert between java.util.Date and java.time.LocalDateTime using the java.time API introduced in Java 8. Here’s how you can perform the conversions:


1. Converting Date to LocalDateTime

You need to use java.time.Instant and java.time.ZoneId to make this conversion. Here’s the process:

package org.kodejava.datetime;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

public class DateToLocalDateTimeExample {
    public static void main(String[] args) {
        // Create a Date object
        Date date = new Date();

        // Convert Date to LocalDateTime
        LocalDateTime localDateTime = date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();

        System.out.println("Date: " + date);
        System.out.println("LocalDateTime: " + localDateTime);
    }
}

2. Converting LocalDateTime to Date

To convert back from LocalDateTime to Date, again you will make use of Instant and ZoneId.

package org.kodejava.datetime;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

public class LocalDateTimeToDateExample {
    public static void main(String[] args) {
        // Create a LocalDateTime object
        LocalDateTime localDateTime = LocalDateTime.now();

        // Convert LocalDateTime to Date
        Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());

        System.out.println("LocalDateTime: " + localDateTime);
        System.out.println("Date: " + date);
    }
}

Explanation:

  1. Date to LocalDateTime:
    • Date.toInstant() converts the Date object into an Instant (a specific point in time).
    • .atZone(ZoneId.systemDefault()) adjusts the instant to your system’s default time zone.
    • .toLocalDateTime() converts the zoned date-time to a LocalDateTime.
  2. LocalDateTime to Date:
    • .atZone(ZoneId.systemDefault()) converts a LocalDateTime into a ZonedDateTime.
    • ZonedDateTime.toInstant() gets an Instant for the given date and time in the local zone.
    • Date.from(Instant) creates a Date object from the Instant.

By using these conversions, you can easily switch between the old java.util.Date and the modern java.time.LocalDateTime API.

How to Calculate Date Differences Using ChronoUnit

You can calculate date differences in Java using the ChronoUnit enum from the java.time package. The ChronoUnit class is used to measure the amount of time between two temporal objects (e.g., LocalDate, LocalDateTime, etc.) in terms of specific time units like DAYS, MONTHS, YEARS, etc.

Here’s an example of how to calculate the difference between two LocalDate objects in various time units:

Example Code

package org.kodejava.datetime;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

public class DateDifferenceExample {
    public static void main(String[] args) {
        // Define two dates
        LocalDate date1 = LocalDate.of(2023, 1, 1);
        LocalDate date2 = LocalDate.of(2025, 8, 7);

        // Calculate differences using ChronoUnit
        long daysBetween = ChronoUnit.DAYS.between(date1, date2);
        long monthsBetween = ChronoUnit.MONTHS.between(date1, date2);
        long yearsBetween = ChronoUnit.YEARS.between(date1, date2);

        // Print results
        System.out.println("Days between: " + daysBetween);
        System.out.println("Months between: " + monthsBetween);
        System.out.println("Years between: " + yearsBetween);
    }
}

Output

Days between: 949
Months between: 31
Years between: 2

Explanation

  1. between() Method:
    • The ChronoUnit.between() method takes two temporal objects as parameters and returns the difference in the specified unit (e.g., days, months, or years).
    • Ensure that the objects provided are compatible (e.g., both are LocalDate or LocalDateTime).
  2. Units of Measurement:
    • The ChronoUnit enum provides different constants such as DAYS, HOURS, WEEKS, MONTHS, YEARS, etc., to calculate differences at the desired granularity.
  3. Signed Differences:
    • The result may be negative if the first date is later than the second date. You can swap the dates if you want an absolute difference.

Other Temporal Types

ChronoUnit also works with other temporal types such as LocalDateTime, ZonedDateTime, Instant, etc. For example:

package org.kodejava.datetime;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

public class LocalDateTimeDifference {
    public static void main(String[] args) {
        LocalDateTime dateTime1 = LocalDateTime.of(2023, 1, 1, 10, 0);
        LocalDateTime dateTime2 = LocalDateTime.of(2025, 8, 7, 12, 30);

        long hoursBetween = ChronoUnit.HOURS.between(dateTime1, dateTime2);
        long minutesBetween = ChronoUnit.MINUTES.between(dateTime1, dateTime2);

        System.out.println("Hours between: " + hoursBetween);
        System.out.println("Minutes between: " + minutesBetween);
    }
}

This will give you the time differences in hours and minutes.

Note

  • ChronoUnit.WEEKS may not align perfectly with ChronoUnit.DAYS due to week boundaries.
  • Always validate whether the specific ChronoUnit applies to the temporal objects you’re comparing (e.g., you can’t use HOURS on LocalDate because it lacks time information).

How to Read Binary Files into Byte Arrays

To read a binary file into a byte array in Java, you can use various ways such as Files.readAllBytes(), FileInputStream, or DataInputStream. Below is an explanation of the most common methods.


Using Files.readAllBytes() (Java NIO)

This is the simplest and most efficient way if you’re using Java 7 or later. The Files.readAllBytes() method reads all the bytes from a file into a byte array.

package org.kodejava.nio;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;

public class BinaryFileToByteArray {
    public static void main(String[] args) {
        Path filePath = Paths.get("path/to/file.bin");
        try {
            byte[] fileBytes = Files.readAllBytes(filePath);
            System.out.println("File read successfully, size: " + fileBytes.length + " bytes");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Using FileInputStream

Another common way is to use FileInputStream in combination with a buffer.

package org.kodejava.nio;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class BinaryFileToByteArray {
    public static void main(String[] args) {
        File file = new File("path/to/file.bin");
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] fileBytes = new byte[(int) file.length()];
            fis.read(fileBytes); // Read file into byte array
            System.out.println("File read successfully, size: " + fileBytes.length + " bytes");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Using DataInputStream

Using DataInputStream with a FileInputStream allows you to work with primitive types and is useful when dealing with binary files.

package org.kodejava.nio;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class BinaryFileToByteArrayExam3 {
    public static void main(String[] args) {
        File file = new File("path/to/file.bin");
        try (DataInputStream dis = new DataInputStream(new FileInputStream(file))) {
            byte[] fileBytes = new byte[(int) file.length()];
            dis.readFully(fileBytes); // Reads the file fully into byte array
            System.out.println("File read successfully, size: " + fileBytes.length + " bytes");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Choosing a Method

  • Files.readAllBytes is the easiest and most concise for modern Java.
  • FileInputStream and DataInputStream provide more flexibility if you need finer control over the file reading process.

Note: Always handle exceptions properly, especially in cases where the file may not exist or the application might not have the necessary permissions.