LoginSignup
3
5

More than 1 year has passed since last update.

Spring Bootを使ってみた!(家計簿アプリ)

Last updated at Posted at 2021-07-01

現状のスキル感

  • エンジニア歴2年程度
  • Servlet, JSPを研修を通して理解できたレベル感。
  • VB.NET, Pythonを多少かじった程度。
  • SpringBootはほぼ初見。

きっかけ

  • SpringBootを試しで使ってみたので、備忘録として掲載します。
  • 制作日数2~3日程で質の担保はできませんので、ご了承下さい。
  • 見た目や例外処理、バリデーションチェックなどはほぼ実装していません。
  • 内容について誤りや改善点などあればご教授頂けると幸いです。

家計簿アプリのイメージスライド

  • 家計簿アプリ
  • CRUD処理を実装
  • 表示の単位は一覧、年別、年別月別を用意
  • 登録、更新、削除は一般的な内容

ソースコード

TOP画面のHTML

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
    <link th:href="@{/css/styles.css}" rel="stylesheet">
    <title>家計簿</title>
</head>

<body>
    <div th:replace="~{block/header::headerAccount}"></div>

    <h1>家計簿一覧画面</h1>
    <table class="table table-striped">
        <tr>
            <th>No</th>
            <th>日時</th>
            <th>種別</th>
            <th>品名</th>
            <th>金額</th>
        </tr>

        <tr th:each="account, accountStat : ${list}">
            <td th:text="${accountStat.count}"></td>
            <td th:text="${account.date}"></td>
            <td th:if="${account.type == 1}">食費</td>
            <td th:if="${account.type == 2}">趣味</td>
            <td th:if="${account.type == 3}">教養</td>
            <td th:text="${account.item}"></td>
            <td th:text="${account.price} + '円'"></td>
        </tr>
    </table>

    <table class="table table-striped">
        <tr>
            <th>合計金額</th>
            <td th:text="${totalPrice} + '円'"></td>
        <tr>
    </table>

    <script th:src="@{/js/bootstrap.bundle.min.js}"></script>
</body>
</html>
  • トップページアクセス時にデータベースから家計簿情報を取得、表示。
  • cssはbootstrapを使用しています。ヘッダーやテーブルの装飾など。
  • thymeleafを利用してth:eachタグでリストの情報を表示している。
  • No情報は画面表示時に1から採番しています。(DBはAUTO_INCREMENTの為。)

Controller

package com.example.demo.controller;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.example.demo.entity.Account;
import com.example.demo.service.AccountService;

/**
 * @author takaaki
 * コントローラークラス
 */
@Controller
@RequestMapping("/account")
public class AccountController {

    private final AccountService service;

    @Autowired
    public AccountController(AccountService service) {
        this.service = service;
    }

    // 全件表示を行う
    @GetMapping
    public String account(Model model) {

        List<Account> list = service.findAll();
        int totalPrice = service.getTotalPrice();
        model.addAttribute("list", list);
        model.addAttribute("totalPrice", totalPrice);
        return "account/index";
    }

    // 新規登録画面へ遷移
    @GetMapping("/insert")
    public String goInsert() {

        return "account/insert";
    }

    // 新規登録画面へ遷移
    @PostMapping("/insert")
    public String insert(Model model, Account account) {

        account = service.insertAccount(account);
        model.addAttribute("account", account);
        return "account/insertComplete";
    }

    // 削除画面へ遷移
    @GetMapping("/delete")
    public String goDelete(Model model) {

        List<Account> list = service.findAll();
        int totalPrice = service.getTotalPrice();
        model.addAttribute("list", list);
        model.addAttribute("totalPrice", totalPrice);
        return "account/delete";
    }

    // 削除確認画面へ遷移
    @GetMapping("/deleteConfirm")
    public String deleteConfirm(Model model, @RequestParam String id) {

        Account account = service.findAcountById(id);
        model.addAttribute("account", account);
        return "account/deleteConfirm";
    }

    // 削除処理を行う
    @PostMapping("/delete")
    public String delete(Model model, @RequestParam String id) {

        Account account = service.findAcountById(id);
        model.addAttribute("account", account);
        service.deleteAcountById(id);
        return "account/deleteComplete";
    }

