Controller - 리뷰 메인화면 호출
// 리뷰 메인 화면
@GetMapping("/review")
public String reviewMain(Model model, HttpSession session) {
List<Review> reviews = reviewService.getAllReview();
model.addAttribute("reviews", reviews);
return "review/reviewMain";
}
- @GetMapping("/review") 메서드는 메인 페이지를 요청할 때 호출됩니다.
- 리뷰 목록 조회: reviewService.getAllReview() 메서드를 통해 전체 리뷰 목록을 가져오고, 이를 reviews라는 이름으로 모델에 추가하여 템플릿에서 사용할 수 있도록 합니다.
Review Main 페이지 ( reviewMain.html )
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>Review Main Page</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11.4.10/dist/sweetalert2.min.css">
<link rel="stylesheet" th:href="@{/css/review.css}">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.4.10/dist/sweetalert2.min.js"></script>
<script th:src="@{/js/review.js}"></script>
</head>
<body>
<th:block th:insert="~{include/header}"></th:block>
<div class="review-main-container">
<h1>리뷰</h1>
<h3>다른 회원이 작성한 리뷰를 읽거나, 나만의 리뷰를 작성해 보세요.</h3>
<a class="review-write-btn" th:href="@{/review-write}">리뷰 작성</a>
<div class="review-list">
<h2>리뷰 목록</h2>
<div class="search-container">
<form id="search_review" method="get">
<select name="searchType">
<option value="search_id">ID</option>
<option value="search_title">제목</option>
</select>
<input type="search" id="search" name="keyword" placeholder="검색어를 입력하세요." />
<button type="button" onclick="search_review()">검색</button>
</form>
</div>
<div th:if="${reviews.isEmpty()}">
<p>작성된 리뷰가 없습니다.</p>
</div>
<div th:unless="${reviews.isEmpty()}">
<div class="review-items">
<div class="review-box" th:each="review : ${reviews}">
<a th:href="@{/review_detail(review_seq=${review.review_seq})}">
<th:block th:if="${#lists.isEmpty(review.uploadedImages)}">
<img th:src="@{/images/no_img.jpg}" alt="이미지 없음" style="width:200px; height:200px;">
</th:block>
<th:block th:unless="${#lists.isEmpty(review.uploadedImages)}">
<div th:with="firstImage=${review.uploadedImages[0]}">
<img th:src="@{${firstImage}}" th:alt="${review.title}" style="width:200px; height:200px;">
</div>
</th:block>
</a>
<h4>제목 : <span th:text="${review.title}"></span></h4>
<h4>작성자 : <span th:text="${review.member.id}"></span></h4>
<h4>조회수 : <span th:text="${review.viewCount}"></span> /
추천수 : <span th:text="${review.recoCount}"></span></h4>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
<a class="review-write-btn" th:href="@{/review-write}">리뷰 작성</a>를 누르면 /review-write URL로 이동합니다.
Controller - 리뷰 작성 화면 호출
// 리뷰 작성 화면
@GetMapping("/review-write")
public String reviewWriteView(Model model, HttpSession session) {
Member loginUser = (Member)session.getAttribute("loginUser");
if(loginUser == null) {
model.addAttribute("message", "로그인 페이지로 이동");
model.addAttribute("text", "리뷰 작성은 로그인 후 이용 가능합니다.");
model.addAttribute("messageType", "info");
return "login/login";
}
return "review/reviewWrite";
}
세션에서 로그인된 사용자의 정보를 확인합니다. 로그인되지 않은 경우, 사용자에게 로그인 페이지로 이동하라는 메시지를 출력하며, 리뷰 작성 페이지에 접근하지 못하도록 합니다.
Review Write 페이지 ( reviewWrite.html )
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>Review Write</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11.4.10/dist/sweetalert2.min.css">
<link rel="stylesheet" th:href="@{/css/review.css}">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.4.10/dist/sweetalert2.min.js"></script>
<script th:src="@{/js/review.js}"></script>
</head>
<body>
<th:block th:insert="~{include/header}"></th:block>
<div class="review-write-container">
<h1>리뷰 작성</h1>
<div class="review-write-content">
<form class="review-write-form" id="review-write-form" method="post" enctype="multipart/form-data">
<input type="text" id="title" name="title" placeholder="제목을 입력해주세요." />
<textarea rows="10" cols="20" name="content" id="content" placeholder="내용을 입력해주세요."></textarea>
<label for="uploadFile">이미지 업로드 (선택 사항):</label>
<input class="uploadFile" type="file" name="uploadFile" id="uploadFile" multiple>
</form>
</div>
<button class="write-btn" type="button" onclick="window.location.href='/review'">목록으로</button>
<button class="write-btn" type="button" onclick="review_write()">리뷰 작성</button>
</div>
</body>
</html>
- 리뷰 작성 페이지(reviewWrite.html)에서는 사용자가 리뷰 제목과 내용을 입력하고, 선택적으로 이미지를 업로드할 수 있습니다.
- 이 폼은 POST 방식으로 /review-write-action 경로에 제출되며, 파일 업로드를 위해 enctype="multipart/form-data" 속성이 설정되어 있습니다.
리뷰 작성 JavaScript 함수 - review_write()
function review_write() {
if($("#title").val() == "") {
swal.fire({
title: '제목을 입력해주세요.',
text: '제목은 필수 입력 항목 입니다.',
icon: 'warning',
confirmButtonText: '확인'
});
$("#title").focus();
return false;
} else if($("#content").val() == "") {
swal.fire({
title: '내용을 입력해주세요.',
text: '내용은 필수 입력 항목 입니다.',
icon: 'warning',
confirmButtonText: '확인'
});
$("#content").focus();
return false;
} else {
swal.fire({
title: '리뷰 작성 성공!',
text: '리뷰 목록 페이지로 이동합니다.',
icon: 'success',
confirmButtonText: '확인'
}).then((result) => {
if (result.isConfirmed) {
$("#review-write-form").attr("action", "/review-write-action").submit();
}
});
}
}
- 필수 입력 항목이 비어있을 경우 경고 메시지를 표시하고 입력을 유도합니다.
- 입력이 올바르면 SweetAlert2를 사용하여 작성 성공 메시지를 표시하고, review-write-form을 /review-write-action 경로로 제출합니다.
리뷰 작성 처리 Controller 메서드 작
// 리뷰 작성 처리
@PostMapping("/review-write-action")
public String reviewWriteAction(Review vo, Model model, HttpSession session,
@RequestParam("uploadFile") MultipartFile[] uploadFile) {
Member loginUser = (Member)session.getAttribute("loginUser");
if(loginUser == null) {
model.addAttribute("message", "로그인 페이지로 이동");
model.addAttribute("text", "리뷰 작성은 로그인 후 이용 가능합니다.");
model.addAttribute("messageType", "info");
return "login/login";
}
vo.setMember(loginUser); // 로그인한 사용자 정보를 리뷰에 설정
List<String> fileUrls = new ArrayList<>();
for (MultipartFile file : uploadFile) {
if (!file.isEmpty()) {
// 파일 경로
String uploadDir = "C:/ThisIsJava/SpringBootWorkspace/Book/uploads/";
// 파일 이름 수정
String originalName = file.getOriginalFilename();
String fileExtension = originalName.substring(originalName.lastIndexOf("."));
String uuid = UUID.randomUUID().toString();
String fileName = uuid + fileExtension;
try {
// 파일 저장
FileUploadUtil.saveFile(uploadDir, fileName, file);
// URL 생성
String fileUrl = "/uploads/" + fileName;
fileUrls.add(fileUrl);
} catch (IOException e) {
e.printStackTrace();
model.addAttribute("message", "파일 업로드 중 오류 발생");
model.addAttribute("messageType", "error");
return "review/review-write";
}
vo.setUploadedImages(fileUrls); // 저장된 파일 경로를 Review 객체에 설정
}
}
reviewService.insertReview(vo);
return "redirect:/review";
}
- 로그인 확인: 사용자가 로그인 상태인지 세션을 통해 확인하며, 미로그인 상태에서는 로그인 페이지로 리다이렉트합니다.
- 업로드 파일 처리:
- 업로드된 파일 배열(MultipartFile[])을 반복하며 각 파일을 지정된 경로에 저장합니다.
- 각 파일의 이름을 고유하게 설정하여 중복을 피하고, 이를 URL 형태로 변환하여 fileUrls 리스트에 추가합니다.
- 리뷰 정보 저장:
- 작성된 리뷰 정보와 업로드된 이미지 경로(fileUrls) 리스트를 Review 객체에 설정하고, reviewService.insertReview(vo)를 호출하여 DB에 저장합니다.
- 저장 성공 시 리뷰 메인 페이지로 리다이렉트됩니다.
( 이미지 파일 업로드는 따로 작성할게요... '(_ _)' ;; )
'SpringBoot 프로젝트' 카테고리의 다른 글
Spring Boot - 리뷰 CRUD기능 구현하기 (4) (0) | 2024.11.19 |
---|---|
Spring Boot - 리뷰 CRUD기능 구현하기 (3) (2) | 2024.11.19 |
Spring Boot - 리뷰 CRUD기능 구현하기 (1) (4) | 2024.11.18 |
Spring Boot로 간단한 ID와 비밀번호 찾기 기능 구현하기 (0) | 2024.11.18 |
Spring Boot로 회원가입 기능 구현 (2) | 2024.11.18 |