In one of the classic articles for newbies who recently flashed on Habré, it was told about creating a basic Web application in Java. It all started with a servlet, then creating a JSP page, and finally deploying it to a container. Looking at it with a fresh look, I realized that for just for beginners it probably looks absolutely creepy - against the background of simple and understandable PHP or Node.js, where everything is simple - the controller wrote, returned the object, it became JSON or HTML. In order to dispel this feeling a bit, I decided to write a "Guide for beginners in Spring". The purpose of this article is to show that building Web applications in Java, moreover, on the Spring Framework is not painful and painful wading through the web.xml, persistence.xml, beans.xml, and picking up the application as a house of cards piece by piece, but quite to itself fast and comfortable process. Audience - novice developers, developers in other languages, well, and those who have seen Spring in its not the best times.
In this article, we will look at what modern 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. Strangely enough, most articles (in Russian) for beginners that I found in the search top describe both manual context creation, application launch, and configuration via XML - of course, it is not necessary to do any of this in the modern Spring.
For a start, a couple of words, what is Spring. Nowadays, the term "Spring" often means a whole family of projects. For the most part, they are developed and supervised by Pivotal and community forces. The key (but not all) Spring family projects are:
Spring Framework (or Spring Core)
The core of the platform provides the basic tools for creating applications - managing components (beans, beans ), dependency injection, MVC framework, transactions, basic database access. These are mainly low-level components and abstractions. In essence, it is implicitly used by all other components.
Spring MVC (part of the Spring Framework)
It is worth mentioning separately, because we will be talking mainly about web applications. Operates with the concepts of controllers, request mappings, various HTTP abstractions, etc. Normal template engines such as Thymeleaf, Freemaker, Mustache are integrated with Spring MVC, plus there are third-party integrations with a bunch of others. So no horror like JSP or JSF is needed.
Spring data
Data access: relational and non-relational databases, KV storages, etc.
Spring cloud
Many useful for microservice 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.
A typical web application will most likely include a suite like Spring MVC, Data, Security. Below we will see how this all works together.
A special note is Spring Boot - this is the cherry on the cake (and some people think that the cake itself), which allows you to avoid all the horror of the XML configuration. Boot allows you to quickly create and configure (i.e., configure dependencies between components) an application, package it into a self-sufficient artifact being executed. This is the link that brings together a set of components into a ready-made application. A couple of things you need to know about Spring Boot:
localhost:27017
localhost
To create a simple application, to know how to create a Maven project from scratch, how to configure plugins, to create a JAR, what are some layouts in a JAR, how to configure Surefire to run tests, how to install and run Tomcat locally, and even more, how DispatcherServlet works is completely unnecessary.
A modern Spring application is created in two steps:
Spring Initializr allows you to "type" in your application the necessary components, which then Spring Boot (it is automatically included in all projects created at Initializr) will put together.
Anything can be used as a development environment, for example, the free IntelliJ IDEA CE does a great job - just import the created pom.xml (Maven) or build.gradle (Gradle) file into the IDE.
It is worth mentioning the Spring Boot component called DevTools . It solves the problem of the local development cycle, which previously looked like:
In those ancient times, a saying was born that Spring is a DSL for converting XML configs into spectra.
With Spring Boot DevTools enabled, the development cycle is shortened to:
DevTools will automatically check for changes in the compiled code or templates, and very quickly restart (hot reload) only the "combat" part of the application (like nodemon, if you are familiar with the world of node.js). Moreover, DevTools includes integration with Live Reload and after installing the extension in the browser, it is enough to compile the project in IDEA so that it is automatically updated in the browser.
Okay, it's time to get down to the practical part. So, our goal is to create a web application that gives the welcome page, accesses its own API, receives JSON with data from the database and displays them in a table.
To start, 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
imported into IDEA. That's it, the app is ready to launch! You can run it from the command line with the command ./mvnw spring-boot:run
or directly from 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 the Spring Boot - using Embedded Tomcat
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 worth paying attention to.
ModelAndView
- then Spring knows that you need to take a view of index.html
from the resources/templates
folder (this is the default agreement) and pass the model thereWith Kotlin, this would have looked even better and simpler, but this would require the introduction of a large number of new concepts at once - language, framework. It’s better to start small.
The class marked as @Controller
automatically registered in the MVC router, and using the annotations @(Get|Post|Put|Patch)Mapping
you can register different paths.
All files from the resources/static/
directory are considered static, you can store CSS and images there.
We use Mustache (Handlebar) syntax, so the template is very similar to plain HTML.
<!DOCTYPE html> <html lang="en"> <body> <h1>Welcome to Spring, {{ name }}</h1> </body> </html>
After compiling the project (⌘ / Ctrl + F9) - you can immediately go to http://localhost:8080
and see the created page.
To begin with, we describe our subject area. We will collect visitor statistics - every time someone visits the main page, we will write this into the database. The model looks extremely primitive:
@Entity public class Visit { @Id @GeneratedValue public Long id; public String description; }
Anticipating the sequence of comments "As without getters and setters" and "Where is equals / hashCode", these elements are deliberately omitted in order to simplify the code. A completely monstrous mistake in Java design that makes writing this nonsense (getters and comparison methods) is, of course, a separate conversation. Kotlin this problem, by the way, solves.
We again very actively use annotations - this time from Spring Data (more precisely, JPA is a dense specification for data access). This class describes a model with two fields, one of which is automatically generated. This class will automatically create a data model (table) in the database.
Now it's time to create a repository for this model. It is even easier than the controller.
@Repository public interface VisitsRepository extends CrudRepository<Visit, Long> { }
All, the repository can be used to work with the database - read and write notes. An attentive reader should work WTF detector - what happens here at all? We define the interface and suddenly it starts working with the base? It's like that. Thanks to the magic of Spring Boot and Spring Data "under the hood", the following happens:
DataSource
(this is the key component for connecting to the database) so that the application works with this databaseCrudRepository
and automatically generates default implementations for them, which include the basic methods of the repository, such as findOne
, findAll
, save
etc.@Repository
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 use the dependency injection mechanism provided by the Spring Framework. To do this, oddly enough, you just need to declare a dependency in our controller.
@Controller public class IndexController { final VisitsRepository visitsRepository; public IndexController(VisitsRepository visitsRepository) { this.visitsRepository = visitsRepository; } ... }
Having seen the VisitRepository
type parameter in our constructor, Spring will find the repository created by Spring Data and transfer 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); }
The next step is to return all records from the database in JSON format, so that they can be read later on the client.
For REST, Spring has a separate type of controller called @RestController
, whose code is not much different from a regular 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(); } }
What to look for:
@RequestMapping
Now, when you request http://localhost:8080/api/visits
(after having compiled the project and letting DevTools update the application), we will get JSON with the necessary data.
Leaving outside the scope of this article, an example can be seen in the source code. The purpose of this code is to demonstrate how to get JSON data from the server, integration with client frameworks React, Angular etc is intentionally left outside the scope of this article.
Spring also provides powerful tools for Integration and Unit testing applications. An example of code that checks the controller:
@Test public void indexControllerShouldReturnHtmlPage() throws Exception { mockMvc.perform(get("/")) .andExpect(status().isOk()) .andExpect(content().string(containsString("Welcome to Spring"))); }
Using abstractions such as MockMvc
you can easily test the external interface of an application, while at the same time having access to its internals. For example, you can completely replace the components of the application for moki (stub).
Similarly, for the test APIs, there is a set of helpers for testing 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 on it much now.
There are several options for building and running our application in production.
Thus, building and running the application looks like:
./mvnw package
java -jar ./target/demo-0.0.1-SNAPSHOT.jar
Deploying this JAR file does not require anything other than installed Java (JRE). This is the so-called fat JAR - it includes the built-in servlet container (Tomcat by default) and the framework, and all the dependency libraries. In fact, it is the only deployment artifact - 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 needed).
On the basis of this file, you can easily create a Docker image or install it as a daemon. More details are available in the official documentation .
It turned out, nevertheless, very concisely - but to put even the simplest introductory course on Spring into the framework of one article is not very simple. I hope this helps someone to take the first steps in Spring, and at least understand their fundamental concepts.
As you have noticed, the word "Magic Spring" sounded many times in the text of the article. In essence, this is a very "magical" framework - even having looked at the very tip of the iceberg, we have already seen that Spring does a lot of things in the background. This is both a plus and a minus of the framework. Plus, undoubtedly, many complex things (very many) can be made with one annotation or dependence. The minus is the hidden complexity - to solve some difficult problems, to make the framework work in extreme cases or understand all the subtleties and aspects you need to know it well.
To make the “know” stage as easy as possible, Spring has excellent documentation, a huge community, and clean sources that can be read. If you place Spring on the Rich Hickey scale, it (Spring) will undoubtedly fall into easy, but certainly not simple. But for a modern enterprise (and not just an enterprise), it provides incredible opportunities to get a production-ready application very quickly and focus on the logic of the application, rather than the infrastructure around it.
Source: https://habr.com/ru/post/333756/
All Articles