A CRUD Interface for Your Spring Data Repository Using Across

Across Framework tutorial: part 1

In this first part, we’ll show you how to generate a CRUD administration interface to manage a Spring data repository in less than thirty minutes, using the Across EntityModule. Across is a free, open source Java framework built on top of Spring.

This is the first part of a three part Across tutorial based on our talk at Devoxx Belgium 2017. In the second part, we’ll focus on customizing the CRUD interface; in the third part we’ll take a look at WebCmsModule, which provides basic webcms functionality.

You can find part 2 right here; the last part of the tutorial is right here. Follow us on Facebook or Twitter so you don’t miss them.

Introduction

In this post, we’ll show how easy it is to set up a decent CRUD backend in no time to manage entities of a domain model with the use of EntityModule. In addition, we’ll also add an additional entity to show the ease of expanding the domain of a project.

Building the application

Just like Spring has a project initializer to quickly start developing an application, there’s also one for Across. The Across Initializr provides several options to quick-start your development, as well as some documented example code.

Setup

We’ll start off our development with the following configuration:

Four modules

  • AcrossWebModule

    Activates Spring MVC Configuration

  • AdminWebModule

    Provides a secure section for an administration interface

  • AcrossHibernateJpaModule (including sample entities)

    Provides a shared entity manager

    Provides our blogpost and author entities

  • EntityModule

    Provides us with a CRUD administration interface

A default message source

The Across Initializr will generate a Maven project based on the chosen settings, which we’ll be able to start up immediately. Don’t forget to activate the ‘dev’ profile in your run configuration, as this will enable devtools and speed up the development process. During the following sections, we’ll primarily focus on the added value that EntityModule provides.

When we start the application, we’ll see that all our modules are being bootstrapped, and once the startup has completed, we’ll be able to navigate to our website, which by default can be found on http://localhost:8080. Since we’re going to develop a CRUD application, we’ll be spending our time in the secured section that AdminWebModule provides, which is by default configured to be on /admin. When we log in with the oh-so-secure credentials (username and password: admin), we’ll receive a CRUD administration interface for our sample entities out of the box. The default credentials are provided by the AdminWebUserConfiguration, which sets up a Spring Security configuration for that user. Should you include UserModule, these credentials will correspond to an actual user.

The first thing we notice is that there are two sections available: Entity management and Developer tools. The former contains the various modules and the entities they provide, the latter provides us with information about the registered entities and is available because development mode is activated.

The sample entities provide a default domain model, which is based on JpaRepositories and Persistable entities as we are used to from Spring Framework, including some test data for us to experiment with.

What happened thus far? We have a domain model that was picked up and some test data was created through the use of installers. Installers are simply classes that will be executed during the startup phase of the application. EntityModule (in combination with HibernateJpaModule and AdminWebModule) then provided us with a useable administration interface, giving us the possibility to manage these entities.

We haven’t written any code yet, and we already got a decent backend with some entities, cool! However, how much work would it be to extend the domain model and add another entity?

Adding an entity

Let’s assume that in our application, we’ll be paying the authors for the blogposts they write, so how about we add an Invoice entity?

Let’s create a package invoice under domain.blog where we put our Invoice entity. Why would we put it here? Because for EntityModule to be able to detect our entities, we first need to tell it where to look. This happens in the EntityScanConfiguration class, which will scan for entities inside of the domain.blog package.

The invoice entity will be implemented using the Persistable interface, is linked to an author and a blogpost, has an amount and a status, and can optionally contain a note. We’ve also added a getLabel() method, which will be used by entity module to provide us with a more readable label for invoices. Aside from that, we’ve added some annotations for validation, found in javax.persistance and javax.validation.constraints, and @Data from Lombok which implements various methods (setters, getters, toString ...).

The invoice entity:

@Data
@Entity
public class Invoice implements Persistable<Long> {
   @Id
   @GeneratedValue
   private Long id;

   @ManyToOne
   @NotNull
   private Author author;

