배너 화면 요청을 처리하는 핸들러 생성
package me.weekbelt.studyolle.study;
@RequiredArgsConstructor
@RequestMapping("/study/{path}/settings")
@Controller
public class StudySettingsController {
// ......
@GetMapping("/banner")
public String studyImageForm(@CurrentAccount Account account,
@PathVariable String path, Model model) {
Study study = studyService.getStudyToUpdate(account, path);
model.addAttribute(account);
model.addAttribute(study);
return "study/settings/banner";
}
}
배너 화면 구현(study/settings/banner.html)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments.html::head"></head>
<body class="bg-light">
<div th:replace="fragments.html::main-nav"></div>
<div th:replace="fragments.html::study-banner"></div>
<div class="container">
<div th:replace="fragments.html::study-info"></div>
<div th:replace="fragments.html::study-menu(studyMenu='settings')"></div>
<div class="row mt-3 justify-content-center">
<div class="col-2">
<div th:replace="fragments.html::study-settings-menu(currentMenu='image')"></div>
</div>
<div class="col-8">
<div th:replace="fragments.html::message"></div>
<div class="row">
<h2 class="col-sm-12">배너 이미지 사용</h2>
</div>
<form th:if="${!study.useBanner}" action="#"
th:action="@{'/study/' + ${study.getPath()} + '/settings/banner/enable'}" method="post" novalidate>
<div class="alert alert-primary" role="alert">
스터디 메뉴에서 스터디 배너 이미지를 사용합니다. 스터디 배너 이미지를 아직 설정하지 않았다면, 기본 배너 이미지를 사용합니다.
</div>
<div class="form-group">
<button class="btn btn-outline-primary btn-block" type="submit" aria-describedby="submitHelp">배너 이미지
사용하기
</button>
</div>
</form>
<form th:if="${study.useBanner}" action="#"
th:action="@{'/study/' + ${study.getPath()} + '/settings/banner/disable'}" method="post" novalidate>
<div class="alert alert-primary" role="alert">
스터디 메뉴에서 스터디 배너 이미지를 사용하지 않습니다. 스터디 목록에서는 배너 이미지를 사용합니다.
</div>
<div class="form-group">
<button class="btn btn-outline-primary btn-block" type="submit" aria-describedby="submitHelp">배너 이미지
사용하지 않기
</button>
</div>
</form>
<hr/>
<div class="row">
<h2 class="col-sm-12">배너 이미지 변경</h2>
</div>
<form id="imageForm" action="#" th:action="@{'/study/' + ${study.getPath()} + '/settings/banner'}"
method="post" novalidate>
<div class="form-group">
<input id="studyImage" type="hidden" name="image" class="form-control"/>
</div>
</form>
<div class="card text-center">
<div id="current-study-image" class="mt-3">
<img class="rounded" th:src="${study.image}" width="640" alt="name" th:alt="${study.title}"/>
</div>
<div id="new-study-image" class="mt-3"></div>
<div class="card-body">
<div class="custom-file">
<input type="file" class="custom-file-input" id="study-image-file">
<label class="custom-file-label" for="study-image-file"></label>
</div>
<div id="new-study-image-control" class="mt-3">
<button class="btn btn-outline-primary btn-block" id="cut-button">자르기</button>
<button class="btn btn-outline-success btn-block" id="confirm-button">확인</button>
<button class="btn btn-primary btn-block" id="save-button">저장</button>
<button class="btn btn-outline-warning btn-block" id="reset-button">취소</button>
</div>
<div id="cropped-new-study-image" class="mt-3"></div>
</div>
</div>
</div>
</div>
<div th:replace="fragments.html::footer"></div>
</div>
<script th:replace="fragments.html::tooltip"></script>
<link href="/node_modules/cropper/dist/cropper.min.css" rel="stylesheet">
<script src="/node_modules/cropper/dist/cropper.min.js"></script>
<script src="/node_modules/jquery-cropper/dist/jquery-cropper.min.js"></script>
<script type="application/javascript">
$(function () {
cropper = '';
let $confirmBtn = $("#confirm-button");
let $resetBtn = $("#reset-button");
let $cutBtn = $("#cut-button");
let $saveBtn = $("#save-button");
let $newStudyImage = $("#new-study-image");
let $currentStudyImage = $("#current-study-image");
let $resultImage = $("#cropped-new-study-image");
let $studyImage = $("#studyImage");
$newStudyImage.hide();
$cutBtn.hide();
$resetBtn.hide();
$confirmBtn.hide();
$saveBtn.hide();
$("#study-image-file").change(function (e) {
if (e.target.files.length === 1) {
const reader = new FileReader();
reader.onload = e => {
if (e.target.result) {
if (!e.target.result.startsWith("data:image")) {
alert("이미지 파일을 선택하세요.");
return;
}
let img = document.createElement("img");
img.id = 'new-study';
img.src = e.target.result;
img.setAttribute('width', '100%');
$newStudyImage.html(img);
$newStudyImage.show();
$currentStudyImage.hide();
let $newImage = $(img);
$newImage.cropper({aspectRatio: 13 / 2});
cropper = $newImage.data('cropper');
$cutBtn.show();
$confirmBtn.hide();
$resetBtn.show();
}
};
reader.readAsDataURL(e.target.files[0]);
}
});
$resetBtn.click(function () {
$currentStudyImage.show();
$newStudyImage.hide();
$resultImage.hide();
$resetBtn.hide();
$cutBtn.hide();
$confirmBtn.hide();
$saveBtn.hide();
$studyImage.val('');
});
$cutBtn.click(function () {
let dataUrl = cropper.getCroppedCanvas().toDataURL();
if (dataUrl.length > 1000 * 1024) {
alert("이미지 파일이 너무 큽니다. 1024000 보다 작은 파일을 사용하세요. 현재 이미지 사이즈 " + dataUrl.length);
return;
}
let newImage = document.createElement("img");
newImage.id = "cropped-new-study-image";
newImage.src = dataUrl;
newImage.width = 640;
$resultImage.html(newImage);
$resultImage.show();
$confirmBtn.show();
$confirmBtn.click(function () {
$newStudyImage.html(newImage);
$cutBtn.hide();
$confirmBtn.hide();
$studyImage.val(dataUrl);
$saveBtn.show();
});
});
$saveBtn.click(function () {
$("#imageForm").submit();
})
});
</script>
</body>
</html>
이미지 파일 업로드시 고려할 점
이미지 파일인지 확인 (이미지가 아닌 파일을 업로드 하려는건 아닌지 확인)
settings/profile.html에서 js부분 수정 (이미지 파일인지 확인)
// ....
<script type="application/javascript">
$(function() {
// .......
$("#profile-image-file").change(function(e) {
if (e.target.files.length === 1) {
const reader = new FileReader();
reader.onload = e => {
// 추가 ---------
if (e.target.result) {
if (!e.target.result.startsWith("data:image")) {
alert("이미지 파일을 선택하세요.");
return;
}
// ...........
}
};
reader.readAsDataURL(e.target.files[0]);
}
});
// ...........
});
</script>
</body>
</html>
이미지 크기 확인 (너무 큰 이미지 업로드 하지 않도록)
settings/profile.html에서 js 부분 수정
// .....
<script type="application/javascript">
$(function() {
// ........
$cutBtn.click(function () {
let dataUrl = cropper.getCroppedCanvas().toDataURL();
// 추가
if (dataUrl.length > 1000 * 1024) {
alert("이미지 파일이 너무 큽니다. 1024000 보다 작은 파일을 사용하세요. 현재 이미지 사이즈 " + dataUrl.length);
return;
}
// ...............
});
});
</script>
</body>
</html>
서버 요청 크기 설정
# 톰캣 기본 요청 사이즈는 2MB 입니다. 그것보다 큰 요청을 받고 싶은 경우에 이 값을 조정해야 합니다.
server.tomcat.max-http-form-post-size=5MB
application.properties에 추가
// .......
# 톰캣 기본 요청 사이즈는 2MB 입니다. 그것보다 큰 요청을 받고 싶은 경우에 이 값을 조정해야 합니다.
server.tomcat.max-http-form-post-size=5MB
// .......
스터디 배너 업데이트 처리 핸들러 작성
package me.weekbelt.studyolle.study;
@RequiredArgsConstructor
@RequestMapping("/study/{path}/settings")
@Controller
public class StudySettingsController {
// ......
@PostMapping("/banner")
public String studyImageSubmit(@CurrentAccount Account account, @PathVariable String path,
String image, RedirectAttributes attributes){
Study study = studyService.getStudyToUpdate(account, path);
studyService.updateStudyImage(study, image);
attributes.addFlashAttribute("message", "스터디 이미지를 수정했습니다.");
return "redirect:/study/" + getPath(path) + "/settings/banner";
}
}
배너 이미지 업데이트 처리를 위한 updateStudyImage메소드 작성
package me.weekbelt.studyolle.study;
@RequiredArgsConstructor
@Transactional
@Service
public class StudyService {
// .......
public void updateStudyImage(Study study, String image) {
study.setImage(image);
}
}
배너 이미지 사용/비사용 요청을 받을 핸들러 작성
package me.weekbelt.studyolle.study;
@RequiredArgsConstructor
@RequestMapping("/study/{path}/settings")
@Controller
public class StudySettingsController {
// .........
@PostMapping("/banner/enable")
public String enableStudyBanner(@CurrentAccount Account account, @PathVariable String path) {
Study study = studyService.getStudyToUpdate(account, path);
studyService.enableStudyBanner(study);
return "redirect:/study/" + getPath(path) + "/settings/banner";
}
@PostMapping("/banner/disable")
public String disableStudyBanner(@CurrentAccount Account account, @PathVariable String path) {
Study study = studyService.getStudyToUpdate(account, path);
studyService.disableStudyBanner(study);
return "redirect:/study/" + getPath(path) + "/settings/banner";
}
}
배너 이미지 사용/비사용 처리를 위한 enableStudyBanner, disableStudyBanner 메소드 작성
package me.weekbelt.studyolle.study;
@RequiredArgsConstructor
@Transactional
@Service
public class StudyService {
// ..........
public void enableStudyBanner(Study study) {
study.setUseBanner(true);
}
public void disableStudyBanner(Study study) {
study.setUseBanner(false);
}
}
참고: https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-JPA-%EC%9B%B9%EC%95%B1#
'스프링과 JPA 기반 웹 어플리케이션 개발 > 4부 스터디' 카테고리의 다른 글
55. 스터디 설정 - 상태변경 (0) | 2020.04.24 |
---|---|
54. 스터디 설정 - 태그/지역 (0) | 2020.04.24 |
52. 스터디 설정 - 소개 수정 (0) | 2020.04.24 |
51. 스터디 폼 & 개설 & 멤버 조회 테스트 (0) | 2020.04.24 |
50. 스터디 구성원 조회 (0) | 2020.04.23 |