Here I will show you how to create HTTP server in Java to serve static resources using sun’s HttpServer. An HTTP Server is bound to an IP address and port number and listens for incoming requests and returns responses to clients. Simple http server is flexible to be added into complex projects for rendering HTML elements or serving as a backend server.

An HTTP server in Java can be created in four steps:

1. Create HttpServer object
2. Attach one or more HttpHandler objects to HttpServer object
3. Create class to implement HttpHandler to process GET/POST requests
4. Start HttpServer

You can find more details about sun’s HttpServer on Oracle docs.

Here I will use a sample HTML project to serve from my created http server. The sample website is already included into downloaded zip file.

Usage Details of the HTTP myserver:

1. Extract the zip folder into your desired location
2. Navigate to the bin directory using cmd or console window
3. Execute the start.bat file
4. Now point to the URL http://localhost:8000 in browser

You can stop server by pressing Ctrl+c key from your keyboard. You can find below image for starting and stopping log output.

create http server in Java to serve static resources

If you want to change the default port (for example, 9000) then you can modify the start.bat file to pass port number as a second parameter. For example,

 java -jar %ServerHome%/lib/myserver.jar %ServerHome% 9000

The lib directory contains the jar file that contains required Java class files to serve your static resources.

The webapp directory contains HTML project including HTML, css, images etc.

Now you will see pages are appearing in the browser. Now you can navigate to different menu on browser given serving from the sample HTML project.

You can also download the sample HTML project from here.

You can download the source entire source code of the project from below link.

myserver-source

Here you need to focus on the class ServerResourceHandler that handles actually static resources from your given root directory of the website.

The source of the ServerResourceHandler is given below, you can find rest of the source code in the downloaded zip file.

In the below class we have implemented the HttpHandler as we are using Sun’s HttpServer and we have also overridden the handle() method to serve our static resources.

Sun’s HttpServer provides HttpExchange with very useful information for serving our content from directories.

We pass three parameters to our constructor – root directory of the web application, whether content should be compressed before sending to the client or browser, whether content should be cacheable for subsequent request for faster processing.

public class ServerResourceHandler implements HttpHandler {

	private static final Logger LOGGER = Logger.getLogger(ServerResourceHandler.class.getName());

	private final String pathToRoot;
	private final boolean gzippable;
	private final boolean cacheable;
	private final Map<String, Resource> resources = new HashMap<>();

	public ServerResourceHandler(String pathToRoot, boolean gzippable, boolean cacheable) throws IOException {
		this.pathToRoot = pathToRoot.endsWith(ServerConstant.FORWARD_SINGLE_SLASH) ? pathToRoot
				: pathToRoot + ServerConstant.FORWARD_SINGLE_SLASH;
		this.gzippable = gzippable;
		this.cacheable = cacheable;

		File[] files = new File(pathToRoot).listFiles();
		if (files == null) {
			throw new IllegalStateException("Couldn't find webroot: " + pathToRoot);
		}
		for (File f : files) {
			processFile("", f, gzippable);
		}
	}

	@Override
	public void handle(HttpExchange httpExchange) throws IOException {
		String requestPath = httpExchange.getRequestURI().getPath();

		LOGGER.info("Requested Path: " + requestPath);

		serveResource(httpExchange, requestPath);
	}

	private class Resource {
		public final byte[] content;

		public Resource(byte[] content) {
			this.content = content;
		}
	}

	private void processFile(String path, File file, boolean gzippable) throws IOException {
		if (!file.isDirectory()) {
			resources.put(path + file.getName(), new Resource(readResource(new FileInputStream(file), gzippable)));
		}

		if (file.isDirectory()) {
			for (File sub : file.listFiles()) {
				processFile(path + file.getName() + ServerConstant.FORWARD_SINGLE_SLASH, sub, gzippable);
			}
		}
	}

