Spring Boot + Reactで家計簿アプリを作ってみた（PostgreSQL対応版）

**今回は、PostgreSQLを使った**家計簿アプリ**のバックエンドをSpring Bootで構築し、Reactでフロントエンドを作成します。Eclipseを使って開発することを想定し、PostgreSQL用の設定も含めて解説します。**

今回の記事のソースコード

https://github.com/y-t0910/yuto-takahashi-educure-app

# 1. 環境構築
バックエンド：Spring Bootプロジェクトの作成（Eclipse使用）
Eclipseを起動し、Spring Initializrで新規プロジェクトを作成します。
必要な依存関係：
Spring Web
Spring Data JPA
PostgreSQL Driver

# 2. PostgreSQLのセットアップ
PostgreSQLのインストール

公式サイトからPostgreSQLをインストールします。
データベースとユーザーの作成

```sql
CREATE DATABASE kakeibo;
CREATE USER kakeibo_user WITH ENCRYPTED PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE kakeibo TO kakeibo_user;
```
PostgreSQLサーバーを起動し、kakeiboデータベースが作成されていることを確認します。

# 3. Spring Bootの設定（PostgreSQL対応）
**application.propertiesの設定**
```properties
spring.datasource.url=jdbc:postgresql://localhost:5432/kakeibo
spring.datasource.username=kakeibo_user
spring.datasource.password=password
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
```

# 4. エンティティの作成
**Expense.java**
```java
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Expense {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String description;
    private int amount;

    // コンストラクタ、ゲッター、セッター
    public Expense() {}

    public Expense(String description, int amount) {
        this.description = description;
        this.amount = amount;
    }

    public Long getId() { return id; }
    public String getDescription() { return description; }
    public int getAmount() { return amount; }

    public void setDescription(String description) { this.description = description; }
    public void setAmount(int amount) { this.amount = amount; }
}
```

# 5. リポジトリとコントローラの作成
**ExpenseRepository.java**
```java
import org.springframework.data.jpa.repository.JpaRepository;

public interface ExpenseRepository extends JpaRepository<Expense, Long> {}
ExpenseController.java
```

```java
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/api/expenses")
public class ExpenseController {

    private final ExpenseRepository expenseRepository;

    public ExpenseController(ExpenseRepository expenseRepository) {
        this.expenseRepository = expenseRepository;
    }

    @GetMapping
    public List<Expense> getAllExpenses() {
        return expenseRepository.findAll();
    }

    @PostMapping
    public Expense createExpense(@RequestBody Expense expense) {
        return expenseRepository.save(expense);
    }

    @DeleteMapping("/{id}")
    public void deleteExpense(@PathVariable Long id) {
        expenseRepository.deleteById(id);
    }
}
```

# 6. フロントエンドの設定（React）

**プロジェクトの作成と依存パッケージのインストール**
```bash
npx create-react-app kakeibo-app --template typescript
cd kakeibo-app
npm install axios chart.js react-chartjs-2
ReactのApp.tsx
```

```tsx
import React, { useEffect, useState } from 'react';
import axios from 'axios';

interface Expense {
  id: number;
  description: string;
  amount: number;
}

const App: React.FC = () => {
  const [expenses, setExpenses] = useState<Expense[]>([]);
  const [description, setDescription] = useState('');
  const [amount, setAmount] = useState(0);

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

  const fetchExpenses = async () => {
    const response = await axios.get('/api/expenses');
    setExpenses(response.data);
  };

  const addExpense = async () => {
    await axios.post('/api/expenses', { description, amount });
    fetchExpenses();
  };

  const deleteExpense = async (id: number) => {
    await axios.delete(`/api/expenses/${id}`);
    fetchExpenses();
  };

  return (
    <div className="App">
      <h1>家計簿アプリ</h1>
      <input 
        type="text" 
        placeholder="説明" 
        value={description} 
        onChange={(e) => setDescription(e.target.value)} 
      />
      <input 
        type="number" 
        placeholder="金額" 
        value={amount} 
        onChange={(e) => setAmount(Number(e.target.value))} 
      />
      <button onClick={addExpense}>追加</button>

      <ul>
        {expenses.map((expense) => (
          <li key={expense.id}>
            {expense.description}: {expense.amount}円
            <button onClick={() => deleteExpense(expense.id)}>削除</button>
          </li>
        ))}
      </ul>
    </div>
  );
};
```

export default App;
バックエンドとフロントエンドの接続
package.jsonにプロキシ設定
ReactからSpring BootのAPIを呼び出すために、package.jsonにプロキシを設定します。

```json
"proxy": "http://localhost:8080"
```

# 7. 動作確認
PostgreSQLを起動し、kakeiboデータベースが正常に作成されていることを確認します。

Spring Bootを起動します。

```bash
mvn spring-boot:run
```
Reactを起動します。
```bash
npm start
```
ブラウザでhttp://localhost:3000にアクセスし、家計簿アプリが表示されることを確認します。

# 8. まとめ
今回の家計簿アプリでは、Spring Bootを使ってバックエンドを構築し、PostgreSQLをデータベースに使用しました。ReactからAPIを呼び出してデータを表示・追加・削除することで、フロントエンドとバックエンドを連携させました。

今後の拡張例
認証機能の追加：JWTを使ったログイン機能
カテゴリ別の管理：支出をカテゴリに分類
グラフ表示の強化：月別・年別の支出グラフの追加

今回は家計簿アプリを作ったものを記事にしました。

**毎日更新していますので、@y-t0910をフォロー,いいねしていただけると嬉しいです。**