Skip to content

Commit 6d6440e

Browse files
committed
added persistent JPA H2 database
1 parent 367cb92 commit 6d6440e

8 files changed

Lines changed: 208 additions & 228 deletions

File tree

README.md

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,47 +6,60 @@ A RESTful API for managing tasks built with Java 21 and Spring Boot.
66

77
## Tech Stack
88

9-
| Layer | Technology |
10-
|---|---|
11-
| Language | Java 21 |
12-
| Framework | Spring Boot 4.1.0-M2 |
13-
| Persistence | In-memory HashMap |
9+
| Layer | Technology |
10+
|------------|------------------------|
11+
| Language | Java 21 |
12+
| Framework | Spring Boot 4.1.0-M2 |
13+
| Persistence| H2 (file-based) |
14+
| ORM | Spring Data JPA |
1415
| Validation | Spring Boot Validation |
15-
| Build Tool | Maven |
16-
| CI/CD | GitHub Actions |
16+
| Build Tool | Maven |
17+
| CI/CD | GitHub Actions |
1718

1819
---
1920

2021
## Getting Started
2122

2223
**Prerequisites:** Java 21+ (Maven wrapper included)
23-
2424
```bash
2525
git clone https://github.com/ColtonRandall/task-manager-api.git
2626
cd task-manager-api
2727
./mvnw spring-boot:run
2828
```
2929

3030
The API starts on `http://localhost:8080`. To build a JAR:
31-
3231
```bash
3332
./mvnw -B package
3433
java -jar target/task-manager-api-0.0.1-SNAPSHOT.jar
3534
```
3635

3736
---
3837

38+
## Database
39+
40+
This project uses an H2 file-based database, stored at `./data/taskdb`. Data persists between restarts.
41+
42+
To inspect the database while the app is running, open the H2 console at `http://localhost:8080/h2-console` with the following settings:
43+
44+
| Field | Value |
45+
|----------|------------------------------|
46+
| JDBC URL | `jdbc:h2:file:./data/taskdb` |
47+
| Username | `sa` |
48+
| Password | *<blank>* |
49+
50+
---
51+
3952
## Endpoints
4053

41-
| Method | Path | Description |
42-
|---|---|-------------------------|
43-
| POST | /tasks | Create a task |
44-
| GET | /tasks | Fetch all tasks |
45-
| GET | /tasks/{id} | Fetch a task by ID |
46-
| GET | /tasks/search/{name} | Fetch a task by name |
47-
| PATCH | /tasks/{id}/complete | Mark a task as complete |
48-
| DELETE | /tasks/{id} | Soft delete a task |
49-
| PATCH | /tasks/{id} | Undo a delete |
54+
| Method | Path | Description |
55+
|--------|-------------------------|-------------------------|
56+
| POST | `/tasks` | Create a task |
57+
| GET | `/tasks` | Fetch all tasks |
58+
| GET | `/tasks/{id}` | Fetch a task by ID |
59+
| GET | `/tasks/search/{name}` | Fetch a task by name |
60+
| PATCH | `/tasks/{id}/complete` | Mark a task as complete |
61+
| DELETE | `/tasks/{id}` | Soft delete a task |
62+
| PATCH | `/tasks/{id}` | Undo a delete |
5063

5164
### Examples
5265

@@ -67,7 +80,7 @@ curl -s http://localhost:8080/tasks
6780
curl -s -X PATCH http://localhost:8080/tasks/{id}/complete
6881
```
6982

70-
**Delete a task (Soft delete)**
83+
**Delete a task (soft delete)**
7184
```bash
7285
curl -s -X DELETE http://localhost:8080/tasks/{id}
7386
```
@@ -77,20 +90,16 @@ curl -s -X DELETE http://localhost:8080/tasks/{id}
7790
curl -s -X PATCH http://localhost:8080/tasks/{id}
7891
```
7992

80-
> Note: The task store is in-memory and does not persist between restarts.
81-
8293
---
8394

8495
## Tests
85-
8696
```bash
8797
./mvnw test
8898
```
8999

90100
---
91101