    // 更新画面へ遷移
    @GetMapping("/update")
    public String goUpdate(Model model) {

        List<Account> list = service.findAll();
        int totalPrice = service.getTotalPrice();
        model.addAttribute("list", list);
        model.addAttribute("totalPrice", totalPrice);
        return "account/update";
    }

    // 更新入力画面へ遷移
    @GetMapping("/updateInput")
    public String updateInput(Model model, @RequestParam String id) {

        Account account = service.findAcountById(id);
        model.addAttribute("account", account);
        return "account/updateInput";
    }

    // 更新確認画面へ遷移
    @PostMapping("/updateConfirm")
    public String updateConfirm(Model model, Account account) {

        model.addAttribute("account", account);
        return "account/updateConfirm";
    }

    // 更新処理を行う
    @PostMapping("/update")
    public String update(Model model, Account account) {

        model.addAttribute("account", account);
        service.updateAccount(account);
        return "account/updateComplete";
    }

    // 年別集計画面へ遷移
    @GetMapping("/findByYear")
    public String goFindByYear() {

        return "account/findByYear";
    }

    // 年別集計処理を行う
    @PostMapping("/findByYear")
    public String findByYear(Model model, @RequestParam String year) {

        List<Account> list2 = service.findAccountByYear(year);
        int totalPrice = service.getTotalPrice();
        model.addAttribute("totalPrice", totalPrice);
        model.addAttribute("year", year);
        model.addAttribute("list", list2);
        return "account/findByYear";
    }

    // 年別月別集計画面へ遷移
    @GetMapping("/findByYearAndMonth")
    public String goFindByYearAndMonth() {

        return "account/findByYearAndMonth";
    }

    // 年別月別集計処理を行う
    @PostMapping("/findByYearAndMonth")
    public String findByYearAndMonth(Model model, @RequestParam String year, @RequestParam String month) {

        List<Account> list2 = service.findAccountByYearAndMonth(year, month);
        int totalPrice = service.getTotalPrice();
        model.addAttribute("totalPrice", totalPrice);
        model.addAttribute("year", year);
        model.addAttribute("month", month);
        model.addAttribute("list", list2);
        return "account/findByYearAndMonth";
    }
}
  • 全ての画面への遷移を担当。
  • DBにアクセスする為にサービスクラスに処理を投げている。

Service

package com.example.demo.service;

import java.util.Calendar;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.demo.dao.AccountDAO;
import com.example.demo.entity.Account;

/**
 * @author takaaki
 * ロジック担当
 */
@Service
public class AccountService {

    private final AccountDAO dao;

    // 合計金額格納用
    private int totalPrice;

    @Autowired
    public AccountService(AccountDAO dao) {
        this.dao = dao;
    }

    // 全件検索
    public List<Account> findAll() {

        List<Account> list = dao.findAll();
        totalPrice = 0;
        for (Account account : list) {
            totalPrice += account.getPrice();
        }
        return list;
    }

    // 新規登録
    public Account insertAccount(Account account) {

        dao.insertAccount(account);
        return account;
    }

    // 1件検索
    public Account findAcountById(String id) {

        return dao.findAcountById(id);
    }

    // 1件削除
    public void deleteAcountById(String id) {

        dao.deleteAccountById(id);
    }

    // 1件更新
    public void updateAccount(Account account) {

        dao.updateAccount(account);
    }

    // 年別処理を行う
    public List<Account> findAccountByYear(String year) {

        String startDate = year + "-01-01";
        String endDate = year + "-12-31";
        List<Account> list = dao.findAccountByYear(startDate, endDate);
        totalPrice = 0;
        for (Account account : list) {
            totalPrice += account.getPrice();
        }
        return list;

    }

