Tips for Beginners on how to write on Spring in 2017
The goal of this article is to show that creating Web applications in Java, moreover – on the Spring Framework is not pain and painful ripping through web.xml, persistence.XML, beans.xml and picking up the application as a house of cards in pieces, but quite Fast and comfortable process. The audience is beginning developers, developers in other languages, well, those who saw Spring at it’s not the best of times.
Introduction
- In this article, we’ll look at what modern day Spring includes, how to set up a local environment for developing Web applications, and create a simple web application that takes data from the database and renders the HTML page and JSON.
What is Spring?
To start a couple of words, what is Spring. Currently, the term “Spring” often refers to a whole family of projects. For the most part, they are developed and supervised by Pivotal and the community. The key (but not all) Spring family projects are:
Spring Framework (or Spring Core)
- The kernel of the platform provides basic tools for creating applications – managing components (beans), implementing dependencies, MVC framework, transactions, basic access to the database. Basically, these are low-level components and abstractions. In fact, it is implicitly used by all other components.
Spring MVC (part of the Spring Framework)
- It is worth mentioning separately. We will talk mainly about web applications. Operates with concepts of controllers, query mappings, various HTTP abstractions, and so on. With Spring MVC, normal template engines such as Thymeleaf, Freemaker, Mustache are integrated, plus there is third-party integration with a bunch of others. So there’s no need to write horrors like JSP or JSF.
Spring Data
- Access to data: relational and nonrelational databases, KV storage, etc.
Spring Cloud
- A lot of use for the micro service architecture – service discovery, tracing and diagnostics, query balancers, circuit breakers, routers, etc.
Spring Security
- Authorization and authentication, access to data, methods, etc. OAuth, LDAP, and a bunch of different providers.
Spring Integration
- Data processing from different sources. If you want to take an FTP file every hour, split it into strings, which you then filter, and then send to some queue – it’s to Spring Integration.
A typical web application will most likely include a set of Spring MVC, Data, Security. Below we will see how this all works together.
It’s worth noting Spring Boot – it’s a cherry on the cake (and some think it’s the cake itself), which avoids all the horror of the XML configuration. Boot allows you to quickly create and configure (ie, configure dependencies between components) application, package it into an executable self-contained artifact. This is the link that brings together a set of components in the finished application.
A couple of things you need to know about Spring Boot:
- It does not use code generation. From the code that is generated, only the main method is present. If you are looking for a utility for generating applications, it’s more like JHipster
- Does not use XML for configuration. Everything is configured through annotations
- Use auto-configurations to the maximum. If you add a dependency on Mongo and do not specify where to connect – Boot will try localhost: 27017
- The convention over configuration is used. For most configurations, you do not need to configure anything
- It is easy to push aside and “close” the configuration by default. For example, if you specify a host in the settings to connect to Mongo, it will automatically override localhost
Setting up the Environment
In order to create a simple application, know how to create a Maven project from scratch, how to configure plugins to create a JAR, what are the layouts in JAR, how to configure Surefire to run tests, how to install and run locally Tomcat, and even more so, How DispatcherServlet works – absolutely not necessary.
A modern Spring application is created in two steps:
- We go to Spring Initializr.
Spring Initializr allows you to “type” in your application the right components, which then Spring Boot (it is automatically included in all projects created on Initialize) will be put together.
As a development environment, anything is suitable, for example, free IntelliJ IDEA CE works great – just import the created pom.xml (Maven) or build.Gradle (Gradle) file into the IDE.
It’s worth mentioning the Spring Boot component called DevTools. It solves the problem of the local development cycle, which previously looked like:
- Collect WAR locally
- Put it into a Very Strong Enterprise Application Server on a test server, because setting up the OEAC locally requires an incredible skill
- To drink a cup of coffee, i.е. OKEAS restart application at best in a few minutes
- Copy stack error rate
- Go to step 1
In those ancient times, even the saying was born that Spring is a DSL for converting XML configurations into stacks.
With the included Spring Boot DevTools, the development cycle is reduced to:
- Run the application via the green triangle in IDEA
DevTools will automatically check changes in the compiled code or templates, and very quickly reload (hot reload) only the “combat” part of the application (like a demon, if you are familiar with the world of node.js). Moreover, DevTools include integration with Live Reload and after installing the extension in the browser, it is enough to compile the project into IDEA so that it automatically updates in the browser.
Development
Okay, it’s time to get down to the practical part. So, our goal is to create a web application that gives a welcome page, accesses it with its own API, get JSON with the data from the database and print it to the table.
New Project
- First, go to start.spring.io and create a project with Web dependencies, DevTools, JPA (access to relational databases), H2 (simple in-memory database), Mustache (template engine). The generated pom.xml is imported into the IDEA. All, the application is ready to be launched! You can run it from the command line with the ./mvnw spring-boot: run a command or directly from the IDEA by running the main method. Yes, application servers, containers, and deployment are not needed.
More precisely, the container is needed – only it is provided and configured by Spring Boot – using Embedded Tomcat
Controller
So, our next step is to create a controller and return the “home” page. The controller code looks as simple as expected:
@Controller public class IndexController { @GetMapping("/") public ModelAndView index() { Map<String, String> model = new HashMap<>(); model.put("name", "Alexey"); return new ModelAndView("index", model); } }
A couple of things that are worth paying attention to.
- The method returns ModelAndView – Spring knows that you need to take the index.html view from the resources/templates folder (this is the default convention) and pass the model
- The model in our case is just a dictionary, but it can be a strictly-typed model (object) too
With Kotlin this would look even better and easier, but this will require the introduction of a large number of new concepts at once – language, framework. It is better to start small.
- The class marked as @Controller is automatically registered in the MVC router, and using the @ (Get | Post | Put | Patch) Mapping annotations, you can register different paths.
All files from the resources/static/directory are considered static, where you can store CSS and pictures.
Template
We use the Mustache (Handlebar) syntax, so the template is very similar to normal HTML
<!DOCTYPE html> <html lang="en"> <body> <h1>Welcome to Spring, {{ name }}</h1> </body> </html>
After compiling the project (⌘/Ctrl + F9) – you can go directly to http://localhost:8080 and see the created page.
Access to the Database
- First, we describe our subject area. We will collect visitor statistics – every time someone comes to the main page, we will write it to the database. The model looks utterly primitive:
@Entity public class Visit { @Id @GeneratedValue public Long id; public String description; }
Foreseeing the series of comments “As without getters and setters” and “Where is equals / hashCode” – these elements are missed deliberately to simplify the code. Completely monstrous error in the design of Java that makes writing this nonsense (getters and comparison methods) is, of course, a separate conversation. Kotlin, by the way, solves this problem.
- We again use annotations very actively – this time from Spring Data (more precisely, JPA is a dense specification for accessing data). This class describes a model with two fields, one of which is generated automatically. This class will automatically create a data model (table) in the database.
Now for this model, it’s time to create a repository. This is even easier than the controller.
@Repository public interface VisitsRepository extends CrudRepository<Visit, Long> { }
Everything, the repository can be used to work with the database – read and write records. The attentive reader should have a WTF detector – what is going on here? We define the interface and suddenly it starts working with the database? It’s like that.
Thanks to the magic of Spring Boot and Spring Data under the hood, the following happens:
- Seeing in the dependencies H2 (built-in database), Boot automatically configures the DataSource (this is the key component for connecting to the database) so that the application can work with this database
- Spring Data searches for all CrudRepository heirs and automatically generates default implementations for them, which include the basic repository methods, such as find one, find all, save etc.
- Spring automatically configures the layer to access the data – JPA (more precisely, its implementation of Hibernate)
- Thanks to the annotation @Repository, this component becomes available in our application (and we use it in a couple of minutes)
To use the repository in the controller, we will use the dependency injection mechanism provided by the Spring Framework. To do this, strangely enough, you just need to declare the dependency in our controller.
@Controller public class IndexController { final VisitsRepository visitsRepository; public IndexController(VisitsRepository visitsRepository) { this.visitsRepository = visitsRepository; } ... }
Seeing in our constructor a parameter of type VisitRepository, Spring will find the Spring Data repository created and pass it to the constructor.
Now you can write to the database in the controller method.
@GetMapping("/") public ModelAndView index() { Map<String, String> model = new HashMap<>(); model.put("name", "Alexey"); Visit visit = new Visit(); visit.description = String.format("Visited at %s", LocalDateTime.now()); visitsRepository.save(visit); return new ModelAndView("index", model); }
REST Controller
- The next step is to return all records from the database in JSON format so that they can be read on the client later.
For REST in Spring, there is a separate controller type called @RestController, the code of which is not much different from the usual controller.
@RestController @RequestMapping("/api") public class ApiController { final VisitsRepository visitsRepository; public ApiController(VisitsRepository visitsRepository) { this.visitsRepository = visitsRepository; } @GetMapping("/visits") public Iterable<Visit> getVisits() { return visitsRepository.findAll(); } }
Pay attention to:
- This time we define the “prefix” for all controller methods using the basic @RequestMapping
- Dependency implementation works exactly the same as for normal controllers (as well as for everything in Spring)
- The method now returns not the template name, but the model. Spring automatically converts this to an array of JSON objects
- We use the persistence model for serialization in JSON, which in general is not the best practice
Now when requesting http://localhost:8080/api/visits (precompiling the project and giving DevTools an update to the application), we get JSON with the required data.
Client code
- Let’s leave it outside the scope of this article, an example can be seen in the source code. The purpose of this code is to demonstrate exclusively how to get JSON data from the server, integration with client frameworks React, Angular etc are intentionally left outside the scope of this article.
Testing
Spring also provides powerful tools for Integration and Unit testing applications. Example code that the controller checks:
@Test public void indexControllerShouldReturnHtmlPage() throws Exception { mockMvc.perform(get("/")) .andExpect(status().isOk()) .andExpect(content().string(containsString("Welcome to Spring"))); }
- Using abstractions like MockMvc, you can easily test the external interface of the application, while still having access to its insides. For example, you can completely replace the application components with Moki (stubs).
Similarly, for API tests there is a set of helpers for checking JsonPath expressions.
@Test public void apiControllerShouldReturnVisits() throws Exception { mockMvc.perform(get("/")); mockMvc.perform(get("/api/visits")) .andExpect(jsonPath("$.*.description", iterableWithSize(1))); }
Testing in Spring is still a separate topic, so we will not dwell heavily on this now.
Deployment
To assemble and run our application in production there are several options.
- Configure the resulting JAR (or even WAR) into a servlet container, for example, Tomcat. This is not the easiest way, it should only be selected if you already have a working servlet container or application server.
- Use the magic of Spring Boot. The JAR file collected using the Spring Boot plug-in (which is automatically added to projects created through Spring Initializr) is completely self-contained.
Thus, the build and launch of the application look like:
- ./mvnw package
- java -jar ./target/demo-0.0.1-SNAPSHOT.jar
- To deploy this JAR file, you do not need anything other than Java (JRE) installed. This is the so-called fat JAR – it includes both the built-in servlet container (Tomcat by default) and the framework, and all dependency libraries. As a matter of fact, it is the only artifact of the de-attribute, it can simply be copied to the target server and run there.
Moreover, the file can be made “executable” and run it simply from the command line (Java, of course, is still necessary).
Based on this file, you can easily create a Docker image or install it as a daemon.
Conclusion
- It turned out, nevertheless, very concisely – but to lay even the easiest introductory course on Spring in the framework of one article is not very simple. I hope this will help someone to take the first steps in the Spring, and even though understand his fundamental concepts.
- As you notice, the word “Magic Spring” sounded many times in the text of the article. In fact, this is a very “magic” framework – even looking at the very tip of the iceberg, we’ve already seen that Spring does a lot of things in the background. This is both a plus and a minus of the framework.
- Plus, there is no doubt that many complex things (very many) can be made a single annotation or an addiction.
- Minus is a hidden difficulty – to solve some complex problems, to force the framework to work in extreme cases or to understand all the subtleties and aspects you need to know it well.
To make the “know” phase as simple as possible, Spring has excellent documentation, a huge community, and clean sources that can be read. If you place Spring on Rich Hickey’s scale, he (Spring) will undoubtedly fall into easy, but certainly not simple. But for a modern enterprise (and not just an enterprise), it gives incredible opportunities to get a production-ready application very quickly and concentrate on the logic of the application, rather than the infrastructure around.
References
- Source code for GitHub
- The main site Spring with a bunch of different guides spring.io
- Official Spring Framework documentation