92102
## Project Structure
93-
94103
```
95104
src/
96105
├── main/
@@ -110,5 +119,5 @@ src/
110119
└── test/
111120
└── java/com/taskmanagerapi/
112121
├── TaskManagerApiApplicationTests.java
113-
└── TaskServiceTests.java
122+
└── TaskTests.java
114123
```

pom.xml

Lines changed: 75 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,80 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4-
<modelVersion>4.0.0</modelVersion>
5-
<parent>
6-
<groupId>org.springframework.boot</groupId>
7-
<artifactId>spring-boot-starter-parent</artifactId>
8-
<version>4.1.0-M2</version>
9-
<relativePath/> <!-- lookup parent from repository -->
10-
</parent>
11-
<groupId>com.taskManager</groupId>
12-
<artifactId>task-manager-api</artifactId>
13-
<version>0.0.1-SNAPSHOT</version>
14-
<name>task-manager-app</name>
15-
<description>Demo project for Spring Boot</description>
16-
<url/>
17-
<licenses>
18-
<license/>
19-
</licenses>
20-
<developers>
21-
<developer/>
22-
</developers>
23-
<scm>
24-
<connection/>
25-
<developerConnection/>
26-
<tag/>
27-
<url/>
28-
</scm>
29-
<properties>
30-
<java.version>21</java.version>
31-
</properties>
32-
<dependencies>
33-
<dependency>
34-
<groupId>org.springframework.boot</groupId>
35-
<artifactId>spring-boot-h2console</artifactId>
36-
</dependency>
37-
<dependency>
38-
<groupId>org.springframework.boot</groupId>
39-
<artifactId>spring-boot-starter-data-jpa</artifactId>
40-
</dependency>
41-
<dependency>
42-
<groupId>org.springframework.boot</groupId>
43-
<artifactId>spring-boot-starter-validation</artifactId>
44-
</dependency>
45-
<dependency>
46-
<groupId>org.springframework.boot</groupId>
47-
<artifactId>spring-boot-starter-webmvc</artifactId>
48-
</dependency>
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>org.springframework.boot</groupId>
7+
<artifactId>spring-boot-starter-parent</artifactId>
8+
<version>4.1.0-M2</version>
9+
<relativePath/> <!-- lookup parent from repository -->
10+
</parent>
11+
<groupId>com.taskManager</groupId>
12+
<artifactId>task-manager-api</artifactId>
13+
<version>0.0.1-SNAPSHOT</version>
14+
<name>task-manager-app</name>
15+
<description>Demo project for Spring Boot</description>
16+
<url/>
17+
<licenses>
18+
<license/>
19+
</licenses>
20+
<developers>
21+
<developer/>
22+
</developers>
23+
<scm>
24+
<connection/>
25+
<developerConnection/>
26+
<tag/>
27+
<url/>
28+
</scm>
29+
<properties>
30+
<java.version>21</java.version>
31+
</properties>
32+
<dependencies>
33+
<dependency>
34+
<groupId>org.springframework.boot</groupId>
35+
<artifactId>spring-boot-h2console</artifactId>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.springframework.boot</groupId>
39+
<artifactId>spring-boot-starter-validation</artifactId>
40+
</dependency>
41+
<dependency>
42+
<groupId>org.springframework.boot</groupId>
43+
<artifactId>spring-boot-starter-webmvc</artifactId>
44+
</dependency>
45+
<dependency>
46+
<groupId>org.springframework.boot</groupId>
47+
<artifactId>spring-boot-starter-data-jpa</artifactId>
48+
</dependency>
49+
<dependency>
50+
<groupId>com.h2database</groupId>
51+
<artifactId>h2</artifactId>
52+
<scope>runtime</scope>
53+
</dependency>
54+
<dependency>
55+
<groupId>org.springframework.boot</groupId>
56+
<artifactId>spring-boot-starter-data-jpa-test</artifactId>
57+
<scope>test</scope>
58+
</dependency>
59+
<dependency>
60+
<groupId>org.springframework.boot</groupId>
61+
<artifactId>spring-boot-starter-validation-test</artifactId>
62+
<scope>test</scope>
63+
</dependency>
64+
<dependency>
65+
<groupId>org.springframework.boot</groupId>
66+
<artifactId>spring-boot-starter-webmvc-test</artifactId>
67+
<scope>test</scope>
68+
</dependency>
69+
</dependencies>
4970

