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 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
comments powered by Disqus