Java Spring Boot (Part 3)
Neil Haddley โข October 28, 2023
Using Spring Data JPA with an in-memory H2 database to store and list todo items, and deploying the application to Azure
I created a Spring Boot application using Spring Data JPA, which provides high-level, repository-style interfaces for data access and reduces boilerplate code.
Under the hood: How the seed data gets loaded
TodoItemDataLoader is a component that implements CommandLineRunner, so Spring calls its run method once, as the application starts. The method asks the repository for a count, and only when the count is zero does it save the two items, get the milk and rake the leaves. It then logs how many items there are. That is why the todos list is never empty when I open /todos.
JAVA
1package com.haddley.springdatajpa; 2 3import org.springframework.boot.SpringApplication; 4import org.springframework.boot.autoconfigure.SpringBootApplication; 5 6import org.springframework.web.bind.annotation.GetMapping; 7import org.springframework.web.bind.annotation.RequestParam; 8import org.springframework.web.bind.annotation.RestController; 9 10@SpringBootApplication 11@RestController 12public class SpringdatajpaApplication { 13 public static void main(String[] args) { 14 SpringApplication.run(SpringdatajpaApplication.class, args); 15 } 16 17 @GetMapping("/hello") 18 public String hello(@RequestParam(value = "name", defaultValue = "World") String name) { 19 return String.format("Hello %s!", name); 20 } 21}
TodoItem.java
JAVA
1package com.haddley.springdatajpa.models; 2 3import java.time.Instant; 4 5import jakarta.persistence.Entity; 6import jakarta.persistence.GeneratedValue; 7import jakarta.persistence.GenerationType; 8import jakarta.persistence.Id; 9import jakarta.persistence.Table; 10import jakarta.validation.constraints.NotBlank; 11 12import lombok.Getter; 13import lombok.Setter; 14 15@Entity 16@Table(name = "todo_item") 17public class TodoItem { 18 19 @Id 20 @GeneratedValue(strategy = GenerationType.AUTO) 21 @Getter 22 @Setter 23 private Long id; 24 25 @Getter 26 @Setter 27 @NotBlank(message = "Description is required") 28 private String description; 29 30 @Getter 31 @Setter 32 private boolean complete; 33 34 @Getter 35 @Setter 36 private Instant createdDate; 37 38 @Getter 39 @Setter 40 private Instant modifiedDate; 41 42 public TodoItem() {} 43 44 public TodoItem(String description) { 45 this.description = description; 46 this.complete = false; 47 this.createdDate = Instant.now(); 48 this.modifiedDate = Instant.now(); 49 } 50 51 @Override 52 public String toString() { 53 return String.format("TodoItem{id=%d, description='%s', complete='%s', createdDate='%s', modifiedDate='%s'}", id, description, complete, createdDate, modifiedDate); 54 } 55 56 57}
TodoItemRepository.java
JAVA
1package com.haddley.springdatajpa.models; 2 3import com.haddley.springdatajpa.models.TodoItem; 4import org.springframework.data.repository.CrudRepository; 5 6public interface TodoItemRepository extends CrudRepository { 7}
TodoItemDataLoader.java
JAVA
1package com.haddley.springdatajpa.config; 2 3import com.haddley.springdatajpa.models.TodoItem; 4import com.haddley.springdatajpa.repositories.TodoItemRepository; 5 6import org.slf4j.Logger; 7import org.slf4j.LoggerFactory; 8import org.springframework.beans.factory.annotation.Autowired; 9import org.springframework.boot.CommandLineRunner; 10import org.springframework.stereotype.Component; 11 12@Component 13public class TodoItemDataLoader implements CommandLineRunner { 14 15 private final Logger logger = LoggerFactory.getLogger(TodoItemDataLoader.class); 16 17 @Autowired 18 TodoItemRepository todoItemRepository; 19 20 @Override 21 public void run(String... args) throws Exception { 22 loadSeedData(); 23 } 24 25 private void loadSeedData() { 26 if (todoItemRepository.count() == 0) { 27 TodoItem todoItem1 = new TodoItem("get the milk"); 28 TodoItem todoItem2 = new TodoItem("rake the leaves"); 29 30 todoItemRepository.save(todoItem1); 31 todoItemRepository.save(todoItem2); 32 } 33 34 logger.info("Number of TodoItems: {}", todoItemRepository.count()); 35 } 36 37}
SpringdatajpaApplication.java updated
JAVA
1package com.haddley.springdatajpa; 2 3import org.springframework.boot.SpringApplication; 4import org.springframework.boot.autoconfigure.SpringBootApplication; 5 6import org.springframework.web.bind.annotation.GetMapping; 7import org.springframework.web.bind.annotation.RequestParam; 8import org.springframework.web.bind.annotation.RestController; 9 10import com.haddley.springdatajpa.models.TodoItem; 11import com.haddley.springdatajpa.repositories.TodoItemRepository; 12import org.springframework.beans.factory.annotation.Autowired; 13 14import java.util.stream.StreamSupport; 15import java.util.stream.Collectors; 16 17@SpringBootApplication 18@RestController 19public class SpringdatajpaApplication { 20 public static void main(String[] args) { 21 SpringApplication.run(SpringdatajpaApplication.class, args); 22 } 23 24 @GetMapping("/hello") 25 public String hello(@RequestParam(value = "name", defaultValue = "World") String name) { 26 return String.format("Hello %s!", name); 27 } 28 29 @Autowired 30 private TodoItemRepository todoItemRepository; 31 32 @GetMapping("/todos") 33 public String index() { 34 35 Iterable todos = todoItemRepository.findAll(); 36 37 return StreamSupport.stream(todos.spliterator(), false) 38 .map(TodoItem::toString) 39 .collect(Collectors.joining(", ")); 40 41 } 42 43}
application.properties
TEXT
1spring.datasource.url=jdbc:h2:mem:testdb 2spring.datasource.driverClassName=org.h2.Driver 3spring.datasource.username=sa 4spring.datasource.password=password 5spring.jpa.database-platform=org.hibernate.dialect.H2Dialect


















