From e5c39676b9bf793ffb44be750357533f0e55a8a0 Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Sat, 16 Apr 2022 23:58:38 +0900 Subject: [PATCH 01/21] =?UTF-8?q?feat=20:=20ajax=20=ED=86=B5=EC=8B=A0?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=8B=B5=EA=B8=80=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ajax 통신을 위해 scripts 수정 - Question과 Answer가 양방향 연관관계로 json으로 변경 시 순환참조 발생 따라서 Question에 @JsonIgnore 추가 - AnswerController의 create 메서드 반환형을 view가 아닌 Answer를 반환 --- .../codesquad/answer/AnswerController.java | 11 +-- src/main/java/codesquad/qua/Question.java | 2 + src/main/resources/static/js/scripts.js | 91 +++++++++++++++++-- src/main/resources/templates/qna/show.html | 2 +- 4 files changed, 92 insertions(+), 14 deletions(-) diff --git a/src/main/java/codesquad/answer/AnswerController.java b/src/main/java/codesquad/answer/AnswerController.java index aee0cd4c..1d731341 100644 --- a/src/main/java/codesquad/answer/AnswerController.java +++ b/src/main/java/codesquad/answer/AnswerController.java @@ -10,9 +10,7 @@ import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpSession; import java.util.NoSuchElementException; @@ -27,7 +25,8 @@ public class AnswerController { private QuestionRepository questionRepository; @PostMapping("/questions/{question-id}/answers") - public String create(@PathVariable("question-id") Long questionId, Answer answer, HttpSession session, Model model) { + @ResponseBody + public Answer create(@PathVariable("question-id") Long questionId, @RequestBody Answer answer, HttpSession session) { Question question = questionRepository.findById(questionId) .orElseThrow(NoSuchElementException::new); @@ -37,7 +36,7 @@ public String create(@PathVariable("question-id") Long questionId, Answer answer User user = SessionUtil.getUserBySession(session); if (user == null) { - return "/login"; + return null; } answer.setWriter(user.getName()); @@ -45,7 +44,7 @@ public String create(@PathVariable("question-id") Long questionId, Answer answer answerRepository.save(answer); - return "redirect:/questions/" + questionId; + return answer; } @DeleteMapping("/questions/{question-id}/answers/{answer-id}") diff --git a/src/main/java/codesquad/qua/Question.java b/src/main/java/codesquad/qua/Question.java index d601206a..0953b2cf 100644 --- a/src/main/java/codesquad/qua/Question.java +++ b/src/main/java/codesquad/qua/Question.java @@ -2,6 +2,7 @@ import codesquad.answer.Answer; import codesquad.user.User; +import com.fasterxml.jackson.annotation.JsonIgnore; import javax.persistence.*; import java.util.ArrayList; @@ -25,6 +26,7 @@ public class Question { private boolean deletedFlag = false; @OneToMany(mappedBy = "question") + @JsonIgnore private List answers = new ArrayList<>(); public List getAnswers() { diff --git a/src/main/resources/static/js/scripts.js b/src/main/resources/static/js/scripts.js index 01f85bd2..949d950b 100755 --- a/src/main/resources/static/js/scripts.js +++ b/src/main/resources/static/js/scripts.js @@ -1,9 +1,86 @@ -String.prototype.format = function() { +String.prototype.format = function () { var args = arguments; - return this.replace(/{(\d+)}/g, function(match, number) { - return typeof args[number] != 'undefined' - ? args[number] - : match - ; + return this.replace(/{(\d+)}/g, function (match, number) { + return typeof args[number] != 'undefined' ? args[number] : match; }); -}; \ No newline at end of file +}; + +function $(selector) { + return document.querySelector(selector); +} + +document.addEventListener("DOMContentLoaded", () => { + initEvents(); +}) + +function initEvents() { + const answerBtn = $(".submit-write .btn"); + console.log(answerBtn); + if (answerBtn == null) return; + //deleteAnswerHandler + answerBtn.addEventListener("click", registerAnswerHandler); +} + +function fetchManager({url, method, body, headers, callback}) { + fetch(url, {method, body, headers, credentials: "same-origin"}) + .then((response) => { + return response.json(); + }).then((result) => { + callback(result); + }) +} + +function registerAnswerHandler(evt) { + evt.preventDefault(); + const comment = $(".submit-write textarea").value; + document.querySelectorAll(".form-control")[1].value = ""; + + const url = $(".submit-write").action; + console.log(url); + + fetchManager({ + url: url, + method: "POST", + headers: {'content-type': 'application/json'}, + body: JSON.stringify({comment}), + callback: appendAnswer + }) +} + +function appendAnswer({id, comment, question, writer}) { + const html = ` + ` + + $(".qna-comment-slipp-articles").insertAdjacentHTML("beforeend", html); +} \ No newline at end of file diff --git a/src/main/resources/templates/qna/show.html b/src/main/resources/templates/qna/show.html index 6e238477..393a8b15 100644 --- a/src/main/resources/templates/qna/show.html +++ b/src/main/resources/templates/qna/show.html @@ -52,7 +52,7 @@

{{title}}

{{#question.answers}} {{^deletedFlag}} -
+
Date: Sun, 17 Apr 2022 00:09:52 +0900 Subject: [PATCH 02/21] =?UTF-8?q?feat=20:=20ajax=20=ED=86=B5=EC=8B=A0?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=8B=B5=EA=B8=80=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ajax 통신을 위해 scripts 수정 - AnswerRepository에 answer를 조회 시 question을 같이 가져오는 @EntityGraph 사용 - AnswerController에서 view가 아닌 객체를 반환하므로 @Controller -> @RestController 변경 --- .../codesquad/answer/AnswerController.java | 15 +++----- .../codesquad/answer/AnswerRepository.java | 6 +++ src/main/resources/static/js/scripts.js | 37 ++++++++++++++++++- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/main/java/codesquad/answer/AnswerController.java b/src/main/java/codesquad/answer/AnswerController.java index 1d731341..7eec68d1 100644 --- a/src/main/java/codesquad/answer/AnswerController.java +++ b/src/main/java/codesquad/answer/AnswerController.java @@ -7,15 +7,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; -import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpSession; import java.util.NoSuchElementException; -@Controller +@RestController public class AnswerController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @@ -25,7 +23,6 @@ public class AnswerController { private QuestionRepository questionRepository; @PostMapping("/questions/{question-id}/answers") - @ResponseBody public Answer create(@PathVariable("question-id") Long questionId, @RequestBody Answer answer, HttpSession session) { Question question = questionRepository.findById(questionId) .orElseThrow(NoSuchElementException::new); @@ -49,23 +46,23 @@ public Answer create(@PathVariable("question-id") Long questionId, @RequestBody @DeleteMapping("/questions/{question-id}/answers/{answer-id}") @Transactional - public String remove(@PathVariable("question-id") Long questionId, + public Answer remove(@PathVariable("question-id") Long questionId, @PathVariable("answer-id") Long answerId, HttpSession session) { User user = SessionUtil.getUserBySession(session); - Answer answer = answerRepository.findById(answerId) + Answer answer = answerRepository.findFetchJoinById(answerId) .orElseThrow(NoSuchElementException::new); if (user == null) { - return "/login"; + return null; } if (!answer.equalsWriter(user)) { - return "user/login_failed"; + return null; } answer.changeDeletedFlag(); - return "redirect:/questions/" + questionId; + return answer; } } diff --git a/src/main/java/codesquad/answer/AnswerRepository.java b/src/main/java/codesquad/answer/AnswerRepository.java index 6decc11b..bea26622 100644 --- a/src/main/java/codesquad/answer/AnswerRepository.java +++ b/src/main/java/codesquad/answer/AnswerRepository.java @@ -1,6 +1,12 @@ package codesquad.answer; +import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface AnswerRepository extends JpaRepository { + + @EntityGraph(attributePaths = {"question"}) + Optional findFetchJoinById(Long id); } diff --git a/src/main/resources/static/js/scripts.js b/src/main/resources/static/js/scripts.js index 949d950b..18e508db 100755 --- a/src/main/resources/static/js/scripts.js +++ b/src/main/resources/static/js/scripts.js @@ -16,9 +16,15 @@ document.addEventListener("DOMContentLoaded", () => { function initEvents() { const answerBtn = $(".submit-write .btn"); console.log(answerBtn); - if (answerBtn == null) return; - //deleteAnswerHandler + answerBtn.addEventListener("click", registerAnswerHandler); + + const answerList = document.querySelectorAll(".article-hi"); + + answerList.forEach(answer => { + console.log(answer.getElementsByClassName("delete-answer-button")); //htmlcollection + answer.getElementsByClassName("delete-answer-button")[0].addEventListener("click", deleteAnswerHandler); + }); } function fetchManager({url, method, body, headers, callback}) { @@ -83,4 +89,31 @@ function appendAnswer({id, comment, question, writer}) {
` $(".qna-comment-slipp-articles").insertAdjacentHTML("beforeend", html); + initEvents(); +} + +function deleteAnswerHandler(evt) { + evt.preventDefault(); + const url = $(".delete-answer-form").action; + console.log(url); + const id = url.replace(/.+\/(\d+)$/, "$1"); + console.log("deleteAnswerHandler" + url); + console.log("deleteAnswerHandler" + id); + + fetchManager({ + url, + method: 'DELETE', + headers: {'content-type': 'application/json'}, + body: JSON.stringify({id}), + callback: deleteAnswer + }) +} + +function deleteAnswer({id}) { + console.log(id); + const selector = `.article-hi[data-id='${id}']`; + console.log(id); + console.log("deleteAnswer" + selector); + const target = $(selector); + target.parentNode.removeChild(target); } \ No newline at end of file From 62010775f8dac70476407025d5d319aa7f10977b Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Mon, 18 Apr 2022 20:44:14 +0900 Subject: [PATCH 03/21] =?UTF-8?q?feat=20:=20Result=20=EB=B0=98=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Result - 답글 삭제 시 Result 반환하기 위해 생성 AnswerController - 답글 삭제 시 Result 반환 AnswerRepository - 지연로딩으로 인한 JSON 파싱 처리 위해 쿼리 메서드 추가 --- .../codesquad/answer/AnswerController.java | 13 ++++--- .../codesquad/answer/AnswerRepository.java | 2 +- src/main/java/codesquad/response/Result.java | 28 ++++++++++++++ src/main/resources/static/js/scripts.js | 38 ++++++++++++++----- src/main/resources/templates/qna/show.html | 2 +- 5 files changed, 65 insertions(+), 18 deletions(-) create mode 100644 src/main/java/codesquad/response/Result.java diff --git a/src/main/java/codesquad/answer/AnswerController.java b/src/main/java/codesquad/answer/AnswerController.java index 7eec68d1..894f6c74 100644 --- a/src/main/java/codesquad/answer/AnswerController.java +++ b/src/main/java/codesquad/answer/AnswerController.java @@ -2,6 +2,7 @@ import codesquad.qua.Question; import codesquad.qua.QuestionRepository; +import codesquad.response.Result; import codesquad.user.User; import codesquad.utils.SessionUtil; import org.slf4j.Logger; @@ -46,23 +47,23 @@ public Answer create(@PathVariable("question-id") Long questionId, @RequestBody @DeleteMapping("/questions/{question-id}/answers/{answer-id}") @Transactional - public Answer remove(@PathVariable("question-id") Long questionId, + public Result remove(@PathVariable("question-id") Long questionId, @PathVariable("answer-id") Long answerId, HttpSession session) { User user = SessionUtil.getUserBySession(session); - Answer answer = answerRepository.findFetchJoinById(answerId) + Answer answer = answerRepository.findQuestionFetchJoinById(answerId) .orElseThrow(NoSuchElementException::new); if (user == null) { - return null; + return Result.fail("로그인 하세요"); } if (!answer.equalsWriter(user)) { - return null; + return Result.fail("다른 사람 답글은 삭제 못해요"); } answer.changeDeletedFlag(); - return answer; + return Result.ok(answer); } -} +} \ No newline at end of file diff --git a/src/main/java/codesquad/answer/AnswerRepository.java b/src/main/java/codesquad/answer/AnswerRepository.java index bea26622..0caac67f 100644 --- a/src/main/java/codesquad/answer/AnswerRepository.java +++ b/src/main/java/codesquad/answer/AnswerRepository.java @@ -8,5 +8,5 @@ public interface AnswerRepository extends JpaRepository { @EntityGraph(attributePaths = {"question"}) - Optional findFetchJoinById(Long id); + Optional findQuestionFetchJoinById(Long id); } diff --git a/src/main/java/codesquad/response/Result.java b/src/main/java/codesquad/response/Result.java new file mode 100644 index 00000000..627d9f00 --- /dev/null +++ b/src/main/java/codesquad/response/Result.java @@ -0,0 +1,28 @@ +package codesquad.response; + +public class Result { + + private T result; + private String message; + + public Result(T answer, String message) { + this.result = answer; + this.message = message; + } + + public static Result ok(T id) { + return new Result<>(id, null); + } + + public static Result fail(String message) { + return new Result<>(null, message); + } + + public T getResult() { + return result; + } + + public String getMessage() { + return message; + } +} \ No newline at end of file diff --git a/src/main/resources/static/js/scripts.js b/src/main/resources/static/js/scripts.js index 18e508db..c2b69579 100755 --- a/src/main/resources/static/js/scripts.js +++ b/src/main/resources/static/js/scripts.js @@ -5,6 +5,7 @@ String.prototype.format = function () { }); }; + function $(selector) { return document.querySelector(selector); } @@ -20,9 +21,11 @@ function initEvents() { answerBtn.addEventListener("click", registerAnswerHandler); const answerList = document.querySelectorAll(".article-hi"); + console.log("answerList 길이 = " + answerList.length); answerList.forEach(answer => { - console.log(answer.getElementsByClassName("delete-answer-button")); //htmlcollection + console.log(answer.getElementsByClassName("delete-answer-button")[0]); + console.log(answer.getElementsByClassName("delete-answer-button")[1]); answer.getElementsByClassName("delete-answer-button")[0].addEventListener("click", deleteAnswerHandler); }); } @@ -30,9 +33,23 @@ function initEvents() { function fetchManager({url, method, body, headers, callback}) { fetch(url, {method, body, headers, credentials: "same-origin"}) .then((response) => { - return response.json(); - }).then((result) => { - callback(result); + const data = response.json(); + console.log(data); + return data.then(result => { + return { + 'result' : result, + 'status' : response.status + } + }) + }).then( ({result, status}) => { + if(status >= 400) { + console.log('error 가 발생했네요 ', result.error); + }else{ + console.log(result); + callback(result); + } + }).catch(err => { + console.log("oops..", err); }) } @@ -54,6 +71,8 @@ function registerAnswerHandler(evt) { } function appendAnswer({id, comment, question, writer}) { + console.log("id = " + id); + const html = `
@@ -97,8 +116,8 @@ function deleteAnswerHandler(evt) { const url = $(".delete-answer-form").action; console.log(url); const id = url.replace(/.+\/(\d+)$/, "$1"); - console.log("deleteAnswerHandler" + url); - console.log("deleteAnswerHandler" + id); + console.log("deleteAnswerHandler = " + url); + console.log("deleteAnswerHandler = " + id); fetchManager({ url, @@ -109,10 +128,9 @@ function deleteAnswerHandler(evt) { }) } -function deleteAnswer({id}) { - console.log(id); - const selector = `.article-hi[data-id='${id}']`; - console.log(id); +function deleteAnswer({result}) { + console.log("id = " + result.id); + const selector = `.article-hi[data-id='${result.id}']`; console.log("deleteAnswer" + selector); const target = $(selector); target.parentNode.removeChild(target); diff --git a/src/main/resources/templates/qna/show.html b/src/main/resources/templates/qna/show.html index 393a8b15..b2763e2b 100644 --- a/src/main/resources/templates/qna/show.html +++ b/src/main/resources/templates/qna/show.html @@ -52,7 +52,7 @@

{{title}}

{{#question.answers}} {{^deletedFlag}} -
+
Date: Mon, 18 Apr 2022 20:49:51 +0900 Subject: [PATCH 04/21] =?UTF-8?q?feat=20:=20lombok=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 74124c19..a4c3a8ab 100755 --- a/build.gradle +++ b/build.gradle @@ -34,4 +34,5 @@ dependencies { runtime('net.rakugakibox.spring.boot:logback-access-spring-boot-starter:2.7.1') testCompile('org.springframework.boot:spring-boot-starter-test') testCompile('org.assertj:assertj-core:3.10.0') + implementation 'org.projectlombok:lombok' } \ No newline at end of file From 9b474251cc1a710d32511de552f8b5f987ca3d2f Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Mon, 18 Apr 2022 23:07:57 +0900 Subject: [PATCH 05/21] =?UTF-8?q?fix=20:=20=EB=8B=B5=EA=B8=80=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. user1의 답글을 user2가 삭제하려고 시도 2. 에러 발생 3. user2가 자신의 답글을 삭제하려고 시도 4. 에러 발생 3.4 오류 해결 --- src/main/resources/static/js/scripts.js | 14 +++++++------- src/main/resources/templates/qna/show.html | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/resources/static/js/scripts.js b/src/main/resources/static/js/scripts.js index c2b69579..d9ce3a55 100755 --- a/src/main/resources/static/js/scripts.js +++ b/src/main/resources/static/js/scripts.js @@ -100,7 +100,8 @@ function appendAnswer({id, comment, question, writer}) {
- +
@@ -111,19 +112,18 @@ function appendAnswer({id, comment, question, writer}) { initEvents(); } -function deleteAnswerHandler(evt) { - evt.preventDefault(); - const url = $(".delete-answer-form").action; +function deleteAnswerHandler(target) { + // target.preventDefault(); + const value = target.value.split("/"); + console.log("value = " + value); + const url = "/questions/" + value[1] + "/answers/" + value[0]; console.log(url); - const id = url.replace(/.+\/(\d+)$/, "$1"); console.log("deleteAnswerHandler = " + url); - console.log("deleteAnswerHandler = " + id); fetchManager({ url, method: 'DELETE', headers: {'content-type': 'application/json'}, - body: JSON.stringify({id}), callback: deleteAnswer }) } diff --git a/src/main/resources/templates/qna/show.html b/src/main/resources/templates/qna/show.html index b2763e2b..93472dcf 100644 --- a/src/main/resources/templates/qna/show.html +++ b/src/main/resources/templates/qna/show.html @@ -78,7 +78,8 @@

{{title}}

- +
From e99a9659ac61734f7a7356e4ecc8ec93382c204d Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Mon, 18 Apr 2022 23:52:05 +0900 Subject: [PATCH 06/21] =?UTF-8?q?feat=20:=20service=20layer=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/codesquad/user/User.java | 4 ++ .../java/codesquad/user/UserController.java | 52 +++++--------- src/main/java/codesquad/user/UserDto.java | 14 ++++ src/main/java/codesquad/user/UserService.java | 67 +++++++++++++++++++ 4 files changed, 102 insertions(+), 35 deletions(-) create mode 100644 src/main/java/codesquad/user/UserDto.java create mode 100644 src/main/java/codesquad/user/UserService.java diff --git a/src/main/java/codesquad/user/User.java b/src/main/java/codesquad/user/User.java index d6091477..89dd791d 100644 --- a/src/main/java/codesquad/user/User.java +++ b/src/main/java/codesquad/user/User.java @@ -67,6 +67,10 @@ public boolean equalsPassword(String password) { return this.password.equals(password); } + public boolean equalsPassword(UserDto userDto) { + return password.equals(userDto.getPassword()); + } + public boolean equalsId(Long id) { return this.id.equals(id); } diff --git a/src/main/java/codesquad/user/UserController.java b/src/main/java/codesquad/user/UserController.java index 741fdfc5..9f79cc48 100644 --- a/src/main/java/codesquad/user/UserController.java +++ b/src/main/java/codesquad/user/UserController.java @@ -1,9 +1,7 @@ package codesquad.user; -import codesquad.utils.SessionUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -13,70 +11,54 @@ import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpSession; -import java.util.NoSuchElementException; @Controller @RequestMapping("/users") +@RequiredArgsConstructor +@Slf4j public class UserController { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - @Autowired - private UserRepository userRepository; + private final UserService userService; @PostMapping("") public String create(User user) { - logger.info("user = {}", user); - userRepository.save(user); + userService.join(user); return "redirect:/users"; } @GetMapping("") - public String list(Model model) { - model.addAttribute("users", userRepository.findAll()); + public String showUserList(Model model) { + userService.list(model); return "/user/list"; } @GetMapping("{id}") - public ModelAndView show(@PathVariable long id) { + public ModelAndView showUser(@PathVariable long id) { ModelAndView mav = new ModelAndView("user/profile"); - mav.addObject("user", findUserById(id)); + userService.show(id, mav); return mav; } @GetMapping("{id}/form") public String updateForm(Model model, @PathVariable("id") Long id) { - model.addAttribute("user", findUserById(id)); + userService.setUpdateForm(model, id); return "/user/updateForm"; } @PostMapping("{id}/update") - public String update(User changedUser, @PathVariable("id") Long id, HttpSession session) { - User user = SessionUtil.getUserBySession(session); + public String updateUser(User changedUser, @PathVariable("id") Long id, HttpSession session) { - if (user == null || !user.equalsId(id)) { - return "/user/login_failed"; + if (userService.update(changedUser, id, session)) { + return "redirect:/users"; } - user.update(changedUser); - userRepository.save(user); - - return "redirect:/users"; + return "/user/login_failed"; } @PostMapping("/login") - public String login(String userId, String password, HttpSession session) { - User savedUser = userRepository.findByUserId(userId) - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 회원")); - - if (savedUser.equalsPassword(password)) { - SessionUtil.setSession(session, savedUser); - } + public String loginUser(UserDto userDto, HttpSession session) { + userService.login(userDto, session); return "redirect:/users"; } - - private User findUserById(Long id) { - return userRepository.findById(id) - .orElseThrow(NoSuchElementException::new); - } } \ No newline at end of file diff --git a/src/main/java/codesquad/user/UserDto.java b/src/main/java/codesquad/user/UserDto.java new file mode 100644 index 00000000..4cc84253 --- /dev/null +++ b/src/main/java/codesquad/user/UserDto.java @@ -0,0 +1,14 @@ +package codesquad.user; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +public class UserDto { + + private String userId; + private String password; +} diff --git a/src/main/java/codesquad/user/UserService.java b/src/main/java/codesquad/user/UserService.java new file mode 100644 index 00000000..feb08230 --- /dev/null +++ b/src/main/java/codesquad/user/UserService.java @@ -0,0 +1,67 @@ +package codesquad.user; + +import codesquad.utils.SessionUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.ui.Model; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpSession; +import java.util.NoSuchElementException; + +@Service +@RequiredArgsConstructor +@Slf4j +public class UserService { + + private final UserRepository userRepository; + + public void join(User user) { + log.info("user = {}", user); + userRepository.save(user); + } + + public void list(Model model) { + model.addAttribute("users", userRepository.findAll()); + } + + public void show(long userId, ModelAndView modelAndView) { + modelAndView.addObject("user", findUserById(userId)); + } + + public void setUpdateForm(Model model, long userId) { + model.addAttribute("user", findUserById(userId)); + } + + @Transactional + public boolean update(User changedUser, long userId, HttpSession session) { + log.info("changedUser = {}", changedUser); + log.info("userId = {}", userId); + User user = SessionUtil.getUserBySession(session); + + if (user == null || !user.equalsId(userId)) { + return false; + } + + user.update(changedUser); + userRepository.save(user); + + return true; + } + + public void login(UserDto userDto, HttpSession session) { + User savedUser = userRepository.findByUserId(userDto.getUserId()) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 회원")); + + if (savedUser.equalsPassword(userDto)) { + SessionUtil.setSession(session, savedUser); + } + } + + private User findUserById(long userId) { + return userRepository.findById(userId) + .orElseThrow(NoSuchElementException::new); + } +} From 2fc3998231d85f2340ba974f1c21340e5f409622 Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Tue, 19 Apr 2022 01:28:26 +0900 Subject: [PATCH 07/21] =?UTF-8?q?chore=20:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/codesquad/user/UserController.java | 4 ++-- src/main/java/codesquad/user/UserService.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/codesquad/user/UserController.java b/src/main/java/codesquad/user/UserController.java index 9f79cc48..4a4e9136 100644 --- a/src/main/java/codesquad/user/UserController.java +++ b/src/main/java/codesquad/user/UserController.java @@ -21,8 +21,8 @@ public class UserController { private final UserService userService; @PostMapping("") - public String create(User user) { - userService.join(user); + public String join(User user) { + userService.create(user); return "redirect:/users"; } diff --git a/src/main/java/codesquad/user/UserService.java b/src/main/java/codesquad/user/UserService.java index feb08230..da4bf0cb 100644 --- a/src/main/java/codesquad/user/UserService.java +++ b/src/main/java/codesquad/user/UserService.java @@ -18,7 +18,7 @@ public class UserService { private final UserRepository userRepository; - public void join(User user) { + public void create(User user) { log.info("user = {}", user); userRepository.save(user); } From fd0f7524336f65fc75c7452ef4a4512d9d391851 Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Tue, 19 Apr 2022 13:10:00 +0900 Subject: [PATCH 08/21] =?UTF-8?q?feat=20:=20service=20layer=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Question - 생성자 추가 QuestionController - service layer와 분리 --- src/main/java/codesquad/qua/Question.java | 48 ++----- .../codesquad/qua/QuestionController.java | 123 ++++-------------- src/main/java/codesquad/qua/QuestionDto.java | 13 ++ .../codesquad/qua/QuestionRepository.java | 7 + .../java/codesquad/qua/QuestionService.java | 119 +++++++++++++++++ src/main/resources/templates/qna/form.html | 4 + 6 files changed, 183 insertions(+), 131 deletions(-) create mode 100644 src/main/java/codesquad/qua/QuestionDto.java create mode 100644 src/main/java/codesquad/qua/QuestionService.java diff --git a/src/main/java/codesquad/qua/Question.java b/src/main/java/codesquad/qua/Question.java index 0953b2cf..681c2f49 100644 --- a/src/main/java/codesquad/qua/Question.java +++ b/src/main/java/codesquad/qua/Question.java @@ -3,12 +3,16 @@ import codesquad.answer.Answer; import codesquad.user.User; import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Getter; +import lombok.NoArgsConstructor; import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity +@NoArgsConstructor +@Getter public class Question { @Id @@ -23,52 +27,24 @@ public class Question { private String contents; - private boolean deletedFlag = false; + private boolean deletedFlag; @OneToMany(mappedBy = "question") @JsonIgnore - private List answers = new ArrayList<>(); + private List answers; - public List getAnswers() { - return answers; + public Question(QuestionDto questionDto, User user) { + this.writer = user; + this.title = questionDto.getTitle(); + this.contents = questionDto.getContents(); + answers = new ArrayList<>(); + deletedFlag = false; } public void changeDeleteFlag() { deletedFlag = true; } - public boolean isDeletedFlag() { - return deletedFlag; - } - - public User getWriter() { - return writer; - } - - public void setWriter(User writer) { - this.writer = writer; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getContents() { - return contents; - } - - public void setContents(String contents) { - this.contents = contents; - } - - public Long getId() { - return id; - } - public void update(Question question) { this.title = question.getTitle(); this.contents = question.getContents(); diff --git a/src/main/java/codesquad/qua/QuestionController.java b/src/main/java/codesquad/qua/QuestionController.java index 31900344..00de9f63 100644 --- a/src/main/java/codesquad/qua/QuestionController.java +++ b/src/main/java/codesquad/qua/QuestionController.java @@ -1,35 +1,26 @@ package codesquad.qua; -import codesquad.answer.Answer; -import codesquad.answer.AnswerRepository; -import codesquad.user.User; -import codesquad.utils.SessionUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import codesquad.exception.QuestionDeleteException; +import codesquad.exception.QuestionShowException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpSession; -import java.util.NoSuchElementException; @Controller +@RequiredArgsConstructor +@Slf4j public class QuestionController { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - @Autowired - QuestionRepository questionRepository; - - @Autowired - AnswerRepository answerRepository; + private final QuestionService questionService; @GetMapping("/questions/form") public String createForm(HttpSession session) { - User user = SessionUtil.getUserBySession(session); - - if (user == null) { + if (!questionService.setCreateForm(session)) { return "/login"; } @@ -37,122 +28,64 @@ public String createForm(HttpSession session) { } @PostMapping("/questions") - public String create(Question question, HttpSession session) { - User user = SessionUtil.getUserBySession(session); - - if (user == null) { + public String createQuestion(QuestionDto questionDto, HttpSession session) { + if (!questionService.create(questionDto, session)) { return "/login"; } - question.setWriter(user); - questionRepository.save(question); - logger.info("user : {}", question.getWriter().getName()); return "redirect:/"; } @GetMapping("/") - public String list(Model model) { - model.addAttribute("question", questionRepository.findAll()); + public String showQuestionList(Model model) { + model.addAttribute("question", questionService.list()); return "qna/list"; } @GetMapping("/questions/{id}") - public String qnaInfo(Model model, @PathVariable("id") Long id) { - Question question = findQuestionById(id); - model.addAttribute("question", question); - model.addAttribute("count", countAnswers(question)); - + public String showQuestion(Model model, @PathVariable("id") Long id) { + model.addAttribute("question", questionService.findQuestionById(id)); + model.addAttribute("count", questionService.countAnswers(id)); return "qna/show"; } @Transactional @PutMapping("/questions/{id}") - public String update(Question changedQuestion, @PathVariable("id") Long id, HttpSession session) { - User user = SessionUtil.getUserBySession(session); - Question savedQuestion = findQuestionById(id); - - if (user == null || !isQuestionMatchUser(user, savedQuestion)) { + public String updateQuestion(Question changedQuestion, @PathVariable("id") Long id, HttpSession session) { + try { + questionService.update(changedQuestion, id, session); + } catch (QuestionShowException showException) { return "qna/show_failed"; } - logger.info("user: {}", user.getName()); - logger.info("question: {}", savedQuestion.getWriter()); - - savedQuestion.update(changedQuestion); - return "redirect:/"; } @GetMapping("/questions/{id}/updateForm") public String updateForm(Model model, @PathVariable("id") Long id, HttpSession session) { - User user = SessionUtil.getUserBySession(session); - Question savedQuestion = findQuestionById(id); - - if (user == null || !isQuestionMatchUser(user, savedQuestion)) { + try { + questionService.setUpdateForm(id, session); + } catch (QuestionShowException showException) { return "qna/show_failed"; } - logger.info("user: {}", user.getName()); - logger.info("question: {}", savedQuestion.getWriter()); - - model.addAttribute("question", savedQuestion); + model.addAttribute("question", questionService.findQuestionById(id)); return "qna/updateForm"; } @DeleteMapping("/questions/{id}") @Transactional - public String remove(@PathVariable("id") Long id, HttpSession session) { - User user = SessionUtil.getUserBySession(session); - Question savedQuestion = findQuestionById(id); - - logger.info("user: {}", user.getName()); - logger.info("question: {}", savedQuestion.getWriter()); + public String removeQuestion(@PathVariable("id") Long id, HttpSession session) { - if (user == null || !isQuestionMatchUser(user, savedQuestion)) { + try { + questionService.remove(id, session); + } catch (QuestionShowException showException) { return "qna/show_failed"; - } - - if (!canDeleteQuestion(savedQuestion, user)) { + } catch (QuestionDeleteException deleteException) { return "qna/delete_failed"; } - savedQuestion.changeDeleteFlag(); - - for (Answer answer : savedQuestion.getAnswers()) { - answer.changeDeletedFlag(); - } - return "redirect:/questions/" + id; } - - private Question findQuestionById(Long id) { - return questionRepository.findById(id) - .orElseThrow(NoSuchElementException::new); - } - - private boolean isQuestionMatchUser(User loginUser, Question question) { - return question.equalsWriter(loginUser); - } - - private boolean canDeleteQuestion(Question deletedQuestion, User user) { - if (deletedQuestion.hasAnswers()) { - for (Answer answer : deletedQuestion.getAnswers()) { - if (!answer.equalsWriter(user)) { - return false; - } - } - } - return true; - } - - private int countAnswers(Question question) { - int count = 0; - for (Answer answer : question.getAnswers()) { - if (!answer.isDeletedFlag()) { - count++; - } - } - return count; - } } \ No newline at end of file diff --git a/src/main/java/codesquad/qua/QuestionDto.java b/src/main/java/codesquad/qua/QuestionDto.java new file mode 100644 index 00000000..d201101e --- /dev/null +++ b/src/main/java/codesquad/qua/QuestionDto.java @@ -0,0 +1,13 @@ +package codesquad.qua; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class QuestionDto { + + private String writer; + private String title; + private String contents; +} diff --git a/src/main/java/codesquad/qua/QuestionRepository.java b/src/main/java/codesquad/qua/QuestionRepository.java index f70e48fa..b5088d7c 100644 --- a/src/main/java/codesquad/qua/QuestionRepository.java +++ b/src/main/java/codesquad/qua/QuestionRepository.java @@ -1,6 +1,13 @@ package codesquad.qua; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; public interface QuestionRepository extends JpaRepository { + + @Query(value = "select count(*) " + + "from Question q right outer join Answer a " + + "on q.id=a.id " + + "where a.deleted_flag=false", nativeQuery = true) + int countNotDeletedAnswers(long id); } diff --git a/src/main/java/codesquad/qua/QuestionService.java b/src/main/java/codesquad/qua/QuestionService.java new file mode 100644 index 00000000..50857944 --- /dev/null +++ b/src/main/java/codesquad/qua/QuestionService.java @@ -0,0 +1,119 @@ +package codesquad.qua; + +import codesquad.answer.Answer; +import codesquad.exception.QuestionDeleteException; +import codesquad.exception.QuestionShowException; +import codesquad.user.User; +import codesquad.utils.SessionUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpSession; +import java.util.List; +import java.util.NoSuchElementException; + +@Slf4j +@RequiredArgsConstructor +@Service +public class QuestionService { + + private final QuestionRepository questionRepository; + + public boolean setCreateForm(HttpSession session) { + User user = SessionUtil.getUserBySession(session); + + return user != null; + } + + public boolean create(QuestionDto questionDto, HttpSession session) { + log.info("작성자 = {}", questionDto.getWriter()); + log.info("제목 = {}", questionDto.getTitle()); + + User user = SessionUtil.getUserBySession(session); + + if (user == null) { + return false; + } + + questionRepository.save(new Question(questionDto, user)); + + return true; + } + + public List list() { + return questionRepository.findAll(); + } + + public void setUpdateForm(long id, HttpSession session) { + User user = SessionUtil.getUserBySession(session); + Question savedQuestion = findQuestionById(id); + + if (user == null || !isQuestionMatchUser(user, savedQuestion)) { + throw new QuestionShowException(); + } + + log.info("user: {}", user.getName()); + log.info("question: {}", savedQuestion.getWriter()); + } + + public void update(Question changedQuestion, long id, HttpSession session) { + User user = SessionUtil.getUserBySession(session); + Question savedQuestion = findQuestionById(id); + + if (user == null || !isQuestionMatchUser(user, savedQuestion)) { + throw new QuestionShowException(); + } + + log.info("user: {}", user.getName()); + log.info("question: {}", savedQuestion.getWriter()); + + savedQuestion.update(changedQuestion); + } + + public void remove(long id, HttpSession session) { + User user = SessionUtil.getUserBySession(session); + Question savedQuestion = findQuestionById(id); + + log.info("user: {}", user.getName()); + log.info("question: {}", savedQuestion.getWriter()); + + if (user == null || !isQuestionMatchUser(user, savedQuestion)) { + throw new QuestionShowException(); + } + + if (!canDeleteQuestion(savedQuestion, user)) { + throw new QuestionDeleteException(); + } + + savedQuestion.changeDeleteFlag(); + + for (Answer answer : savedQuestion.getAnswers()) { + answer.changeDeletedFlag(); + } + } + + public int countAnswers(long id) { + return questionRepository.countNotDeletedAnswers(id); + } + + public Question findQuestionById(Long id) { + return questionRepository.findById(id) + .orElseThrow(NoSuchElementException::new); + } + + private boolean canDeleteQuestion(Question deletedQuestion, User user) { + if (deletedQuestion.hasAnswers()) { + for (Answer answer : deletedQuestion.getAnswers()) { + if (!answer.equalsWriter(user)) { + return false; + } + } + } + return true; + } + + private boolean isQuestionMatchUser(User loginUser, Question question) { + return question.equalsWriter(loginUser); + } +} diff --git a/src/main/resources/templates/qna/form.html b/src/main/resources/templates/qna/form.html index d442fc9f..0d36189e 100644 --- a/src/main/resources/templates/qna/form.html +++ b/src/main/resources/templates/qna/form.html @@ -7,6 +7,10 @@
{{#sessionedUser}} +
+ + +
From b88e4dcedb1890616372c34842a23dd6855978ed Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Tue, 19 Apr 2022 13:12:18 +0900 Subject: [PATCH 09/21] feat : exception customizing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 서로 다른 에러 발생 시 다른 뷰를 보여야하기 위해 exception 추가 QuestionDeleteException - 삭제할 수 없는 exception 추가 QuestionEditException - 수정할 수 없는 exception 추가 --- .../codesquad/exception/QuestionDeleteException.java | 11 +++++++++++ .../codesquad/exception/QuestionEditException.java | 11 +++++++++++ src/main/java/codesquad/qua/QuestionController.java | 8 ++++---- src/main/java/codesquad/qua/QuestionService.java | 8 ++++---- 4 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 src/main/java/codesquad/exception/QuestionDeleteException.java create mode 100644 src/main/java/codesquad/exception/QuestionEditException.java diff --git a/src/main/java/codesquad/exception/QuestionDeleteException.java b/src/main/java/codesquad/exception/QuestionDeleteException.java new file mode 100644 index 00000000..549f69ae --- /dev/null +++ b/src/main/java/codesquad/exception/QuestionDeleteException.java @@ -0,0 +1,11 @@ +package codesquad.exception; + +public class QuestionDeleteException extends RuntimeException{ + + public QuestionDeleteException() { + } + + public QuestionDeleteException(String message) { + super(message); + } +} diff --git a/src/main/java/codesquad/exception/QuestionEditException.java b/src/main/java/codesquad/exception/QuestionEditException.java new file mode 100644 index 00000000..77411e46 --- /dev/null +++ b/src/main/java/codesquad/exception/QuestionEditException.java @@ -0,0 +1,11 @@ +package codesquad.exception; + +public class QuestionEditException extends RuntimeException { + + public QuestionEditException() { + } + + public QuestionEditException(String message) { + super(message); + } +} diff --git a/src/main/java/codesquad/qua/QuestionController.java b/src/main/java/codesquad/qua/QuestionController.java index 00de9f63..d72bbca5 100644 --- a/src/main/java/codesquad/qua/QuestionController.java +++ b/src/main/java/codesquad/qua/QuestionController.java @@ -1,7 +1,7 @@ package codesquad.qua; import codesquad.exception.QuestionDeleteException; -import codesquad.exception.QuestionShowException; +import codesquad.exception.QuestionEditException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; @@ -54,7 +54,7 @@ public String showQuestion(Model model, @PathVariable("id") Long id) { public String updateQuestion(Question changedQuestion, @PathVariable("id") Long id, HttpSession session) { try { questionService.update(changedQuestion, id, session); - } catch (QuestionShowException showException) { + } catch (QuestionEditException showException) { return "qna/show_failed"; } @@ -65,7 +65,7 @@ public String updateQuestion(Question changedQuestion, @PathVariable("id") Long public String updateForm(Model model, @PathVariable("id") Long id, HttpSession session) { try { questionService.setUpdateForm(id, session); - } catch (QuestionShowException showException) { + } catch (QuestionEditException showException) { return "qna/show_failed"; } @@ -80,7 +80,7 @@ public String removeQuestion(@PathVariable("id") Long id, HttpSession session) { try { questionService.remove(id, session); - } catch (QuestionShowException showException) { + } catch (QuestionEditException showException) { return "qna/show_failed"; } catch (QuestionDeleteException deleteException) { return "qna/delete_failed"; diff --git a/src/main/java/codesquad/qua/QuestionService.java b/src/main/java/codesquad/qua/QuestionService.java index 50857944..c9e677fa 100644 --- a/src/main/java/codesquad/qua/QuestionService.java +++ b/src/main/java/codesquad/qua/QuestionService.java @@ -2,7 +2,7 @@ import codesquad.answer.Answer; import codesquad.exception.QuestionDeleteException; -import codesquad.exception.QuestionShowException; +import codesquad.exception.QuestionEditException; import codesquad.user.User; import codesquad.utils.SessionUtil; import lombok.RequiredArgsConstructor; @@ -50,7 +50,7 @@ public void setUpdateForm(long id, HttpSession session) { Question savedQuestion = findQuestionById(id); if (user == null || !isQuestionMatchUser(user, savedQuestion)) { - throw new QuestionShowException(); + throw new QuestionEditException(); } log.info("user: {}", user.getName()); @@ -62,7 +62,7 @@ public void update(Question changedQuestion, long id, HttpSession session) { Question savedQuestion = findQuestionById(id); if (user == null || !isQuestionMatchUser(user, savedQuestion)) { - throw new QuestionShowException(); + throw new QuestionEditException(); } log.info("user: {}", user.getName()); @@ -79,7 +79,7 @@ public void remove(long id, HttpSession session) { log.info("question: {}", savedQuestion.getWriter()); if (user == null || !isQuestionMatchUser(user, savedQuestion)) { - throw new QuestionShowException(); + throw new QuestionEditException(); } if (!canDeleteQuestion(savedQuestion, user)) { From 70ded2a1a6b8b4b5d3257c4f5fe625ae9ecc9b02 Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Tue, 19 Apr 2022 15:29:04 +0900 Subject: [PATCH 10/21] =?UTF-8?q?feat=20:=20service=20layer=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AnswerController - ApiAnswerController와 AnswerService로 분리 --- src/main/java/codesquad/answer/Answer.java | 51 +++++++------------ ...swerController.java => AnswerService.java} | 39 ++++++-------- .../codesquad/answer/ApiAnswerController.java | 27 ++++++++++ .../codesquad/answer/RequestAnswerDto.java | 10 ++++ .../codesquad/answer/ResponseAnswerDto.java | 16 ++++++ src/main/java/codesquad/response/Result.java | 10 ++-- src/main/resources/static/js/scripts.js | 16 +++--- src/main/resources/templates/qna/show.html | 2 +- 8 files changed, 101 insertions(+), 70 deletions(-) rename src/main/java/codesquad/answer/{AnswerController.java => AnswerService.java} (53%) create mode 100644 src/main/java/codesquad/answer/ApiAnswerController.java create mode 100644 src/main/java/codesquad/answer/RequestAnswerDto.java create mode 100644 src/main/java/codesquad/answer/ResponseAnswerDto.java diff --git a/src/main/java/codesquad/answer/Answer.java b/src/main/java/codesquad/answer/Answer.java index 394b1539..83882fa2 100644 --- a/src/main/java/codesquad/answer/Answer.java +++ b/src/main/java/codesquad/answer/Answer.java @@ -2,10 +2,14 @@ import codesquad.qua.Question; import codesquad.user.User; +import lombok.Getter; +import lombok.NoArgsConstructor; import javax.persistence.*; @Entity +@Getter +@NoArgsConstructor public class Answer { @Id @@ -16,54 +20,35 @@ public class Answer { @JoinColumn(foreignKey = @ForeignKey(name = "fk_answer_to_question")) private Question question; - private String writer; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(foreignKey = @ForeignKey(name = "fk_answer_to_user")) + private User writer; private String comment; - private boolean deletedFlag = false; + private boolean deletedFlag; - public boolean isDeletedFlag() { - return deletedFlag; + public Answer(Question question, User writer, String comment) { + this.question = question; + this.writer = writer; + this.comment = comment; + deletedFlag = false; } public void changeDeletedFlag() { deletedFlag = true; } - public String getWriter() { - return writer; - } - - public void setWriter(String writer) { - this.writer = writer; - } - - public Long getId() { - return id; - } - - public Question getQuestion() { - return question; - } - - public void setQuestion(Question question) { - this.question = question; - } - - public String getComment() { - return comment; - } - - public void setComment(String comment) { - this.comment = comment; - } - public void addQuestion(Question question) { question.getAnswers().add(this); this.question = question; } public boolean equalsWriter(User user) { - return writer.equals(user.getName()); + return writer.equals(user); + } + + public ResponseAnswerDto toResponseAnswerDto() { + return new ResponseAnswerDto(id, comment, question.getId(), writer.getName()); } } diff --git a/src/main/java/codesquad/answer/AnswerController.java b/src/main/java/codesquad/answer/AnswerService.java similarity index 53% rename from src/main/java/codesquad/answer/AnswerController.java rename to src/main/java/codesquad/answer/AnswerService.java index 894f6c74..4c669a7f 100644 --- a/src/main/java/codesquad/answer/AnswerController.java +++ b/src/main/java/codesquad/answer/AnswerService.java @@ -5,50 +5,43 @@ import codesquad.response.Result; import codesquad.user.User; import codesquad.utils.SessionUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpSession; import java.util.NoSuchElementException; -@RestController -public class AnswerController { +@Service +@Slf4j +@RequiredArgsConstructor +public class AnswerService { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - @Autowired - private AnswerRepository answerRepository; - @Autowired - private QuestionRepository questionRepository; + private final AnswerRepository answerRepository; + private final QuestionRepository questionRepository; + + public ResponseAnswerDto create(long questionId, RequestAnswerDto requestAnswerDto, HttpSession session) { + log.info("comment = {}", requestAnswerDto.getComment()); - @PostMapping("/questions/{question-id}/answers") - public Answer create(@PathVariable("question-id") Long questionId, @RequestBody Answer answer, HttpSession session) { Question question = questionRepository.findById(questionId) .orElseThrow(NoSuchElementException::new); - logger.info("답글 내용 : {}", answer.getComment()); - logger.info("답글 작성자 : {}", answer.getWriter()); - User user = SessionUtil.getUserBySession(session); if (user == null) { return null; } - answer.setWriter(user.getName()); + Answer answer = new Answer(question, user, requestAnswerDto.getComment()); answer.addQuestion(question); - answerRepository.save(answer); - return answer; + return answer.toResponseAnswerDto(); } - @DeleteMapping("/questions/{question-id}/answers/{answer-id}") @Transactional - public Result remove(@PathVariable("question-id") Long questionId, - @PathVariable("answer-id") Long answerId, HttpSession session) { + public Result remove(long questionId, long answerId, HttpSession session) { User user = SessionUtil.getUserBySession(session); Answer answer = answerRepository.findQuestionFetchJoinById(answerId) @@ -64,6 +57,6 @@ public Result remove(@PathVariable("question-id") Long questionId, answer.changeDeletedFlag(); - return Result.ok(answer); + return Result.ok(answer.toResponseAnswerDto()); } } \ No newline at end of file diff --git a/src/main/java/codesquad/answer/ApiAnswerController.java b/src/main/java/codesquad/answer/ApiAnswerController.java new file mode 100644 index 00000000..a92c3774 --- /dev/null +++ b/src/main/java/codesquad/answer/ApiAnswerController.java @@ -0,0 +1,27 @@ +package codesquad.answer; + +import codesquad.response.Result; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpSession; + +@RestController +@RequiredArgsConstructor +@Slf4j +public class ApiAnswerController { + + private final AnswerService answerService; + + @PostMapping("/questions/{question-id}/answers") + public ResponseAnswerDto create(@PathVariable("question-id") Long questionId, @RequestBody RequestAnswerDto requestAnswerDto, HttpSession session) { + return answerService.create(questionId, requestAnswerDto, session); + } + + @DeleteMapping("/questions/{question-id}/answers/{answer-id}") + public Result remove(@PathVariable("question-id") Long questionId, + @PathVariable("answer-id") Long answerId, HttpSession session) { + return answerService.remove(questionId, answerId, session); + } +} diff --git a/src/main/java/codesquad/answer/RequestAnswerDto.java b/src/main/java/codesquad/answer/RequestAnswerDto.java new file mode 100644 index 00000000..6ffd5d38 --- /dev/null +++ b/src/main/java/codesquad/answer/RequestAnswerDto.java @@ -0,0 +1,10 @@ +package codesquad.answer; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class RequestAnswerDto { + private String comment; +} diff --git a/src/main/java/codesquad/answer/ResponseAnswerDto.java b/src/main/java/codesquad/answer/ResponseAnswerDto.java new file mode 100644 index 00000000..9a9feb43 --- /dev/null +++ b/src/main/java/codesquad/answer/ResponseAnswerDto.java @@ -0,0 +1,16 @@ +package codesquad.answer; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +public class ResponseAnswerDto { + + private long id; + private String comment; + private long questionId; + private String writer; +} diff --git a/src/main/java/codesquad/response/Result.java b/src/main/java/codesquad/response/Result.java index 627d9f00..423526e0 100644 --- a/src/main/java/codesquad/response/Result.java +++ b/src/main/java/codesquad/response/Result.java @@ -1,5 +1,8 @@ package codesquad.response; +import lombok.Getter; + +@Getter public class Result { private T result; @@ -18,11 +21,4 @@ public static Result fail(String message) { return new Result<>(null, message); } - public T getResult() { - return result; - } - - public String getMessage() { - return message; - } } \ No newline at end of file diff --git a/src/main/resources/static/js/scripts.js b/src/main/resources/static/js/scripts.js index d9ce3a55..0ca971c8 100755 --- a/src/main/resources/static/js/scripts.js +++ b/src/main/resources/static/js/scripts.js @@ -70,8 +70,11 @@ function registerAnswerHandler(evt) { }) } -function appendAnswer({id, comment, question, writer}) { +function appendAnswer({id, comment, questionId, writer}) { console.log("id = " + id); + console.log("comment = " + comment); + console.log("question = " + questionId); + console.log("writer = " + writer); const html = `
@@ -97,11 +100,11 @@ function appendAnswer({id, comment, question, writer}) { href="/questions/413/answers/1405/form">수정
  • - + onclick="deleteAnswerHandler(this)" value="${id}/${questionId}">삭제
  • @@ -109,11 +112,11 @@ function appendAnswer({id, comment, question, writer}) {
    ` $(".qna-comment-slipp-articles").insertAdjacentHTML("beforeend", html); - initEvents(); } function deleteAnswerHandler(target) { - // target.preventDefault(); + if(target.className !== "delete-answer-button") return; + console.log("target = " + target); const value = target.value.split("/"); console.log("value = " + value); const url = "/questions/" + value[1] + "/answers/" + value[0]; @@ -129,7 +132,8 @@ function deleteAnswerHandler(target) { } function deleteAnswer({result}) { - console.log("id = " + result.id); + console.log("result = " + result); + console.log("result.id = " + result.id); const selector = `.article-hi[data-id='${result.id}']`; console.log("deleteAnswer" + selector); const target = $(selector); diff --git a/src/main/resources/templates/qna/show.html b/src/main/resources/templates/qna/show.html index 93472dcf..66093d51 100644 --- a/src/main/resources/templates/qna/show.html +++ b/src/main/resources/templates/qna/show.html @@ -59,7 +59,7 @@

    {{title}}

    class="article-author-thumb" alt="">
    - + 2016-01-12 14:06 From df10b19aa1bf666b0e18779413b923f3921f307a Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Tue, 19 Apr 2022 16:32:40 +0900 Subject: [PATCH 11/21] =?UTF-8?q?fix=20:=20=EB=8B=B5=EA=B8=80=20=EA=B0=9C?= =?UTF-8?q?=EC=88=98=20=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 답글의 개수가 모든 게시글에서 공유가 되는 버그 해결 - 1번 게시글의 답글이 2개, 2번 게시글의 답글이 2개일 경우 모든 게시글의 답글이 4개라고 측정됨 --- src/main/java/codesquad/qua/QuestionRepository.java | 11 ++++++----- src/main/java/codesquad/qua/QuestionService.java | 10 ++++++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/codesquad/qua/QuestionRepository.java b/src/main/java/codesquad/qua/QuestionRepository.java index b5088d7c..bd64d29e 100644 --- a/src/main/java/codesquad/qua/QuestionRepository.java +++ b/src/main/java/codesquad/qua/QuestionRepository.java @@ -2,12 +2,13 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface QuestionRepository extends JpaRepository { - @Query(value = "select count(*) " + - "from Question q right outer join Answer a " + - "on q.id=a.id " + - "where a.deleted_flag=false", nativeQuery = true) - int countNotDeletedAnswers(long id); + @Query("select count(q.id) from Question q" + + " join Answer a" + + " on a.question.id=q.id" + + " where a.deletedFlag=false and q.id=:id") + Long countNotDeletedAnswers(@Param("id") long questionId); } diff --git a/src/main/java/codesquad/qua/QuestionService.java b/src/main/java/codesquad/qua/QuestionService.java index c9e677fa..07cbb8bc 100644 --- a/src/main/java/codesquad/qua/QuestionService.java +++ b/src/main/java/codesquad/qua/QuestionService.java @@ -93,8 +93,14 @@ public void remove(long id, HttpSession session) { } } - public int countAnswers(long id) { - return questionRepository.countNotDeletedAnswers(id); + public long countAnswers(long id) { + Long countAnswer = questionRepository.countNotDeletedAnswers(id); + + if(countAnswer == null) { + return 0L; + } + + return countAnswer; } public Question findQuestionById(Long id) { From 837c0a8501dd8312400641a1b92f2887c9c4d43b Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Tue, 19 Apr 2022 16:48:23 +0900 Subject: [PATCH 12/21] =?UTF-8?q?feat=20:=20=EB=8B=B5=EA=B8=80=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=8B=9C=20Result=20=EB=B0=98=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/codesquad/answer/AnswerService.java | 6 +++--- src/main/java/codesquad/answer/ApiAnswerController.java | 2 +- src/main/resources/static/js/scripts.js | 8 +++++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/codesquad/answer/AnswerService.java b/src/main/java/codesquad/answer/AnswerService.java index 4c669a7f..69136ea9 100644 --- a/src/main/java/codesquad/answer/AnswerService.java +++ b/src/main/java/codesquad/answer/AnswerService.java @@ -21,7 +21,7 @@ public class AnswerService { private final AnswerRepository answerRepository; private final QuestionRepository questionRepository; - public ResponseAnswerDto create(long questionId, RequestAnswerDto requestAnswerDto, HttpSession session) { + public Result create(long questionId, RequestAnswerDto requestAnswerDto, HttpSession session) { log.info("comment = {}", requestAnswerDto.getComment()); Question question = questionRepository.findById(questionId) @@ -30,14 +30,14 @@ public ResponseAnswerDto create(long questionId, RequestAnswerDto requestAnswerD User user = SessionUtil.getUserBySession(session); if (user == null) { - return null; + return Result.fail("로그인 하세요"); } Answer answer = new Answer(question, user, requestAnswerDto.getComment()); answer.addQuestion(question); answerRepository.save(answer); - return answer.toResponseAnswerDto(); + return Result.ok(answer.toResponseAnswerDto()); } @Transactional diff --git a/src/main/java/codesquad/answer/ApiAnswerController.java b/src/main/java/codesquad/answer/ApiAnswerController.java index a92c3774..01584dda 100644 --- a/src/main/java/codesquad/answer/ApiAnswerController.java +++ b/src/main/java/codesquad/answer/ApiAnswerController.java @@ -15,7 +15,7 @@ public class ApiAnswerController { private final AnswerService answerService; @PostMapping("/questions/{question-id}/answers") - public ResponseAnswerDto create(@PathVariable("question-id") Long questionId, @RequestBody RequestAnswerDto requestAnswerDto, HttpSession session) { + public Result create(@PathVariable("question-id") Long questionId, @RequestBody RequestAnswerDto requestAnswerDto, HttpSession session) { return answerService.create(questionId, requestAnswerDto, session); } diff --git a/src/main/resources/static/js/scripts.js b/src/main/resources/static/js/scripts.js index 0ca971c8..ee47ef4f 100755 --- a/src/main/resources/static/js/scripts.js +++ b/src/main/resources/static/js/scripts.js @@ -70,7 +70,13 @@ function registerAnswerHandler(evt) { }) } -function appendAnswer({id, comment, questionId, writer}) { +function appendAnswer({result}) { + console.log("result = " + result); + id = result.id; + comment = result.comment; + questionId = result.questionId; + writer = result.writer; + console.log("id = " + id); console.log("comment = " + comment); console.log("question = " + questionId); From 7ea56a78e39d58a7808307b5b2542679a7870596 Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Wed, 20 Apr 2022 17:14:27 +0900 Subject: [PATCH 13/21] =?UTF-8?q?refactor=20:=20=EC=A7=88=EB=AC=B8=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EC=83=81=ED=83=9C=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EC=8B=9C=20"=EC=A7=88=EB=AC=B8=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EC=83=81=ED=83=9C"=20=EB=A9=94=EC=84=9C=EB=93=9C=20extract?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QuestionService에서 질문 삭제 상태 변경 시 해당 질문에 있는 답글들의 삭제 상태 변경을 Question 에서 수행 --- src/main/java/codesquad/qua/Question.java | 8 ++++++++ src/main/java/codesquad/qua/QuestionService.java | 6 +----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/codesquad/qua/Question.java b/src/main/java/codesquad/qua/Question.java index 681c2f49..b9d68706 100644 --- a/src/main/java/codesquad/qua/Question.java +++ b/src/main/java/codesquad/qua/Question.java @@ -57,4 +57,12 @@ public boolean equalsWriter(User user) { public boolean hasAnswers() { return answers.size() > 0; } + + public void deleteQuestion() { + changeDeleteFlag(); + + for (Answer answer : answers) { + answer.changeDeletedFlag(); + } + } } \ No newline at end of file diff --git a/src/main/java/codesquad/qua/QuestionService.java b/src/main/java/codesquad/qua/QuestionService.java index 07cbb8bc..84fbd1af 100644 --- a/src/main/java/codesquad/qua/QuestionService.java +++ b/src/main/java/codesquad/qua/QuestionService.java @@ -86,11 +86,7 @@ public void remove(long id, HttpSession session) { throw new QuestionDeleteException(); } - savedQuestion.changeDeleteFlag(); - - for (Answer answer : savedQuestion.getAnswers()) { - answer.changeDeletedFlag(); - } + savedQuestion.deleteQuestion(); } public long countAnswers(long id) { From 18331b5ce596670ee6ffa4bc1b65468c31381c01 Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Wed, 20 Apr 2022 17:36:21 +0900 Subject: [PATCH 14/21] =?UTF-8?q?feat=20:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=8B=9C=20DTO=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/codesquad/qua/QuestionService.java | 4 +- .../user/{UserDto.java => LoginUserDto.java} | 2 +- .../java/codesquad/user/SingUpUserDto.java | 16 +++++++ src/main/java/codesquad/user/User.java | 48 +++++-------------- .../java/codesquad/user/UserController.java | 18 +++---- src/main/java/codesquad/user/UserService.java | 35 ++++++-------- 6 files changed, 56 insertions(+), 67 deletions(-) rename src/main/java/codesquad/user/{UserDto.java => LoginUserDto.java} (87%) create mode 100644 src/main/java/codesquad/user/SingUpUserDto.java diff --git a/src/main/java/codesquad/qua/QuestionService.java b/src/main/java/codesquad/qua/QuestionService.java index 84fbd1af..3a59f38e 100644 --- a/src/main/java/codesquad/qua/QuestionService.java +++ b/src/main/java/codesquad/qua/QuestionService.java @@ -89,8 +89,8 @@ public void remove(long id, HttpSession session) { savedQuestion.deleteQuestion(); } - public long countAnswers(long id) { - Long countAnswer = questionRepository.countNotDeletedAnswers(id); + public long countAnswers(long questionId) { + Long countAnswer = questionRepository.countNotDeletedAnswers(questionId); if(countAnswer == null) { return 0L; diff --git a/src/main/java/codesquad/user/UserDto.java b/src/main/java/codesquad/user/LoginUserDto.java similarity index 87% rename from src/main/java/codesquad/user/UserDto.java rename to src/main/java/codesquad/user/LoginUserDto.java index 4cc84253..6c00e26b 100644 --- a/src/main/java/codesquad/user/UserDto.java +++ b/src/main/java/codesquad/user/LoginUserDto.java @@ -7,7 +7,7 @@ @Getter @Setter @AllArgsConstructor -public class UserDto { +public class LoginUserDto { private String userId; private String password; diff --git a/src/main/java/codesquad/user/SingUpUserDto.java b/src/main/java/codesquad/user/SingUpUserDto.java new file mode 100644 index 00000000..4cc78f37 --- /dev/null +++ b/src/main/java/codesquad/user/SingUpUserDto.java @@ -0,0 +1,16 @@ +package codesquad.user; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +public class SingUpUserDto { + + private String userId; + private String password; + private String name; + private String email; +} diff --git a/src/main/java/codesquad/user/User.java b/src/main/java/codesquad/user/User.java index 89dd791d..eaa4b935 100644 --- a/src/main/java/codesquad/user/User.java +++ b/src/main/java/codesquad/user/User.java @@ -1,10 +1,15 @@ package codesquad.user; +import lombok.Getter; +import lombok.NoArgsConstructor; + import javax.persistence.*; import java.util.Objects; @Entity +@NoArgsConstructor +@Getter public class User { @Id @@ -20,40 +25,11 @@ public class User { private String email; - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public Long getId() { - return id; + User(SingUpUserDto singUpUserDto) { + userId = singUpUserDto.getUserId(); + password = singUpUserDto.getPassword(); + name = singUpUserDto.getName(); + email = singUpUserDto.getEmail(); } public void update(User user) { @@ -67,8 +43,8 @@ public boolean equalsPassword(String password) { return this.password.equals(password); } - public boolean equalsPassword(UserDto userDto) { - return password.equals(userDto.getPassword()); + public boolean equalsPassword(LoginUserDto loginUserDto) { + return password.equals(loginUserDto.getPassword()); } public boolean equalsId(Long id) { diff --git a/src/main/java/codesquad/user/UserController.java b/src/main/java/codesquad/user/UserController.java index 4a4e9136..07e8780e 100644 --- a/src/main/java/codesquad/user/UserController.java +++ b/src/main/java/codesquad/user/UserController.java @@ -21,27 +21,27 @@ public class UserController { private final UserService userService; @PostMapping("") - public String join(User user) { - userService.create(user); + public String join(SingUpUserDto singUpUserDto) { + userService.create(singUpUserDto); return "redirect:/users"; } @GetMapping("") public String showUserList(Model model) { - userService.list(model); + model.addAttribute("users", userService.list()); return "/user/list"; } @GetMapping("{id}") public ModelAndView showUser(@PathVariable long id) { ModelAndView mav = new ModelAndView("user/profile"); - userService.show(id, mav); + mav.addObject("user", userService.findUserById(id)); return mav; } @GetMapping("{id}/form") public String updateForm(Model model, @PathVariable("id") Long id) { - userService.setUpdateForm(model, id); + model.addAttribute("user", userService.findUserById(id)); return "/user/updateForm"; } @@ -56,9 +56,11 @@ public String updateUser(User changedUser, @PathVariable("id") Long id, HttpSess } @PostMapping("/login") - public String loginUser(UserDto userDto, HttpSession session) { - userService.login(userDto, session); + public String loginUser(LoginUserDto loginUserDto, HttpSession session) { + if(userService.login(loginUserDto, session)){ + return "redirect:/users"; + } - return "redirect:/users"; + return "/user/login_failed"; } } \ No newline at end of file diff --git a/src/main/java/codesquad/user/UserService.java b/src/main/java/codesquad/user/UserService.java index da4bf0cb..4f5db309 100644 --- a/src/main/java/codesquad/user/UserService.java +++ b/src/main/java/codesquad/user/UserService.java @@ -5,10 +5,9 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.ui.Model; -import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpSession; +import java.util.List; import java.util.NoSuchElementException; @Service @@ -18,27 +17,20 @@ public class UserService { private final UserRepository userRepository; - public void create(User user) { - log.info("user = {}", user); - userRepository.save(user); - } - - public void list(Model model) { - model.addAttribute("users", userRepository.findAll()); + public void create(SingUpUserDto singUpUserDto) { + log.info("singUpUserDto = {}", singUpUserDto); + userRepository.save(new User(singUpUserDto)); } - public void show(long userId, ModelAndView modelAndView) { - modelAndView.addObject("user", findUserById(userId)); - } - - public void setUpdateForm(Model model, long userId) { - model.addAttribute("user", findUserById(userId)); + public List list() { + return userRepository.findAll(); } @Transactional public boolean update(User changedUser, long userId, HttpSession session) { log.info("changedUser = {}", changedUser); log.info("userId = {}", userId); + User user = SessionUtil.getUserBySession(session); if (user == null || !user.equalsId(userId)) { @@ -51,16 +43,19 @@ public boolean update(User changedUser, long userId, HttpSession session) { return true; } - public void login(UserDto userDto, HttpSession session) { - User savedUser = userRepository.findByUserId(userDto.getUserId()) - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 회원")); + public boolean login(LoginUserDto loginUserDto, HttpSession session) { + User savedUser = userRepository.findByUserId(loginUserDto.getUserId()) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 회원")); - if (savedUser.equalsPassword(userDto)) { + if (savedUser.equalsPassword(loginUserDto)) { SessionUtil.setSession(session, savedUser); + return true; } + + return false; } - private User findUserById(long userId) { + public User findUserById(long userId) { return userRepository.findById(userId) .orElseThrow(NoSuchElementException::new); } From 8c605ad32c06d5c3d179145f7e0081c6aa657f00 Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Wed, 20 Apr 2022 17:52:23 +0900 Subject: [PATCH 15/21] =?UTF-8?q?fix=20:=20equals,=20hashcode=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/codesquad/user/User.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/main/java/codesquad/user/User.java b/src/main/java/codesquad/user/User.java index eaa4b935..be483f22 100644 --- a/src/main/java/codesquad/user/User.java +++ b/src/main/java/codesquad/user/User.java @@ -50,21 +50,4 @@ public boolean equalsPassword(LoginUserDto loginUserDto) { public boolean equalsId(Long id) { return this.id.equals(id); } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - User user = (User) o; - return Objects.equals(getId(), user.getId()) && - Objects.equals(getUserId(), user.getUserId()) && - Objects.equals(getPassword(), user.getPassword()) && - Objects.equals(getName(), user.getName()) && - Objects.equals(getEmail(), user.getEmail()); - } - - @Override - public int hashCode() { - return Objects.hash(getId(), getUserId(), getPassword(), getName(), getEmail()); - } } From 0a731ff59ea5ed6f2e76cb567c4dc94221810bc1 Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Wed, 20 Apr 2022 17:57:55 +0900 Subject: [PATCH 16/21] style : code formatting --- .../java/codesquad/exception/QuestionDeleteException.java | 2 +- src/main/java/codesquad/qua/QuestionService.java | 2 +- src/main/java/codesquad/response/Result.java | 4 ++-- src/main/java/codesquad/user/User.java | 1 - 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/codesquad/exception/QuestionDeleteException.java b/src/main/java/codesquad/exception/QuestionDeleteException.java index 549f69ae..11c3b2fe 100644 --- a/src/main/java/codesquad/exception/QuestionDeleteException.java +++ b/src/main/java/codesquad/exception/QuestionDeleteException.java @@ -1,6 +1,6 @@ package codesquad.exception; -public class QuestionDeleteException extends RuntimeException{ +public class QuestionDeleteException extends RuntimeException { public QuestionDeleteException() { } diff --git a/src/main/java/codesquad/qua/QuestionService.java b/src/main/java/codesquad/qua/QuestionService.java index 3a59f38e..7aa5c85a 100644 --- a/src/main/java/codesquad/qua/QuestionService.java +++ b/src/main/java/codesquad/qua/QuestionService.java @@ -92,7 +92,7 @@ public void remove(long id, HttpSession session) { public long countAnswers(long questionId) { Long countAnswer = questionRepository.countNotDeletedAnswers(questionId); - if(countAnswer == null) { + if (countAnswer == null) { return 0L; } diff --git a/src/main/java/codesquad/response/Result.java b/src/main/java/codesquad/response/Result.java index 423526e0..1d68186d 100644 --- a/src/main/java/codesquad/response/Result.java +++ b/src/main/java/codesquad/response/Result.java @@ -5,8 +5,8 @@ @Getter public class Result { - private T result; - private String message; + private final T result; + private final String message; public Result(T answer, String message) { this.result = answer; diff --git a/src/main/java/codesquad/user/User.java b/src/main/java/codesquad/user/User.java index be483f22..47516cff 100644 --- a/src/main/java/codesquad/user/User.java +++ b/src/main/java/codesquad/user/User.java @@ -5,7 +5,6 @@ import lombok.NoArgsConstructor; import javax.persistence.*; -import java.util.Objects; @Entity @NoArgsConstructor From 5358c4a6295a26582b789a5086d783df1c456e14 Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Sat, 23 Apr 2022 00:08:41 +0900 Subject: [PATCH 17/21] =?UTF-8?q?refactor=20:=20@Transactional=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QuestionController -> QuestionService --- src/main/java/codesquad/qua/QuestionController.java | 2 -- src/main/java/codesquad/qua/QuestionService.java | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/codesquad/qua/QuestionController.java b/src/main/java/codesquad/qua/QuestionController.java index d72bbca5..3b80c6e2 100644 --- a/src/main/java/codesquad/qua/QuestionController.java +++ b/src/main/java/codesquad/qua/QuestionController.java @@ -49,7 +49,6 @@ public String showQuestion(Model model, @PathVariable("id") Long id) { return "qna/show"; } - @Transactional @PutMapping("/questions/{id}") public String updateQuestion(Question changedQuestion, @PathVariable("id") Long id, HttpSession session) { try { @@ -75,7 +74,6 @@ public String updateForm(Model model, @PathVariable("id") Long id, HttpSession s } @DeleteMapping("/questions/{id}") - @Transactional public String removeQuestion(@PathVariable("id") Long id, HttpSession session) { try { diff --git a/src/main/java/codesquad/qua/QuestionService.java b/src/main/java/codesquad/qua/QuestionService.java index 7aa5c85a..070ea3a8 100644 --- a/src/main/java/codesquad/qua/QuestionService.java +++ b/src/main/java/codesquad/qua/QuestionService.java @@ -8,6 +8,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpSession; import java.util.List; @@ -57,6 +58,7 @@ public void setUpdateForm(long id, HttpSession session) { log.info("question: {}", savedQuestion.getWriter()); } + @Transactional public void update(Question changedQuestion, long id, HttpSession session) { User user = SessionUtil.getUserBySession(session); Question savedQuestion = findQuestionById(id); @@ -71,6 +73,7 @@ public void update(Question changedQuestion, long id, HttpSession session) { savedQuestion.update(changedQuestion); } + @Transactional public void remove(long id, HttpSession session) { User user = SessionUtil.getUserBySession(session); Question savedQuestion = findQuestionById(id); From 933acf55749c0e1e98d2528cfbea32c6eb6fa743 Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Sat, 23 Apr 2022 00:36:15 +0900 Subject: [PATCH 18/21] =?UTF-8?q?fix=20:=20Question=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존 Question에 Setter를 없애서 form에서 데이터를 가져오지 못한 것 해결 --- src/main/java/codesquad/qua/Question.java | 2 +- src/main/java/codesquad/qua/QuestionController.java | 2 +- src/main/java/codesquad/qua/QuestionService.java | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/codesquad/qua/Question.java b/src/main/java/codesquad/qua/Question.java index b9d68706..07ee65f3 100644 --- a/src/main/java/codesquad/qua/Question.java +++ b/src/main/java/codesquad/qua/Question.java @@ -45,7 +45,7 @@ public void changeDeleteFlag() { deletedFlag = true; } - public void update(Question question) { + public void update(QuestionDto question) { this.title = question.getTitle(); this.contents = question.getContents(); } diff --git a/src/main/java/codesquad/qua/QuestionController.java b/src/main/java/codesquad/qua/QuestionController.java index 3b80c6e2..26b2d491 100644 --- a/src/main/java/codesquad/qua/QuestionController.java +++ b/src/main/java/codesquad/qua/QuestionController.java @@ -50,7 +50,7 @@ public String showQuestion(Model model, @PathVariable("id") Long id) { } @PutMapping("/questions/{id}") - public String updateQuestion(Question changedQuestion, @PathVariable("id") Long id, HttpSession session) { + public String updateQuestion(QuestionDto changedQuestion, @PathVariable("id") Long id, HttpSession session) { try { questionService.update(changedQuestion, id, session); } catch (QuestionEditException showException) { diff --git a/src/main/java/codesquad/qua/QuestionService.java b/src/main/java/codesquad/qua/QuestionService.java index 070ea3a8..85f078a8 100644 --- a/src/main/java/codesquad/qua/QuestionService.java +++ b/src/main/java/codesquad/qua/QuestionService.java @@ -59,7 +59,7 @@ public void setUpdateForm(long id, HttpSession session) { } @Transactional - public void update(Question changedQuestion, long id, HttpSession session) { + public void update(QuestionDto changedQuestion, long id, HttpSession session) { User user = SessionUtil.getUserBySession(session); Question savedQuestion = findQuestionById(id); @@ -68,7 +68,8 @@ public void update(Question changedQuestion, long id, HttpSession session) { } log.info("user: {}", user.getName()); - log.info("question: {}", savedQuestion.getWriter()); + log.info("question content: {}", changedQuestion.getContents()); + log.info("question title: {}", changedQuestion.getTitle()); savedQuestion.update(changedQuestion); } @@ -119,6 +120,7 @@ private boolean canDeleteQuestion(Question deletedQuestion, User user) { } private boolean isQuestionMatchUser(User loginUser, Question question) { + log.info("match User? = {}", question.equalsWriter(loginUser)); return question.equalsWriter(loginUser); } } From 349926b577dd31ace2a34e5d16236c81bd15f022 Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Sat, 23 Apr 2022 00:39:24 +0900 Subject: [PATCH 19/21] =?UTF-8?q?fix=20:=20User=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존 User에 Setter를 없애서 form에서 데이터를 가져오지 못한 것 해결 --- src/main/java/codesquad/user/User.java | 2 +- src/main/java/codesquad/user/UserController.java | 2 +- src/main/java/codesquad/user/UserService.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/codesquad/user/User.java b/src/main/java/codesquad/user/User.java index 47516cff..1180ce89 100644 --- a/src/main/java/codesquad/user/User.java +++ b/src/main/java/codesquad/user/User.java @@ -31,7 +31,7 @@ public class User { email = singUpUserDto.getEmail(); } - public void update(User user) { + public void update(SingUpUserDto user) { if (equalsPassword(user.getPassword())) { name = user.getName(); email = user.getEmail(); diff --git a/src/main/java/codesquad/user/UserController.java b/src/main/java/codesquad/user/UserController.java index 07e8780e..4250da52 100644 --- a/src/main/java/codesquad/user/UserController.java +++ b/src/main/java/codesquad/user/UserController.java @@ -46,7 +46,7 @@ public String updateForm(Model model, @PathVariable("id") Long id) { } @PostMapping("{id}/update") - public String updateUser(User changedUser, @PathVariable("id") Long id, HttpSession session) { + public String updateUser(SingUpUserDto changedUser, @PathVariable("id") Long id, HttpSession session) { if (userService.update(changedUser, id, session)) { return "redirect:/users"; diff --git a/src/main/java/codesquad/user/UserService.java b/src/main/java/codesquad/user/UserService.java index 4f5db309..49c59ce4 100644 --- a/src/main/java/codesquad/user/UserService.java +++ b/src/main/java/codesquad/user/UserService.java @@ -27,7 +27,7 @@ public List list() { } @Transactional - public boolean update(User changedUser, long userId, HttpSession session) { + public boolean update(SingUpUserDto changedUser, long userId, HttpSession session) { log.info("changedUser = {}", changedUser); log.info("userId = {}", userId); From c76123bc328daaed5b369e17e98a41416b63d9bf Mon Sep 17 00:00:00 2001 From: hyeonwoo Date: Sat, 23 Apr 2022 00:46:52 +0900 Subject: [PATCH 20/21] =?UTF-8?q?fix=20:=20User=20=EB=8F=99=EC=9D=BC?= =?UTF-8?q?=EC=84=B1=20=ED=8C=90=EB=8B=A8=20=EC=97=90=EB=9F=AC=20=EB=B0=9C?= =?UTF-8?q?=EC=83=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit equals를 overriding 하지 않아 같은 id를 가져도 User가 같지 않다는 에러 해결 --- src/main/java/codesquad/user/User.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/codesquad/user/User.java b/src/main/java/codesquad/user/User.java index 1180ce89..1e3f3917 100644 --- a/src/main/java/codesquad/user/User.java +++ b/src/main/java/codesquad/user/User.java @@ -5,6 +5,7 @@ import lombok.NoArgsConstructor; import javax.persistence.*; +import java.util.Objects; @Entity @NoArgsConstructor @@ -49,4 +50,17 @@ public boolean equalsPassword(LoginUserDto loginUserDto) { public boolean equalsId(Long id) { return this.id.equals(id); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + User user = (User) o; + return Objects.equals(getId(), user.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(getId()); + } } From ae2071fdbee6bb83da3e05803f43981b4591203b Mon Sep 17 00:00:00 2001 From: user Date: Fri, 6 May 2022 17:36:22 +0900 Subject: [PATCH 21/21] =?UTF-8?q?refactor=20:=20=EC=98=A4=ED=83=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20DB=20=EC=A0=91=EA=B7=BC=20?= =?UTF-8?q?=EC=A4=84=EC=9D=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존 코드에선 DB에서 정보를 가져오고, 세션 체크를 하여 필요없는 DB 커넥션 발생 세션 체크를 먼저 하고 DB 접근을 하여 불필요한 DB 접근을 줄이기 --- src/main/java/codesquad/answer/AnswerService.java | 12 ++++++------ .../user/{SingUpUserDto.java => SignUpUserDto.java} | 2 +- src/main/java/codesquad/user/User.java | 12 ++++++------ src/main/java/codesquad/user/UserController.java | 6 +++--- src/main/java/codesquad/user/UserService.java | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) rename src/main/java/codesquad/user/{SingUpUserDto.java => SignUpUserDto.java} (89%) diff --git a/src/main/java/codesquad/answer/AnswerService.java b/src/main/java/codesquad/answer/AnswerService.java index 69136ea9..4e9c4468 100644 --- a/src/main/java/codesquad/answer/AnswerService.java +++ b/src/main/java/codesquad/answer/AnswerService.java @@ -24,15 +24,15 @@ public class AnswerService { public Result create(long questionId, RequestAnswerDto requestAnswerDto, HttpSession session) { log.info("comment = {}", requestAnswerDto.getComment()); - Question question = questionRepository.findById(questionId) - .orElseThrow(NoSuchElementException::new); - User user = SessionUtil.getUserBySession(session); if (user == null) { return Result.fail("로그인 하세요"); } + Question question = questionRepository.findById(questionId) + .orElseThrow(NoSuchElementException::new); + Answer answer = new Answer(question, user, requestAnswerDto.getComment()); answer.addQuestion(question); answerRepository.save(answer); @@ -44,13 +44,13 @@ public Result create(long questionId, RequestAnswerDto reques public Result remove(long questionId, long answerId, HttpSession session) { User user = SessionUtil.getUserBySession(session); - Answer answer = answerRepository.findQuestionFetchJoinById(answerId) - .orElseThrow(NoSuchElementException::new); - if (user == null) { return Result.fail("로그인 하세요"); } + Answer answer = answerRepository.findQuestionFetchJoinById(answerId) + .orElseThrow(NoSuchElementException::new); + if (!answer.equalsWriter(user)) { return Result.fail("다른 사람 답글은 삭제 못해요"); } diff --git a/src/main/java/codesquad/user/SingUpUserDto.java b/src/main/java/codesquad/user/SignUpUserDto.java similarity index 89% rename from src/main/java/codesquad/user/SingUpUserDto.java rename to src/main/java/codesquad/user/SignUpUserDto.java index 4cc78f37..bc6b0794 100644 --- a/src/main/java/codesquad/user/SingUpUserDto.java +++ b/src/main/java/codesquad/user/SignUpUserDto.java @@ -7,7 +7,7 @@ @Getter @Setter @AllArgsConstructor -public class SingUpUserDto { +public class SignUpUserDto { private String userId; private String password; diff --git a/src/main/java/codesquad/user/User.java b/src/main/java/codesquad/user/User.java index 1e3f3917..cfa3a98a 100644 --- a/src/main/java/codesquad/user/User.java +++ b/src/main/java/codesquad/user/User.java @@ -25,14 +25,14 @@ public class User { private String email; - User(SingUpUserDto singUpUserDto) { - userId = singUpUserDto.getUserId(); - password = singUpUserDto.getPassword(); - name = singUpUserDto.getName(); - email = singUpUserDto.getEmail(); + User(SignUpUserDto signUpUserDto) { + userId = signUpUserDto.getUserId(); + password = signUpUserDto.getPassword(); + name = signUpUserDto.getName(); + email = signUpUserDto.getEmail(); } - public void update(SingUpUserDto user) { + public void update(SignUpUserDto user) { if (equalsPassword(user.getPassword())) { name = user.getName(); email = user.getEmail(); diff --git a/src/main/java/codesquad/user/UserController.java b/src/main/java/codesquad/user/UserController.java index 4250da52..7e22e8a6 100644 --- a/src/main/java/codesquad/user/UserController.java +++ b/src/main/java/codesquad/user/UserController.java @@ -21,8 +21,8 @@ public class UserController { private final UserService userService; @PostMapping("") - public String join(SingUpUserDto singUpUserDto) { - userService.create(singUpUserDto); + public String join(SignUpUserDto signUpUserDto) { + userService.create(signUpUserDto); return "redirect:/users"; } @@ -46,7 +46,7 @@ public String updateForm(Model model, @PathVariable("id") Long id) { } @PostMapping("{id}/update") - public String updateUser(SingUpUserDto changedUser, @PathVariable("id") Long id, HttpSession session) { + public String updateUser(SignUpUserDto changedUser, @PathVariable("id") Long id, HttpSession session) { if (userService.update(changedUser, id, session)) { return "redirect:/users"; diff --git a/src/main/java/codesquad/user/UserService.java b/src/main/java/codesquad/user/UserService.java index 49c59ce4..9d52a70c 100644 --- a/src/main/java/codesquad/user/UserService.java +++ b/src/main/java/codesquad/user/UserService.java @@ -17,9 +17,9 @@ public class UserService { private final UserRepository userRepository; - public void create(SingUpUserDto singUpUserDto) { - log.info("singUpUserDto = {}", singUpUserDto); - userRepository.save(new User(singUpUserDto)); + public void create(SignUpUserDto signUpUserDto) { + log.info("singUpUserDto = {}", signUpUserDto); + userRepository.save(new User(signUpUserDto)); } public List list() { @@ -27,7 +27,7 @@ public List list() { } @Transactional - public boolean update(SingUpUserDto changedUser, long userId, HttpSession session) { + public boolean update(SignUpUserDto changedUser, long userId, HttpSession session) { log.info("changedUser = {}", changedUser); log.info("userId = {}", userId);