In this article, I will describe the 9 steps to build a backend project with Spring Boot following the best practices. I will show what are the main components and the best practices to follow.

Project Creation

First, I have Spring Initializr to build my project.

This site allows me to build a Spring Boot project with the adequate package structure and Maven (or Gradle) configuration.

I can add in the website all the dependencies I need. I can also configure the Spring Boot version or Java version.

For more details, check this detailed article.

Controllers and Services

The controllers and services are the one which contain all the logic of the application.

The controllers are the one which receive the Web requests. They parse the JSON content into objects. They read the request parameters. And also transform the output objects into JSON content.

The services have the business logic of the application.

Both the services and controllers are instantiated by the Spring context and used in the dependency injection.

Separating the logic between controllers and services allow the implementation of a layered architecture. Also known as the 3-tiers architecture.

You can find more details about the implementation of a 3-tiers architecture in this article.

Security

Once the application is created and contains all the business logic, it’s time to secure it.

First, I must configure the public routes and the protected routes in the Spring Security configuration.

Then, I must choose an authentication system. It can be with JWT, Cookie or OAuth2.

Those 3 types of authentication require a different configuration. JWT and Cookies authentication system require an HTTP filter to read and validate each request manually.

Those two methods store the password in the personal database. If I don’t want to manage the user’s credentials, I can use OAuth2. This way, all the user’s credentials are delegated to a third-party system like Github or Google.

Then comes the difference between a stateful application and a stateless application. With a stateless application, the backend stores nothing about the user’s history, about the user’s session. And when using a stateful application, the user’s session is stored in the backend.

But to store the user’s session securely, I need to use a key-value storage system like Redis.

With Spring Security, I can also protect my routes depending on the user’s roles. This is called Authorization.

Finally, to increase even more the security of my application, I can activate the CSRF protection with Spring Security.

Database Connection

Most of the backend applications need a database connection. This can be done configuring the database connection and entity definition with JPA.

The entity definition is the reflect of the database structure. JPA will validate at the start up that the entities and the database tables match perfectly.

To create the schema of the database programmatically, I can do it with Liquibase or Flyway. Those libraries run a set of SQL files before running the application. This way I ensure the database has the latest schema version before running the application.

Useful Libraries

There are a lot of libraries to include in a Spring Boot project. But when starting a new project, I always include those two libraries. Lombok and Mapstruct.

I add Lombok to generate all the constructors, getters, setters and some other utility methods. Instead of writing hundreds of lines for each entity with the constructors, getters and setters, Lombok has few annotations that generate all of this when building the project.

A best practice in the applications is to separate the entities of the database with the objects returned by the controllers. This is the separation of concern pattern. But to have this logic I need methods to map each field from one object to the other. Mapstruct is here to help me.

I just need to define an interface with some method names and Mapstruct will figure out the mapping of the fields with the same name. If I want some customization, I can add annotations with these details.

Exception Handling

Exceptions will occur in all applications. But the way they are handled is the key.

By default, if an exception occurs, a stacktrace is returned to the HTTP client with a 500 error code. Nevertheless, this is not the behavior I want. The stacktrace shows critical information about the application. It shows the structure of the application.

And when the application is protected by Spring Security, by default the exceptions redirect the user to the login page.

Configuring an Aspect and an exception handler, I can easily catch all the errors of the application to return a custom message and custom HTTP code.

Handling Files

When developing a backend, most of the times I need to handle files upload or download. This can be done with the MultipartFile object of Spring Boot.

But when storing the files in a Spring Boot application, I can’t choose the application’s server as the storage system. I need to choose a more persistent system as a NFS of Blob Storage.

Tests

The tests are not part of the production application but are one of the most important block of an application.

The tests are here to ensure the application is stable. They help me to ensure each new feature doesn’t break the application.

There are different layers of tests. The most basic are the unit tests (with JUnit and Mockit) and the integration tests (with MockMvc, DBUnit and H2).

Logs

Finally, after an application is released, all the feedback I have are the logs produced by the application itself. This is why I must pay a particular attention about writing good logs.

I must pay special attention on where to store the logs, the size of the log files, if they are streamed or not, if they block the application or not.

A solution is to use Slf4J as the interface to write logs in the application. Then choose Logback or Log4J2 as the logger implementation.

Conclusion

Creating a Spring Boot application is a long journey. But the previous 9 steps are the most used to ensure a stable and good quality backend.