SpringBootでJPQLで範囲時間を抽出し、小数点以下2位の切り上げ方を解説しています

SpringBoot

はじめに

学習時間管理アプリ#5の解説記事となります。

作成する過程で、ビジネスロジックの実装を行っており、SpringBootでJPQLで範囲時間を抽出し、小数点以下2位の切り上げ方などを解説しています。

前回記事はこちらからどうぞ!!

改修要件

今回は以下の要件を改修していきます。

一覧画面

  • 選択した表示年月のみを画面に表示する事(#6で実装します)
  • 今月の学習累計時間を画面に表示する事
  • 先月の学習累計時間を画面に表示する事
  • 詳細画面の処理…JavaScriptの日付を自動に取得する処理をJST取得にする事(#6で実装します)

※現在はUTCになっているため使用できるが実用できない

コーディング

学習累計時間に関連する機能を実装

改修の目的:
月毎の学習時間を累計し一覧画面に表示する事ができる
今月と先月の累計時間を当月の画面で確認する事ができる

実装内容:
・学習開始と学習終了の時間差の差し引きを合算するクエリの作成
・当月と先月を判断する処理の実装

勉強時間の合算を計算するクエリを定義する

「StudyTimeRepository.java」を編集します。11行~12行目が追加箇所です。

StudyTimeRepository.java
package com.app.progTrack.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import com.app.progTrack.entity.StudyTime;

public interface StudyTimeRepository extends JpaRepository<StudyTime, Long>{
	 
	 @Query("SELECT SUM(TIMESTAMPDIFF(MINUTE, s.startTime, s.endTime)) FROM StudyTime s WHERE MONTH(s.startTime) = :month AND YEAR(s.startTime) = :year AND s.endTime IS NOT NULL")
	 Long findTotalStudyTimeByMonth(@Param("month") int month, @Param("year") int year);
	 
}

上記のコードを解説します。

SQLの知識が無い方はちょっと難しいと思いますので、こんな仕組みで動いているんだな程度の理解でよいと思います。

SQLの構文が横で並んでいると見づらいので、通常のSQL構文のように組み替えます。

SQL
SELECT SUM(TIMESTAMPDIFF(MINUTE, s.startTime, s.endTime)) 
FROM StudyTime s 
WHERE MONTH(s.startTime) = :month 
AND YEAR(s.startTime) = :year 
AND s.endTime IS NOT NULL

SELECT句


FROM句


WHERE句


findTotalStudyTimeByMonthメソッド部分

StudyTimeRepository.java
Long findTotalStudyTimeByMonth(@Param("month") int month, @Param("year") int year);

@Param(“month”)と@Param(“year”)はメソッドの引数とクエリ内のパラメーターを紐づけている

つまりこういう事です。


「StudyTimeService.java」を編集します。以下を追加・編集しています。

  • 28~31行目
  • 53行目
StudyTimeService.java
package com.app.progTrack.service;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.List;

import org.springframework.stereotype.Service;

import com.app.progTrack.entity.StudyTime;
import com.app.progTrack.repository.StudyTimeRepository;

@Service
public class StudyTimeService {
	private final StudyTimeRepository studyTimeRepository;
	
	public StudyTimeService(StudyTimeRepository studyTimeRepository) {
		this.studyTimeRepository = studyTimeRepository;
	}
	
	// 学習時間の打刻セット
	public void saveStudyTime(StudyTime studyTime) {

		studyTimeRepository.save(studyTime);
	}
	
	// 月毎の累計時間を取得する
	public long getTotalStudyTimeForMonth(int month, int year) {
		Long total = studyTimeRepository.findTotalStudyTimeByMonth(month, year);
		return total != null ? total : 0; // nullの場合は0を返す
	}
	
	// 最後のレコードを取得する
	public StudyTime getLastStudyTime() {
		List<StudyTime> studyTimes = studyTimeRepository.findAll();
		return studyTimes.isEmpty() ? null : studyTimes.get(studyTimes.size() - 1);
	}
	
	// UTCからJSTへ変換する処理
	public LocalDateTime convertToJST(LocalDateTime utcDateTime) {
		// LocalDateTimeをUTCのZoneTimeに変換
		ZonedDateTime utcZoned = utcDateTime.atZone(ZoneId.of("UTC"));
		// UTCからJSTへ同じ瞬間の時間を取得
		ZonedDateTime jstZonde = utcZoned.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
		// LocalDateTimeに変換する
		return jstZonde.toLocalDateTime();
	}
	
	// 学習中の判定をする
	public boolean isLiarningActive() {
		StudyTime lastStudyTime = getLastStudyTime(); // 最後のレコードを取得
		// lastStudyTimeがnullではない 且つ getIsLearningメソッドがtrueの場合に戻り値はtrueが返る
		return lastStudyTime != null && Boolean.TRUE.equals(lastStudyTime.getIsLearning());
	}
	
	// 一覧ページ表示用
	public List<StudyTime> getAllStudyTimes() {
		return studyTimeRepository.findAll();
	}
	// 編集用
	public StudyTime getStudyTime(Long id) {
		return studyTimeRepository.findById(id).orElse(null);
	}
	// 削除用
	public void deleteStudyTime(Long id) {
		studyTimeRepository.deleteById(id);
	}
}

28~31行目、追加の解説

StudyTimeService.java
 // 月毎の累計時間を取得する
	public long getTotalStudyTimeForMonth(int month, int year) {
		Long total = studyTimeRepository.findTotalStudyTimeByMonth(month, year);
		return total != null ? total : 0; // nullの場合は0を返す
	}

「StudyTimeRepository.java」で定義したクエリを呼び出し、引数に年度と月を渡すことで、該当月であれば、時間数を計算し「total」へ格納する。もしない場合は0を格納する。

「total != null ? total : 0;」で返さないとnullが返ってしまい、「NullPointerException」でエラーになります。

53行目、編集の解説

StudyTimeService.java
return studyTimes.isEmpty() ? null : studyTimes.get(studyTimes.size() - 1);

こちらも「NullPointerException」のエラーを回避するために、「studyTimes.isEmpty() ? null」を追加し、nullを返さないようにしています。

「StudyTimeController.java」を編集します。

  • 39~43行目を追加
StudyTimeController.java
package com.app.progTrack.controller;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.List;
import java.util.Locale;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.app.progTrack.entity.StudyTime;
import com.app.progTrack.service.StudyTimeService;

@Controller
@RequestMapping("/studytime")
public class StudyTimeController {
	private final StudyTimeService studyTimeService;
	
	public StudyTimeController(StudyTimeService studyTimeService) {
		this.studyTimeService = studyTimeService;
	}
	
	@GetMapping
	public String listStudyTimes(Model model) {
		List<StudyTime> studyTimes = studyTimeService.getAllStudyTimes();
		model.addAttribute("studyTimes", studyTimes);
		
		// 現在の月と前月の累計時間を取得する
		int currentMonth = LocalDate.now().getMonthValue();
		int currentYear = LocalDate.now().getYear();
		long currentMonthTotal = studyTimeService.getTotalStudyTimeForMonth(currentMonth, currentYear);
		
		long lastMonthTotal = studyTimeService.getTotalStudyTimeForMonth(currentMonth - 1 == 0 ? 12 : currentMonth -1 , currentMonth - 1 == 0 ? currentYear - 1 : currentYear);
		
		
		model.addAttribute("currentMonthTotal", currentMonthTotal);
		model.addAttribute("lastMonthTotal", lastMonthTotal);
		
		return "studytime/studyTimeList";
	}
	
	@GetMapping("/new")
	public String newStudyTimeForm(Model model) {
		
		// ベースとなる日付を取得する この場合はJST取得の日付 現在の時刻取得用
		LocalDateTime currentDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
		// どういう型で用意するかを定義
		DateTimeFormatter dateFormateer = DateTimeFormatter.ofPattern("MM/dd"); // 日付で形成する
		DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); // 時間で形成する
		// 現在の時刻にあてはめる
		String date = currentDateTime.format(dateFormateer);
		String time = currentDateTime.format(timeFormatter);

		model.addAttribute("studyTimeObject", new StudyTime());
		model.addAttribute("date", date);
		model.addAttribute("time", time); //ページが読み込まれた時の初期表示の時刻表示用
		// 曜日を取得する
		model.addAttribute("currentDayOfWeek", currentDateTime.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.JAPAN));
		// 学習中フラグの状態を追加する
		model.addAttribute("isLearningActive", studyTimeService.isLiarningActive());
		return "studytime/studyTimeForm";
	}
	
	// 時刻を返すエンドポイント
	@GetMapping("/current-time")
	@ResponseBody
	public String getCurrentTime() {
		LocalDateTime currentDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
		return currentDateTime.format(formatter);
	}
	
	@PostMapping
	public String createStudyTime(@ModelAttribute StudyTime studyTime, @RequestParam String action) {
		
		if ("start".equals(action)) {
			studyTime.setStartTime(studyTimeService.convertToJST(LocalDateTime.now(ZoneId.of("UTC"))));
			studyTime.setEndTime(null);
			studyTime.setIsLearning(true);
			studyTimeService.saveStudyTime(studyTime);
		} else if ("end".equals(action)) {
			// 直近の学習セッションを取得する
			StudyTime lastStudyTime = studyTimeService.getLastStudyTime();
			
			if (lastStudyTime != null) {
				lastStudyTime.setEndTime(studyTimeService.convertToJST(LocalDateTime.now(ZoneId.of("UTC"))));
				lastStudyTime.setIsLearning(false);
				studyTimeService.saveStudyTime(lastStudyTime);
			}
		}
		
		return "redirect:/studytime";
	}
	
	@GetMapping("/{id}/edit")
	public String editStudyTimeForm(@PathVariable Long id, Model model) {
		StudyTime studyTime = studyTimeService.getStudyTime(id);
		model.addAttribute("studyTimeObject", studyTime);
		return "studytime/edit";
	}
	
	@PostMapping("/{id}")
	public String updateStudyTime(@PathVariable Long id, @ModelAttribute StudyTime studyTime) {
		studyTime.setStudyTimesId(id);
		studyTimeService.saveStudyTime(studyTime);
		return "redirect:/studytime";
	}
	
	@PostMapping("/{id}/delete")
	public String deleteStudyTime(@PathVariable Long id) {
		studyTimeService.deleteStudyTime(id);
		return "redirect:/studytime";
	}
}

