Sunday, July 6, 2025

To-Do List (CRUD) Web Application using Java Spring Boot, MySQL (via WampServer64), and React.js, all using Notepad as your IDE

 ๐Ÿ“‹ Introduction

In this project, we’ll build a simple To-Do List Web Application using Java Spring Boot for the backend, MySQL (via WampServer64) for data storage, and React.js for the frontend. This app lets users perform basic CRUD operations—create, read, update, and delete tasks. It’s perfect for beginners who want to understand how to connect a Java backend with a modern JavaScript frontend. Uniquely, we'll use Notepad as our code editor, proving that you don’t need heavy IDEs to create a fully functional full-stack application from scratch.

๐Ÿงฑ Part 1: Set Up the Backend (Java Spring Boot)

๐Ÿ”น Step 1: Generate Spring Boot Project

  1. Go to https://start.spring.io

  2. Fill in the following:

    • Project: Maven

    • Language: Java

    • Spring Boot: (Use the latest stable version)

    • Group: com.example

    • Artifact: todo

    • Name: todo

    • Description: Simple ToDo List

    • Package name: com.example.todo

    • Packaging: Jar

    • Java version: (Pick what you have installed)

  3. Dependencies:

    • Spring Web

    • Spring Data JPA

    • MySQL Driver

    • Spring Boot DevTools (optional for auto-reload)

  4. Click Generate, and it will download a .zip file.

  5. Extract the zip to your preferred folder (e.g., C:\todo-backend).




๐Ÿ”น Step 2: Configure MySQL Database on WampServer64

  1. Launch WampServer and open phpMyAdmin (usually at http://localhost/phpmyadmin).

  2. Create a new database:

    • Name: todo_db

  3. Create a MySQL user or use root (default with no password unless you've changed it).


๐Ÿ”น Step 3: Configure application.properties

Open src/main/resources/application.properties in Notepad:

1
2
3
4
5
6
7
spring.datasource.url=jdbc:mysql://localhost:3306/todo_db
spring.datasource.username=root
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
server.port=8080

๐Ÿ”น Step 4: Create the To-Do Entity

Create a file Todo.java in src/main/java/com/example/todo/model/:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.example.todo.model;

import jakarta.persistence.*;

@Entity
public class Todo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;
    private boolean completed;

    // Getters and setters
    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; }
}

๐Ÿ”น Step 5: Create Repository

Create TodoRepository.java in src/main/java/com/example/todo/repository/:

1
2
3
4
5
6
7
package com.example.todo.repository;

import com.example.todo.model.Todo;
import org.springframework.data.jpa.repository.JpaRepository;

public interface TodoRepository extends JpaRepository<Todo, Long> {
}

๐Ÿ”น Step 6: Create REST Controller

Create TodoController.java in src/main/java/com/example/todo/controller/:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.example.todo.controller;

import com.example.todo.model.Todo;
import com.example.todo.repository.TodoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@CrossOrigin(origins = "*") // allow frontend
@RequestMapping("/api/todos")
public class TodoController {

    @Autowired
    private TodoRepository repository;

    @GetMapping
    public List<Todo> getAll() {
        return repository.findAll();
    }

    @PostMapping
    public Todo create(@RequestBody Todo todo) {
        return repository.save(todo);
    }

    @PutMapping("/{id}")
    public Todo update(@PathVariable Long id, @RequestBody Todo todo) {
        Todo existing = repository.findById(id).orElseThrow();
        existing.setTitle(todo.getTitle());
        existing.setCompleted(todo.isCompleted());
        return repository.save(existing);
    }

    @DeleteMapping("/{id}")
    public void delete(@PathVariable Long id) {
        repository.deleteById(id);
    }
}

๐Ÿ”น Step 7: Run the Backend

Open CMD, navigate to the project folder:

cd C:\todo-backend

.\mvnw spring-boot:run

Backend should start on http://localhost:8080


๐ŸŒ Part 2: Set Up the Frontend (React.js)

๐Ÿ”น Step 1: Create React App

  1. Open CMD and run:

npx create-react-app todo-frontend
cd todo-frontend
  1. Start the app:

npm start

It should open http://localhost:3000.


๐Ÿ”น Step 2: Create Simple CRUD UI

In src/App.js, replace with:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import React, { useState, useEffect } from 'react';

const API_URL = "http://localhost:8080/api/todos";

function App() {
  const [todos, setTodos] = useState([]);
  const [title, setTitle] = useState("");

  useEffect(() => {
    fetchTodos();
  }, []);

  const fetchTodos = async () => {
    const res = await fetch(API_URL);
    const data = await res.json();
    setTodos(data);
  };

  const addTodo = async () => {
    if (!title.trim()) return;
    await fetch(API_URL, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ title, completed: false }),
    });
    setTitle("");
    fetchTodos();
  };

  const toggleTodo = async (todo) => {
    await fetch(`${API_URL}/${todo.id}`, {
      method: "PUT",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ ...todo, completed: !todo.completed }),
    });
    fetchTodos();
  };

  const deleteTodo = async (id) => {
    await fetch(`${API_URL}/${id}`, { method: "DELETE" });
    fetchTodos();
  };

  return (
    <div style={{ padding: 20 }}>
      <h2>To-Do List</h2>
      <input value={title} onChange={(e) => setTitle(e.target.value)} />
      <button onClick={addTodo}>Add</button>
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            <span
              onClick={() => toggleTodo(todo)}
              style={{
                textDecoration: todo.completed ? "line-through" : "none",
                cursor: "pointer",
              }}
            >
              {todo.title}
            </span>
            &nbsp;
            <button onClick={() => deleteTodo(todo.id)}>X</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;

๐Ÿ”น Step 3: Allow CORS (already done)

We’ve already allowed CORS in the controller using:

@CrossOrigin(origins = "*")

 

๐Ÿงช Test Everything

  1. Open http://localhost:3000 in your browser.

You should now be able to:

  • Add a to-do
  • Toggle completion
  • Delete items

 The todo_db current contents:


The todo_db table structure(created automatically):



No comments:

Post a Comment

Deploying a React Frontend to Railway: A Complete Guide (To-Do App)

 If you've already deployed your Java Spring Boot backend to Railway, congratulations — the hardest part is done! ๐ŸŽ‰ Now it’s time to ...