ArticleController.java
@PreAuthorize("isAuthenticated()")
@GetMapping("/{id}/modify")
public String showModify(@AuthenticationPrincipal MemberContext memberContext, Model model, @PathVariable Long id) {
Article article = articleService.getForPrintArticleById(id);
if (memberContext.memberIsNot(article.getAuthor())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
}
model.addAttribute("article", article);
return "article/modify";
}
@PostMapping("/{id}/modify")
public String modify(@AuthenticationPrincipal MemberContext memberContext, Model model, @PathVariable Long id, @Valid ArticleForm articleForm) {
return "/article/%d".formatted(id);
}
memberContext
의 memberIsNot
메서드를 사용했다.MemberContext.java
public boolean memberIs(Member member) {
return id.equals(member.getId());
}
public boolean memberIsNot(Member member) {
return memberIs(member) == false;
}
modify.html
<!DOCTYPE html>
<html layout:decorate="~{layout/layout.html}">
<head>
<title>글수정</title>
</head>
<body>
<section layout:fragment="content">
<div class="container">
<h1>글수정</h1>
<script>
function ModifyForm__submit(form) {
form.subject.value = form.subject.value.trim();
if (form.subject.value.length == 0) {
alert("제목을 입력해주세요.");
form.subject.focus();
return;
}
form.content.value = form.content.value.trim();
if (form.content.value.length == 0) {
alert("내용을 입력해주세요.");
form.content.focus();
return;
}
form.submit();
}
</script>
<form th:action method="POST" enctype="multipart/form-data" onsubmit="ModifyForm__submit(this); return false;">
<div>
<span>제목</span>
<input type="text" name="subject" th:value="${article.subject}">
</div>
<div>
<span>내용</span>
<textarea name="content" th:text="${article.content}"></textarea>
</div>
<div>
<span>본문이미지</span>
<div>
<input type="file" name="common__inBody__1" accept="image/png, image/gif, image/jpeg">
</div>
<div>
<input type="file" name="common__inBody__2" accept="image/png, image/gif, image/jpeg">
</div>
</div>
<div>
<span>글수정</span>
<input type="submit" value="수">
</div>
</form>
</div>
</section>
</body>
</html>
ArticleController
@PreAuthorize("isAuthenticated()")
@PostMapping("/{id}/modify")
public String modify(@AuthenticationPrincipal MemberContext memberContext, Model model, @PathVariable Long id, @Valid ArticleForm articleForm) {
Article article = articleService.getForPrintArticleById(id);
if (memberContext.memberIsNot(article.getAuthor())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
}
articleService.modify(article, articleForm.getSubject(), articleForm.getContent());
String msg = Util.url.encode("%d번 게시물이 수정되었습니다.".formatted(id));
return "redirect:/article/%d?msg=%s".formatted(id, msg);
}
@PreAuthorize
어노테이션을 달았다. isAuthenticated()
를 설정하면 로그인한 회원만이 사용할 수 있다.ArticleService.java
public void modify(Article article, String subject, String content) {
article.setSubject(subject);
article.setContent(content);
articleRepository.save(article);
}
th:block
을 사용하지 않는다면?div 태그
를 반복문으로 같이 돌리면 문제가 생길 수 있다.<div th:each="user : ${userList}">
<span th:text="user.username}">username</span>
<span th:text="user.age}">age</span>
</div>
<div th:each="user : ${userList}">
<span th:text="${user.username} + ' & ' + ${user.age}">username&age</span>
</div>
th:block
을 사용한다면?<th:block th:each="user : ${userList}">
<div>
<span th:text="user.username}">username</span>
<span th:text="user.age}">age</span>
</div>
<div>
<span th:text="${user.username} + ' & ' + ${user.age}">username&age</span>
</div>
</th:block>
⇒ **th:block
은 렌더링 될 때 사라지고, 웹브라우저에는 두 개의 <div>
태그의 반복문 결과만 나온다.**
modify.html
<th:block th:each="i : ${#numbers.sequence(1, 5)}" th:with="genFile=${article.extra.genFileMap.get('common\_\_inBody\_\_' + i)}">
<div>
<span th:text="|${i}번 이미지|"></span>
<th:block th:if="${genFile != null}">
<hr>
<a th:href="@{${genFile.url}}" target="_blank">
<img class="w-10 h-10 object-cover rounded" title="새창에서 크게 보기" th:src="@{${genFile.url}}" alt="">
<br>
<label>
<input type="checkbox" value="" th:name="|delete___common\_\_inBody\_\_${i}|">
<span>이미지 삭제</span>
</label>
</a>
</th:block>
<hr>
<input type="file" th:name="|common\_\_inBody\_\_${i}|"
accept="image/png, image/gif, image/jpeg">
</div>
</th:block>
th:block
을 했다.write.html
<th:block th:each="i : ${#numbers.sequence(1, 5)}">
<div>
<span th:text="|${i}번 이미지|"></span>
<input type="file" th:name="|common\_\_inBody\_\_${i}|" accept="image/png, image/gif, image/jpeg">
</div>
</th:block>
ArticleController.java
@PreAuthorize("isAuthenticated()")
@PostMapping("/{id}/modify")
@ResponseBody
public String modify(@AuthenticationPrincipal MemberContext memberContext, Model model, @PathVariable Long id, @Valid ArticleForm articleForm, **MultipartRequest multipartRequest**) {
Article article = articleService.getForPrintArticleById(id);
if (memberContext.memberIsNot(article.getAuthor())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
}
**Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
RsData<Map<String, GenFile>> saveFilesRsData = genFileService.saveFiles(article, fileMap);**
articleService.modify(article, articleForm.getSubject(), articleForm.getContent());
String msg = Util.url.encode("%d번 게시물이 수정되었습니다.".formatted(id));
return "redirect:/article/%d?msg=%s".formatted(id, msg);
}
public void merge(GenFile other) {
relTypeCode = other.getRelTypeCode();
relId = other.getRelId();
typeCode = other.getTypeCode();
type2Code = other.getType2Code();
fileExtTypeCode = other.getFileExtTypeCode();
fileExtType2Code = other.getFileExtType2Code();
fileSize = other.getFileSize();
fileNo = other.getFileNo();
fileExt = other.getFileExt();
fileDir = other.getFileDir();
originFileName = other.getOriginFileName();
}
public String getFilePath() {
return AppConfig.GET_FILE_DIR_PATH + "/" + getFileDir() + "/" + getFileName();
}
merge
메서드를구현GenFileService.java
@Transactional
public GenFile save(GenFile genFile) {
Optional<GenFile> opOldGenFile = genFileRepository.findByRelTypeCodeAndRelIdAndTypeCodeAndType2CodeAndFileNo(genFile.getRelTypeCode(), genFile.getRelId(), genFile.getTypeCode(), genFile.getType2Code(), genFile.getFileNo());
if (opOldGenFile.isPresent()) {
GenFile oldGenFile = opOldGenFile.get();
deleteFileFromStorage(oldGenFile);
oldGenFile.merge(genFile);
genFileRepository.save(oldGenFile);
return oldGenFile;
}
genFileRepository.save(genFile);
return genFile;
}
private void deleteFileFromStorage(GenFile genFile) {
new File(genFile.getFilePath()).delete();
}