본문 바로가기

사이드 프로젝트/To do list

[Spring project] Task 리스트 조회, 입력

<form th:action="@{/tasks}" th:object="${task}" method="post">
    <label for="taskName">Task 이름:</label>
    <input type="text" id="taskName" th:field="*{taskName}" placeholder="Task 이름" required/>

    <label for="status">상태:</label>
    <input type="text" id="status" th:field="*{status}" placeholder="상태" required/>

    <label for="totoId">Toto ID:</label>
    <input type="number" id="totoId" th:field="*{toto.totoNo}" placeholder="Toto ID" required/>

    <button type="submit">저장</button>
</form>

Task 엔티티 생성


Task 엔티티는 작업의 이름, 상태, 생성/수정 시간을 관리하며, Toto라는 다른 엔티티와 다대일 관계로 연결된다. writeDt와 modifyDt는 자동으로 현재 날짜와 시간을 설정하며, status는 입력되지 않았을 때 기본값으로 "N"을 설정.

package com.babobird.Toto.entity;

import com.babobird.Toto.dto.TaskFormDto;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.time.LocalDateTime;

@Entity
@Table(name="task")
@Getter
@Setter
@ToString
public class Task{

    @Id
    @Column(name = "task_no")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int taskNo; // 할 일 번호

    @Column(name="task_nm", nullable = false, length = 100)
    private String taskNm; // 할 일 이름

    @Enumerated(EnumType.STRING)
    @Column(name="task_status")
            private TaskStatus status; // 진행 상태

    @Column(name = "write_dt")
    private LocalDateTime writeDt; // 작성일

    @Column(name = "modify_dt")
    private LocalDateTime modifyDt; // 수정일

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "toto_no")
    private Toto toto;

    // @PrePersist: 엔티티가 처음 저장될 때 실행
    @PrePersist
    protected void onCreate() {
        if (status == null) {
            status = TaskStatus.N;  // status가 없을 경우 기본값 "N" 설정
        }

        writeDt = LocalDateTime.now();
        modifyDt = LocalDateTime.now();
    }

    // @PreUpdate: 엔티티가 업데이트될 때 실행
    @PreUpdate
    protected void onUpdate() {
        if (status == null) {
            status = TaskStatus.N;  // status가 없을 경우 기본값 "N" 설정
        }
        modifyDt = LocalDateTime.now();
    }

    //getter setter
    //...
}

 

 

* 참고

@ManyToOne(fetch = FetchType.LAZY)는 JPA(Java Persistence API)에서 다대일 관계(Many-to-One)를 설정할 때 사용되는 어노테이션이다. 이 어노테이션은 엔티티 간의 관계와 지연 로딩(Lazy Loading) 방식을 지정하는 역할을 한다

 

컨트롤러


컨트롤러는 Task 입력 폼을 보여주고, 입력된 데이터를 저장하는 역할을 합니다. 또한 Task 조회 기능도 담당합니다.

 

 

 

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import com.babobird.Toto.entity.Task;
import com.babobird.Toto.service.TaskService;

import java.util.List;

@Controller
public class TaskController {

    private final TaskService taskService;

    public TaskController(TaskService taskService) {
        this.taskService = taskService;
    }

    // Task 입력 폼을 제공하는 GET 메서드
    @GetMapping("/tasks/new")
    public String showTaskForm(Model model) {
        model.addAttribute("task", new Task());
        return "task-form";
    }

    // Task 입력을 처리하는 POST 메서드
    @PostMapping("/tasks")
    public String saveTask(@ModelAttribute Task task) {
        taskService.saveTask(task);
        return "redirect:/tasks";
    }

    // 특정 Toto의 Task 목록을 조회하는 GET 메서드
    @GetMapping("/totos/{totoNo}/tasks")
    public String getTasksByTotoNo(@PathVariable int totoNo, Model model) {
        List<Task> tasks = taskService.getTasksByTotoNo(totoNo);
        model.addAttribute("tasks", tasks);
        return "layouts/tasks";
    }
}

 

 

문제와 해결 과정


1. Task 입력 기능 개발 중 발생한 문제

Task 입력 폼을 만들고, 컨트롤러에서 이 폼을 렌더링하도록 했지만 Thymeleaf 템플릿 처리 오류가 발생

오류 메시지:

org.thymeleaf.exceptions.TemplateProcessingException: Could not parse as expression: "" (template: "task/inputForm" - line 20, col 28)

 

원인:

이 오류는 Thymeleaf가 템플릿에서 표현식을 처리하는 중에 발생. 컨트롤러에서 모델에 task 객체를 전달하지 않아서 템플릿에서 task 객체를 찾을 수 없었기 때문이다.

문제 해결:

  1. 모델에 Task 객체 추가
    컨트롤러에서 모델에 task 객체를 추가하지 않았기 때문에 템플릿에서 해당 객체를 찾을 수 없었다. 이를 해결하기 위해 컨트롤러에서 Task 객체를 모델에 추가하는 코드를 작성.
@GetMapping("/tasks/new")
public String showTaskForm(Model model) {
    model.addAttribute("task", new Task());  // Task 객체를 모델에 추가
    return "task-form";
}
 

2. Task 상태 기본값 설정 관련 문제

Task 입력 폼에서 status 값을 비워두고 저장했을 때, 저장된 데이터에서 status가 null로 남아있는 문제가 있었다.

해결 방법:

이 문제를 해결하기 위해, Task 엔티티에서 status 필드가 비어 있으면 기본값 "N"을 설정하도록 **@PrePersist**와 **@PreUpdate**를 사용

 
 
@Entity
public class Task {

    ...

    @PrePersist
    protected void onCreate() {
        if (status == null || status.isEmpty()) {
            status = "N";  // 기본값 설정
        }
    }

    @PreUpdate
    protected void onUpdate() {
        if (status == null || status.isEmpty()) {
            status = "N";  // 기본값 설정
        }
    }
}

 

 

결론


이번 포스팅에서는 Spring BootThymeleaf를 사용하여 Task 입력 및 조회 기능을 구현했다. 엔티티 관리날짜 처리, 기본값 설정 등을 통해 작업을 효율적으로 처리했다. 다음 작업은 수정, 삭제 작업을 진행할 예정이다.