Spring Boot @Repository
last modified August 2, 2023
Spring Boot @Repository tutorial shows how to use the @Repository
annotation in a Spring application.
Spring is a popular Java application framework and Spring Boot is an evolution of Spring that helps create stand-alone, production-grade Spring based applications easily.
@Repository
@Repository is a Spring annotation that indicates that the
decorated class is a repository. A repository is a mechanism for encapsulating
storage, retrieval, and search behavior which emulates a collection of objects.
It is a specialization of the @Component annotation allowing for
implementation classes to be autodetected through classpath scanning.
@ComponentScan ensures that the classes decorated with
@Component and their derivatives including @Repository
are found and registered as Spring beans.
@ComponentScan is automatically included with
@SpringBootApplication.
Spring Boot @Repository example
The following application demonstrates the usage of @Repository.
It shows a list of countries in an HTML table to the user.
build.gradle
...
src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ ├── Application.java
│ │ ├── controller
│ │ │ └── MyController.java
│ │ ├── model
│ │ │ └── Country.java
│ │ ├── repository
│ │ │ └── CountryRepository.java
│ │ └── service
│ │ ├── CountryService.java
│ │ └── ICountryService.java
│ └── resources
│ ├── application.yml
│ ├── import.sql
│ ├── static
│ │ └── index.html
│ └── templates
│ └── showCountries.ftlh
└── test
├── java
└── resources
This is the project structure.
plugins {
id 'org.springframework.boot' version '3.1.1'
id 'io.spring.dependency-management' version '1.1.0'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-freemarker'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'
}
This is the Gradle build file. The h2 dependency includes the H2
database driver.
Spring Boot starters are a set of convenient dependency descriptors which
greatly simplify configuration. The spring-boot-starter-web enables
web applications, both classic and RESTFul. The
spring-boot-starter-web-freemarker is a starter for building web
applications with Freemarker template engine. It uses Tomcat as the default
embedded container. The spring-boot-starter-data-jpa is a starter
for using Spring Data JPA with Hibernate.
server:
port: 8086
servlet:
context-path: /SpringBootRepository
spring:
main:
banner-mode: "off"
jpa:
database: h2
hibernate:
dialect: org.hibernate.dialect.H2Dialect
ddl-auto: create-drop
In the application.yml file we write various configuration settings
of a Spring Boot application. The port sets for server port and the
context-path context path (application name). After these settings,
we access the application at localhost:8086/SpringBootRepository/.
With the banner-mode property we turn off the Spring banner.
The JPA database value specifies the target database to operate on.
We specify the Hibernate dialect, org.hibernate.dialect.H2Dialect in our case.
The ddl-auto is the data definition language mode; the create-drop
option automatically creates and drops the database schema. The H2 database is run in memory.
INSERT INTO countries(name, population) VALUES('China', 1382050000);
INSERT INTO countries(name, population) VALUES('India', 1313210000);
INSERT INTO countries(name, population) VALUES('USA', 324666000);
INSERT INTO countries(name, population) VALUES('Indonesia', 260581000);
INSERT INTO countries(name, population) VALUES('Brazil', 207221000);
INSERT INTO countries(name, population) VALUES('Pakistan', 196626000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Bangladesh', 162099000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Russia', 146838000);
INSERT INTO countries(name, population) VALUES('Japan', 126830000);
INSERT INTO countries(name, population) VALUES('Mexico', 122273000);
INSERT INTO countries(name, population) VALUES('Philippines', 103738000);
INSERT INTO countries(name, population) VALUES('Ethiopia', 101853000);
INSERT INTO countries(name, population) VALUES('Vietnam', 92700000);
INSERT INTO countries(name, population) VALUES('Egypt', 92641000);
INSERT INTO countries(name, population) VALUES('Germany', 82800000);
INSERT INTO countries(name, population) VALUES('the Congo', 82243000);
INSERT INTO countries(name, population) VALUES('Iran', 82800000);
INSERT INTO countries(name, population) VALUES('Turkey', 79814000);
INSERT INTO countries(name, population) VALUES('Thailand', 68147000);
INSERT INTO countries(name, population) VALUES('France', 66984000);
INSERT INTO countries(name, population) VALUES('United Kingdom', 60589000);
INSERT INTO countries(name, population) VALUES('South Africa', 55908000);
INSERT INTO countries(name, population) VALUES('Myanmar', 51446000);
INSERT INTO countries(name, population) VALUES('South Korea', 68147000);
INSERT INTO countries(name, population) VALUES('Colombia', 49129000);
INSERT INTO countries(name, population) VALUES('Kenya', 47251000);
INSERT INTO countries(name, population) VALUES('Spain', 46812000);
INSERT INTO countries(name, population) VALUES('Argentina', 43850000);
INSERT INTO countries(name, population) VALUES('Ukraine', 42603000);
INSERT INTO countries(name, population) VALUES('Sudan', 41176000);
INSERT INTO countries(name, population) VALUES('Algeria', 40400000);
INSERT INTO countries(name, population) VALUES('Poland', 38439000);
The schema is automatically created by Hibernate; later, the
import.sql file is executed to fill the table with data.
package com.zetcode.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.util.Objects;
@Entity
@Table(name = "countries")
public class Country {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int population;
public Country() {
}
public Country(Long id, String name, int population) {
this.id = id;
this.name = name;
this.population = population;
}
public Long getId() {
return 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 boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Country country = (Country) o;
return population == country.population &&
Objects.equals(id, country.id) &&
Objects.equals(name, country.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name, population);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Country{");
sb.append("id=").append(id);
sb.append(", name='").append(name).append('\'');
sb.append(", population=").append(population);
sb.append('}');
return sb.toString();
}
}
This is the Country entity. Each entity must have at least two
annotations defined: @Entity and @Id. Previously, we
have set the ddl-auto option to create-drop which means
that Hibernate will create the table schema from this entity.
@Entity
@Table(name = "countries")
public class Country {
The @Entity annotation specifies that the class is an
entity and is mapped to a database table. The @Table annotation
specifies the name of the database table to be used for mapping.
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
The @Id annotation specifies the primary key of an entity and
the @GeneratedValue gives the generation strategy for the values
of primary keys.
package com.zetcode.repository;
import com.zetcode.model.Country;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CountryRepository extends CrudRepository<Country, Long> {
}
CountryRepository is decorated with the @Repository
annotation.
By extending from the Spring CrudRepository, we have
some methods for our data repository implemented, including findAll.
This saves some boilerplate code.
package com.zetcode.service;
import com.zetcode.model.Country;
import java.util.List;
public interface ICountryService {
List<Country> findAll();
}
ICountryService contains the findAll contract method.
package com.zetcode.service;
import com.zetcode.model.Country;
import com.zetcode.repository.CountryRepository;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class CountryService implements ICountryService {
private final CountryRepository repository;
public CountryService(CountryRepository repository) {
this.repository = repository;
}
@Override
public List<Country> findAll() {
return (List<Country>) repository.findAll();
}
}
CountryService contains the implementation of the
findAll method.
private final CountryRepository repository;
public CountryService(CountryRepository repository) {
this.repository = repository;
}
CountryRepository is injected.
@Override
public List<Country> findAll() {
return (List<Country>) repository.findAll();
}
The findAll method returns the list of all countries from the
database.
package com.zetcode.controller;
import com.zetcode.model.Country;
import com.zetcode.service.ICountryService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.HashMap;
import java.util.List;
@Controller
public class MyController {
private final ICountryService countryService;
public MyController(ICountryService countryService) {
this.countryService = countryService;
}
@GetMapping("/countries")
public ModelAndView getCountries() {
var countries = (List<Country>) countryService.findAll();
var params = new HashMap<String, Object>();
params.put("countries", countries);
return new ModelAndView("showCountries", params);
}
}
MyController handles a request from the client.
@Controller
public class MyController {
A controller is annotated with @Controller annotation.
private final ICountryService countryService;
public MyController(ICountryService countryService) {
this.countryService = countryService;
}
ICountryService is injected into the countryService
attribute.
var countries = (List<Country>) countryService.findAll();
From the service object, we retrieve all countries with the findAll
method.
var params = new HashMap<String, Object>();
params.put("countries", countries);
return new ModelAndView("showCountries", params);
The processing is send to the showCountries.ftlh template file,
along with the list of countries.
<!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>
<p>
<a href="countries">Show countries</a>
</p>
</body>
</html>
This is the home page. It contains a link to get all countries.
<!DOCTYPE html>
<html>
<head>
<title>Show countries</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h2>List of countries</h2>
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th>Population</th>
</tr>
<#list countries as country>
<tr>
<td>${country.id}</td>
<td>${country.name}</td>
<td>${country.population}</td>
</tr>
</#list>
</table>
</body>
</html>
This is the showCountries.ftlh template file. With the
#list directive, we show all the items from the list.
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);
}
}
Application is the entry point which sets up Spring Boot
application. The @SpringBootApplication annotation enables
auto-configuration and component scanning. It is a convenience annotation for
@Configuration, @EnableAutoConfiguration, and
@ComponentScan annotations.
$ ./gradlew bootRun
We run the application and navigate to localhost:8086/SpringBootRepository/.
In this article we have shown how to use @Repository annotation
in a Spring application.