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

[시온] step6. 페이지 나누기 #105

Open
wants to merge 36 commits into
base: ehdrhelr
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
0a0f518
refactor : JSON API, AJAX를 활용하여 답변 추가할 수 있도록 변경
ehdrhelr Mar 16, 2021
59be0e4
refactor : 답변 삭제 Ajax 처리
ehdrhelr Mar 17, 2021
01f657f
refactor : 메인화면 질문의 답변 수를 필드로 생성하여 처리
ehdrhelr Mar 17, 2021
90216e5
refactor : 도메인 클래스에 대한 중복 제거 및 리팩토링
ehdrhelr Mar 17, 2021
df71b8f
feat : Swagger 라이브러리 추가하여 테스트
ehdrhelr Mar 17, 2021
e207458
fix : Ajax를 통해 새로 추가한 답변이 삭제되지 않는 버그 해결
ehdrhelr Mar 17, 2021
7f59720
fix : upstream에 merge된 my branch로 rebase하는 과정에서 충돌 해결
ehdrhelr Mar 18, 2021
bbfcbf2
fix : 로그아웃창 상태에서 답변하기 클릭시 알람 생성
ehdrhelr Mar 19, 2021
7ff1cc5
fix : 답변 생성 및 삭제시 질문 상세화면에 나오는 답변갯수 ajax처리
ehdrhelr Mar 19, 2021
f848d41
fix : 답변 생성시 최신 답변이 아래로 가도록 수정
ehdrhelr Mar 19, 2021
05e2efb
fix : ajax를 통해 새로 추가된 답변 수정 기능 버그 해결
ehdrhelr Mar 19, 2021
7a82526
fix : 비로그인상태에서 댓글 삭제시 알림창 표시
ehdrhelr Mar 19, 2021
89c8659
test : Paging TDD를 위한 테스트 코드 작성
ehdrhelr Mar 20, 2021
be60b62
feat : 테스트 코드를 만족하는 Paging 처리 기능 추가
ehdrhelr Mar 20, 2021
772f915
feat : index 화면에 현재 페이지에 따른 페이징 화면 출력
ehdrhelr Mar 21, 2021
da01083
feat : 페이지 번호 이벤트 처리
ehdrhelr Mar 21, 2021
e7ab515
fix : 삭제된 질문까지 출력하는 오류 해결하고 최신 질문순으로 정렬
ehdrhelr Mar 21, 2021
e2bdff2
refactor : 변수명 변경과 코드 간결화로 가독성을 높임, 주석 추가
ehdrhelr Mar 21, 2021
a0534c0
refactor : 피드백받아 1차 수정
ehdrhelr Mar 26, 2021
7513ee4
refactor : var를 const로 변경
ehdrhelr Mar 27, 2021
441e981
refactor : 500에러를 발생시키지 않고 오류페이지 출력
ehdrhelr Mar 27, 2021
a6b9f19
refactor : 메서드명 변경 formattedCreateDate -> formattedCreateDateTime
ehdrhelr Mar 27, 2021
6335ea9
style : add new line at end of file
ehdrhelr Mar 27, 2021
9387663
Merge pull request #91 from ehdrhelr/step5
ksundong Mar 27, 2021
7a9b61f
test : Paging TDD를 위한 테스트 코드 작성
ehdrhelr Mar 20, 2021
c9aec75
feat : 테스트 코드를 만족하는 Paging 처리 기능 추가
ehdrhelr Mar 20, 2021
720bfe7
feat : index 화면에 현재 페이지에 따른 페이징 화면 출력
ehdrhelr Mar 21, 2021
37aa9a4
feat : 페이지 번호 이벤트 처리
ehdrhelr Mar 21, 2021
6b4a5cc
fix : 삭제된 질문까지 출력하는 오류 해결하고 최신 질문순으로 정렬
ehdrhelr Mar 21, 2021
b629215
refactor : 변수명 변경과 코드 간결화로 가독성을 높임, 주석 추가
ehdrhelr Mar 21, 2021
5f5b78f
refactor : 1차 피드백 반영
ehdrhelr Mar 27, 2021
004415b
refactor : step5 -> upstream/ehdrhelr에 머지된 후, upstream/ehdrhelr으로 ste…
ehdrhelr Mar 30, 2021
1b61829
chore : upstream/ehdrhelr으로 rebase후 충돌 해결
ehdrhelr Mar 30, 2021
20fea2e
refactor : step5 -> upstream/ehdrhelr에 머지된 후, upstream/ehdrhelr으로 ste…
ehdrhelr Mar 30, 2021
3522d7f
refactor : PageDTO에 Page를 매개변수로 받도록 하고 Page의 정보를 바탕으로 Pagination
ehdrhelr Mar 31, 2021
742de0d
fix : index.html에 page번호 안나오는 버그 수정
ehdrhelr Mar 31, 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
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ dependencies {

// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '2.4.3'

compile 'io.springfox:springfox-swagger2:2.6.1'
compile 'io.springfox:springfox-swagger-ui:2.6.1'
}

test {
Expand Down
27 changes: 27 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,39 @@

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.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@EnableSwagger2
@EnableJpaAuditing
@SpringBootApplication
public class QnaApplication {

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

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("spring-boot-qna")
.description("spring-boot-qna")
.build();
}

@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("spring-boot-qna")
.apiInfo(this.apiInfo())
.select()
.paths(PathSelectors.ant("/api/**"))
.build();
}
}
24 changes: 4 additions & 20 deletions src/main/java/com/codessquad/qna/controller/AnswerController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.codessquad.qna.domain.answer.Answer;
import com.codessquad.qna.domain.question.Question;
import com.codessquad.qna.domain.user.User;
import com.codessquad.qna.exception.NotAuthorizationException;
import com.codessquad.qna.service.AnswerService;
import com.codessquad.qna.service.QuestionService;
import com.codessquad.qna.utils.HttpSessionUtils;
Expand All @@ -26,27 +27,17 @@ public AnswerController(AnswerService answerService, QuestionService questionSer

@PostMapping("/")
public String createAnswer(@PathVariable Long questionId, Answer answer, HttpSession session) {
if (!HttpSessionUtils.isLoginUser(session)) {
return "redirect:/users/login";
}
User sessionedUser = HttpSessionUtils.getUserFromSession(session);
answer.setWriter(sessionedUser);
answerService.create(questionId, answer);
answerService.create(questionId, answer, sessionedUser);
return "redirect:/questions/" + questionId;
}

@GetMapping("/{id}/form")
public String getUpdateForm(@PathVariable Long questionId, @PathVariable Long id, Model model, HttpSession session) {
if (!HttpSessionUtils.isLoginUser(session)) {
return "redirect:/users/login";
}
Question question = questionService.findById(questionId);
Answer answer = answerService.findById(id);
User sessionedUser = HttpSessionUtils.getUserFromSession(session);
if (!answer.isWrittenBy(sessionedUser)) {
throw new IllegalStateException("자신이 작성한 답변만 수정할 수 있습니다.");
}

answer.isWrittenBy(sessionedUser);
model.addAttribute("question", question);
model.addAttribute("answer", answer);

Expand All @@ -62,15 +53,8 @@ public String updateAnswer(@PathVariable Long questionId, @PathVariable Long id,

@DeleteMapping("/{id}")
public String deleteAnswer(@PathVariable Long questionId, @PathVariable Long id, HttpSession session) {
if (!HttpSessionUtils.isLoginUser(session)) {
return "redirect:/users/login";
}
Answer answer = answerService.findById(id);
User sessionedUser = HttpSessionUtils.getUserFromSession(session);
if (!answer.isWrittenBy(sessionedUser)) {
throw new IllegalStateException("자신이 작성한 답변만 삭제할 수 있습니다.");
}
answerService.deleteById(id);
answerService.deleteById(id, sessionedUser);

return "redirect:/questions/" + questionId;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.codessquad.qna.controller;

import com.codessquad.qna.domain.answer.Answer;
import com.codessquad.qna.domain.user.User;
import com.codessquad.qna.service.AnswerService;
import com.codessquad.qna.utils.HttpSessionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;

@RequestMapping("/api/questions/{questionId}/answers")
@RestController
public class ApiAnswerController {

private final AnswerService answerService;

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

@PostMapping("/")
public Answer createAnswer(@PathVariable Long questionId, Answer answer, HttpSession session) {
User sessionedUser = HttpSessionUtils.getUserFromSession(session);
return answerService.create(questionId, answer, sessionedUser);
}

@DeleteMapping("/{id}")
public Answer delete(@PathVariable Long id, HttpSession session) {
Answer answer = answerService.findById(id);
User loginUser = HttpSessionUtils.getUserFromSession(session);
answerService.deleteById(id, loginUser);
return answer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.codessquad.qna.controller;

import com.codessquad.qna.domain.pagination.Criteria;
import com.codessquad.qna.domain.question.Question;
import com.codessquad.qna.service.QuestionService;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/api/questions")
@RestController
public class ApiQuestionController {

private final QuestionService questionService;

public ApiQuestionController(QuestionService questionService) {
this.questionService = questionService;
}

@GetMapping("/")
public Page<Question> pagingList(Criteria criteria) {
return questionService.pagingList(criteria);
}
}
24 changes: 24 additions & 0 deletions src/main/java/com/codessquad/qna/controller/ApiUserController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.codessquad.qna.controller;

import com.codessquad.qna.domain.user.User;
import com.codessquad.qna.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/api/users")
@RestController
public class ApiUserController {

private final UserService userService;

public ApiUserController(UserService userService) {
this.userService = userService;
}

@GetMapping("{id}")
public User show(@PathVariable Long id) {
return userService.findById(id);
}
}
15 changes: 12 additions & 3 deletions src/main/java/com/codessquad/qna/controller/IndexController.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
package com.codessquad.qna.controller;

import com.codessquad.qna.domain.pagination.Criteria;
import com.codessquad.qna.domain.pagination.PageDTO;
import com.codessquad.qna.domain.question.Question;
import com.codessquad.qna.service.QuestionService;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.Optional;

@Controller
public class IndexController {

private final QuestionService questionService;

public IndexController (QuestionService questionService) {
public IndexController(QuestionService questionService) {
this.questionService = questionService;
}

@GetMapping("/")
public String goMain(Model model) {
model.addAttribute("questions", questionService.findAll());
public String goMain(Optional<Integer> pageNum, Model model) { // 메인화면(Url 매핑 -> "/") 진입 시 1페이지로 설정
Criteria criteria = new Criteria(pageNum.orElse(1));
Page<Question> questions = questionService.pagingList(criteria);
model.addAttribute("pageMaker", new PageDTO(questions));
model.addAttribute("questions", questions);
return "index";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.codessquad.qna.domain.answer.Answer;
import com.codessquad.qna.domain.question.Question;
import com.codessquad.qna.domain.user.User;
import com.codessquad.qna.exception.NotAuthorizationException;
import com.codessquad.qna.service.AnswerService;
import com.codessquad.qna.service.QuestionService;
import com.codessquad.qna.utils.HttpSessionUtils;
Expand All @@ -27,9 +28,7 @@ public QuestionController(QuestionService questionService, AnswerService answerS

@GetMapping("/form")
public String getQuestionForm(HttpSession session) {
if (!HttpSessionUtils.isLoginUser(session)) {
return "redirect:/users/login";
}
HttpSessionUtils.isLoginUser(session);
return "/qna/form";
}

Expand All @@ -45,23 +44,16 @@ public String createQuestion(Question question, HttpSession session) {
public String getQuestion(@PathVariable Long id, Model model) {
Question question = questionService.findById(id);
List<Answer> answers = answerService.findAllByQuestionId(id);

model.addAttribute("question", question);
model.addAttribute("answers", answers);

return "/qna/show";
}

@GetMapping("/{id}/form")
public String getUpdateForm(@PathVariable Long id, HttpSession session, Model model) {
if (!HttpSessionUtils.isLoginUser(session)) {
return "redirect:/users/login";
}
Question question = questionService.findById(id);
User sessionedUser = HttpSessionUtils.getUserFromSession(session);
if (!question.isWrittenBy(sessionedUser)) {
throw new IllegalStateException("자신이 작성한 글만 수정할 수 있습니다.");
}
question.isWrittenBy(sessionedUser);
model.addAttribute("question", question);
return "/qna/update_form";
}
Expand All @@ -74,14 +66,9 @@ public String updateQuestion(@PathVariable Long id, Question questionWithUpdated

@DeleteMapping("/{id}")
public String deleteQuestion(@PathVariable Long id, HttpSession session) {
if (!HttpSessionUtils.isLoginUser(session)) {
return "redirect:/users/login";
}
Question question = questionService.findById(id);
User sessionedUser = HttpSessionUtils.getUserFromSession(session);
if (!question.isWrittenBy(sessionedUser)) {
throw new IllegalStateException("자신이 작성한 글만 삭제할 수 있습니다.");
}
question.isWrittenBy(sessionedUser);
questionService.deleteById(id);
return "redirect:/";
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.codessquad.qna.controller;

import com.codessquad.qna.domain.user.User;
import com.codessquad.qna.exception.NotAuthorizationException;
import com.codessquad.qna.service.UserService;
import com.codessquad.qna.utils.HttpSessionUtils;
import org.springframework.stereotype.Controller;
Expand Down Expand Up @@ -40,13 +41,8 @@ public String getProfile(@PathVariable Long id, Model model) {

@GetMapping("/{id}/form")
public String getUpdateForm(@PathVariable Long id, Model model, HttpSession session) {
if (!HttpSessionUtils.isLoginUser(session)) {
return "redirect:/users/login";
}
User sessionedUser = HttpSessionUtils.getUserFromSession(session);
if (!sessionedUser.isYourId(id)) {
throw new IllegalStateException("자신의 정보만 수정할 수 있습니다.");
}
sessionedUser.isYourId(id);
User user = userService.findById(id);
model.addAttribute("user", user);
return "/users/updateForm";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.codessquad.qna.controller.advice;

import 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;

@ControllerAdvice
public class ControllerExceptionHandler {

@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(NotAuthorizationException.class)
public String handleNotAuthorization(
NotAuthorizationException notAuthorizationException, Model model) {
model.addAttribute("errorMessage", notAuthorizationException.getMessage());
return "error/401";
}

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(AnotherAnswerException.class)
public String HandleAnotherAnswer(AnotherAnswerException anotherAnswerException, Model model) {
model.addAttribute("errorMessage", anotherAnswerException.getMessage());
return "/error/400";
}

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(WrongPasswordException.class)
public String handleWrongPassword(WrongPasswordException wrongPasswordException, Model model) {
model.addAttribute("errorMessage", wrongPasswordException.getMessage());
return "/error/400";
}

@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler(UserNotFoundException.class)
public String handleUserNotFound(UserNotFoundException userNotFoundException, Model model) {
model.addAttribute("errorMessage", userNotFoundException.getMessage());
return "/error/404";
}

@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler(AnswerNotFoundException.class)
public String handleAnswerNotFound(AnswerNotFoundException answerNotFoundException, Model model) {
model.addAttribute("errorMessage", answerNotFoundException.getMessage());
return "/error/404";
}

@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler(QuestionNotFoundException.class)
public String handleNotFound(QuestionNotFoundException QuestionNotFoundException, Model model) {
model.addAttribute("errorMessage", QuestionNotFoundException.getMessage());
return "/error/404";
}

}
Loading