해당 게시글은 점프 투 스프링부트 교재를 통한 개인 학습 용도이며 기초 세팅은 생략하였습니다.
자바 8, 스프링부트 2.7.7버전입니다.
답변 등록 버튼 만들기
<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>
이제 <답변등록> 버튼을 누르면 POST 방식으로 /answer/create/<질문id> URL이 호출(submit)될 것이다. 하지만 아직 /answer/create/<질문id> URL에 대한 매핑이 없으므로 버튼을 누르면 다음과 같은 404 페이지가 나타난다.
답변 서비스 만들기
답변을 저장하는 AnswerService를 작성하자
package com.example.board.answer;
import java.time.LocalDateTime;
import org.springframework.stereotype.Service;
import com.example.board.question.Question;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Service
public class AnswerService {
private final AnswerRepository answerRepository;
public void create(Question question, String content) {
Answer answer = new Answer();
answer.setContent(content);
answer.setCreateDate(LocalDateTime.now());
answer.setQuestion(question);
this.answerRepository.save(answer);
}
}
답변 생성을 위해 create 메서드를 추가했다.
메서드 내의 입력받은 content와 question을 사용하여 객체를 생성하여 리파지토리에 저장했다.
답변 컨트롤러 만들기
package com.example.board.answer;
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;
import com.example.board.question.Question;
import com.example.board.question.QuestionService;
import lombok.RequiredArgsConstructor;
@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 = this.questionService.getQuestion(id);
this.answerService.create(question, content);
return String.format("redirect:/question/detail/%s", id);
}
}
답변 컨트롤러의 URL 프리픽스도 /answer로 고정했다.
그리고 /answer/create/{id}와 같은 URL 요청시 createAnswer 메서드가 호출되도록 @PostMapping으로 매핑했다.
@PostMapping은 @GetMapping과 동일하게 매핑을 담당하는 역할을 하지만 POST요청만 받아들일 경우에 사용한다.
만약 위 URL을 GET방식으로 요청할 경우에는 오류가 발생한다.
@PostMapping(value="/create/{id}") 대신 @PostMapping("/create/{id}") 처럼 value는 생략해도 된다.
그리고 createAnswer 메서드의 매개변수에는 @RequestParam String content 항목이 추가되었다.
이 항목은 템플릿에서 답변으로 입력한 내용(content)을 얻기 위해 추가되었다.템플릿의 답변 내용에 해당하는 textarea의 name 속성명이 content이기 때문에 여기서도 변수명을 content로 사용해야 한다.
만약 content 대신 다른 이름으로 사용하면 오류가 발생할 것이다.
createAnswer 메서드의 URL 매핑 /create/{id}에서 {id}는 질문의 id 이므로 이 id 값으로 질문을 조회하고 없을 경우에는 404 오류가 발생할 것이다.
AnswerService의 create 메서드를 호출하여 답변을 저장할수 있게 했다.
질문 상세 페이지 답변 표시하기
<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>
기존 코드에서 답변을 확인할 수 있는 영역을 추가했다.
#lists.size(question.answerList)}는 답변 개수를 의미한다.
#lists.size(이터러블객체)는 타임리프가 제공하는 유틸리티로 객체의 길이를 반환한다.
답변은 question 객체의 answerList를 순회하여 <li> 엘리먼트로 표시했다.
2023.04 ~ 백엔드 개발자의 기록
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!