Spring Boot Todo Web Application with MySQL

Absolutely. Since you’ve already been setting up Java + Maven + MySQL + Eclipse on Ubuntu, here is a complete beginner-friendly tutorial to build a Spring Boot Todo Web Application with MySQL.

We’ll use:

  • Java 17+
  • Maven
  • Spring Boot
  • Spring Web
  • Spring Data JPA
  • MySQL
  • Thymeleaf
  • Eclipse/STS
  • HTML/CSS

1. Project architecture

We will build:

Todo Web Application
       |
       v
   Controller
       |
       v
    Service
       |
       v
  Repository
       |
       v
     MySQL

The browser will provide a simple UI:

+----------------------------------+
|          TODO APPLICATION        |
+----------------------------------+
| Add Todo: [ Learn Spring ] [Add]|
+----------------------------------+
| ID | Todo             | Action   |
| 1  | Learn Java       | Delete   |
| 2  | Learn Spring     | Delete   |
+----------------------------------+

2. Create Spring Starter Project

Open Spring Initializr:

Spring Initializr

Select:

Project: Maven
Language: Java
Spring Boot: latest stable version
Group: com.example
Artifact: todo
Name: todo
Packaging: Jar
Java: 17 or newer

Add these dependencies:

Spring Web
Spring Data JPA
MySQL Driver
Thymeleaf
Spring Boot DevTools

Then click Generate and download the ZIP.

Extract it:

cd ~/Downloads
unzip todo.zip
cd todo

Open it in Eclipse:

File
 → Import
 → Maven
 → Existing Maven Projects
 → Select todo folder
 → Finish

3. Create MySQL database

Start MySQL:

sudo systemctl start mysql

Open MySQL:

sudo mysql

Create the database:

CREATE DATABASE todo_db;

Create a user:

CREATE USER 'todo_user'@'localhost'
IDENTIFIED BY 'todo_password';

Give permissions:

GRANT ALL PRIVILEGES ON todo_db.* 
TO 'todo_user'@'localhost';

Apply:

FLUSH PRIVILEGES;

Check:

SHOW DATABASES;

Exit:

exit;

4. Configure Spring Boot

Open:

src/main/resources/application.properties

Add:

spring.application.name=todo

spring.datasource.url=jdbc:mysql://localhost:3306/todo_db
spring.datasource.username=todo_user
spring.datasource.password=todo_password

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

spring.jpa.properties.hibernate.format_sql=true

spring.thymeleaf.cache=false

server.port=8080

Important

This setting:

spring.jpa.hibernate.ddl-auto=update

allows Hibernate/JPA to automatically create/update tables based on our Java entity.

For example, our Java class:

@Entity
public class Todo {
    ...
}

will result in a table similar to:

todo
----------------
id
title
completed

5. Create Todo Entity

Create:

src/main/java/com/example/todo/model/Todo.java

Code:

package com.example.todo.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Todo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    private boolean completed;

    public Todo() {
    }

    public Todo(String title) {
        this.title = title;
        this.completed = false;
    }

    public Long getId() {
        return id;
    }

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

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public boolean isCompleted() {
        return completed;
    }

    public void setCompleted(boolean completed) {
        this.completed = completed;
    }
}

6. Create Repository

Create:

src/main/java/com/example/todo/repository/TodoRepository.java
package com.example.todo.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.todo.model.Todo;

public interface TodoRepository extends JpaRepository<Todo, Long> {

}

That’s it.

Spring Data JPA automatically provides methods such as:

findAll()
findById()
save()
deleteById()
count()

So we don’t need to manually write SQL for basic CRUD operations.


7. Create Service

Create:

src/main/java/com/example/todo/service/TodoService.java
package com.example.todo.service;

import java.util.List;

import org.springframework.stereotype.Service;

import com.example.todo.model.Todo;
import com.example.todo.repository.TodoRepository;

@Service
public class TodoService {

    private final TodoRepository todoRepository;

    public TodoService(TodoRepository todoRepository) {
        this.todoRepository = todoRepository;
    }

    public List<Todo> getAllTodos() {
        return todoRepository.findAll();
    }

    public void addTodo(String title) {
        Todo todo = new Todo(title);
        todoRepository.save(todo);
    }

    public void deleteTodo(Long id) {
        todoRepository.deleteById(id);
    }

    public void toggleTodo(Long id) {

        Todo todo = todoRepository.findById(id)
                .orElseThrow();

        todo.setCompleted(!todo.isCompleted());

        todoRepository.save(todo);
    }
}

8. Create Web Controller

Create:

src/main/java/com/example/todo/controller/TodoController.java
package com.example.todo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.example.todo.service.TodoService;

@Controller
public class TodoController {

    private final TodoService todoService;

    public TodoController(TodoService todoService) {
        this.todoService = todoService;
    }

    @GetMapping("/")
    public String home(Model model) {

        model.addAttribute(
                "todos",
                todoService.getAllTodos()
        );

        return "index";
    }

    @PostMapping("/add")
    public String addTodo(
            @RequestParam String title) {

        todoService.addTodo(title);

        return "redirect:/";
    }

    @GetMapping("/delete")
    public String deleteTodo(
            @RequestParam Long id) {

        todoService.deleteTodo(id);

        return "redirect:/";
    }

    @GetMapping("/toggle")
    public String toggleTodo(
            @RequestParam Long id) {

        todoService.toggleTodo(id);

        return "redirect:/";
    }
}

