Static resource handling

In the most simple case, you simply want to serve the contents of a directory:

public class ResourceHandling {
    public static void main(String[] args) {
        MuServer server = MuServerBuilder.httpServer()
            .addHandler(ResourceHandlerBuilder.fileHandler("/path/on/disk"))
            .start();
        System.out.println("Started server at " + server.uri());
    }
}
(see full file)

Or if you have bundled some static data into an uber jar, you'll want to serve it from the classpath:

ResourceHandlerBuilder.classpathHandler("/web")

Or perhaps you want to serve from a local path during development and from the classpath when running as an uber jar. In this case, the following builder can be used:

ResourceHandlerBuilder.fileOrClasspath("src/main/resources/web", "/web")

This means: "if there is a directory called src/main/resources/web then use that, otherwise load from /web on the classpath".

Paths

If you wish to serve the files from another path, you can add a resource handler to a ContextHandlerBuilder. The following would server all resources from the /web classpath path on the /static/ path:

public class ResourceHandlingWithContext {
    public static void main(String[] args) {
        MuServer server = MuServerBuilder.httpServer()
            .addHandler(context("static")
                .addHandler(ResourceHandlerBuilder.classpathHandler("/web"))
            )
            .start();
        System.out.println("Stylesheet available at "
            + server.uri().resolve("/static/mu.css"));
    }
}
(see full file)

See more info about contexts.

Mime Types and Headers

Mu Server comes with some opinionated response headers. For example, Javascript and CSS files are served with a short-lived cache value, while HTML pages have no cache, and most text files are served with utf-8 encoding.

You can browse the full list of mime types and headers.

To customize response headers on a request-by-request basis, a ResourceCustomizercan be used. For example, if you have a convention that any javascript files that end with the extension .immutable.js should never be downloaded twice, then you can set an aggressive cache control header for these files like so:

public class ResourceHandlingWithCustomization {
    public static void main(String[] args) {
        MuServer server = MuServerBuilder.httpServer()
            .addHandler(
                ResourceHandlerBuilder.fileHandler("/path/on/disk")
                    .withResourceCustomizer(new ResourceCustomizer() {
                        public void beforeHeadersSent(MuRequest request, Headers responseHeaders) {
                            if (request.relativePath().endsWith(".immutable.js")) {
                                responseHeaders.set(HeaderNames.CACHE_CONTROL,
                                    "max-age=31536000, public, immutable");
                            }
                        }
                    })
            )
            .start();
        System.out.println("Started server at " + server.uri());
    }
}
(see full file)

You can also customize headers based on file extensions. For example, perhaps you have .dan files that do not have any mime type or headers configured by default. To set custom headers for .dan files, you would use the following code:

public class ResourceMimeTypes {
    public static void main(String[] args) {
        MuServer server = MuServerBuilder.httpServer()
            .addHandler(resourceHandler())
            .start();
        System.out.println("Started server at " + server.uri());
    }

    public static ResourceHandlerBuilder resourceHandler() {
        Map<String, ResourceType> resourceTypes = ResourceType.getDefaultMapping();
        boolean useGzip = false;
        resourceTypes.put("dan",
            new ResourceType("text/plain",
                Headers.http2Headers()
                    .add("cache-control", "max-age=300")
                    .add("x-custom-header", "danbo"),
                useGzip, asList("dan")
            ));
        return ResourceHandlerBuilder
            .fileOrClasspath("src/main/resources/web", "/web")
            .withExtensionToResourceType(resourceTypes);
    }
}
(see full file)

You can try downloading a .dan file and viewing the response headers here: /dan-file.dan

More details

Range requests are enabled for all resource downloads. This allows for resumable downloads and seeking while streaming audio and video files.

See the ResourceHandlerBuilder JavaDoc for more options.