Quarkus 1.1 was released and in the announcement surprisingly a new template extension was mentioned: Qute. Qute was made for Quarkus: it works in dev mode and you can compile to native image using Graal. In this post I will share the application I created to test the template engine.
How Qute works with Quarkus?
Qute works like very other Quarkus extension: convention over configuration and simple setup. It has support for custom tags and the template language is very simple.
You can place templates in resource/templates and then inject them in your code. So if you have:
src/main/resources/templates/productTemplate.html
You can inject it using:
@Inject
io.quarkus.qute.Template productTemplate;
Later you can create instances from this template passing variables and return them in JAX-RS methods. Yes, you can use JAX-RS as controller:
@GET
@Produces(MediaType.TEXT_HTML)
public TemplateInstance getProductsHtml() {
return postsTemplate.data("products", products);
}
And it is not only about HTML, take a look at Qute guide for more information.
The microblog example
We want to create a page where you can make quick posts, for this a single entity Micropost which will be handled by MicropostResource and rendered by postsTemplate.html.
Micropost is a Panache entity, which makes very easier to access databases;
MicropostResource is a JAX-RS resource and makes use of Qute templates
postsTemplate.html is a simple HTML file that prints a list of posts
Everything is put together by index.html. See the sources below:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<h1>Microblog</h1> | |
<div> | |
<h3>New post</h3> | |
<form id="newPostForm" method="POST"> | |
<textarea placeholder="Say something..." name="content" class="contentInput" required></textarea> <br /> | |
<label for="author">Author: </label><br /><input type="text" placeholder="Tell me your name" name="author" | |
required /> <br /> | |
<input type="submit" value="Post" /> | |
</form> | |
</div> | |
<h2>Posts</h2> | |
<div class="postsContainer"> | |
</div> | |
<script lang="js"> | |
$(() => { | |
loadPosts(); | |
const newPostForm = $("#newPostForm"); | |
newPostForm.submit(e => { | |
e.preventDefault(); | |
$.ajax({ | |
type: "POST", | |
url: "/micropost", | |
data: newPostForm.serialize() | |
}).done(data => { | |
newPostForm.trigger("reset"); | |
loadPosts(); | |
}); | |
return false; | |
}) | |
}); | |
function loadPosts() { | |
$.ajax({ | |
headers: { | |
Accept: "text/html", | |
}, | |
url: "/micropost" | |
}).done(data => { | |
$(".postsContainer").html(data); | |
}); | |
} | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Date; | |
import javax.persistence.Entity; | |
import io.quarkus.hibernate.orm.panache.PanacheEntity; | |
@Entity | |
public class Micropost extends PanacheEntity { | |
public String author; | |
public String content; | |
public Date date; | |
public static Micropost create(String author, String content) { | |
Micropost post = new Micropost(); | |
post.author = author; | |
post.content = content; | |
post.date = new Date(); | |
return post; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Arrays; | |
import java.util.List; | |
import javax.annotation.PostConstruct; | |
import javax.enterprise.context.ApplicationScoped; | |
import javax.inject.Inject; | |
import javax.transaction.Transactional; | |
import javax.ws.rs.*; | |
import javax.ws.rs.core.MediaType; | |
import org.fxapps.model.Micropost; | |
import io.quarkus.panache.common.Sort; | |
import io.quarkus.qute.Template; | |
import io.quarkus.qute.TemplateInstance; | |
@Path("/micropost") | |
@ApplicationScoped | |
public class MicropostResource { | |
@Inject | |
Template postsTemplate; | |
@PostConstruct | |
@Transactional | |
public void start() { | |
Arrays.asList( | |
Micropost.create("Antonio", "I love playing with my Legos"), | |
Micropost.create("Luana", "I like Painting and I should do it more often"), | |
Micropost.create("William", "I love Java")) | |
.forEach(e -> e.persist()); | |
} | |
@GET | |
@Produces(MediaType.TEXT_HTML) | |
public TemplateInstance getPostsHtml() { | |
final List<Micropost> posts = Micropost.findAll(Sort.descending("date")).list(); | |
return postsTemplate.data("posts", posts); | |
} | |
@POST | |
@Transactional | |
public void create(@FormParam("author") String author, @FormParam("content") String content) { | |
Micropost.create(author, content).persist(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{#for post in posts} | |
<div class="postContainer"> | |
<em><strong>{post.author}</strong> said</em>: | |
<p> | |
<blockquote>{post.content}</blockquote> | |
</p> | |
<small>{post.date}</small> | |
</div> | |
{/for} |
Next steps
The application can evolve to add more quarkus extension and learn more (validation, security, more CRUD operations and so on), but for me it was enough to see Qute in action. For it was a great step towards making microfrontends easier to implement using Quarkus.
The code is on my github.
Comentários
Postar um comentário