5 min to read
[스프링부트 시리즈30] 앵커기능 추가하기
앵커기능 추가하기
이번에는 SBB의 문제점을 해결하려고 한다. 발견된 문제점은 답변을 작성하거나 수정하면 페이지 상단으로 스크롤이 이동해서 자신이 작성한 답변을 확인하려면 다시 스크롤을 내려서 확인해야 한다는 점이다. 이 문제는 답변을 추천한 경우에도 동일하게 발생한다. Ajax와 같은 비동기 통신 기술로 이 문제를 해결할 수도 있지만 여기서는 보다 쉬운 방법을 사용하려고 한다. HTML에는 URL 호출 시 원하는 위치로 이동해 주는 앵커(anchor) 태그 즉, <a>
태그가 있는데, 이를 활용하면 답변 등록, 답변 수정, 답변 추천 시 앵커 태그를 이용하여 원하는 위치로 이동할 수 있다.
답변 앵커 추가하기
앵커 태그인 <a>
태그는 이미 우리에게 익숙하다. 이를 활용해 사용자가 다른 웹 페이지로 이동하거나 동일한 페이지 내에서 특정 위치로 스크롤하도록 만들 수 있다. 먼저 답변 작성, 수정 시에 이동해야 할 앵커 태그를 질문 상세 템플릿에 추가해 보자.
[파일명:/templates/question_detail.html]
(... 생략 ...)
<!-- 답변의 갯수 표시 -->
<h5 class="border-bottom my-3 py-2"
th:text="|${#lists.size(question.answerList)}개의 답변이 있습니다.|"></h5>
<!-- 답변 반복 시작 -->
<div class="card my-3" th:each="answer : ${question.answerList}">
<a th:id="|answer_${answer.id}|"></a>
<div class="card-body">
(... 생략 ...)
답변이 반복되어 표시되도록 하는 th:each
문장 바로 다음에 <a th:id="|answer_${answer.id}|"></a>
와 같이 앵커 태그를 추가했다. 앵커 태그의 id
속성은 유일한 값이어야 하므로 답변의 id
값을 사용했다.
앵커 태그의
id
속성이 유일하지 않고 중복된 값이 존재한다면 맨 처음 한 개를 제외한 나머지 앵커는 제대로 동작하지 않는다.
리다이렉트 수정하기
이제 답변을 등록하거나 수정할 때 앞서 지정한 앵커 태그를 사용해 원하는 화면 위치로 이동할 수 있도록 코드를 수정하려고 한다. 먼저 답변 컨트롤러에서 답변 등록 또는 답변 수정을 하고 난 뒤, URL을 리다이렉트하는 코드를 살펴보자.
return String.format(“redirect:/question/detail/%s”, answer.getQuestion().getId());
이와 같은 코드에 앵커를 포함하여 다음과 같이 수정할 수 있다.
return String.format(“redirect:/question/detail/%s#answer_%s”, answer.getQuestion().getId(), answer.getId());
리다이렉트되는 질문 상세 페이지 URL에 #answer_%s
를 이와 같이 삽입하여 앵커를 추가한 것이다. 이때 수정해야 하는 곳은 총 3곳으로 답변 등록, 수정, 추천 부분에서 리다이렉트와 관련된 코드를 수정하면 된다. 이와 관련된 코드를 수정하기 전에 답변 서비스를 잠시 먼저 수정한 후 진행하도록 하자.
답변 서비스 수정하기
답변 컨트롤러에서 답변이 등록된 위치로 이동하려면 반드시 답변 객체, 즉 Answer
객체가 필요하다. 그동안 AnswerService
에서는 답변 등록 시 답변 객체를 리턴하지 않으므로 다음과 같이 AnswerService
를 먼저 수정해 보자.
[파일명: /answer/AnswerService.java]
(... 생략 ...)
public class AnswerService {
(... 생략 ...)
public Answer create(Question question, String content, SiteUser author) {
Answer answer = new Answer();
answer.setContent(content);
answer.setCreateDate(LocalDateTime.now());
answer.setQuestion(question);
answer.setAuthor(author);
this.answerRepository.save(answer);
return answer;
}
(... 생략 ...)
}
답변 컨트롤러 수정하기
답변 컨트롤러의 리다이렉트와 관련된 코드를 다음과 같이 직접 수정해 보자.
[파일명:/sbb/src/main/java/com/mysite/sbb/answer/AnswerController.java]
(... 생략 ...)
public class AnswerController {
(... 생략 ...)
@PreAuthorize("isAuthenticated()")
@PostMapping("/create/{id}")
public String createAnswer(Model model, @PathVariable("id") Integer id,
@Valid AnswerForm answerForm, BindingResult bindingResult, Principal principal) {
Question question = this.questionService.getQuestion(id);
SiteUser siteUser = this.userService.getUser(principal.getName());
if (bindingResult.hasErrors()) {
model.addAttribute("question", question);
return "question_detail";
}
Answer answer = this.answerService.create(question,
answerForm.getContent(), siteUser);
return String.format("redirect:/question/detail/%s#answer_%s",
answer.getQuestion().getId(), answer.getId());
}
(... 생략 ...)
@PreAuthorize("isAuthenticated()")
@PostMapping("/modify/{id}")
public String answerModify(@Valid AnswerForm answerForm, @PathVariable("id") Integer id,
BindingResult bindingResult, Principal principal) {
if (bindingResult.hasErrors()) {
return "answer_form";
}
Answer answer = this.answerService.getAnswer(id);
if (!answer.getAuthor().getUsername().equals(principal.getName())) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "수정권한이 없습니다.");
}
this.answerService.modify(answer, answerForm.getContent());
return String.format("redirect:/question/detail/%s#answer_%s",
answer.getQuestion().getId(), answer.getId());
}
(... 생략 ...)
@PreAuthorize("isAuthenticated()")
@GetMapping("/vote/{id}")
public String answerVote(Principal principal, @PathVariable("id") Integer id) {
Answer answer = this.answerService.getAnswer(id);
SiteUser siteUser = this.userService.getUser(principal.getName());
this.answerService.vote(answer, siteUser);
return String.format("redirect:/question/detail/%s#answer_%s",
answer.getQuestion().getId(), answer.getId());
}
}
답변을 작성, 수정, 추천한 후에 해당 답변으로 이동할 수 있도록 앵커 태그를 추가했다.
답변 앵커 기능 확인하기
질문 상세 페이지에서 답변을 등록, 수정, 추천을 실행하면 자신이 작업한 답변 부분으로 돌아온다. 즉, 스크롤이 지정한 앵커로 이동함을 확인할 수 있다.
스크롤 이동을 체감하려면 답변 수가 많아야 한다. 앵커 기능을 확인하기 전에 먼저 여러 개의 답변을 등록해 보자.