Uncategorized

バックエンドでよりJavaを使用する

今までのタイマーはほとんどフロントエンドで行っていたので編集を行います

タイマー機能をバックエンドに移行する

  1. タイマーの状態管理用のエンティティを作成
  2. タイマー制御用のサービスを作成
  3. WebSocketを使用してフロントエンドとリアルタイム通信を実装

タイマーのエンティティを作成

package com.example.PomodoroTimer.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import lombok.Data;

@Entity
@Data
public class Timer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private int workDuration; // 作業時間(分)
    private int breakDuration; // 休憩時間(分)
    private int remainingTime; // 残り時間(秒)
    private boolean isRunning; // タイマーが実行中かどうか
    private boolean isWorkTime; // 作業時間か休憩時間か
}

タイマー制御用のサービスを作成

package com.example.PomodoroTimer.service;

import com.example.PomodoroTimer.domain.Timer;
import org.springframework.stereotype.Service;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.beans.factory.annotation.Autowired;

@Service
public class TimerService {
    
    @Autowired
    private SimpMessagingTemplate messagingTemplate;
    
    private Timer currentTimer;
    
    public TimerService() {
        this.currentTimer = new Timer();
        this.currentTimer.setWorkDuration(25);
        this.currentTimer.setBreakDuration(5);
        this.currentTimer.setRemainingTime(25 * 60);
        this.currentTimer.setRunning(false);
        this.currentTimer.setWorkTime(true);
    }
    
    public Timer getCurrentTimer() {
        return currentTimer;
    }
    
    public void startTimer() {
        currentTimer.setRunning(true);
        notifyTimerUpdate();
    }
    
    public void pauseTimer() {
        currentTimer.setRunning(false);
        notifyTimerUpdate();
    }
    
    public void resetTimer() {
        currentTimer.setRemainingTime(currentTimer.isWorkTime() ? 
            currentTimer.getWorkDuration() * 60 : 
            currentTimer.getBreakDuration() * 60);
        currentTimer.setRunning(false);
        notifyTimerUpdate();
    }
    
    public void switchMode() {
        currentTimer.setWorkTime(!currentTimer.isWorkTime());
        currentTimer.setRemainingTime(currentTimer.isWorkTime() ? 
            currentTimer.getWorkDuration() * 60 : 
            currentTimer.getBreakDuration() * 60);
        currentTimer.setRunning(false);
        notifyTimerUpdate();
    }
    
    @Scheduled(fixedRate = 1000)
    public void updateTimer() {
        if (currentTimer.isRunning() && currentTimer.getRemainingTime() > 0) {
            currentTimer.setRemainingTime(currentTimer.getRemainingTime() - 1);
            notifyTimerUpdate();
            
            if (currentTimer.getRemainingTime() == 0) {
                currentTimer.setRunning(false);
                switchMode();
            }
        }
    }
    
    private void notifyTimerUpdate() {
        messagingTemplate.convertAndSend("/topic/timer", currentTimer);
    }
}

WebSocketの設定をする

WebSocket:WebブラウザとWebサーバーの間で、双方向かつ永続的な通信チャネルを確立するための技術

package com.example.PomodoroTimer.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")
                .setAllowedOrigins("http://localhost:8080")
                .withSockJS();
    }
}

タイマー制御用のコントローラーを作成

package com.example.PomodoroTimer.controller;

import com.example.PomodoroTimer.domain.Timer;
import com.example.PomodoroTimer.service.TimerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/timer")
@CrossOrigin(origins = "http://localhost:8080")
public class TimerController {

    @Autowired
    private TimerService timerService;

    @GetMapping("/current")
    public Timer getCurrentTimer() {
        return timerService.getCurrentTimer();
    }

    @PostMapping("/start")
    public void startTimer() {
        timerService.startTimer();
    }

    @PostMapping("/pause")
    public void pauseTimer() {
        timerService.pauseTimer();
    }

    @PostMapping("/reset")
    public void resetTimer() {
        timerService.resetTimer();
    }

    @PostMapping("/switch")
    public void switchMode() {
        timerService.switchMode();
    }
}

主な変更点は以下の4点

  1. Timerエンティティ:タイマーの状態を管理
  2. TimerService:タイマーの制御ロジックを実装
  3. WebSocketConfig:リアルタイム通信の設定
  4. TimerController:REST APIエンドポイントの提供

-Uncategorized