<상세 페이지> 에서 Edit 버튼을 만들고, Edit 버튼을 통해 <수정 페이지>에서 내용을 편집하고, 해당 게시물의 데이터를 수정한다!
<a href="/articles/{{article.id}}/edit" class="btn btn-primary">Edit</a>
<상세 페이지>에 해당하는 show.mustache 파일에서 맨 끝에 버튼을 넣는 코드를 추가하였다.
/articles/1/edit 이라면 id가 1인 게시물의 edit 페이지로 이동하는 href도 추가하였다.
해당 show.mustache 뷰 페이지는 ArticleController에서 show() 메서드와 연결되어 있다. show() 메서드 내에서 "article"이라는 이름으로 articleEntity를 모델에 등록하였다.
따라서 show.mustache 뷰 페이지 파일에서
{{article.id}} 로 엔티티의 id에 접근할 수 있다.
<ArticleController의 show() 메서드>
@GetMapping("/articles/{id}")
public String show(@PathVariable Long id, Model model) {
log.info("id = " + id);
Article articleEntity = articleRepository.findById(id).orElse(null);
model.addAttribute("article", articleEntity);
return "articles/show";
}
/articles/{id}/edit 이라는 URL이 요청되면 실행되는 edit() 메서드를 만든다.
@GetMapping("/articles/{id}/edit")
public String edit(@PathVariable Long id, Model model) {
Article articleEntity = articleRepository.findById(id).orElse(null);
model.addAttribute("article", articleEntity);
return"articles/edit";
}
@GetMapping("/articles/{id}/edit")
/articles/{id}/edit 이라는 URL이 요청되면 해당 메소드를 실행한다는 의미
@PathVariable : GetMapping에 있는 id를 그대로 매개변수로 가져오는 어노테이션.
Article articleEntity = articleRepository.findById(id).orElse(null);
리파지터리로 findById(id) 메서드를 호출하여 해당 id의 데이터를 가져와서 articleEntity 라는 엔티티에 저장한다.
model.addAttribute("article", articleEntity);
Model의 addAttribute 메서드를 사용해서 뷰 페이지에서 데이터를 넣을 수 있도록 한다. article 이라는 이름으로 articleEntity 엔티티 데이터를 등록한다.
edit 뷰 페이지는 우선 articles/new 뷰 페이지의 코드를 복붙해온다.
{{>layouts/header}}
{{#article}}
<form class="container" action="/articles/update" method="post">
<input name="id" type="hidden" value="{{id}}">
<div class="mb-3">
<label class="form-label">제목</label>
<input type="text" class="form-control" name="title" value="{{title}}">
</div>
<div class="mb-3">
<label class="form-label">내용</label>
<textarea class="form-control" rows="3" name="content">{{content}}</textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
<a href="/articles/{{id}}">Back</a>
</form>
{{/article}}
{{>layouts/footer}}
edit 페이지의 폼에서는 폼 제출을 하고 나면 /articles/update로 보낼 것이기 때문에 action부분을 수정해준다.
바로 아래 input을 추가해준다.
글을 업데이트할 때 서버가 어떤 글인지 알아야하기 때문에 이 글의 식별자 (id)를 추가해줘야 한다.
Controller의 edit() 메서드에서 article 이라는 이름으로 엔티티를 만들었으니, form 전체는 {{#article}} {{/article}} 로 묶어준다.
title/content의 기본 값이 해당 aritcle의 title/content 값이 들어가 있을 수 있도록 value={{title}} value={{content}} 추가.
Back 버튼을 눌렀을 때는 이전 페이지인 해당 id의 게시글을 보여주는 페이지로 돌아가야하기 때문에 <a href="/articles/{{id}}">Back</a>로 변경
앞에서 edit.mustache에서 폼 데이터를 "/articles/update"로 post 형식으로 보냈다. 따라서, 컨트롤러에서 @PostMapping("/articles/update")가 달린 update() 메서드를 만들어야 한다.
@PostMapping("/articles/update")
public String update(ArticleForm form) {
log.info(form.toString());
Article articleEntity = form.toEntity();
log.info(articleEntity.toString());
Article target = articleRepository.findById(articleEntity.getId()).orElse(null);
if(target != null) {
articleRepository.save(articleEntity);
}
return "redirect:/articles/" + articleEntity.getId();
}
@PostMapping("/articles/update")
/articles/update로 폼 데이터가 전송되면 해당 메소드가 실행된다는 의미.
public String update(ArticleForm form)
edit 페이지에서 폼 데이터를 전송했다. 폼 데이터는 꼭 DTO로 받아와야 하기 때문에 매개변수에 DTO인 ArticleForm 타입을 넣어준다.
Article articleEntity = form.toEntity();
DB에 접근해서 입력/수정/삭제하려면 Entity를 통해서 접근해야 하기 때문에 toEntity() 메서드를 호출하여 articleEntity 객체에 엔티티를 저장한다.
Article target = articleRepository.findById(articleEntity.getId()).orElse(null);
앞서 저장된 articleEntity는 "수정 페이지에서 전달된 폼 데이터"를 가지고 있다. 하지만 여기 target이라는 객체는 "수정 페이지에서 전달된 폼 데이터"의 고유값인 Id에 해당하는 데이터를 의미한다. 즉!!!!! 그 id로 이미!!저장된 데이터!
따라서
if(target != null) { articleRepository.save(articleEntity); }
그 id로 이미 저장된 데이터가 있다면?
리파지터리를 사용하여 "수정 페이지에서 전달된 폼 데이터"를 save 한다.
여기서 save를 하게 되면 데이터는 덮어쓰기 되어 데이터 수정이 된다.
return "redirect:/articles/" + articleEntity.getId(); : return 값으로는 해당 id의 상세 페이지로 이동할 수 있도록 해야 한다. id 부분은 엔티티에 따라 매번 바뀌기 때문에 articleEntity.getId()로 id를 가져오고 리다이렉트를 사용한 /articles/와 + 연산자로 연결시켜준다.
처음에는 하나도 이해가 안됐는데 복습하다보니 점점 감이 잡히고 어떻게 돌아가는건지 이해가 되기 시작했다. 하지만 아직 설명하는 건 참 힘든 것 같다.... 주절 주저리