3/21 TIL - 점프투스프링부트 따라하기2

큰모래·2023년 3월 21일
0
post-custom-banner

점프투스프링부트 따라하기


2-07. 질문 목록과 템플릿


QuestionController

  • list를 조회할 때 JpaRepositoryfindAll 을 통해 전체 목록 객체를 만든다.
  • 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";
    }
}

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>

2-09. 서비스


QuestionService

  • QuestionController에서 QuestionRepository에 접근하는 것이 아닌 QuestionService에서 접근한다. ( QuestionController → QuestionService → QuestionRepository)

@Service
@RequiredArgsConstructor
public class QuestionService {

    private final QuestionRepository questionRepository;

    public List<Question> getList() {
        return questionRepository.findAll();
    }
}

QuestionController

  • QuestionServicegetList 메서드를 통해 리스트를 불러온다.

@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";
    }
}

2-10. 질문 상세

질문 목록 리스트에서 제목을 클릭했을 때 질문 상세 링크로 넘어가는 기능을 추가해보자!


QuestionController 추가

  • @PathVariable : 경로 변수로 넘어온 id를 인자로 받는다.
  • questionServicegetQuestion을 통해 question 객체를 받는다.
  • 받은 question 객체를 modelview 페이지에 넘겨준다.
		@GetMapping("/detail/{id}")
    public String detail(@PathVariable Long id, Model model) {
        Question question = questionService.getQuestion(id);
        model.addAttribute("question", question);
        return "question_detail";
    }

QuestionService 추가

  • JpaRepositoryfindById를 통해 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");
		}

DataNotFoundException

  • 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);
    }
}

question_list

  • 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>

question_detail

<!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>

2-11. 답변 등록


질문에 답변을 등록하는 기능을 만들어 봅시다!
답변 내용 추가 후 버튼 클릭 → 질문 상세글에 답변 저장 및 답변 리스트 쫘악 보여주기

AnswerController

  • createAnswer 메서드를 통해 답변을 등록한다.
  • 이때, 매개변수로 경로변수 id와 답변 내용을 저장할 content를 받는다.
  • questionServicegetQuestion을 통해 idquestion 객체를 반환받는다.
  • answerServicecreate메서드를 통해 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;
    }

}

AnswerService

  • 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_detail

  • questionanswer는 양방향 참조 관계이므로 answer를 저장하면 question에서도 답변을 확인할 수 있다.
  • ${#lists.size(question.answerList)} : answerList의 크기를 반환받는다.
  • th:each를 통해 question.answerListanswer 객체들을 조회한다.
<!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>
profile
큰모래
post-custom-banner

0개의 댓글