본 프로젝트는 “스프링부트 3 백엔드 개발자 되기” 서적을 참고하여 진행하였음
트러블슈팅
•
스프링 부트 3.2 버전 매개변수 이름 인식 문제
◦
스프링 부트 3.2부터 매개변수 이름을 인식하지 못하는 문제가 있는데 자바 컴파일러에 -parameter 옵션을 넣어주어야 애노테이션의 이름을 생략할 수 있다.
◦
해당 케이스 같은 경우 빌드 시 Gradle이 아닌 IntelliJ IDEA 로 설정되어 있어서 발생한 문제였다.
◦
Gradle을 사용해서 빌드하고 실행한다. 이렇게 하면 parameter 추가할 필요 없다.
◦
만약에 IntelliJ IDEA 로 유지를 하고 사용해야 한다면 애너테이션 옆에 -parameter 옵션을 추가해주어야 한다.
◦
스프링 부트 3.2 전까지는 바이트코드를 파싱해서 매개변수 이름을 추론하려고 시도했으나 스프링 부트 3.2부터는 이런 시도를 하지 않는다.
그래서 에러가 발생한 것이다.
•
에러 해결 후 정상적으로 글 상세 화면이 잘 나오는 것을 확인할 수 있다.
삭제 기능 구현
•
글 상세 화면에서 [삭제] 버튼을 눌러 글을 삭제하는 기능 구현
// 삭제 기능 - resources/static/js/article.js
const deleteButton = document.getElementById('delete-btn');
if (deleteButton) {
deleteButton.addEventListener('click', event => {
let id = document.getElementById('article-id').value;
fetch(`/api/articles/${id}`, {
method: 'DELETE'
})
.then(() => {
alert('삭제가 완료되었습니다.');
location.replace('/articles');
})
})
}
JavaScript
복사
해당 자바스크립트 코드는 HTML에서 id를 delete-btn으로 설정한 엘리먼트를 찾아 그 엘리먼트에서 클릭 이벤트가 발생하면 fetch() 메서드를 통해 /api/articles/ DELETE 요청을 보내는 역할을 한다.
fetch() 메서드에 이어지는 then() 메서드는 fetch()가 잘 완료되면 연이어 실행되는 메서드이다. alert() 메서드는 then() 메서드가 실행되는 시점에 웹 브라우저 화면으로 삭제가 완료되었음을 알리는
팝업을 띄워주고, location.replace() 메서드는 실행 시 사용자의 웹 브라우저 화면을 현재 주소에 기반하여 옮겨준다.
•
테스트 확인 - 삭제 알람 및 DB에서 삭제된 내용 확인
수정/생성 기능 추가
•
수정 로직 - URL에 ?id=123과 같이 수정할 글의 id를 쿼리 파라미터에 추가해 요청한다.
•
뷰에서는 쿼리 파라미터의 id 여부에 따라 [수정]과 [생성] 중 적절한 버튼을 보여줘야 한다.
◦
쿼리 파라미터
▪
HTTP 요청에서 URL의 끝에 ‘?’로 시작하는 키 값으로 이루어진 문자열이며 ‘&’로 구분한다.
▪
키 : id, 값: 123
▪
쿼리 파라미터가 있는 경우 컨트롤러 메서드 수정이 필요한데 엔티티를 조회하여 기존 글 데이터를 모델에 넣어 화면에 보여줘야 한다.
▪
만약에 쿼리 파라미터가 없다면 새 글이므로 화면에 아무것도 보여줄 필요가 없다.
•
생성 로직
•
수정 화면 보여주기 위한 컨트롤러 작성
// BlogViewController.java
@GetMapping("/new-article")
// id 키를 가진 쿼리 파라미터 값을 id 변수에 매핑(id가 없을 수도 있다)
public String newArticle(@RequestParam(required = false) Long id, Model model) {
if (id == null) { // id가 없으면 생성
model.addAttribute("article", new ArticleViewResponse());
} else { // id가 없으면 수정
Article article = blogService.findById(id);
model.addAttribute("article", new ArticleViewResponse(article));
}
return "newArticle";
}
Java
복사
•
수정/생성 뷰
◦
newArticle.html
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>블로그 글</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"/>
</head>
<body>
<div class="p-5 mb-5 text-center</> bg-light">
<h1 class="mb-3">My Blog</h1>
<h4 class="mb-3">블로그에 오신 것을 환영합니다.</h4>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-lg-8">
<article>
<input type="hidden" id="article-id" th:value="${article.id}">
<header class="mb-4">
<input type="text" class="form-control" placeholder="제목"
id="title" th:value="${article.title}">
</header>
<section class="mb-5">
<textarea class="form-control h-25" rows="10" placeholder="내용"
id="content" th:text="${article.content}"></textarea>
</section>
<button th:if="${article.id} != null" type="button" id="modify-btn" class="btn btn-primary btn-sm">수정</button>
<button th:if="${article.id} == null" type="button" id="create-btn" class="btn btn-primary btn-sm">등록</button>
</article>
</div>
</div>
</div>
</body>
</html>
HTML
복사
◦
article.js
// 수정 기능
// id가 modify-btn인 엘리먼트 조회
const modifyButton = document.getElementById('modify-btn');
if (modifyButton) {
// 클릭 이벤트가 감지되면 수정 API 요청
modifyButton.addEventListener('click', event => {
let params = new URLSearchParams(location.search);
let id = params.get('id');
fetch(`/api/articles/${id}`, { // fetch 메서드를 통해 수정 API로 /api/articles/ PUT 요청 보냄
method: 'PUT',
headers: {
"Content-Type": "application/json", // 요청 형식 지가
},
body: JSON.stringify({ // title과 content를 가져옴
title: document.getElementById('title').value,
content: document.getElementById('content').value
})
})
.then(() => {
alert('수정이 완료되었습니다.');
location.replace(`articles/${id}`);
});
});
}
JavaScript
복사
◦
테스트 확인 - 수정 알람 및 DB에서 수정된 내용 확인