9. Understand the Controller

When the browser visits:

http://localhost:8080/

Spring calls:

@GetMapping("/")
public String home(Model model)

It gets the todos:

todoService.getAllTodos()

and sends them to Thymeleaf:

model.addAttribute("todos", ...);

Finally:

return "index";

means:

templates/index.html

will be displayed.


10. Create HTML page

Create:

src/main/resources/templates/index.html

Put:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">

    <title>Todo Application</title>

    <style>

        body {
            font-family: Arial, sans-serif;
            background: #f4f4f4;
            margin: 40px;
        }

        .container {
            max-width: 700px;
            margin: auto;
            background: white;
            padding: 30px;
            border-radius: 10px;
        }

        h1 {
            text-align: center;
        }

        form {
            display: flex;
            gap: 10px;
            margin-bottom: 25px;
        }

        input {
            flex: 1;
            padding: 10px;
        }

        button {
            padding: 10px 15px;
            cursor: pointer;
        }

        table {
            width: 100%;
            border-collapse: collapse;
        }

        th, td {
            padding: 12px;
            border-bottom: 1px solid #ddd;
        }

        .completed {
            text-decoration: line-through;
        }

        a {
            margin-right: 10px;
        }

    </style>
</head>

<body>

<div class="container">

    <h1>Todo Application</h1>

    <form action="/add" method="post">

        <input
            type="text"
            name="title"
            placeholder="Enter todo"
            required>

        <button type="submit">
            Add
        </button>

    </form>

    <table>

        <thead>

        <tr>
            <th>ID</th>
            <th>Todo</th>
            <th>Action</th>
        </tr>

        </thead>

        <tbody>

        <tr th:each="todo : ${todos}">

            <td th:text="${todo.id}">
                1
            </td>

            <td>

                <span
                    th:text="${todo.title}"
                    th:classappend="${todo.completed} ? 'completed' : ''">
                    Learn Spring
                </span>

            </td>

            <td>

                <a
                    th:href="@{/toggle(id=${todo.id})}">
                    Toggle
                </a>

                <a
                    th:href="@{/delete(id=${todo.id})}">
                    Delete
                </a>

            </td>

        </tr>

        </tbody>

    </table>

</div>

</body>

</html>

11. Run the application

In Eclipse:

Right click TodoApplication.java
        ↓
Run As
        ↓
Spring Boot App

Or from terminal:

./mvnw spring-boot:run

You should see something similar to:

Tomcat started on port 8080
Started TodoApplication

Open:

http://localhost:8080

12. Test the application

Enter:

Learn Java

Click:

Add

Then:

Learn Spring Boot

Click:

Add

Your page should show:

+--------------------------------------+
|          Todo Application            |
+--------------------------------------+
| [ Learn Spring Boot       ] [ Add ] |
+--------------------------------------+
| ID | Todo              | Action      |
| 1  | Learn Java        | Toggle Delete|
| 2  | Learn Spring Boot | Toggle Delete|
+--------------------------------------+

13. Check MySQL

Open MySQL:

mysql -u todo_user -p

Enter:

todo_password

Select database:

USE todo_db;

Show tables:

SHOW TABLES;

You should see something similar to:

todo

Check records:

SELECT * FROM todo;

Example:

+----+------------------+-----------+
| id | title            | completed |
+----+------------------+-----------+
|  1 | Learn Java       | 0         |
|  2 | Learn Spring Boot| 0         |
+----+------------------+-----------+

14. Understand the complete flow

When you click Add:

HTML
 |
 | POST /add
 v
TodoController
 |
 v
TodoService
 |
 v
TodoRepository
 |
 v
Hibernate/JPA
 |
 v
MySQL

For example:

todoRepository.save(todo);

causes Hibernate to generate an SQL INSERT similar to:

INSERT INTO todo
(title, completed)
VALUES
('Learn Spring Boot', false);

When you open /:

Browser
   |
   v
Controller
   |
   v
Service
   |
   v
Repository
   |
   v
MySQL
   |
   v
Thymeleaf
   |
   v
HTML

15. Project structure

Your final project should look approximately like:

todo/
│
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/todo/
│   │   │       │
│   │   │       ├── TodoApplication.java
│   │   │       │
│   │   │       ├── controller/
│   │   │       │   └── TodoController.java
│   │   │       │
│   │   │       ├── model/
│   │   │       │   └── Todo.java
│   │   │       │
│   │   │       ├── repository/
│   │   │       │   └── TodoRepository.java
│   │   │       │
│   │   │       └── service/
│   │   │           └── TodoService.java
│   │   │
│   │   └── resources/
│   │       │
│   │       ├── templates/
│   │       │   └── index.html
│   │       │
│   │       └── application.properties
│   │
│   └── test/
│
├── pom.xml
└── mvnw

What you have learned

This small project covers the core Spring Boot concepts:

TechnologyPurpose
Spring BootApplication framework
Spring WebHTTP/web requests
ControllerHandles browser requests
ServiceBusiness logic
RepositoryDatabase operations
JPA/HibernateJava ↔ SQL mapping
MySQLPersistent database
ThymeleafHTML templates
MavenDependency/build management
EclipseDevelopment IDE

Next useful step: add Edit Todo, validation, Bootstrap styling, REST APIs (GET/POST/PUT/DELETE), and a proper database schema so this becomes a more realistic Spring Boot CRUD project.

Leave a Reply

Your email address will not be published. Required fields are marked *