	private byte[] readResource(final InputStream in, final boolean gzip) throws IOException {
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		OutputStream gout = gzip ? new GZIPOutputStream(bout) : new DataOutputStream(bout);
		byte[] bs = new byte[4096];
		int r;
		while ((r = in.read(bs)) >= 0) {
			gout.write(bs, 0, r);
		}
		gout.flush();
		gout.close();
		in.close();
		return bout.toByteArray();
	}

	private void serveResource(HttpExchange httpExchange, String requestPath) throws IOException {
		requestPath = requestPath.substring(1);
		requestPath = requestPath.replaceAll(ServerConstant.FORWARD_DOUBLE_SLASH, ServerConstant.FORWARD_SINGLE_SLASH);
		if (requestPath.length() == 0) {
			requestPath = "index.html";
		}
		serveFile(httpExchange, pathToRoot + requestPath);
	}

	private void serveFile(HttpExchange httpExchange, String resourcePath) throws IOException {
		File file = new File(resourcePath);
		if (file.exists()) {
			InputStream in = new FileInputStream(resourcePath);

			Resource res = null;

			if (cacheable) {
				if (resources.get(resourcePath) == null) {
					res = new Resource(readResource(in, gzippable));
				} else {
					res = resources.get(resourcePath);
				}
			} else {
				res = new Resource(readResource(in, gzippable));
			}

			if (gzippable) {
				httpExchange.getResponseHeaders().set(ServerConstant.CONTENT_ENCODING, ServerConstant.ENCODING_GZIP);
			}

			String mimeType = ServerUtil.getFileMime(resourcePath);
			writeOutput(httpExchange, res.content.length, res.content, mimeType);
		} else {
			showError(httpExchange, 404, "The requested resource was not found on server");
		}
	}

	private void writeOutput(HttpExchange httpExchange, int contentLength, byte[] content, String contentType)
			throws IOException {
		if (HttpMethod.HEAD.getName().equals(httpExchange.getRequestMethod())) {
			Set<Map.Entry<String, List<String>>> entries = httpExchange.getRequestHeaders().entrySet();
			String response = "";
			for (Map.Entry<String, List<String>> entry : entries) {
				response += entry.toString() + "n";
			}
			httpExchange.getResponseHeaders().set(ServerConstant.CONTENT_TYPE, ServerConstant.TEXT_PLAIN);
			httpExchange.sendResponseHeaders(200, response.length());
			httpExchange.getResponseBody().write(response.getBytes());
			httpExchange.getResponseBody().close();
		} else {
			httpExchange.getResponseHeaders().set(ServerConstant.CONTENT_TYPE, contentType);
			httpExchange.sendResponseHeaders(200, contentLength);
			httpExchange.getResponseBody().write(content);
			httpExchange.getResponseBody().close();
		}
	}

	private void showError(HttpExchange httpExchange, int respCode, String errDesc) throws IOException {
		String message = "HTTP error " + respCode + ": " + errDesc;
		byte[] messageBytes = message.getBytes(ServerConstant.ENCODING_UTF8);

		httpExchange.getResponseHeaders().set(ServerConstant.CONTENT_TYPE, ServerConstant.TEXT_PLAIN);
		httpExchange.sendResponseHeaders(respCode, messageBytes.length);

		OutputStream os = httpExchange.getResponseBody();
		os.write(messageBytes);
		os.close();
	}

}

The home page on browser you will find similar to the below image:

create HTTP server in Java to serve static resources

That’s all. Hope you got idea how to create http server in Java to serve static resources.

There are many areas where you can improve:

  1. This supports only single web application, so you can create multiple contexts to serve from multiple web applications
  2. This does not support Query Parameters, so you can improve code to support Query Parameters
  3. This does not handle most of the http status codes, you can improve
  4. This does not support all four Content-Encoding, you can improve on this

Thanks for reading.

Tags:

I am a professional Web developer, Enterprise Application developer, Software Engineer and Blogger. Connect me on Roy Tutorials | TwitterFacebook Google PlusLinkedin | Reddit

Leave a Reply

Your email address will not be published. Required fields are marked *