(코딩 자율학습 스프링 부트3) 4장
게시글 Update
게시판에 작성한 글을 수정하기 위해서는 해당 글을 불러와 수정할 수 있는 입력 상태로 만들어야 한다 이후 내용을 입력하고 다시 전송하면 DB에 반영돼 최종적으로 수정된다
[수정 단계]
<상세 페이지>
에서 [Edit] 버튼을 클릭한다- 요청을 받은 컨트롤러는 해당 글의 id로 DB에서 데이터를 찾아 가져온다
- 컨트롤러는 가져온 데이터를 뷰에서 사용할 수 있도록 모델에 등록한다
- 모델에 등록된 데이터를
<수정 페이지>
에서 보여 준다 그러면 사용자가 내용을 수정할 수 있는 상태가 된다 - 폼 데이터(수정 요청 데이터)를 DTO에 담아 컨트롤러에서 받는다
- DTO를 엔티티로 변환한다
- DB에서 기존 데이터를 수정 데이터로 갱신한다
- 수정 데이터를
<상세 페이지>
로 리다이렉트 한다
<상세 페이지>
에서 Edit 버튼 생성
- show.mustache 파일
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{{>layouts/header}}
{{#article}}
<table class="table">
<thead>
<tr>
<th scope="col">Id</th>
<th scope="col">Title</th>
<th scope="col">Content</th>
<th scope="col">Handle</th>
</tr>
</thead>
<tbody>
<tr>
<th>{{id}}</th>
<td>{{title}}</td>
<td>{{content}}</td>
</tr>
</tbody>
</table>
<a href="/articles/{{article.id}}/edit" class="btn btn-primary">Edit</a>
<a href="/articles/{{article.id}}/delete" class="btn btn-danger">Delete</a>
<a href="/articles">Go to Article List</a>
{{/article}}
{{>layouts/footer}}
href 속성 값의 URL을 보면 id가 article의 속성이므로 {{article.id}}로 사용했는데 표 보통 article의 사용 범위를 {{#article}}{{/article}} 형식으로 지정한 경우에는 {{id}}만 써도 되지만 범위를 따로 지정하지 않았다면 점(.)을 사용해 {{article.id}}라고 표시해야 한다
<상세 페이지>
에서 Edit 버튼을 누를시 <수정 페이지>
로 이동할 수 있도록 Controller에서 맵핑 라우팅을 추가한다
- ArticleController 파일
1
2
3
4
5
6
7
8
9
10
11
@GetMapping("/articles/{id}/edit")
public String edit(@PathVariable Long id, Model model) {
//수정할 데이터 가져오기
Article articleEntity = articleRepository.findById(id).orElse(null); // db에서 수정할 데이터 가져오기
//모델에 데이터 등록하기
model.addAttribute("article", articleEntity);//articleEntity를 article로 등록
// 뷰페이지 설정하기
return "articles/edit";
}
[Tip]
- public String edit(
@PathVariable
Long id, Model model) 부분에서@PathVariable
는 id변수가 URL 주소에 있는 id변수를 받아 오는 것으로 어노테이션을 특정 지정해야한다Model model
은 모델을 사용하기 위해model 객체
를 받아온다addAttribute()
메서드로 모델에 데이터를 등록한다article
이라는 이름으로 앞에서 가져온articleEntity
를 등록한다(이렇게 하면 DB에서 가져온 데이터를article
이라는 이름으로 뷰 페이지에서 사용할 수 있다)
<수정 페이지>
파일 생성
- edit.mustache 파일
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{{>layouts/header}}
{{#article}}
<form class="container" action="/articles/update" method="post"> <!-- 부트스트랩 css코드 -->
<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}}"> <!-- DTO의 title 필드와 연결 -->
</div>
<div class="mb-3">
<label class="form-label">내용</label>
<textarea class="form-control" rows="3" name="content">{{content}}</textarea> <!-- DTO의 content 필드와 연결 -->
</div>
<button type="submit" class="btn btn-primary">Submit</button>
<a href="/articles/{{id}}">Back</a>
</form>
{{/article}}
{{>layouts/footer}}
<수정 페이지>
에서 Submit 버튼을 누를시 DB에 수정된 값으로 반영하고 리다이렉션을 위한 라우팅 추가
- ArticleController 파일
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@PostMapping("/articles/update")
public String update(ArticleForm form) {// 매개변수로 DTO 받아 오기
log.info(form.toString()); // DTO 데이터가 잘들어있는지 로그 찍기
Article articleEntity = form.toEntity(); //DTO(form)를 엔티티(articleEntity)로 변환하기
log.info(articleEntity.toString()); //엔티티로 잘 변환됐는지 로그 찍기
//DB에서 기존 데이터 가져오기
Article target = articleRepository.findById(articleEntity.getId()).orElse(null);
//기존 데이터 값을 갱신하기
if (target != null) {
articleRepository.save(articleEntity); // 엔티티를 DB에 저장(갱신)
}
return "redirect:/articles/" + articleEntity.getId();
}
sequenceDiagram
edit(수정페이지)->>+DTO(컨트롤러): 데이터 수정 요청 (HTTP)
DTO(컨트롤러)->>+엔티티(리파지터리): DTO를 엔티티로 변환
엔티티(리파지터리)->>+SQL: DB 갱신 (JPA)
SQL ->>+edit(수정페이지): 리다이렉트
- MVC(Model-View-Controller): 서버 역할을 분담해 처리하는 기법
- JPA(Java Persisitence API): 서버와 DB 간 소통에 관여하는 기술
- SQL(Structured Query Language): DB 데이터를 관리하는 언어
- HTTP(HyperText Transfer Protocol): 데이터를 주고받기 위한 통신 규약
게시글 Delete
[삭제 단계]
- 클라이언트가 http 메서드로 특정 게시글의 삭제를 요청
- 삭제 요청을 받은 컨트롤러는 리파지터리를 통해 db에 저장된 데이터를 찾아 삭제한다 이 작업은 기존 데이터가 있는 경우에만 수행된다
- 삭제가 완료되면 클라이언트를 결과 페이지로 리다이렉트한다
sequenceDiagram
show(상세페이지)->>+컨트롤러: /articles/{id}/delete
컨트롤러->>+리파지터리: delete(id)
컨트롤러->>+show(상세페이지): redirect:/articles
[Tip] 결과 페이지로 리다이렉트할 때 클라이언트에게 삭제 완료 메시지를 띄워주고 싶다면 사용되는 클래스가
RedirectAttributes
이다RedirectAttributes
객체의addFlashAttribute()
라는 메서드는 리다이렉트된 페이지에서 사용할 일회성 데이터를 등록할 수 있다
<상세 페이지>
삭제 버튼 추가하기
- show.mustache 파일
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{{>layouts/header}}
{{#article}}
<table class="table">
<thead>
<tr>
<th scope="col">Id</th>
<th scope="col">Title</th>
<th scope="col">Content</th>
<th scope="col">Handle</th>
</tr>
</thead>
<tbody>
<tr>
<th>{{id}}</th>
<td>{{title}}</td>
<td>{{content}}</td>
</tr>
</tbody>
</table>
<a href="/articles/{{article.id}}/edit" class="btn btn-primary">Edit</a>
<a href="/articles/{{article.id}}/delete" class="btn btn-danger">Delete</a>
<a href="/articles">Go to Article List</a>
{{/article}}
{{>layouts/footer}}
컨트롤러
에서 삭제 요청에 따른 처리 만들기
- ArticleController 파일
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@GetMapping("/articles/{id}/delete") //URL 요청 접수
public String delete(@PathVariable Long id, RedirectAttributes rttr) { //메서드 생성 및 null 값 반환
log.info("삭제 요청이 들어왔습니다!!");
// 1. 삭제할 대상 가져오기
Article target = articleRepository.findById(id).orElse(null);
log.info(target.toString());
// 2. 대상 엔티티 삭제하기
if (target != null) { //삭제할 대상이 있는지 확인
articleRepository.delete(target); //delete() 메서드로 대상 삭제
rttr.addFlashAttribute("msg", "삭제됐습니다!");
}
// 3. 결과 페이지로 리다이렉트하기
return "redirect:/articles";
}
[Tip]
- 삭제할 대상 가져오기 DB에 접근해 데이터를 처리할 때는 JPA의 리파지터리를 이용한다
articleRepository.findById(id)
메서드로 DB에 해당 id를 가진 데이터가 있는지 찾아서 만약 찾으면Article
타입의target
변수에 저장하고, 찾지 못하면null을
반환findById(id)
를 호출할 때 사용한 id 변수는 delete() 메서드에 선언되지 않았다 이 id는@GetMapping("/articles/{id}/delete")
의 URL 주소에서 가져오므로 delete() 메서드의 매개변수로@PathVariable Long id
를 써준다
This post is licensed under
CC BY 4.0
by the author.