39~43行目、追加の解説

StudyTimeController.java
// 現在の月と前月の累計時間を取得する
		int currentMonth = LocalDate.now().getMonthValue();
		int currentYear = LocalDate.now().getYear();
		long currentMonthTotal = studyTimeService.getTotalStudyTimeForMonth(currentMonth, currentYear);
		
		long lastMonthTotal = studyTimeService.getTotalStudyTimeForMonth(currentMonth - 1 == 0 ? 12 : currentMonth -1 , currentMonth - 1 == 0 ? currentYear - 1 : currentYear);

「long currentMonthTotal」当月の学習時間を格納しています。

「long lastMonthTotal」先月の学習時間を格納しています。以下が処理内容です。

現在の月が1月の場合は前年の12月を参照し、それ以外の場合は単に前の月を参照して、対応する月の学習時間の合計を取得する。

「studyTimeList.html」を編集します。

  • 10~11行目を追加しています。

こちらに関しては単純にフロントエンドに渡しているだけですね。

studyTimeList.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="UTF-8">
	<title>学習時間一覧</title>
</head>
<body>
	<h1>学習時間一覧</h1>
	<a th:href="@{/studytime/new}">学習を開始する</a>
	<p>当月の学習時間: <sapn th:text="${currentMonthTotal}"></sapn></p>
	<p>前月の学習時間: <sapn th:text="${lastMonthTotal}"></sapn></p>
	<table>
		<tr>
			<th>日付</th>
			<th>開始時間</th>
			<th>終了時間</th>
			<th>操作</th>
		</tr>
		<tr th:each="studyTime : ${studyTimes}">
			<td th:text="${studyTime.startTime.format(T(java.time.format.DateTimeFormatter).ofPattern('yyyy/MM/dd'))}"></td>
			<td th:text="${studyTime.startTime.format(T(java.time.format.DateTimeFormatter).ofPattern('HH時mm分'))}"></td>
			<td th:text="${studyTime.endTime != null ? studyTime.endTime.format(T(java.time.format.DateTimeFormatter).ofPattern('HH時mm分')): ''}"></td>
			<td>
				<a th:href="@{/studytime/{id}/edit(id=${studyTime.studyTimesId})}">編集</a>
				<form th:action="@{/studytime/{id}/delete(id=${studyTime.studyTimesId})}" method="post" style="display: inline;">
					<button type="submit">削除</button>
				</form>
			</td>
		</tr>
	</table>
