진행 순서
- 리뷰 등록하기
- 리뷰 리스트 보여주기
- 특정 리뷰 선택하기
- 리뷰 수정과 삭제
- 원본 이미지 보기
- (+) 영화 삭제, 수정, 검색
1. 리뷰 등록하기
: 화면에 버튼 추가 후, 버튼 클릭시 reviewModal을 통해 등록 수행
(1) <div> class 속성값이 uploadResult 밑에 버튼을 추가
(2) 리뷰 숫자 보여주는 부분 아래 쪽에 Review Register 글자를 가지는 버튼 추가
(3) 영화 리뷰를 보여주는 공간인 reviewList 클래스로 div 생성
<!-- 리뷰 등록을 위한 review count, review register 버튼 추가-->
<button type="button" class="btn btn-primary">
Review Count <span class="badge badge-light">[[${dto.reviewCnt}]]</span>
</button>
<button type="button" class="btn btn-info addReviewBtn">
Review Register
</button>
<!-- 영화 리뷰를 보여주는 공간으로 활용-->
<div class="list-group reviewList">
</div>
(4) addReviewBtn을 이용해 reviewModal창 처리
1. 입력 부분을 통해 추가할 기능이 필요하므로 변수로 외부로 빼서 선언
2. 모달창 내부에 필요없는 버튼 보이지 않게 처리한 후에 띄우게 설정
//addReviewBtn 클릭시 reviewModal창 보여주도록
$(".reviewModal").modal("show"); //미리 보기용
//1. 입력 부분을 통해 추가할 기능이 필요하므로 변수로 외부로 빼서 선언
var reviewModal = $(".reviewModal");
var inputMid = $('input[name="mid"]');
var inputText = $('input[name="text"]');
$(".addReviewBtn").click(function () {
inputMid.val("");
inputText.val("");
//2. 모달창 내부에 필요없는 버튼 보이지 않게 처리한 후에 띄우게 설정
$(".removeBtn , .modifyBtn").hide();
$(".reviewSaveBtn").show();
reviewModal.modal('show');
});
(5) Save changes 클릭시 영화 리뷰 등록 처리하도록 이벤트 처리
: 버튼 클래스 속성값으로 reviewSaveBtn 지정
// (5) Save changes 클릭시 영화 리뷰 등록 처리하도록 이벤트 처리
// : 버튼 클래스 속성값으로 reviewSaveBtn 지정
$('.reviewSaveBtn').click(function() {
//버튼 클릭시 회원의 데이터를 JSON 데이터로 만들어 전송
var data = {mno:mno, grade:grade, text:inputText.val(), mid: inputMid.val() };
console.log(data);
$.ajax({
url:'/reviews/'+mno,
type:"POST",
data:JSON.stringify(data),
contentType:"application/json; charset=utf-8",
dataType:"text",
//전송 성공시 reload를 통해 URL 다시 호출
success: function(result){
console.log("result: " + result);
self.location.reload();
}
})
//이후 모달창 숨기기
reviewModal.modal('hide');
});
2. 리뷰 리스트 보여주기
(1) 새로고침시 평균 평점과 리뷰 개수는 가져온다.
(2) 실제 리뷰 내용을 가져오지 않는 문제
-> Ajax를 이용해 MovieReviewDTO 리스트를 JSON으로 받는데, 함수를 작성해 페이지 열릴 때마다 호출하도록 처리
//리뷰 리스트 보여주는 함수 작성
//(1) 새로고침시 평균 평점과 리뷰 개수는 가져온다.
//(2) 실제 리뷰 내용을 가져오지 않는 문제
//-> 페이지가 열리면 바로 리뷰 데이터들을 가져와서 사용한다.
function getMovieReviews() {
function formatTime(str){
var date = new Date(str);
return date.getFullYear() + '/' +
(date.getMonth() + 1) + '/' +
date.getDate() + ' ' +
date.getHours() + ':' +
date.getMinutes();
}
$.getJSON("/reviews/"+ mno +"/all", function(arr){
var str ="";
$.each(arr, function(idx, review){
console.log(review);
str += ' <div class="card-body" data-reviewnum='+review.reviewnum+' data-mid='+review.mid+'>';
str += ' <h5 class="card-title">'+review.text+' <span>'+ review.grade+'</span></h5>';
str += ' <h6 class="card-subtitle mb-2 text-muted">'+review.nickname+'</h6>';
str += ' <p class="card-text">'+ formatTime(review.regDate) +'</p>';
str += ' </div>';
});
$(".reviewList").html(str);
});
}
//페이지 열리면 jQuery의 getJSON()을 이용해 MovieReviewController호출해 reviewList 클래스 속성 지정된 <div> 내용을 채운다.
//따라서 영화와 함께 리뷰도 같이 출력
getMovieReviews();
3. 특정 리뷰 선택하기
: 리뷰 목록에서 특정 리뷰 선택시 수정 삭제 가능하도록 reviewModal 창 보이게 처리
-> 모달창 내부 버튼을 상황에 맞게 노출 / 비노출 처리
//특정 리뷰 선택하기
//-> 수정 삭제 가능하도록 모달창 띄우기
//외부에 선언해 나중에 수정이나 삭제 작업에 사용할 수 있도록
var reviewnum;
$(".reviewList").on("click", ".card-body", function() {
//상황에 따라 버튼 노출 처리
$(".reviewSaveBtn").hide();
$(".removeBtn , .modifyBtn").show();
//리뷰 선택시 해당 리뷰의 정보를 가져온다.
var targetReview = $(this);
reviewnum = targetReview.data("reviewnum");
console.log("reviewnum: "+ reviewnum);
inputMid.val(targetReview.data("mid"));
inputText.val(targetReview.find('.card-title').clone().children().remove().end().text());
var grade = targetReview.find('.card-title span').html();
$(".starrr a:nth-child("+grade+")").trigger('click');
//수정 작업을 할 수 있도록 모달창을 띄운다
$('.reviewModal').modal('show');
});
4. 영화 리뷰 수정과 삭제
: Ajax를 통한 PUT방식 / DELETE 방식으로 동작하는데
처리 후에 현재 페이지를 재호출해 서버로부터 변경된 데이터를 받도록 처리
//4. 영화 리뷰 수정과 삭제
// : Ajax를 통한 PUT방식 / DELETE 방식으로 동작하는데
// 처리 후에 현재 페이지를 재호출해 서버로부터 변경된 데이터를 받도록 처리
$(".modifyBtn").on("click", function(){
var data = {reviewnum: reviewnum, mno:mno, grade:grade, text:inputText.val(), mid: inputMid.val() };
console.log(data);
$.ajax({
url:'/reviews/'+mno +"/"+ reviewnum ,
type:"PUT",
data:JSON.stringify(data),
contentType:"application/json; charset=utf-8",
dataType:"text",
success: function(result){
console.log("result: " + result);
self.location.reload();
}
})
reviewModal.modal('hide');
});
$(".removeBtn").on("click", function(){
var data = {reviewnum: reviewnum};
console.log(data);
$.ajax({
url:'/reviews/'+mno +"/"+ reviewnum ,
type:"DELETE",
contentType:"application/json; charset=utf-8",
dataType:"text",
success: function(result){
console.log("result: " + result);
self.location.reload();
}
})
reviewModal.modal('hide');
});
5. 원본 이미지 보기
: 섬네일 클릭시 원본 파일 볼 수 있는 방법 제공
섬네일 클릭시 원본 파일 볼 수 있는 방식
- UploadController에 지정된 이미지 조회 기능 활용
- 섬네일 파일 호출시 이름규칙을 이용해 특정 파라미터값 존재시 's_'없는 원본 파일 전달
2번 방식으로 구현
변경 전의 UploadController의 getFile()
//URL로 이미지 전송을 위한 메서드
@GetMapping("/display")
public ResponseEntity<byte[]> getFile(String fileName){
ResponseEntity<byte[]> result = null;
try{
String srcFileName = URLDecoder.decode(fileName, "UTF-8");
log.info("fileName : "+ srcFileName);
File file = new File(uploadPath+File.separator+srcFileName);
log.info("file : "+ file);
HttpHeaders header = new HttpHeaders();
//MIME타입 처리
//: 마임 타입이란 클라이언트에게 전송된 문서의 다양성을 알려주기 위한 메커니즘 -> 올바른 마임타입 전송하도록 설정필요
header.add("Content-Type", Files.probeContentType(file.toPath()));
//: 확장자를 통해 마임타입을 판단하는데, 확장자가 없으면 null을 반환한다.
//파일 데이터 처리
result = new ResponseEntity<>(FileCopyUtils.copyToByteArray(file), header, HttpStatus.OK);
//ResponseEntity에 바이트 배열로 만든 파일, 헤더, 상태코드 전달
}
catch (Exception e){
log.error(e.getMessage());
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
return result;
}
변경 후의 UploadController의 getFile()
//URL로 이미지 전송을 위한 메서드
//-> 섬네일 클릭시 원본 이미지 반환을 위한 size 인자 추가
@GetMapping("/display")
public ResponseEntity<byte[]> getFile(String fileName , String size){
ResponseEntity<byte[]> result = null;
try{
String srcFileName = URLDecoder.decode(fileName, "UTF-8");
log.info("fileName : "+ srcFileName);
File file = new File(uploadPath+File.separator+srcFileName);
//섬네일 클릭시 원본 이미지 출력 위한 추가
if(size !=null && size.equals("1")){
file = new File(file.getParent(), file.getName().substring(2));
}
log.info("file : "+ file);
HttpHeaders header = new HttpHeaders();
//MIME타입 처리
//: 마임 타입이란 클라이언트에게 전송된 문서의 다양성을 알려주기 위한 메커니즘 -> 올바른 마임타입 전송하도록 설정필요
header.add("Content-Type", Files.probeContentType(file.toPath()));
//: 확장자를 통해 마임타입을 판단하는데, 확장자가 없으면 null을 반환한다.
//파일 데이터 처리
result = new ResponseEntity<>(FileCopyUtils.copyToByteArray(file), header, HttpStatus.OK);
//ResponseEntity에 바이트 배열로 만든 파일, 헤더, 상태코드 전달
}
catch (Exception e){
log.error(e.getMessage());
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
return result;
}
: File에 원본이미지 이름이 담는다.
Read.html
<!-- 섬네일 파일 클릭시 원본 이미지 반환을 위해, 섬네일 이름을 알 수 있도록 data-file 속성 추가-->
<div class="uploadResult">
<ul >
<li th:each="movieImage: ${dto.imageDTOList}" th:data-file="${movieImage.getThumbnailURL()}">
<img th:if="${movieImage.path != null}" th:src="|/display?fileName=${movieImage.getThumbnailURL()}|">
</li>
</ul>
</div>
(1) th:data-file의 섬네일 이름을 가져와 ImageModal창에 이미지 태그로 추가
(2) size 파라미터 값을 이용해 원본 이미지를 가져오도록
//섬네일 클릭시 원본 이미지 출력을 위해, data의 file속성에 추가한 섬네일 파일 이름을 가져와서 원본 이미지 출력
$(".uploadResult li").click(function() {
var file = $(this).data('file');
console.log(file);
$('.imageModal .modal-body').html("<img style='width:100%' src='/display?fileName="+file+"&size=1' >")
$(".imageModal").modal("show");
});
(1) size 파라미터를 이용해 원본 파일인지 섬네일인지 구분
(2) size 변수 값이 1일 경우 원본 파일 전송
(3) read.html 에서 섬네일 부분의 <li> 태그에 data-file 속성으로 섬네일 이름 알 수 있도록 처리
6. 영화의 수정, 삭제, 검색 구현
-> 이미지 데이터를 업데이트 하는 게 아니라 새로 구성하도록 설정
'Server Programming > Spring Boot Backend Programming' 카테고리의 다른 글
[Spring 부트 - 운동 클럽 프로젝트] 1. 스프링 시큐리티 연동 (2) CSRF 와 접근 제한 설정 (0) | 2022.10.19 |
---|---|
[Spring 부트 - 운동 클럽 프로젝트] 1. 스프링 시큐리티 연동 (1) 기본 설정 (0) | 2022.10.19 |
[Spring 부트 - 영화 리뷰 프로젝트] 6. Ajax로 영화 리뷰 처리 (1) 리뷰 구성 (0) | 2022.10.18 |
[Spring 부트 - 영화 리뷰 프로젝트] 5. 영화 조회 처리 (0) | 2022.10.18 |
[Spring 부트 - 영화 리뷰 프로젝트] 4. 영화 목록 처리 (0) | 2022.10.18 |