   @ManyToOne
   @NotNull
   private BlogPost blogPost;

   @Temporal( TemporalType.DATE )
   private Date receivedDate;

   @NotNull
   @Min( value = 0 )
   private BigDecimal amount;

   @NotNull
   private Status status = Status.RECEIVED;

   enum Status {
       RECEIVED,
       APPROVED,
       PAID
   }

   private String note;

   @Override
   public boolean isNew() {
       return id == null;
   }


   public String getLabel() {
       return "Invoice-" + getId();
   }
}

Besides the entity, we’ll also need a JpaRepository so that we can actually persist changes to the database. We’ll create an InvoiceRepository, which simply extends JpaRepository and JpaSpecificationExecutor.

public interface InvoiceRepository extends JpaSpecificationExecutor<Invoice>, JpaRepository<Invoice, Long> {
}

Normally we’d also manually map the entity to a database table, but since this is just a demo application, we’ll let Hibernate do the heavy lifting. We’ll simply add the following property to our yaml configuration:

acrossHibernate:
  hibernate-properties:
    hibernate.hbm2ddl.auto: update

Once we reload the application, we’ll notice that we have an additional entity in our administration UI. Awesome! All we did was add an entity and a repository, and now we can manage our invoices from the backend.

We can also see that there are several annotations present on the properties of our Invoice. Ranging from persistence to validation annotations, EntityModule will do its best to find them and take them into account when generating the administration interface for the entity. When we try to create a new invoice, we’ll get the following:

img

It’s clear that the validation annotations have been detected and that the form is rendered accordingly, as well as that our entity is validated when we try to persist it.

Our NotNull annotations were picked up: our fields annotated with @NotNull now have an asterisk (*) next to them and have to be filled in.

Status was prefilled with ‘Received’. Here, we also immediately notice that once a @NotNull property was selected, the empty option is no longer available.

The @Min annotation was picked up, we can not enter an amount less than 0.

@Temporal(TemporalType.DATE) tells JPA to only persist the date and not the timestamp, so our interface no longer shows a timestamp either.

We can now fill in the form correctly and create an invoice for ‘The Across Team’ author.

Let’s take a closer look at the relationships between our entities. Our Invoice entity refers to both an Author and a Blogpost. If we go take a look at those entities, we’ll notice there’s an additional tab generated on their update form!

It’s clear that the validation annotations have been detected and that the form is rendered accordingly, as well as that our entity is validated when we try to persist it.

  • Our NotNull annotations were picked up: our fields annotated with @NotNull now have an asterisk (*) next to them and have to be filled in.

  • Status was prefilled with ‘Received’. Here, we also immediately notice that once a @NotNull property was selected, the empty option is no longer available.

  • The @Min annotation was picked up, we can not enter an amount less than 0.

  • @Temporal(TemporalType.DATE) tells JPA to only persist the date and not the timestamp, so our interface no longer shows a timestamp either.

We can now fill in the form correctly and create an invoice for ‘The Across Team’ author.

Let’s take a closer look at the relationships between our entities. Our Invoice entity refers to both an Author and a Blogpost. If we go take a look at those entities, we’ll notice there’s an additional tab generated on their update form!

EntityModule will try to work out the relations defined by the entities and will list the ones related to the entity we’re currently viewing.

Conclusion

What have we done thus far? We generated a simple application using Across Initializr. This included several modules, which generated a decent administration interface based on a simple domain model. Then, we proceeded to add an additional entity named Invoice, along with a repository for persistence, as well as annotations to provide some validation.

In this part we’ve focused on the added value that EntityModule brings to an application - starting from a domain model - as well as how it integrates with existing Spring features like JpaRepository and Persistable. In the next part, we’ll be focusing on how we can further customize this interface.

Dit blog is geschreven door de specialisten van Foreach.

Inmiddels is Foreach onderdeel van iO. Meer weten? Neem gerust contact op!

logo iO