본문 바로가기
Spring

2022-09-28 스프링 (질문 상세)

by allwing12 2022. 9. 28.
<table>
    <thead>
    <tr>
        <th>글 번호</th>
        <th>제목</th>
        <th>내용</th>
        <th>작성일시</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="question, loop : ${questionList}">
        <td th:text="${question.id}"></td>
        <td>
            <a th:href="@{|/question/detail/${question.id}|}" th:text="${question.subject}"></a>
        </td>
        <td th:text="${question.content}"></td>
        <td th:text="${question.createDate}"></td>
    </tr>
    </tbody>
</table>

 

위의 코드는 질문 목록의 제목을 클릭했을 때 상세화면이 호출되도록 제목에 링크를 추가하는 것이다.

a태그를 사용한게 보이는데 위와 같이 하게 되면 상세페이지 처럼 누를 수 있게 작동을 한다.

타임리프에서 th:href처럼 URL 주소를 나타낼때에는 반드시 @{문자와} 문자 사이에 입력해야한다고 한다.

그리고 URL주소는 문자열 /question/detail/과 ${question.id} 값이 조합되어서

/question/detail/${question/id}로 만들어졌고 이때 좌우에 | 문자 없이 사용하면 오류 발생한다고 한다.

타임리프는 문자열을 연결 할 때 | 문자를 사용한다고 한다.

 

 

 

어쨋든 위와 같이 코드를 한 후에 들어가게 로컬서버에 들어가게 되면 제목이 위와 같이 a 태그 처럼 변한다.

그리고 들어가게 되면 

 

 

 

이렇게 404 에러가 발생을 하는데 당연히 URL 요청에 대한 매핑이 없기 때문이다.

이 오류를 해결하기 위해서는 질문 상세 페이지에 대한 URL 매핑을 해야하고

그 매핑은 QuestionController에 진행을 해야한다.

 

 

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

 

우선 QuestionController에 다가 위와 같은 코드를 추가를 했다.

위의 코드는 id 값으로 Question 데이터를 조회를 하는 getQuestion 메서드를 추가를 한 것이고

리포지터리로 얻은 Question 객체는 Optional 객체라서 위와 같이 isPresent 메서드로 해당

데이터가 존재 하는지에 대한 검사를 하는 로직이 필요하다.

그렇기 때문에 if문을 활용을 해서 id 값에 해당하는 Question 데이터가 있으면 그 데이터를 

없으면 DataNotFoundException을 발생시키도록 한 것인데 DataNotFoundException 클래스도 없고

저런 오류 자체가 존재 하지 않는 커스텀Exception 이라고 생각하면 된다.

그래서 DataNotFoundException 라는 클래스를 만들거다.

 

package com.mysite.sbb.util;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.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);
    }
}

 

새로운 클래스를 만들어서 위와 같은 코드를 작성을 했다.

이 코드는 다음과 같다고 한다.

DataNotFoundException은 RuntimeException을 상속을 한 상태이다

그래서 만약 DataNotFoundException 이 발생을 하게 되면 @ResponseStatus 애너테이션에 의해서

404오류가 나타나게 한 것이다.

 

그리고 이게 QuestionController 에서 QuestionService의 getQuestion 메서드를 호출해서

Question 객체를 템플릿에 전달 할 수 있도록 QuestionController를 수정할거다.

 

 

@RequestMapping("/question/detail/{id}")
public String detail(Model model, @PathVariable Integer id) {
    Question question = questionService.getQuestion(id);
    model.addAttribute("question", question);
    return "Question_Detail";
}

 

이렇게 RequestMapping에 "/question/detail/{id} 라고 한 것은 질문 상세를 눌렀을 때 URL 요청이

localhost:포트번호/question/detail/id 로 들어가지기 때문이다 그렇기 때문에 각 id 마다 해당되는

데이터를 가져오기 위해서 마지막에 {id}를 넣은 것이라고 생각하면 된다.

그리고 이제 html 인 템플릿을 만들어서 해당 화면에 내용이 뜨게만 하면 된다.

그래서 템플릿에 파일에다가 html로 지정해놓고

 

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

 

위와 같은 코드를 만들면 이제 상세 페이지에 질문과 내용이 확인이 될거다.

 

 

이런식으로 확인이 될거고 만약 주소에 없는 id 값을 넣게 되면 아까 만들었던 Exception화면이 뜨는데

그 때 뜨는 오류는 404 오류가 발생을 할 것이다.

 

 

이런식으로 발생을 할 것이다 이렇게 되면 정상적으로 잘 되고 있는거라고 생각을 하면 된다.

그리고 이 때 동안 만든 패키지와 클래스,HTML은 다음 사진과 같다.

 

 

 

보고 있는 교재에서는 파일을 따로 폴더별로 나눠서 하진 않았지만 수업에서는 이렇게

구분하기 쉽게 폴더를 따로 만들어서 구분을 해서 진행을 했기 때문에 만든 패키지들도 많이 있고

그 안에 클래스들과 템플릿에 html 파일이 저렇게 있다고 생각하면 된다.

 

자 마지막으로 URL 프리픽스 라는 것이 있다 이게 뭐냐면 이때동안 만든 것들의 URL 요청을 보게 되면

전부 /question 으로 시작하는 것을 알 수 있는데 이런 경우에는 클래스명 위에 @RequestMapping("/question")

애너테이션을 추가하고 메서드 단 위에서는 /question 을 생략한 그 뒷 부분만 적어도 정상적으로 실행이 된다는 것

 

@RequestMapping("/list")
public String list(Model model) {

    List<Question> questionList = questionService.getList();
    model.addAttribute("questionList", questionList);
    return "question_list";
}
@RequestMapping("/detail/{id}")
public String detail(Model model, @PathVariable Integer id) {
    Question question = questionService.getQuestion(id);
    model.addAttribute("question", question);
    return "Question_Detail";
}

 

위 코드를 보면 원래 list와 deatil 클래스의 @RequestMapping에도 그냥 "/list" , "/detail/{id}" 가 아닌

"/question/list" , "/question/detail/{id} 였던 것을 알 수 있는데 그 부분에서 중복되는 quesion을 없앤

모습을 볼 수 있는데 위에서 말한 것 처럼 URL 프리픽스라고 해서 중복되는 URL 요청을 삭제하고 

전역변수처럼 전역에 @RequestMapping을 "/question" 으로 애너테이션을 추가하면 된다.

 

댓글