</body>
</html>

それでは、ブラウザで確認してみましょう!!

時間数を分で取得しているため、このような表示ですが、時間数の取得が出来ましたね!!

「HH.m」の形式に変換する

このままでは実用できないので、上記の形式へ変換します。そのためには、コントローラーで取得している当月の学習時間と先月の学習時間の記述部分を修正する必要があります。

「StudyTimeController.java」を編集します。

  • 42~48行目を編集しています。
StudyTimeController.java
package com.app.progTrack.controller;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.List;
import java.util.Locale;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.app.progTrack.entity.StudyTime;
import com.app.progTrack.service.StudyTimeService;

@Controller
@RequestMapping("/studytime")
public class StudyTimeController {
	private final StudyTimeService studyTimeService;
	
	public StudyTimeController(StudyTimeService studyTimeService) {
		this.studyTimeService = studyTimeService;
	}
	
	@GetMapping
	public String listStudyTimes(Model model) {
		List<StudyTime> studyTimes = studyTimeService.getAllStudyTimes();
		model.addAttribute("studyTimes", studyTimes);
		
		// 現在の月と前月の累計時間を取得する
		int currentMonth = LocalDate.now().getMonthValue();
		int currentYear = LocalDate.now().getYear();
		// 当月の学習時間を算出
		double currentMonthTotal = studyTimeService.getTotalStudyTimeForMonth(currentMonth, currentYear) / 60.0;
		
		// 現在の月 - 前月 = 0 なら 12を返す 0でないなら-1を引いた数字を返す
		int lastMonth = currentMonth - 1 == 0 ? 12 : currentMonth -1;
		int lastYear = currentMonth - 1 == 0 ? currentYear - 1 : currentYear;
		// 前月の学習時間を算出
		double lastMonthTotal = studyTimeService.getTotalStudyTimeForMonth(lastMonth,  lastYear) / 60.0;
		
		model.addAttribute("currentMonthTotal", currentMonthTotal);
		model.addAttribute("lastMonthTotal", lastMonthTotal);
		
		return "studytime/studyTimeList";
	}
	
