2023.08.08 ~ 08.10 수업
교재 : 스프링부트3 백엔드 개발자 되기
◎ 블로그 화면 구성하기
- 템플릿 엔진(타임리프) 이용
- 글 목록, 글 내용, 수정 화면으로 구성
2023.08.09 - [백엔드/웹 개발] - 블로그 화면 구성하기 - 타임리프3 (블로그 글 뷰 구현하기)
블로그 화면 구성하기 - 타임리프3 (블로그 글 뷰 구현하기)
2023.08.07 수업 교재 : 스프링부트3 백엔드 개발자 되기 ☆ 데이터베이스 오라클과 연결하기 1. build.gradle 설정 - 오라클 사용(기존에 설정해 둔 주석 열기) - h2 주석 닫기 runtimeOnly 'com.oracle.database.jdb
dustj0824.tistory.com
이어서
▶ 블로그 글 삭제하기
- 컨트롤러에서 삭제 요청
- /api/articles/${id} 로 요청이 온 글 삭제하기 구현
-> service의 deleteById() 가 사용됨
0. API 관련 클래스 작성
0-1) BlogApiController 작성
package net.choongang.ewha.hithymeleaf.controller;
@RequiredArgsConstructor
@RestController
public class BlogApiController {
private final BlogService blogService;
// 1. addArticle() : 글을 생성하고 생성된 블로그 글 반환
@PostMapping("/api/articles")
public ResponseEntity<Article> addArticle(@RequestBody AddArticleRequest request) {
Article savedArticle = blogService.save(request);
return ResponseEntity.status(HttpStatus.CREATED)
.body(savedArticle);
}
// 2. findAllArticles() : 글 목록 조회하고 응답
@GetMapping("/api/articles")
public ResponseEntity<List<ArticleResponse>> findAllArticles() {
List<ArticleResponse> articles = blogService.findAll()
.stream()
.map(ArticleResponse::new)
.toList();
return ResponseEntity.ok()
.body(articles);
}
// 3. findArticle() : 지정 글 조회하고 응답 (상세보기 기능에 해당)
@GetMapping("/api/articles/{id}")
public ResponseEntity<ArticleResponse> findArticle(@PathVariable long id) {
Article article = blogService.findById(id);
return ResponseEntity.ok()
.body(new ArticleResponse(article));
}
// 4. deleteArticle() : 지정 글 삭제(응답은 필요 없음)
@DeleteMapping("/api/articles/{id}")
public ResponseEntity<Void> deleteArticle(@PathVariable long id) {
blogService.deleteById(id);
return ResponseEntity.ok()
.build();
}
// 5. updateArticle() : 지정 글 수정하고 응답
@PutMapping("/api/articles/{id}")
public ResponseEntity<Article> updateArticle(@PathVariable long id,
@RequestBody UpdateArticleRequest request) {
Article updatedArticle = blogService.update(id, request);
return ResponseEntity.ok()
.body(updatedArticle);
}
}
0-2) ArticleResponse 작성
- 요청에 응답할 DTO
- 글을 응답해준다(제목, 내용으로 구성됨)
- 삭제에서는 필요 없는 부분이지만 컨트롤러를 만들 때 글 조회 메소드를 처리하기 위해 만들어주어야 함
package net.choongang.ewha.hithymeleaf.dto;
@Getter
// Article엔티티의 응답용 객체로 임시저장용이므로 데이터 변수구조는 같고 메소드는 생성자만 있으면 됨
// 임시객체이므로 VO객체가 아니라 DTO객체
public class ArticleResponse {
private final String title;
private final String content;
public ArticleResponse(Article article) {
this.title = article.getTitle();
this.content = article.getContent();
}
}
1. 삭제 기능 코드 작성하기
1-1. HTML 수정하기
- 삭제버튼에 id 값 주기
- 블로그 글 id 추가
- article.js 임포트 하기
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>블로그 글</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/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">
<div class="row">
<div class="col-lg-8">
<article>
<!-- 블로그 글 id 추가 -->
<input type="hidden" id="article-id" th:value="${article.id}">
<header class="mb-4">
<h1 class="fw-bolder mb-1" th:text="${article.title}"></h1>
<div
class="text-muted fst-italic mb-2"
th:text="|Posted on ${#temporals.format(article.createdAt, 'yyyy-MM-dd HH:mm')} |"
></div>
</header>
<section class="mb-5">
<p class="fs-5 mb-4" th:text="${article.content}"></p>
</section>
<button type="button" class="btn btn-primary btn-sm">수정</button>
<button type="button" id="delete-btn" class="btn btn-secondary btn-sm">삭제</button>
</article>
</div>
</div>
</div>
<!-- article.js 파일 추가 -->
<script src="/js/article.js"></script>
</body>
</html>
<input type=“hidden”>
사용자에게는 보이지 않는 숨겨진 입력 필드를 정의
숨겨진 입력 필드는 폼 제출 시에 사용자가 변경해서는 안 되는 데이터를 함께 보낼 때 사용
ex) 데이터베이스 테이블의 Primary Key 값
이 Primary Key 값을 통해 데이터베이스에서 해당 레코드를 식별하여 정보를 알맞게 삭제/수정
1-2 자바스크립트 사용
-> crud중에 create update delete 실행 시 에러검사나 실행 기능 검사를 목적
경로 : HiThymeleaf/src/main/resources/static
폴더 : js
파일명 : article.js
- 람다함수 사용
- HTML에서 id로 설정한 엘리먼트를 찾아(getElementById) 그 엘리먼트에서 클릭 이벤트가 발생하면 fetch()를 통해 DELETE요청을 보내는 역할
- deleteButton 객체에 'click' 이벤트를 addEventListener()로 등록. 이때 fetch()를 사용하여 비동기 처리할 콜백함수 정의
// 삭제버튼이 눌렸으면 그 삭제버튼의 이벤트 핸들러 등록
// 삭제버튼의 html태그 얻어오기
const deleteButton = document.getElementById('delete-btn');
// deleteButton이 있으면 이벤트 등록
if(deleteButton) {
deleteButton.addEventListener('click', event => {
let id = document.getElementById('article-id').value;
fetch(`/api/articles/${id}`, {
method: 'DELETE'
})
.then(()=> {
alert('삭제가 완료되었습니다.');
location.replace('/articles'); // 리스트 화면으로 이동
});
});
}
1) 정식함수
function 함수명(매개변수..) {
return;
}
2) 익명함수
- 함수명이 없는 함수
- 콜백함수 정의에 사용
- 로컬변수에 값으로 대입
- 인라인 익명함수
3) 람다함수(화살표 함수)
- 익명함수를 화살표를 사용하여 간단하게 만듦
- 기본적으로 리턴값이 있음(마지막 계산 값)
fetch() : HTTP response 객체를 래핑한 Promise 객체를 반환한다. 따라서 프로미스의 후속 처리 메서드인 then을 사용
- 가져오고자 하는 리소스의 경로를 나타내는 하나의 인수를 가짐
then() : 서버응답결과를 처리한다. fetch()가 잘 완료되면 연이어 실행된다. 응답결과를 처리할 함수가 정의됨
alert() : then()이 실행되는 시점에 웹 브라우저 화면으로 삭제가 완려되었음을 알려주는 경고창
location.replace() : 기존 주소 덮어쓰기(전으로 돌리기 불가). 실행 시 사용자의 웹 브라우저 화면을 현재 주소를 기반해 옮겨줌
-> assign()을 사용하면 새롭게 이동하는 것이므로 히스토리가 남아 이전으로 돌아갈 수 있는 위험 발생
* fetch :
자바스크립트 API 라이브러리
주로 비동기 방식으로 ajax의 단점(불편하고 복잡한 응답처리와 연속된 callback 호출 등)을 해결하기위해 나온 Rest방식(UI가 없다)에 적합하다
fetch(`/api/articles/${id}`, { // 요청정보 : 없음
method: 'DELETE' // 요청메소드 : delete
}) // 실제 요청하는 주소는 경로변수를 이용한 방법으로 데이터 전송
- 요청정보 : post, put으로 요청하는 경우 폼데이터
★ 기능 추가해보기
* 구현하고자 하는 기능
- 삭제버튼을 누르면 '삭제를 하시겠습니까 ?' 라는 확인 문구 출력하여
확인을 누르면 글 삭제, 취소를 누르면 글이 삭제되지 않는 기능
- 자바스크립트의 confirm() 메서드 활용
const deleteButton = document.getElementById('delete-btn');
// deleteButton이 있으면 이벤트 등록
if(deleteButton) {
deleteButton.addEventListener('click', event => {
console.log('삭제 버튼 작동')
let id = document.getElementById('article-id').value;
if(confirm(`${id}` + "를 삭제 하시겠습니까?")) {
fetch(`/api/articles/${id}`, {
method: 'DELETE'
})
.then(()=> {
alert('삭제가 완료되었습니다.');
location.replace('/articles');
});
} else {
alert('취소 되었습니다.');
}
});
}
'백엔드 > 웹 개발' 카테고리의 다른 글
Maven 프로젝트 Gradle로 변환하기 (0) | 2023.08.16 |
---|---|
블로그 화면 구성하기 - 타임리프5 (블로그 글 수정/생성 기능 추가하기) (0) | 2023.08.11 |
필터, 정규표현식 (0) | 2023.08.03 |
리스너(Listener) (0) | 2023.07.04 |
사용자 정의 쿠키(자동로그인) (0) | 2023.07.03 |