Spring Boot basic annotations

In this tutorial, we cover basic Spring Boot annotations, including @Bean, @Service, @Configuration, @Controller, @RequestMapping, @Repository, @Autowired, and @SpringBootApplication.

Spring is a popular Java application framework for creating enterprise applications. Spring Boot is the next step in evolution of Spring framework. It helps create stand-alone, production-grade Spring based applications with minimal effort. It does not use XML configurations anymore and implements the convention over configuration principle.

Annotation is a form of metadata which provides data about a program that is not part of the program itself. Annotations do not have direct effect on the operation of the code they annotate.

In the example application, we have these Spring Boot annotations:

@Component is a generic stereotype for a Spring managed component. It turns the class into a Spring bean at the auto-scan time. Classes decorated with this annotation are considered as candidates for auto-detection when using annotation-based configuration and classpath scanning. @Repository, @Service, and @Controller are specializations of @Component for more specific use cases.

There are also Hibernate @Entity, @Table, @Id, and @GeneratedValue annotations in the example.

Application

The following application is a Spring Boot application which returns data from an H2 database using Spring Data JPA. The application uses FreeMarker as a template engine.

$ tree
.
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── Application.java
    │   │           ├── bean
    │   │           │   └── City.java
    │   │           ├── conf
    │   │           │   └── MvcConfig.java
    │   │           ├── controller
    │   │           │   └── MyController.java
    │   │           ├── repository
    │   │           │   └── CityRepository.java
    │   │           └── service
    │   │               ├── CityService.java
    │   │               └── ICityService.java
    │   └── resources
    │       ├── application.yml
    │       ├── import.sql
    │       ├── mytemplates
    │       │   ├── index.ftl
    │       │   └── showCities.ftl
    │       └── static
    │           └── css
    │               └── style.css
    └── test
        └── java

This is the project structure.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zetcode</groupId>
    <artifactId>SpringBootRestDataJPA</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
    </parent>
    
    <dependencies>
        
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>    
</project>

This is the Maven build file.

application.yml
server:
    context-path: /cities

spring: 
    main:
        banner-mode: "off"       
    datasource:
        platform: h2

logging: 
    level: 
        org: 
            springframework: ERROR

In the application.yml file we write various configuration settings of a Spring Boot application.

City.java
package com.zetcode.bean;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "CITIES")
public class City {
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;
    private int population;

    public City() {
    }

    public City(Long id, String name, int population) {
        this.id = id;
        this.name = name;
        this.population = population;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }

    @Override
    public String toString() {
        return "City{" + "id=" + id + ", name=" + name
                + ", population=" + population + '}';
    }
}

This is the City entity. Each entity must have at least two annotations defined: @Entity and @Id. The @Entity annotation specifies that the class is an entity and is mapped to a database table. The @Table entity specifies the name of the database table to be used for mapping. The @Id annotation specifies the primary key of an entity and the @GeneratedValue provides for the specification of generation strategies for the values of primary keys.

MvcConfig.java
package com.zetcode.conf;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;

@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {

    @Bean
    public FreeMarkerConfigurer freemarkerConfig() {

        FreeMarkerConfigurer conf = new FreeMarkerConfigurer();
        conf.setTemplateLoaderPath("classpath:/mytemplates/");
        conf.setDefaultEncoding("UTF-8");

        return conf;
    }

    @Bean
    public FreeMarkerViewResolver freemarkerViewResolver() {
        
        FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
        
        resolver.setCache(false);
        resolver.setSuffix(".ftl");
        
        return resolver;
    }
}

The MvcConfig allows Java-based configuration for Spring MVC. The @Configuration annotation marks the class as a configuration class; Spring creates beans from the provided bean definitions. @Bean is used to explicitly declare a single bean in a configuration class. (@Component based beans are autodetected.) In our case, @Bean annotation creates two FreeMarker configuration beans. (Freemaker is being autoconfigured by Spring Boot but we can provide our own configuration via Java configuration beans.)

import.sql
INSERT INTO CITIES(NAME, POPULATION) VALUES('Bratislava', 432000);
INSERT INTO CITIES(NAME, POPULATION) VALUES('Budapest', 1759000);
INSERT INTO CITIES(NAME, POPULATION) VALUES('Prague', 1280000);
INSERT INTO CITIES(NAME, POPULATION) VALUES('Warsaw', 1748000);
INSERT INTO CITIES(NAME, POPULATION) VALUES('Los Angeles', 3971000);
INSERT INTO CITIES(NAME, POPULATION) VALUES('New York', 8550000);
INSERT INTO CITIES(NAME, POPULATION) VALUES('Edinburgh', 464000);
INSERT INTO CITIES(NAME, POPULATION) VALUES('Berlin', 3671000);

The schema is automatically created by Hibernate; later, the import.sql file is executed to fill the table with data.

CityRepository.java
package com.zetcode.repository;

import com.zetcode.bean.City;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CityRepository extends CrudRepository<City, Long> {

}

The @Repository annotation is used to define a repository.

ICityService.java
package com.zetcode.service;

import com.zetcode.bean.City;
import java.util.List;

public interface ICityService {

    public List<City> findAll();
}

ICityService provides contract method to get all cities.

CityService.java
package com.zetcode.service;

import com.zetcode.bean.City;
import com.zetcode.repository.CityRepository;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class CityService implements ICityService {

    @Autowired
    private CityRepository cityRepository;

    @Override
    public List<City> findAll() {

        List<City> cities = (List<City>) cityRepository.findAll();
        
        return cities;
    }
}

The @Service annotation declares CityService to be a service class; a class that provides business services. The @Autowired annotation marks cityRepository to be injected with CityRepository.

MyController.java
package com.zetcode.controller;

import com.zetcode.bean.City;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.zetcode.service.ICityService;

@Controller
public class MyController {

    @Autowired
    private ICityService cityService;
    
    @RequestMapping("/")
    public String index(Model model) {
        
        return "index";
    }    

    @RequestMapping("/showCities")
    public ModelAndView showCities() {

        List<City> cities = cityService.findAll();

        Map<String, Object> params = new HashMap<>();
        params.put("cities", cities);

        return new ModelAndView("showCities", params);
    }
}

The @Controller annotation marks a class as a web controller. The @RequestMapping maps HTTP request with a path to a controller method. In the second case, it maps the /showCities URL to the showCities() method.

index.ftl
<!DOCTYPE html>
<html>
    <head>
        <title>Home page</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <a href="showCities">Show cities</a>
    </body>
</html>

This is the index.ftl template file. It contains a link to create a request to show all cities.

showCities.ftl
<!DOCTYPE html>
<html>
    <head>
        <title>Cities</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="css/style.css" />
        </head>
    <body>
        <h2>List of cities</h2>
        
        <table>
            <tr>
                <th>Id</th>  
                <th>Name</th>  
                <th>Population</th>
            </tr>        

            <#list cities as city>
                <tr>
                    <td>${city.id}</td> 
                    <td>${city.name}</td> 
                    <td>${city.population}</td>
                </tr>
            </#list>        
        </table>                
    </body>
</html>

This is the showCities.ftl template file. It uses FreeMarker #list macro di display all city objects.

style.css
h2 {color: blue}

td:nth-child(3) {
    text-align: right;
}

This is the style.css template file.

Application.java
package com.zetcode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

The @SpringBootApplication enables auto-configuration and component scanning.

In this tutorial, we have covered a few Spring Boot annotations. You might also be interested in the related tutorials: