Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[이노] step 5. XHR과 AJAX #136

Open
wants to merge 21 commits into
base: eNoLJ
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4800a4a
Create ApiAnswerController class
eNoLJ Mar 20, 2021
80f2763
Fix logger of deleteAnswer in AnswerController class
eNoLJ Mar 20, 2021
dd23874
Add @JsonIgnore annotation in User and Question class
eNoLJ Mar 20, 2021
9894af8
Create event in scripts.js
eNoLJ Mar 20, 2021
3f5b778
Modify save method in AnswerService class
eNoLJ Mar 20, 2021
5038c3c
Modify action of form tag in show.html
eNoLJ Mar 20, 2021
6b82801
Add @ResponseStatus of handleUserSessionException method in GlobalExc…
eNoLJ Mar 20, 2021
c232a83
Modify answer delete url in show.html
eNoLJ Mar 20, 2021
6fe83fb
Create an event to delete a answer
eNoLJ Mar 20, 2021
839a6cd
Create deleteAnswer method in ApiAnswerController class
eNoLJ Mar 20, 2021
954ae0b
Add @OrderBy annotation in Question class
eNoLJ Mar 20, 2021
c63eebe
Create updateAnswerCount method in scripts.js
eNoLJ Mar 20, 2021
77f3452
Refactor : Entity 클래스의 update 메소드 리팩토링
eNoLJ Mar 27, 2021
7101788
Refactor : Controller 클래스의 @PathVariable 어노테이션을 활용하여 query string을 받는…
eNoLJ Mar 27, 2021
22f80f3
Feat : 에러 메세지를 상수로 관리하는 ErrorMessage enum 생성
eNoLJ Mar 27, 2021
103a3f2
Refactor : ErrorMessage enum을 활용하여 리팩토링
eNoLJ Mar 27, 2021
630d91a
Feat : AbstractEntity class 생성
eNoLJ Mar 27, 2021
201df39
Refactor : AbstractEntity class를 사용하여 리팩토링
eNoLJ Mar 27, 2021
5bf8245
Feat : Swagger2 라이브러리를 이용한 API 문서화
eNoLJ Mar 27, 2021
7fe0468
Style : 메소드 순서 변경, 불필요한 코드 삭제
eNoLJ Mar 30, 2021
28d66bf
Refactor : Question 클래스의 matchWriterOfAnswerList 메소드 수정
eNoLJ Mar 30, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ dependencies {
developmentOnly 'org.springframework.boot:spring-boot-devtools'
compile 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.3.2'
runtimeOnly 'com.h2database:h2:1.4.192'
compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
}

test {
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/com/codessquad/qna/QnaApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,40 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@SpringBootApplication
@EnableJpaAuditing
@EnableSwagger2
public class QnaApplication {

public static void main(String[] args) {
SpringApplication.run(QnaApplication.class, args);
}

@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("QnaApplication")
.apiInfo(apiInfo())
.select()
.paths(PathSelectors.ant("/api/**"))
.build();
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("My Qna API")
.description("My Qna API")
.version("2.0")
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,30 @@ public AnswerController(AnswerService answerService) {
}

@PostMapping("/answer/{questionId}")
public String createAnswer(@PathVariable("questionId") Long questionId, Answer answer, HttpSession session) {
public String createAnswer(@PathVariable Long questionId, Answer answer, HttpSession session) {
this.answerService.save(questionId, answer, getUserFromSession(session));
logger.info("댓글 등록 요청");
return "redirect:/question/" + questionId;
}

@GetMapping("/answer/{id}")
public String viewUpdateAnswer(@PathVariable("id") Long id, Model model, HttpSession session) {
public String viewUpdateAnswer(@PathVariable Long id, Model model, HttpSession session) {
model.addAttribute("answer", this.answerService.verifyAnswer(id, getUserFromSession(session)));
logger.info("댓글 수정 페이지 요청");
return "qna/updateAnswer";
}

@PutMapping("/answer/{id}")
public String updateAnswer(@PathVariable("id") Long id, Answer answer, HttpSession session) {
public String updateAnswer(@PathVariable Long id, Answer answer, HttpSession session) {
this.answerService.update(id, answer, getUserFromSession(session));
logger.info("댓글 수정 요청");
return "redirect:/question/" + this.answerService.findQuestionId(id);
}

@DeleteMapping("/answer/{id}")
public String deleteAnswer(@PathVariable("id") Long id, HttpSession session) {
public String deleteAnswer(@PathVariable Long id, HttpSession session) {
this.answerService.delete(id, getUserFromSession(session));
logger.info("질문 삭제 요청");
logger.info("댓글 삭제 요청");
return "redirect:/question/" + this.answerService.findQuestionId(id);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.codessquad.qna.controller;

import com.codessquad.qna.model.Answer;
import com.codessquad.qna.service.AnswerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RestController;

import javax.servlet.http.HttpSession;

import static com.codessquad.qna.controller.HttpSessionUtils.getUserFromSession;

@RestController
public class ApiAnswerController {

private final Logger logger = LoggerFactory.getLogger(AnswerController.class);
private final AnswerService answerService;

public ApiAnswerController(AnswerService answerService) {
this.answerService = answerService;
}

@PostMapping("/api/answer/{questionId}")
public Answer createAnswer(@PathVariable Long questionId, Answer answer, HttpSession session) {
logger.info("댓글 등록 요청");
return this.answerService.save(questionId, answer, getUserFromSession(session));
}

@DeleteMapping("/api/answer/{id}")
public Answer deleteAnswer(@PathVariable Long id, HttpSession session) {
logger.info("댓글 삭제 요청");
return this.answerService.delete(id, getUserFromSession(session));
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.codessquad.qna.controller;

import com.codessquad.qna.exception.ErrorMessage;
import com.codessquad.qna.exception.UserSessionException;
import com.codessquad.qna.model.User;

Expand All @@ -15,7 +16,7 @@ public static boolean isLoginUser(HttpSession session) {

public static User getUserFromSession(HttpSession session) {
if (!isLoginUser(session)) {
throw new UserSessionException();
throw new UserSessionException(ErrorMessage.NEED_LOGIN);
}
return (User) session.getAttribute(USER_SESSION_KEY);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,28 +45,28 @@ public String createQuestion(Question question, HttpSession session) {
}

@GetMapping("/question/{id}")
public String viewQuestion(@PathVariable("id") Long id, Model model) {
public String viewQuestion(@PathVariable Long id, Model model) {
model.addAttribute("question", this.questionService.findById(id));
logger.info("상세 질문 페이지 요청");
return "qna/show";
}

@GetMapping("/question/{id}/form")
public String viewUpdateQuestion(@PathVariable("id") Long id, Model model, HttpSession session) {
public String viewUpdateQuestion(@PathVariable Long id, Model model, HttpSession session) {
model.addAttribute("question", this.questionService.verifyQuestion(id, getUserFromSession(session)));
logger.info("질문 수정 페이지 요청");
return "qna/updateForm";
}

@PutMapping("/question/{id}/form")
public String updateQuestion(@PathVariable("id") Long id, Question question, HttpSession session) {
public String updateQuestion(@PathVariable Long id, Question question, HttpSession session) {
this.questionService.update(id, question, getUserFromSession(session));
logger.info("질문 수정 요청");
return "redirect:/question/" + id;
}

@DeleteMapping("/question/{id}")
public String deleteQuestion(@PathVariable("id") Long id, HttpSession session) {
public String deleteQuestion(@PathVariable Long id, HttpSession session) {
boolean result = this.questionService.delete(id, getUserFromSession(session));
logger.info("질문 삭제 요청");
return result ? "redirect:/" : "redirect:/question/" + id;
Expand Down
15 changes: 5 additions & 10 deletions src/main/java/com/codessquad/qna/controller/UserController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.codessquad.qna.model.User;
import com.codessquad.qna.service.UserService;
import org.omg.CORBA.Request;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
Expand All @@ -12,7 +11,6 @@
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import static com.codessquad.qna.controller.HttpSessionUtils.USER_SESSION_KEY;
Expand All @@ -36,8 +34,7 @@ public String viewSingUp() {
}

@PostMapping("/user/form")
public String signUp(User user, HttpServletRequest request) {
request.setAttribute("path", "/user/form");
public String signUp(User user) {
this.userService.save(user);
logger.info("회원가입 요청");
return "redirect:/user/list";
Expand All @@ -50,8 +47,7 @@ public String viewLogin() {
}

@PostMapping("/user/login")
public String login(String userId, String password, HttpServletRequest request, HttpSession session) {
request.setAttribute("path", "/user/login");
public String login(String userId, String password, HttpSession session) {
session.setAttribute(USER_SESSION_KEY, this.userService.login(userId, password));
logger.info("로그인 요청");
return "redirect:/";
Expand All @@ -72,22 +68,21 @@ public String viewUserList(Model model) {
}

@GetMapping("/user/{userId}/profile")
public String viewProfile(@PathVariable("userId") String userId, Model model) {
public String viewProfile(@PathVariable String userId, Model model) {
model.addAttribute("user", this.userService.findByUserId(userId));
logger.info("유저 프로필 페이지 요청");
return "user/profile";
}

@GetMapping("/user/{id}/form")
public String viewUpdateProfile(@PathVariable("id") Long id, Model model, HttpSession session) {
public String viewUpdateProfile(@PathVariable Long id, Model model, HttpSession session) {
model.addAttribute("user", this.userService.verifyUser(id, getUserFromSession(session)));
logger.info("유저 정보 수정 페이지 요청");
return "user/updateForm";
}

@PutMapping("/user/{id}/form")
public String updateProfile(@PathVariable("id") Long id, User user, String oldPassword, HttpServletRequest request, HttpSession session) {
request.setAttribute("path", "/user/updateForm");
public String updateProfile(@PathVariable Long id, User user, String oldPassword, HttpSession session) {
this.userService.update(id, user, oldPassword, getUserFromSession(session));
logger.info("유저 정보 수정 요청");
return "redirect:/user/list";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.codessquad.qna.exception;

public class EntityNotFoundException extends RuntimeException {

public EntityNotFoundException(ErrorMessage errorMessage) {
super(errorMessage.getErrorMessage());
}

}
24 changes: 24 additions & 0 deletions src/main/java/com/codessquad/qna/exception/ErrorMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.codessquad.qna.exception;

public enum ErrorMessage {

USER_NOT_FOUND("해당 유저를 찾을 수 없습니다."),
QUESTION_NOT_FOUND("해당 질문을 찾을 수 없습니다."),
ANSWER_NOT_FOUND("해당 답변을 찾을 수 없습니다."),
NEED_LOGIN("로그인이 필요한 서비스입니다."),
ILLEGAL_USER("접근 권한이 없는 유저입니다."),
DUPLICATED_ID("이미 사용중인 아이디입니다."),
LOGIN_FAILED("아이디 또는 비밀번호가 틀립니다. 다시 로그인 해주세요."),
WRONG_PASSWORD("기존 비밀번호가 일치하지 않습니다.");

private final String errorMessage;

ErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}

public String getErrorMessage() {
return errorMessage;
}

Comment on lines +3 to +23
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}
Original file line number Diff line number Diff line change
@@ -1,36 +1,44 @@
package com.codessquad.qna.exception;

import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import static com.codessquad.qna.controller.HttpSessionUtils.getUserFromSession;
import static com.codessquad.qna.controller.HttpSessionUtils.isLoginUser;

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(NotFoundException.class)
private String handleNotFoundException() {
@ExceptionHandler(EntityNotFoundException.class)
private String handleEntityNotFoundException() {
return "redirect:/";
}

@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(UserSessionException.class)
private String handleUserSessionException(Model model, UserSessionException e) {
model.addAttribute("errorMessage", e.getMessage());
return "/user/login";
}

@ExceptionHandler(UserAccountException.class)
private String handleUserAccountException(Model model, HttpSession session, HttpServletRequest request, UserAccountException e) {
private String handleUserAccountException(Model model, HttpSession session, UserAccountException e) {
model.addAttribute("errorMessage", e.getMessage());
if (isLoginUser(session)) {
model.addAttribute("user", getUserFromSession(session));
switch (e.getErrorMessage()) {
case DUPLICATED_ID:
return "/user/form";
case LOGIN_FAILED:
return "/user/login";
case WRONG_PASSWORD:
model.addAttribute("user", getUserFromSession(session));
return "/user/updateForm";
default:
return "/";
}
return (String) request.getAttribute("path");
}

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@

public class UserAccountException extends RuntimeException {

public UserAccountException(String errorMessage) {
super(errorMessage);
private ErrorMessage errorMessage;

public UserAccountException(ErrorMessage errorMessage) {
super(errorMessage.getErrorMessage());
this.errorMessage = errorMessage;
}

public ErrorMessage getErrorMessage() {
return errorMessage;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

public class UserSessionException extends RuntimeException {

public UserSessionException() {
super("접근권한이 없는 사용자입니다.");
public UserSessionException(ErrorMessage errorMessage) {
super(errorMessage.getErrorMessage());
}

}
Loading