	@GetMapping("/new")
	public String newStudyTimeForm(Model model) {
		
		// ベースとなる日付を取得する この場合はJST取得の日付 現在の時刻取得用
		LocalDateTime currentDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
		// どういう型で用意するかを定義
		DateTimeFormatter dateFormateer = DateTimeFormatter.ofPattern("MM/dd"); // 日付で形成する
		DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); // 時間で形成する
		// 現在の時刻にあてはめる
		String date = currentDateTime.format(dateFormateer);
		String time = currentDateTime.format(timeFormatter);

		model.addAttribute("studyTimeObject", new StudyTime());
		model.addAttribute("date", date);
		model.addAttribute("time", time); //ページが読み込まれた時の初期表示の時刻表示用
		// 曜日を取得する
		model.addAttribute("currentDayOfWeek", currentDateTime.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.JAPAN));
		// 学習中フラグの状態を追加する
		model.addAttribute("isLearningActive", studyTimeService.isLiarningActive());
		return "studytime/studyTimeForm";
	}
	
	// 時刻を返すエンドポイント
	@GetMapping("/current-time")
	@ResponseBody
	public String getCurrentTime() {
		LocalDateTime currentDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
		return currentDateTime.format(formatter);
	}
	
	@PostMapping
	public String createStudyTime(@ModelAttribute StudyTime studyTime, @RequestParam String action) {
		
		if ("start".equals(action)) {
			studyTime.setStartTime(studyTimeService.convertToJST(LocalDateTime.now(ZoneId.of("UTC"))));
			studyTime.setEndTime(null);
			studyTime.setIsLearning(true);
			studyTimeService.saveStudyTime(studyTime);
		} else if ("end".equals(action)) {
			// 直近の学習セッションを取得する
			StudyTime lastStudyTime = studyTimeService.getLastStudyTime();
			
			if (lastStudyTime != null) {
				lastStudyTime.setEndTime(studyTimeService.convertToJST(LocalDateTime.now(ZoneId.of("UTC"))));
				lastStudyTime.setIsLearning(false);
				studyTimeService.saveStudyTime(lastStudyTime);
			}
		}
		
		return "redirect:/studytime";
	}
	
	@GetMapping("/{id}/edit")
	public String editStudyTimeForm(@PathVariable Long id, Model model) {
		StudyTime studyTime = studyTimeService.getStudyTime(id);
		model.addAttribute("studyTimeObject", studyTime);
		return "studytime/edit";
	}
	
	@PostMapping("/{id}")
	public String updateStudyTime(@PathVariable Long id, @ModelAttribute StudyTime studyTime) {
		studyTime.setStudyTimesId(id);
		studyTimeService.saveStudyTime(studyTime);
		return "redirect:/studytime";
	}
	
	@PostMapping("/{id}/delete")
	public String deleteStudyTime(@PathVariable Long id) {
		studyTimeService.deleteStudyTime(id);
		return "redirect:/studytime";
	}
}

