Spring Boot based site and api for EuregJUG

Building your own JUG?
January 14, 2016 by Michael

Since March 2015 Stefan and i are building the EuregJUG Maas-Rhine, a cross-border, english-language Java User Group, located in Aachen. I’ve been blogging about regularly since then (see all posts here) and it’s developing quite well so far. We had 4 well visited talks, nice meetings in between and good conversations.

We noticed some problems, though, especially for managing events. Most Germans use Xing, Dutch and Belgians often use LinkedIn and there’s also Lanyard in the mix. Then there’s java.de running a calendar aggregate which needs an ics somewhere which would also be nice for other people. Our events are free, but for planning resources some kind of registration is a must.

In late 2015 i had the idea of building “our own JUG”. The first feedback was disappointing, though, so i postponed those ideas into my “end of the year” holiday:

  • Basic blogging (for annoucment like this), supporting Markdown or AsciiDoc as input
  • Handling of events (publishing as iCal, crossposting them to XING and Lanyard and certainly registration for those events)
  • Integration of our twitter feed
  • Maybe a mobile app based on JavaFX and Gluon?

Why doing this myself? I’m quite sure i can setup yet another WordPress project, stuff some plugins into it and be good to run, but the time needed would be the same or longer than doing this with the tools I “love”, namely Java inside the Spring eco system. So here we go:

After about 16 to 20 hours after christmas i had the basic site up and running with basic blogging and managing events (calendar, registration). At the moment i use a simple REST api with the awesome Paw as a generic REST client.

That sounds not to much, but the site is fully responsive, has nice database migrations, showcases Springs content negotiating and different views and last but not least, can run locally and without much ado inside “the cloud”, in this case as Stéphane told use in “Building cloud native apps with Spring Boot”.

We’ve made it into Joshs “This Week in Spring column for January 12th, 2016. Thanks a lot!

The site is live at euregjug.eu, the source code is fully available under an Open Source license at github and i’m gonna walk you through some of the interesting and useful parts:

Hibernate

I’m still using Hibernate for many, many database related things. Vlad just recently told me how small the Hibernate core team is. I was deeply impressed.

Hibernate has its problems, especially when used wrong (for example, everywhere where pure SQL or slim wrapper like jOOQ would be a better solution), but when it comes to a design that basically is model-driven, it’s still shines.

The current domain model looks like this:

Domain model

I can generate the entities if i want but writing them down isn’t hard either and it just works.

Put Spring Data JPA into the mix and you get many relevant access methods for free. Have a look at the PostEntity and the corresponding repository interfaces and implementations (PostRepository, PostRepositoryExt and PostRepositoryImpl) to see some more “unusual” stuff done with Hibernate / Spring Data JPA.

I’d appreciate some more love for Hibernate, especially in the light of JHipster which got quite some traction and uses Hibernate as it’s persistence provider.

Flyway

In case you haven’t heard of Flyway, let me introduce you to a super nice way to manage your database migrations in a greenfield project (should also work with existing schemes).

With Flyway i can use SQL scripts to create my schema without ever touching a SQL client, it supports a variety of database servers.

Why writing SQL scripts anyway when there are JPA entities at hand? Hibernate does a good job mapping my tables to objects but i prefer defining my schemas by hand. I have full control over column names, keys, foreign keys, indices, datatypes etc.

Flyway can be run used from the command-line, Maven, Gradle and Ant but also from a Java Api. This is what Spring Boot automatically supports and this is what i use; you’ll finde all migrations in the main/resources.

You’ll notice that there are 3 subdirectories: common, h2 and postgresql. I’ll want the application to be database agnostic (which is easy using Hibernate with the correct dialect), but the development and test database supports slightly different features than the production target.

I use this little trick inside my application properties:

flyway.locations = classpath:db/migrations/common,\
classpath:db/migrations/${spring.datasource.platform:postgresql}

Flyway supports multiple schema locations and Spring Boot supports properties referencing other properties. So i always add the common migrations and then the database specific migrations, depending on the spring.datasource.platform property (or using postgresql if there is none).

The migrations are just numbered and named .sql files, but you can use a programmatic approach as well. Flyway generates a schema table, which can also be mapped to entities if you like. That’s pretty much all there is and my database has always the correct version.

Content negotiation, Thymeleaf and other views

Pretty much everything today is based on an API and often Single Page Applications. I won’t go into details for the API i created for managing the content (all controllers named *ApiController).

Instead, focus on the IndexController. From an architectural point of view, this is not a nice class, because i stuffed everything “Web” into it.

Have a look at the #index method (Notice the nice mapping of the Pageable, Spring Data JPA returns in line 96):

