Intro
In this time, I will try Micronaut.
I will add a page and uploading files function.
Installation and creating a application
To create a Micronaut application, I should install CLI tool.
After installing, I create a simple application.
mn create-app micronaut-sample
Adding a Thymeleaf page
Because the created project only has a main class and some property files, I will add a controller class and a Thymeleaf page.
build.gradle.kts
plugins {
id("com.github.johnrengelman.shadow") version "8.1.1"
id("io.micronaut.application") version "4.2.1"
id("io.micronaut.aot") version "4.2.1"
}
version = "0.1"
group = "micronaut.sample"
repositories {
mavenCentral()
}
dependencies {
annotationProcessor("io.micronaut:micronaut-http-validation")
annotationProcessor("io.micronaut.serde:micronaut-serde-processor")
implementation("io.micronaut.serde:micronaut-serde-jackson")
// Add this
implementation("io.micronaut.views:micronaut-views-thymeleaf")
compileOnly("io.micronaut:micronaut-http-client")
runtimeOnly("ch.qos.logback:logback-classic")
testImplementation("io.micronaut:micronaut-http-client")
}
application {
mainClass.set("micronaut.sample.Application")
}
java {
sourceCompatibility = JavaVersion.toVersion("17")
targetCompatibility = JavaVersion.toVersion("17")
}
graalvmNative.toolchainDetection.set(false)
micronaut {
runtime("netty")
testRuntime("junit5")
processing {
incremental(true)
annotations("micronaut.sample.*")
}
aot {
optimizeServiceLoading.set(false)
convertYamlToJava.set(false)
precomputeOperations.set(true)
cacheEnvironment.set(true)
optimizeClassLoading.set(true)
deduceEnvironment.set(true)
optimizeNetty.set(true)
}
}
src/main/java/micronaut/sample/pages/PageController.java
package micronaut.sample.pages;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Produces;
import io.micronaut.scheduling.TaskExecutors;
import io.micronaut.scheduling.annotation.ExecuteOn;
import io.micronaut.views.View;
@Controller("/")
public class PageController {
@Produces(MediaType.TEXT_HTML)
@ExecuteOn(TaskExecutors.BLOCKING)
@View("uploadFiles")
@Get("/files")
public HttpResponse<String> getFilePage() {
return HttpResponse.ok();
}
}
src/main/resources/views/uploadFiles.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Uploading File Page</title>
<meta charset="utf-8">
</head>
<body>
<h1>Hello World!</h1>
<div>
<input type="file" id="speadsheet_input">
<button onclick="UploadFilePage.send()">Send</button>
<script src="js/uploadFiles.page.js"></script>
</div>
</body>
</html>
ts/uploadFiles.page.ts
window.UploadFilePage = {
send() {
const fileInput = document.getElementById("speadsheet_input") as HTMLInputElement;
const files = fileInput.files;
if(files == null || files.length <= 0) {
return;
}
if(files[0] == null) {
return;
}
const form = new FormData();
form.append("file", files[0]);
fetch("http://localhost:8080/files/spreadsheets", {
method: "POST",
mode: "cors",
headers: {
"fileName": files[0].name
},
body: form
}).then((res) => res.text())
.then((res) => console.log(res))
.catch(err => console.error(err));
},
}
Adding static files
To load JavaScript(TypeScript) files and CSS files, I will add a path to publish static files.
src/main/resources/application.properties
micronaut.application.name=micronaut-sample
# Add this
micronaut.router.static-resources.*.enabled=true
micronaut.router.static-resources.*.paths=classpath:static
After adding these two lines, I can access the files in "src/main/resources/static".
Receiving and reading files
I can receive "multipart/form-data" as "io.micronaut.http.server.multipart.MultipartBody".
src/main/java/micronaut/sample/files/FileController.java
package micronaut.sample.files;
import java.io.IOException;
import java.util.Optional;
import io.micronaut.http.HttpHeaders;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Body;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.server.multipart.MultipartBody;
@Controller("/files")
public class FileController {
@Post(uri = "/spreadsheets", consumes = MediaType.MULTIPART_FORM_DATA, produces = MediaType.TEXT_PLAIN)
public String uploadSpreadsheet(HttpHeaders headers, @Body MultipartBody file) {
return "Not implemented";
}
}
Reading received files
"MultipartBody" extends "Publisher< CompletedPart>".
I will add Project Reactor to read received files.
build.gradle.kts
...
dependencies {
annotationProcessor("io.micronaut:micronaut-http-validation")
annotationProcessor("io.micronaut.serde:micronaut-serde-processor")
implementation("io.micronaut.serde:micronaut-serde-jackson")
implementation("io.micronaut.views:micronaut-views-thymeleaf")
// add this
implementation("io.projectreactor:reactor-core:3.6.1")
compileOnly("io.micronaut:micronaut-http-client")
runtimeOnly("ch.qos.logback:logback-classic")
testImplementation("io.micronaut:micronaut-http-client")
}
...
FileController.java
package micronaut.sample.files;
import java.io.IOException;
import java.util.Optional;
import io.micronaut.http.HttpHeaders;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Body;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.server.multipart.MultipartBody;
import reactor.core.publisher.Mono;
@Controller("/files")
public class FileController {
@Post(uri = "/spreadsheets", consumes = MediaType.MULTIPART_FORM_DATA, produces = MediaType.TEXT_PLAIN)
public Mono<String> uploadSpreadsheet(HttpHeaders headers, @Body MultipartBody file) {
return Mono.from(file).map(f -> {
try {
byte[] fileData = f.getBytes();
Optional<String> fn = headers.findFirst("fileName");
String fileName = "";
if(fn.isPresent()) {
fileName = fn.get();
}
return "File: " + fileName + " Len: " + fileData.length;
} catch (IOException e) {
e.printStackTrace();
}
return "";
});
}
}
Receiving over 1MB files
By default, the application only can receive less than 1MB files.
To change the limitation, I add "micronaut.server.multipart.max-file-size" into application.properties.
src/main/resources/application.properties
micronaut.application.name=micronaut-sample
micronaut.router.static-resources.*.enabled=true
micronaut.router.static-resources.*.paths=classpath:static
# add this
micronaut.server.multipart.max-file-size=20971520
Top comments (3)
Can you point me to a resource for unit testing for Quarkus? I'll be more than grateful if you do.
Thank you for reading my post.
I haven't tried Quarkus yet. If I come into contact with Quarkus in the future, I will post about it.
Using it myself and loving the speed, lightweight footprint and easy of integrating with GraalVM, AWS Lambda and gRPC.