42~48行目 解説

StudyTimeController.java
		// 当月の学習時間を算出
		double currentMonthTotal = studyTimeService.getTotalStudyTimeForMonth(currentMonth, currentYear) / 60.0;
		
		// 現在の月 - 前月 = 0 なら 12を返す 0でないなら-1を引いた数字を返す
		int lastMonth = currentMonth - 1 == 0 ? 12 : currentMonth -1;
		int lastYear = currentMonth - 1 == 0 ? currentYear - 1 : currentYear;
		// 前月の学習時間を算出
		double lastMonthTotal = studyTimeService.getTotalStudyTimeForMonth(lastMonth,  lastYear) / 60.0;

目的としては小数点で表示して小数点以下は「分」で表示したいので、まず変数の型を「long」→「double」へ変更しています。

前月の学習時間部分はいままで一行で書いているコードを分割しないと、計算が正しく行われなかったための修正となります。

ブラウザで確認してみましょう!!

小数点第一位まで表示し、小数点第二位を切り上げる

「StudyTimeController.java」を編集します。

  • 42~52行目を編集しています。
StudyTimeController.java
package com.app.progTrack.controller;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.List;
import java.util.Locale;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.app.progTrack.entity.StudyTime;
import com.app.progTrack.service.StudyTimeService;

@Controller
@RequestMapping("/studytime")
public class StudyTimeController {
	private final StudyTimeService studyTimeService;
	
	public StudyTimeController(StudyTimeService studyTimeService) {
		this.studyTimeService = studyTimeService;
	}
	
	@GetMapping
	public String listStudyTimes(Model model) {
		List<StudyTime> studyTimes = studyTimeService.getAllStudyTimes();
		model.addAttribute("studyTimes", studyTimes);
		
		// 現在の月と前月の累計時間を取得する
		int currentMonth = LocalDate.now().getMonthValue();
		int currentYear = LocalDate.now().getYear();
		// 当月の学習時間を算出
		double currentMonthTotal = studyTimeService.getTotalStudyTimeForMonth(currentMonth, currentYear) / 60.0;
		
		// 現在の月 - 前月 = 0 なら 12を返す 0でないなら-1を引いた数字を返す
		int lastMonth = currentMonth - 1 == 0 ? 12 : currentMonth -1;
		int lastYear = currentMonth - 1 == 0 ? currentYear - 1 : currentYear;
		// 前月の学習時間を算出
		double lastMonthTotal = studyTimeService.getTotalStudyTimeForMonth(lastMonth,  lastYear) / 60.0;
		
		model.addAttribute("currentMonthTotal", currentMonthTotal);
		model.addAttribute("lastMonthTotal", lastMonthTotal);
		
		return "studytime/studyTimeList";
	}
	