@RequestMapping({"", "/", "/feed"})
public String index(
    final @RequestParam(required = false, defaultValue = "0") Integer page,
    final Model model
) {
model
	.addAttribute("upcomingEvents", this.eventRepository.findUpcomingEvents())
	.addAttribute("links", this.linkRepository.findAllByOrderByTypeAscSortColAscTitleAsc().stream().collect(groupingBy(LinkEntity::getType)))
	.addAttribute("posts", this.postRepository.findAll(new PageRequest(page, 5, Direction.DESC, "publishedOn", "createdAt")).map(postRenderingService::render))	
	;
return "index";
}

This method returns a view name, “index” and provides the model with everything needed on the page. The first view template with the name “index” is this Thymeleaf template. Thymeleaf is a modern way of writing server side templates with Java. Modeled closely to HTML5, passing parameters, attributes and all kinds of stuff to the generated HTML is really easy and smooth. The linked index template has pretty much all of it: Conditionals, loops, includes.

There’s a second view named index, the IndexRssView based on Springs AbstractRssFeedView which uses rometools to generate RSS and Atom feeds. This view is chosen when a user specifically requests the content type application/rss+xml or specifies the rss extension. So i have nothing to change inside the controller which is view agnostic.

It’s pretty easy to create your own views. I wanted to have an iCal calendar on the site and i wrote the EventsIcalView in no time. The view is filled through the events method. Important thing for views with a content type unknown to Spring: Register their path extension and content type, see the WebConfig which extends WebMvcConfigurerAdapter:

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.mediaType("ics", MediaType.valueOf("text/calendar"));
}

Going “cloud native”

I really liked Stéphane and my goal was running this app in the “cloud”, namely Pivotal Cloud Foundry.

Problems arise: Which database to use in development and production? Where to store files? What about caching?

I roughly followed this post about Binding to Data Services with Spring Boot in Cloud Foundry by Dave and i just can say: It works.

For the database: I have H2 on the path during development and a application-default.properties with some explicit configuration

spring.datasource.platform = h2
spring.datasource.driver-class-name = org.h2.Driver
spring.datasource.url = jdbc:h2:file:${user.dir}/var/default/db/euregjug;FILE_LOCK=FS;MODE=PostgreSQL

but no explicit datasource. The only reason for my configuration of the datasource url is the fact that i don’t want to refill the database with content everytime i restart the development process.

Inside my Pivotal account i’ve bound a PostgreSQL service to the app and everytime i push the app, the H2 database is replaced by the PostgreSQL. Awesome.

Another cool thing is the cache abstraction, enabled inside the application with @EnableCaching and used for the heavy rendering of AsciiDoc blog posts inside the PostRenderingService:

@Cacheable(cacheNames = "renderedPosts", key = "#post.id")
public Post render(final PostEntity post) {
    String renderedContent = null;
    if(post.getFormat() != Format.asciidoc) {
        renderedContent = "<strong>Could not render content.</strong>";
    } else {
        renderedContent = renderer.render(post.getContent());
    }
 
    return new Post(post.getPublishedOn(), post.getSlug(), post.getTitle(), renderedContent);
}

When i run this locally, Spring Boot creates an in-memory cache inside my JVM, when running in the cloud the Redis cache bound the app is used without any further configuration. Sweet.

At the moment i’m stuffing static resources into a MongoDB / GridFS instance but i probably should write an abstraction around that, too.

Outlook

I hope you like the short overview of the new EuregJUG site. It was really fun to implement. As you may have noticed there is no Xing or any other integration yet. Also, no client for publishing content. So there’s still stuff to do.

Instead of writing blog post we can meet and do stuff together. What is in there for me and you?

  • I’m hoping to meet more interesting peoples with different views than i have. If we decide building something based on the Spring stack, i can offer solid to deep Spring and Spring Boot knowledge and tutoring that stuff
  • Learning different approaches than those we see in our daily job
  • Having fun

I’m trying not to jump onto the latest hype, but I’m open for other technologies as well, even if i do a lot with Spring (Why? See the timeframe i had for the basic application and how sweet it runs… And also because the community of the ecosystem really rocks, have a look at this thread for example).

Immediate plans are:

  • creating a client. Not a webpage but a fat client based on JavaFX, which should be deployable to iOS and Android as well.
  • Using my half-done Spring Boot Wro4j starter to optimize CSS / JavaScript resources

No comments yet

One Trackback/Pingback
  1. […] great success Flyway by Boxfuse in several projects and not only in jOOQ projects (see for example this post about the Euregio JUGs backend which is Hibernate […]

Post a Comment

Your email is never published nor shared. Required fields are marked *