50-
<dependency>
51-
<groupId>com.h2database</groupId>
52-
<artifactId>h2</artifactId>
53-
<scope>runtime</scope>
54-
</dependency>
55-
<dependency>
56-
<groupId>org.springframework.boot</groupId>
57-
<artifactId>spring-boot-starter-data-jpa-test</artifactId>
58-
<scope>test</scope>
59-
</dependency>
60-
<dependency>
61-
<groupId>org.springframework.boot</groupId>
62-
<artifactId>spring-boot-starter-validation-test</artifactId>
63-
<scope>test</scope>
64-
</dependency>
65-
<dependency>
66-
<groupId>org.springframework.boot</groupId>
67-
<artifactId>spring-boot-starter-webmvc-test</artifactId>
68-
<scope>test</scope>
69-
</dependency>
70-
</dependencies>
71-
72-
<build>
73-
<plugins>
74-
<plugin>
75-
<groupId>org.springframework.boot</groupId>
76-
<artifactId>spring-boot-maven-plugin</artifactId>
77-
</plugin>
78-
</plugins>
79-
</build>
71+
<build>
72+
<plugins>
73+
<plugin>
74+
<groupId>org.springframework.boot</groupId>
75+
<artifactId>spring-boot-maven-plugin</artifactId>
76+
</plugin>
77+
</plugins>
78+
</build>
8079

8180
</project>

src/main/java/com/taskmanagerapi/model/Task.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
package com.taskmanagerapi.model;
22

3+
import jakarta.persistence.*;
4+
35
import java.time.LocalDateTime;
46
import java.time.temporal.ChronoUnit;
57
import java.util.UUID;
68

9+
@Entity
10+
@Table(name = "tasks")
711
public class Task {
812

13+
@Id
914
private String id;
15+
16+
@Enumerated(EnumType.STRING)
17+
private TaskStatus status;
18+
1019
private String name;
1120
private String description;
1221
private LocalDateTime createdAt;
13-
private TaskStatus status;
1422

1523
public Task(String name, String description) {
1624
this.id = UUID.randomUUID().toString();
@@ -20,6 +28,10 @@ public Task(String name, String description) {
2028
this.status = TaskStatus.CREATED;
2129
}
2230

31+
// Default constructor for JPA
32+
protected Task() {
33+
}
34+
2335
public String getId() {
2436
return id;
2537
}

src/main/java/com/taskmanagerapi/repository/TaskRepository.java

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,13 @@
22

33
import com.taskmanagerapi.model.Task;
44
import com.taskmanagerapi.model.TaskStatus;
5+
import org.springframework.data.jpa.repository.JpaRepository;
56

6-
import java.util.ArrayList;
7-
import java.util.HashMap;
87
import java.util.List;
9-
import java.util.Map;
108
import java.util.Optional;
119

12-
public class TaskRepository {
10+
public interface TaskRepository extends JpaRepository<Task, String> {
11+
Optional<Task> findTaskByName(String name);
1312

14-
private final Map<String, Task> taskStore = new HashMap<>();
15-
16-
public void save(Task task) {
17-
taskStore.put(task.getId(), task);
18-
}
19-
20-
public List<Task> findAllTasks() {
21-
return new ArrayList<>(taskStore.values());
22-
}
23-
24-
public Optional<Task> findTaskById(String id) {
25-
return Optional.ofNullable(taskStore.get(id));
26-
}
27-
28-
public Optional<Task> findTaskByName(String name) {
29-
return taskStore.values().stream()
30-
.filter(task -> task.getName().equals(name))
31-
.findFirst();
32-
}
33-
34-
public List<Task> findTasksByStatus(TaskStatus status) {
35-
return taskStore.values().stream()
36-
.filter(task -> status.equals(task.getStatus())) // "status" first to avoid NullPointer
37-
.toList();
38-
}
39-
40-
public void delete(String id) {
41-
taskStore.remove(id);
42-
}
43-
}
13+
List<Task> findTasksByStatus(TaskStatus status);
14+
}

0 commit comments

Comments
 (0)