	@GetMapping("/new")
	public String newStudyTimeForm(Model model) {
		
		// ベースとなる日付を取得する この場合はJST取得の日付 現在の時刻取得用
		LocalDateTime currentDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
		// どういう型で用意するかを定義
		DateTimeFormatter dateFormateer = DateTimeFormatter.ofPattern("MM/dd"); // 日付で形成する
		DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); // 時間で形成する
		// 現在の時刻にあてはめる
		String date = currentDateTime.format(dateFormateer);
		String time = currentDateTime.format(timeFormatter);

		model.addAttribute("studyTimeObject", new StudyTime());
		model.addAttribute("date", date);
		model.addAttribute("time", time); //ページが読み込まれた時の初期表示の時刻表示用
		// 曜日を取得する
		model.addAttribute("currentDayOfWeek", currentDateTime.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.JAPAN));
		// 学習中フラグの状態を追加する
		model.addAttribute("isLearningActive", studyTimeService.isLiarningActive());
		return "studytime/studyTimeForm";
	}
	
	// 時刻を返すエンドポイント
	@GetMapping("/current-time")
	@ResponseBody
	public String getCurrentTime() {
		LocalDateTime currentDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
		return currentDateTime.format(formatter);
	}
	
	@PostMapping
	public String createStudyTime(@ModelAttribute StudyTime studyTime, @RequestParam String action) {
		
		if ("start".equals(action)) {
			studyTime.setStartTime(studyTimeService.convertToJST(LocalDateTime.now(ZoneId.of("UTC"))));
			studyTime.setEndTime(null);
			studyTime.setIsLearning(true);
			studyTimeService.saveStudyTime(studyTime);
		} else if ("end".equals(action)) {
			// 直近の学習セッションを取得する
			StudyTime lastStudyTime = studyTimeService.getLastStudyTime();
			
			if (lastStudyTime != null) {
				lastStudyTime.setEndTime(studyTimeService.convertToJST(LocalDateTime.now(ZoneId.of("UTC"))));
				lastStudyTime.setIsLearning(false);
				studyTimeService.saveStudyTime(lastStudyTime);
			}
		}
		
		return "redirect:/studytime";
	}
	
	@GetMapping("/{id}/edit")
	public String editStudyTimeForm(@PathVariable Long id, Model model) {
		StudyTime studyTime = studyTimeService.getStudyTime(id);
		model.addAttribute("studyTimeObject", studyTime);
		return "studytime/edit";
	}
	
	@PostMapping("/{id}")
	public String updateStudyTime(@PathVariable Long id, @ModelAttribute StudyTime studyTime) {
		studyTime.setStudyTimesId(id);
		studyTimeService.saveStudyTime(studyTime);
		return "redirect:/studytime";
	}
	
	@PostMapping("/{id}/delete")
	public String deleteStudyTime(@PathVariable Long id) {
		studyTimeService.deleteStudyTime(id);
		return "redirect:/studytime";
	}
}

42~52行目 解説

まず既存の変数をアンダーバーを付けて変更しています。フロントエンドで渡している変数を変えるのが面倒だったので(笑)そのままに据え置いた形です。

StudyTimeController.java
		// 小数点第二位を切り上げてから小数点第一位まで表示する
		String currentMonthTotal = String.format("%.1f", Math.ceil(_currentMonthTotal * 10) / 10);
		String lastMonthTotal = String.format("%.1f", Math.ceil(_lastMonthTotal * 10) / 10);
  • 「Math.ceil(_currentMonthTotal * 10) / 10」最初に10倍して小数点第一位を整数部分として切り上げ、その後10で割ることで小数点第一位までの値を取得している
  • 「String.format(“%.1f”)」切り上げた結果を小数点第一位までフォーマットする。

それではブラウザで確認してみましょう!!

おわりに

大分、学習アプリらしくなってきましたね。後半になるにつれてコードが複雑になるので、説明が冗長ですみません。少しでもお役にたてれば嬉しい限りです。それでは次回の記事でお会いしましょう!

コメント