    // 年別月別処理を行う
    public List<Account> findAccountByYearAndMonth(String year, String month) {

        int yearInt = Integer.parseInt(year);
        int monthInt = Integer.parseInt(month);
        String startDate = year + "-" + month + "-" + "01";
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, yearInt);
        calendar.set(Calendar.MONTH, monthInt - 1);
        int result = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        String endDate = year + "-" + month + "-" + result;
        List<Account> list = dao.findAccountByYearAndMonth(startDate, endDate);
        totalPrice = 0;
        for (Account account : list) {
            totalPrice += account.getPrice();
        }
        return list;

    }

    public int getTotalPrice() {
        return totalPrice;
    }

    public void setTotalPrice(int totalPrice) {
        this.totalPrice = totalPrice;
    }
}
  • DAOクラスにアクセスしてCRUD処理を実行する。
  • 年別処理は検索範囲を「入力した月-01-01」から「入力した月-12-31」に設定。
  • 年別月別処理は検索範囲を動的に取得。末尾の日が年度によって異なる為。

Repository

package com.example.demo.dao;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import com.example.demo.entity.Account;

/**
 * @author takaaki
 * DAOクラス
 */
@Repository
public class AccountDAO {

    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public AccountDAO(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    // 全件検索処理
    public List<Account> findAll() {

        String sql = "SELECT id, date, type, item, price FROM account order by date, id";
        List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sql);
        List<Account> list = new ArrayList<>();

        for (Map<String, Object> result : resultList) {

            Account account = new Account();
            account.setId((int) result.get("id"));
            Date date = (Date) result.get("date");
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String strDate = dateFormat.format(date);
            account.setDate(strDate);
            account.setType((int) result.get("type"));
            account.setItem((String) result.get("item"));
            account.setPrice((int) result.get("price"));
            list.add(account);
        }
        return list;
    }

    // 新規登録処理
    public void insertAccount(Account account) {

        jdbcTemplate.update("insert into account (date, type, item, price) values (?,?,?,?)",
                account.getDate(), account.getType(), account.getItem(), account.getPrice());
    }

    // ID検索処理
    public Account findAcountById(String id) {

        String sql = "SELECT id, date, type, item, price FROM account where id = ?";
        Map<String, Object> result = jdbcTemplate.queryForMap(sql, id);

        Account account = new Account();
        account.setId((int) result.get("id"));
        Date date = (Date) result.get("date");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String strDate = dateFormat.format(date);
        account.setDate(strDate);
        account.setType((int) result.get("type"));
        account.setItem((String) result.get("item"));
        account.setPrice((int) result.get("price"));

        return account;
    }

    // 削除処理
    public void deleteAccountById(String id) {

        jdbcTemplate.update("delete from account where id = ?", id);
    }

    // 更新処理
    public void updateAccount(Account account) {

        jdbcTemplate.update("update account set date = ?, type = ?, item = ?, price = ? where id = ?",
                account.getDate(), account.getType(), account.getItem(), account.getPrice(), account.getId());
    }

    // 年別検索処理
    public List<Account> findAccountByYear(String startDate, String endDate) {

        String sql = "SELECT id, date, type, item, price FROM account "
                + "where date between ? and ? order by date, id";
        List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sql,
                startDate, endDate);
        List<Account> list = new ArrayList<>();

        for (Map<String, Object> result : resultList) {

            Account account = new Account();
            account.setId((int) result.get("id"));
            Date date = (Date) result.get("date");
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String strDate = dateFormat.format(date);
            account.setDate(strDate);
            account.setType((int) result.get("type"));
            account.setItem((String) result.get("item"));
            account.setPrice((int) result.get("price"));
            list.add(account);
        }
        return list;
    }

    // 年別月別検索処理
    public List<Account> findAccountByYearAndMonth(String startDate, String endDate) {

        String sql = "SELECT id, date, type, item, price FROM account "
                + "where date between ? and ? order by date, id";
        List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sql,
                startDate, endDate);
        List<Account> list = new ArrayList<>();

        for (Map<String, Object> result : resultList) {

            Account account = new Account();
            account.setId((int) result.get("id"));
            Date date = (Date) result.get("date");
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String strDate = dateFormat.format(date);
            account.setDate(strDate);
            account.setType((int) result.get("type"));
            account.setItem((String) result.get("item"));
            account.setPrice((int) result.get("price"));
            list.add(account);
        }
        return list;
    }
}
  • 購入日をEntityがString型、DBはDate型で設計したのでキャスト処理が必要。

全部を書き出すには分量が多すぎるので、次回以降に処理の詳細を記載していこうと思います。

3
5
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
3
5