エンジニアとしての市場価値を測りませんか?PR

企業からあなたに合ったオリジナルのスカウトを受け取って、市場価値を測りましょう

1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

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

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

1. 環境構築

バックエンド:Spring Bootプロジェクトの作成(Eclipse使用)
Eclipseを起動し、Spring Initializrで新規プロジェクトを作成します。
必要な依存関係:
Spring Web
Spring Data JPA
PostgreSQL Driver

2. PostgreSQLのセットアップ

PostgreSQLのインストール

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

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の設定

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

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

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

public interface ExpenseRepository extends JpaRepository<Expense, Long> {}
ExpenseController.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)

プロジェクトの作成と依存パッケージのインストール

npx create-react-app kakeibo-app --template typescript
cd kakeibo-app
npm install axios chart.js react-chartjs-2
ReactのApp.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にプロキシを設定します。

"proxy": "http://localhost:8080"

7. 動作確認

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

Spring Bootを起動します。

mvn spring-boot:run

Reactを起動します。

npm start

ブラウザでhttp://localhost:3000にアクセスし、家計簿アプリが表示されることを確認します。

8. まとめ

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

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

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

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

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Qiita Conference 2025 will be held!: 4/23(wed) - 4/25(Fri)

Qiita Conference is the largest tech conference in Qiita!

Keynote Speaker

ymrl、Masanobu Naruse, Takeshi Kano, Junichi Ito, uhyo, Hiroshi Tokumaru, MinoDriven, Minorun, Hiroyuki Sakuraba, tenntenn, drken, konifar

View event details
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?