Spring MVC First Application
As it happens, that I never seriously worked with Spring. I finally have a reason to start studying this. So first we’ll learn the basics, and then write a simple Web application. Fortunately, Spring is well documented.
Spring
Currently, the term “Spring” refers to a whole set of projects. These include:
- Spring Framework
- Spring MVC (part of Spring Framework)
- Spring Data
- Spring Cloud
- Spring Security
- Spring Integration
- Spring Boot
Spring MVC, Data, Security is set for a sample web application.
Spring Boot
Spring Boot is the cherry on the top, that is. This allows you to easy create and configure stand-alone applications.
Some features:
- no requirement for XML configuration
- automatically configure Spring whenever possible
- no code generation
- embeded Tomcat, Jetty or Undertow directly
This is the link that brings together a set of components in the finished application.
Application
To create a simple project, just open Spring Initializr and add dependencies to project. For this project I added: Web, DevTools, JPA, H2, Mustache and Lombok.
Main
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@SpringBootApplication
The @SpringBootApplication
annotation is equivalent to using @Configuration
, @EnableAutoConfiguration
and @ComponentScan
with their default attributes.
@Configuration
Indicates that a class declares one or more @Bean
methods and may be processed by the Spring.
@EnableAutoConfiguration
Enable auto-configuration of the Spring Application Context, attempting to guess and configure beans that you are likely to need. Auto-configuration classes are usually applied based on your classpath and what beans you have defined. Auto-configuration tries to be as intelligent as possible and will back-away as you define more of your own configuration. You can always manually exclude()
any configuration that you never want to apply (use excludeName()
if you don’t have access to them). You can also exclude them via the spring.autoconfigure.exclude
property. Auto-configuration is always applied after user-defined beans have been registered.
@ComponentScan
Configures component scanning directives for use with @Configuration
classes. Either basePackageClasses()
or basePackages()
(or its alias value()
) may be specified to define specific packages to scan. If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.
Controller
@Controller
public class IndexController {
@GetMapping("/")
public ModelAndView index() {
val model = new HashMap<String, String>();
model.put("name", "VsSekorin");
return new ModelAndView("index", model);
}
}
@Controller
Indicates that an annotated class is a “Controller”. It is typically used in combination with annotated handler methods based on the RequestMapping
annotation.
@GetMapping
Annotation for mapping HTTP GET requests onto specific handler methods. It acts as a shortcut for @RequestMapping(method = RequestMethod.GET)
.
ModelAndView
Represents a model and view returned by a handler, to be resolved by a DispatcherServlet
. The model is a Map
, allowing the use of multiple objects keyed by name.
View
Create a simple template using Mustache:
<!DOCTYPE html>
<html lang="en">
<body>
<h1>Hello, {{ name }}</h1>
</body>
</html>
Model
It is necessary to describe the domain. We will save the date and time of visiting the index page.
@Entity
public class Visit {
@Id @GeneratedValue
@Getter @Setter
private Long id;
@Getter @Setter
private LocalDateTime time;
public Visit() {
this.time = LocalDateTime.now();
}
}
This class describes a model with two fields, the first field (id
) will be generated automatically. Table for this class will be created in database. Now we need to create a repository to access our data.
Repository
@Repository
interface VisitRepository extends CrudRepository<Visit, Long> {
}
Yes, just interface, without implementation — that’s enough.
@Repository
Indicates that an annotated class is a “Repository”, originally defined by Domain-Driven Design (Evans, 2003) as “a mechanism for encapsulating storage, retrieval, and search behavior which emulates a collection of objects”. As of Spring 2.5, this annotation also serves as a specialization of @Component
, allowing for implementation classes to be autodetected through classpath scanning.
Controller with VisitRepository
@Controller
public class IndexController {
private final VisitRepository visitRepository;
@Autowired
public IndexController(VisitRepository visitRepository) {
this.visitRepository = visitRepository;
}
@GetMapping("/")
public ModelAndView index() {
val model = new HashMap<String, String>();
model.put("name", "VsSekorin");
this.visitRepository.save(new Visit());
return new ModelAndView("index", model);
}
}
@Autowired
Marks a constructor, field, setter method or config method as to be autowired by Spring’s dependency injection facilities.
Only one constructor (at max) of any given bean class may carry this annotation, indicating the constructor to autowire when used as a Spring bean. Such a constructor does not have to be public.
Note that actual injection is performed through a BeanPostProcessor
which in turn means that you cannot use @Autowired
to inject references into BeanPostProcessor
or BeanFactoryPostProcessor
types.
BeanPostProcessor
Factory hook that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.
REST Controller
@RestController
@RequestMapping("/api")
public class ApiController {
private final VisitRepository visitRepository;
@Autowired
public ApiController(VisitRepository visitRepository) {
this.visitRepository = visitRepository;
}
@GetMapping("/visits")
public Iterable<Visit> getVisits() {
return this.visitRepository.findAll();
}
}
@RestController
A convenience annotation that is itself annotated with @Controller
and @ResponseBody
. Types that carry this annotation are treated as controllers where @RequestMapping
methods assume @ResponseBody
semantics by default.
@RequestMapping
Annotation for mapping web requests onto methods in request-handling classes with flexible method signatures. This annotation can be used both at the class and at the method level.
Testing
ExampleApplicationTests
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class ExampleApplicationTests {
@Autowired
private MockMvc mockMvc;
@Test
public void index() throws Exception {
mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("Hello")));
}
}
@RunWith
When a class is annotated with @RunWith
or extends a class annotated with @RunWith
, JUnit will invoke the class it references to run the tests in that class instead of the runner built into JUnit.
SpringRunner
is an alias for the SpringJUnit4ClassRunner
. To use this class, simply annotate a JUnit 4 based test class with @RunWith(SpringRunner.class)
.
@SpringBootTest
Annotation that can be specified on a test class that runs Spring Boot based tests.
@AutoConfigureMockMvc
Annotation that can be applied to a test class to enable and configure auto-configuration of MockMvc
.
Deployment
./mvnw package
java -jar ./target/example-0.0.1-SNAPSHOT.jar