<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를 사용해서 코드를 줄일 수 있다고 한다.
'Spring' 카테고리의 다른 글
| 2022-10-04 스프링(질문 등록 폼 생성) (0) | 2022.10.04 |
|---|---|
| 2022-09-30 스프링(부트스트랩) (1) | 2022.09.30 |
| 2022-09-28 스프링 (질문 상세) (0) | 2022.09.28 |
| 2022-09-28 스프링 (서비스) (0) | 2022.09.28 |
| 2022-09-27 스프링(질문 목록 및 템플릿 / Root URL) (0) | 2022.09.27 |
댓글