list
를 조회할 때 JpaRepository
의 findAll
을 통해 전체 목록 객체를 만든다.model.addAttribute
를 통해 View
로 모델 객체를 넘긴다.@Controller
@RequestMapping("/question")
@RequiredArgsConstructor
public class QuestionController {
private final QuestionRepository questionRepository;
@GetMapping("/list")
public String list(Model model) {
List<Question> questionList = questionRepository.findAll();
model.addAttribute("questionList", questionList);
return "question_list";
}
}
th:each
를 통해 questionList
에서 question
객체를 하나하나씩 꺼낸다. (반복문)th:text
를 통해 꺼낸 question
객체의 원소를 출력한다.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<table>
<thead>
<tr>
<th>제목</th>
<th>작성일지</th>
</tr>
</thead>
<tbody>
<tr th:each="question : ${questionList}" >
<td th:text="${question.subject}"></td>
<td th:text="${question.createData}"></td>
</tr>
</tbody>
</table>
</html>
QuestionController
에서 QuestionRepository
에 접근하는 것이 아닌 QuestionService
에서 접근한다. ( QuestionController → QuestionService → QuestionRepository)
@Service
@RequiredArgsConstructor
public class QuestionService {
private final QuestionRepository questionRepository;
public List<Question> getList() {
return questionRepository.findAll();
}
}
QuestionService
의 getList
메서드를 통해 리스트를 불러온다.
@Controller
@RequestMapping("/question")
@RequiredArgsConstructor
public class QuestionController {
private final QuestionService questionService;
@GetMapping("/list")
public String list(Model model) {
List<Question> questionList = questionService.getList();
model.addAttribute("questionList", questionList);
return "question_list";
}
}
질문 목록 리스트에서 제목을 클릭했을 때 질문 상세 링크로 넘어가는 기능을 추가해보자!
@PathVariable
: 경로 변수로 넘어온 id
를 인자로 받는다.questionService
의 getQuestion
을 통해 question
객체를 받는다.question
객체를 model
로 view
페이지에 넘겨준다. @GetMapping("/detail/{id}")
public String detail(@PathVariable Long id, Model model) {
Question question = questionService.getQuestion(id);
model.addAttribute("question", question);
return "question_detail";
}
JpaRepository
의 findById
를 통해 Optional
객체를 반환받는다.Optional
객체가 null
이 아니라면 question
객체를 리턴null
이라면 임의로 정의한 DataNotFoundException
을 발생시킨다.
public Question getQuestion(Long id) {
Optional<Question> question = questionRepository.findById(id);
if (question.isPresent()) {
return question.get();
}
throw new DataNotFoundException("question not found");
}
ResponseStatus
를 통해 응답상태를 지정할 수 있다.
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "entity not found")
public class DataNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public DataNotFoundException(String message) {
super(message);
}
}
th:href
를 통해 동적으로 페이지 링크를 연결한다.||
를 통해 문자열과 타임리프 객체를 같이 사용할 수 있다.<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<table>
<thead>
<tr>
<th>제목</th>
<th>작성일지</th>
</tr>
</thead>
<tbody>
<tr th:each="question : ${questionList}" >
<td>
<a th:href="@{|/question/detail/${question.id}|}" th:text="${question.subject}"></a>
</td>
<td th:text="${question.createData}"></td>
</tr>
</tbody>
</table>
</html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${question.subject}"></h1>
<div th:text="${question.content}"></div>
</body>
</html>
질문에 답변을 등록하는 기능을 만들어 봅시다!
답변 내용 추가 후 버튼 클릭 → 질문 상세글에 답변 저장 및 답변 리스트 쫘악 보여주기
createAnswer
메서드를 통해 답변을 등록한다.id
와 답변 내용을 저장할 content
를 받는다.questionService
의 getQuestion
을 통해 id
로 question
객체를 반환받는다.answerService
의 create
메서드를 통해 question
객체와 content
로 답변을 생성한다.
@Controller
@RequestMapping("/answer")
@RequiredArgsConstructor
public class AnswerController {
private final QuestionService questionService;
private final AnswerService answerService;
@PostMapping("/create/{id}")
public String createAnswer(@PathVariable Long id, @RequestParam String content) {
Question question = questionService.getQuestion(id);
answerService.create(question, content);
return "redirect:/question/detail/" + id;
}
}
answer
객체를 생성하고 원소값을 주입한다.answerRepository
에 객체 저장
@Service
@RequiredArgsConstructor
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);
answerRepository.save(answer);
}
}
question
과 answer
는 양방향 참조 관계이므로 answer
를 저장하면 question
에서도 답변을 확인할 수 있다.${#lists.size(question.answerList)}
: answerList
의 크기를 반환받는다.th:each
를 통해 question.answerList
의 answer
객체들을 조회한다.<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<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>
</body>
</html>