Java / Gradle

Serving static resources in a Micronaut Framework application

Learn how to expose static resources such as CSS or images in a Micronaut Framework application.

Tim Yates
On this guide
In this section

Getting Started

In this guide, we will create a Micronaut application written in Java.

What you will need

To complete this guide, you will need the following:

Solution

We recommend that you follow the instructions in the next sections and create the application step by step. However, you can go right to the completed example.

Writing the Application

Create an application using the Micronaut Command Line Interface or with Micronaut Launch.

mn create-app example.micronaut.micronautguide \
    --features=validation,views-thymeleaf \
    --build=gradle \
    --lang=java \
    --test=junit
Note
If you don’t specify the --build argument, Gradle with the Kotlin DSL is used as the build tool.
If you don’t specify the --lang argument, Java is used as the language.
If you don’t specify the --test argument, JUnit is used for Java and Kotlin, and Spock is used for Groovy.

The previous command creates a Micronaut application with the default package example.micronaut in a directory named micronautguide.

If you use Micronaut Launch, select Micronaut Application as application type and add validation, and views-thymeleaf features.

Note
If you have an existing Micronaut application and want to add the functionality described here, you can view the dependency and configuration changes from the specified features, and apply those changes to your application.

Views

To use the Thymeleaf Java template engine to render views in a Micronaut application, add the following dependency on your classpath.

build.gradle
implementation("io.micronaut.views:micronaut-views-thymeleaf")

Thymeleaf template

Create a Thymeleaf template in src/main/resources/views/index.html:

src/main/resources/views/index.html

Message service

Create an interface that describes our message service.

java/src/main/java/example/micronaut/MessageService.java
package example.micronaut;

import io.micronaut.core.annotation.NonNull;
import jakarta.validation.constraints.NotBlank;

interface MessageService {

    String sayHello(@NonNull @NotBlank String name);
}

And then create a default implementation of the service.

java/src/main/java/example/micronaut/MyMessageService.java

Controller

Create a controller that takes a name and generates our templated HTML page.

java/src/main/java/example/micronaut/MainController.java

Assets

Then create a static CSS file in src/main/resources/static/css/style.css:

src/main/resources/static/css/style.css
html, body {
    margin: 0;
    padding: 0.5em;
    background: #eee;
    font-family: sans-serif;
    color: #333;
}

section {
    display: flex;
    flex-direction: column;
    text-align: center;
    justify-content: left;
    width: fit-content;
}

section h1 {
    margin: 0;
    padding: 0.5em;
    font-size: 1.5em;
    font-variant: small-caps;
}

And a static PNG file in src/main/resources/static/images/micronaut_stacked_black.png:

micronaut stacked black

Configuration

We can then add a static-mapping to our application.properties so that any missing requests are attempted to be resolved from the static assets.

First configure a route /css/*.css to map any routes matching that pattern to be mapped to the static/css resources.

src/main/resources/application.properties
micronaut.router.static-resources.css.mapping=/css/*.css
micronaut.router.static-resources.css.paths=classpath\:static/css
  • The first line matches any request to the server that does not match a controller route.

  • The second line defines that the classpath inside a root static directory should be searched for the resource.

This means that a request to /css/style.css will be resolved to src/main/resources/static/css/style.css (if that resource exists and there is no matching controller path).

And then configure a route /images/** to be mapped to the static/images resources. We use a wildcard here as images may have different file extensions.

src/main/resources/application.properties
micronaut.router.static-resources.images.mapping=/images/**
micronaut.router.static-resources.images.paths=classpath\:static/images

This means that a request to /images/some/image.png will be resolved to src/main/resources/static/images/some/image.png (if that resource exists and there is no matching controller path).

A note on wildcard mappings

For every request, the framework searches for a controller route; if no route is found, it searches for a static resource. In the above configuration, we could have used a single wildcard mapping for all assets similar to:

A wasteful wildcard example
micronaut.router.static-resources.assets.mapping=/**
micronaut.router.static-resources.assets.paths=classpath\:static

However, searching for a static resource in every request is a waste. We know specific paths (e.g., /bogus) will not match any resource.

Therefore, as we only want to search for static resources for paths starting with /css or /images, we can limit our static resource mappings to these paths.

Testing

Create a test that verifies the MessageService is working as expected.

java/src/test/java/example/micronaut/MessageServiceTest.java

And another that verifies the generated HTML contains the expected text.

java/src/test/java/example/micronaut/MainControllerTest.java

And another that verifies the static resources are returned on the expected URLs.

java/src/test/java/example/micronaut/StaticResourceTest.java

Testing the Application

To run the tests:

./gradlew test

Then open build/reports/tests/test/index.html in a browser to see the results.

Running the Application

To run the application, use the ./gradlew run command, which starts the application on port 8080.

Visit http://localhost:8080/hello/Micronaut and the browser displays our templated HTML page with styling and an image.

Next Steps

Help with the Micronaut Framework

The Micronaut Foundation sponsored the creation of this Guide. A variety of consulting and support services are available.

License

Note
All guides are released with an Apache License 2.0 for the code and a Creative Commons Attribution 4.0 license for the writing and media (images).