본문 바로가기
Spring

2022-09-29 스프링 (답변 등록,저장,표시)

by allwing12 2022. 9. 29.
<h1 th:text="${question.subject}"></h1>
<div th:text = "${question.content}"></div>

<form th:action="@{|/answer/create/${question.id}|}" method="post">
    <textarea name="content" id="content"rows="15"></textarea>
    <input type="submit" value="답변등록">
</form>

 

우선 위의 코드를 통해서 질문 상세 페이지에 답변을 등록할 수 있는 인풋창을 만든다.

이렇게 해서 디테일 창에 들어가게 되면 

 

 

위의 사진과 같은 내용을 확인할 수 있다, 원래 이전에 없던 답변 등록할 수 있는 칸을 따로 만들었다고 생각하자.

그리고 이렇게 했다면 이제 answer 즉 답변에 대한 것들을 만들어야하는 상황이다.

 

 

package com.mysite.sbb.answer.controller;

import com.mysite.sbb.answer.Service.AnswerService;
import com.mysite.sbb.question.Service.QuestionService;
import com.mysite.sbb.question.domain.Question;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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;

@RequestMapping("/answer")
@RequiredArgsConstructor
@Controller
public class AnswerController {
    private final QuestionService questionService;
    private final AnswerService answerService;

    @PostMapping("/create/{id}")
    public String createAnswer(Model model, @PathVariable("id") Integer id, @RequestParam String content){
        Question question = questionService.getQuestion(id);
        answerService.create(question, content);
        // 할 일 : 답변 생성
        return String.format("redirect:/question/detail/%s", id);
    }
}

 

답변에 대한 AnswerController 도 만들어야한다 그리고 위와 같이 만든다.

우선적으로 private final AnswerService answerService는 없기 때문에 answerService도 만들어야한다.

그 전에, createAnswer 에 대해서 생각해보자 AnswerController 에 먼저 QuestionService를 불러야한다.

QuestionService를 부르는 이유는 당연히 질문 상세에 대한 내용을 불러와야하기 때문이다.

그리고 PostMapping을 통해서 매핑을 해주는데 create/{id} 를 작성한다 , id는 우리가 디테일 페이지로 들어가면

id 값을 통해서 계속해서 불러오기 때문에 id 값을 통해서 불러온다고 생각해야한다.

 

그리고 createAnswer 안에 Question question = qusetionService.getQuestion(id) 를 해놨는데

이것도 동일하게 질문에 대한 상세를 불러오는거라고 생각하면 쉽다.

그리고 return 값으로 String.format 으로 redirect를 하여 질문을 달면 새로고침 되서 그 창에 머물게 한다.

이렇게까지 한 후에 AnswerService를 만들어야한다.

 

 

 

package com.mysite.sbb.answer.Service;

import com.mysite.sbb.answer.dao.AnswerRepository;
import com.mysite.sbb.answer.domain.Answer;
import com.mysite.sbb.question.domain.Question;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

@Service
@RequiredArgsConstructor
public class AnswerService {
    private final AnswerRepository answerRepository;
    public void create(Question question, String content) {
        Answer answer = new Answer();
        answer.setCreateDate(LocalDateTime.now());
        answer.setQuestion(question);
        answer.setContent(content);
        answerRepository.save(answer);
    }
}

 

 

바로 위의 코드에서 answerService.create(question, content) 가 있는데 Service에 create가 없으면

계속 해서 빨간색으로 떠 있을거다 그걸 이제 AnswerService 클래스에 void로 해서 만든다.

그리고 AnswerService 는 당연히 AnswerRepository를 불러와야한다.

 

그리고 create void 안에는 질문을 달았을 때 들어갈 새로운 Answer 객체를 만들어준 후 그 안에 들어가는 것들은

setCreateDate(LocalDateTime.now) << 답변을 단 시간과

setQuestion (question) , setContent(content) 를 통해서 받은 것들을 전부 Answer 객체에 저장을 한다.

이렇게 하고 답변을 등록한 후에 데이터베이스를 확인해보면 답변이 데이터베이스에 저장된 것을 확인할 수 있다.

 

 

Fetch 타입의 종류는 LAZY와 EAGER가 있는데 EAGER의 경우에는 그냥 항상 모든 정보를 가져온다고 생각하면 된다.

LAZY의 경우에는 필요한 경우에만 코드를 작성해서 정보를 가져올 수 있다.

이 Fetch는 OneToMany 또는 ManyToOne 을 눌렀을 때 자세하게 나와있는데 이건 이 전 글에도 작성 되어있다.

Fetch 타입은 뭐가 좋다고 할 수 없다 그냥 상황에 맞게 사용을 하면 된다.

 

 

<h1 th:text="${question.subject}"></h1>
<div th:text = "${question.content}"></div>

<h5 th:text="|${#lists.size(question.answerList)}개의 답변이 있습니다.|"></h5>
<div>
    <ul>
        <li th:each="answer : ${question.answerList}" th:text="${answer.content}"></li>
    </ul>
</div>

<form th:action="@{|/answer/create/${question.id}|}" method="post">
    <textarea name="content" id="content"rows="15"></textarea>
    <input type="submit" value="답변등록">
</form>

 

자, 그리고 위에는 답변을 직접적으로 표시하기 위해 위의 코드를 작성을 했다.

h5 부터 /div까지 추가한 내용이라고 생각하면 된다.

 

 

작성하고 나면 위와같이 표시가 되며 답변의 개수만큼 표시가 된다.

#lists.size(question.asnwerlist) 는 답변의 개수를 의미하며 lists.size는 타임리프가 제공하는

유틸리티로 객체의 길이를 반환하는거라고 한다.

답변 자체는 question 객체의 answerlist를 순회하여 li 엘리먼트로 표시하는거라고 생각하면 된다.

 

 

    public Question getQuestion(Integer id) {
//        Optional<Question> questionOptional = questionRepository.findById(id);
//        if(questionOptional.isPresent()) {
//            return questionOptional.get();
//        } else {
//            throw new DataNotFoundException("question not found");
//        }
        return questionRepository.findById(id).orElseThrow(() -> new DataNotFoundException("question not found"));
    }

 

이건 부가적인 건데 위의 코드는 QuestionService에 있는 코드 중 하나이다.

원래 주석처리 한 부분 대로 사용을 했으나 orElseThrow를 사용해서 코드를 줄일 수 있다고 한다.

 

댓글