-
Notifications
You must be signed in to change notification settings - Fork 14
[1주차 미션] 구현 완료했습니다. 리뷰 부탁드립니다. #82
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
base: jeongin
Are you sure you want to change the base?
Changes from all commits
d964fa5
c2a8bb1
90273dc
e2652c9
5054a4e
8218760
97a4aa2
123f64e
4515430
63c99ce
9e2d8ae
382a57d
92f9a9b
d913d6e
52bffd1
c8b0b11
eb1d90c
e06bf9c
f2ad0aa
ed79049
30f2e6a
9f2fa60
a1ed8bd
35a173d
69b83ea
f8e118b
34f467f
0f27f1a
201d490
d8268ec
06ad635
3df9a5e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,22 +1,36 @@ | ||
| package codesquad; | ||
|
|
||
| import codesquad.repository.ArrayUserRepository; | ||
| import codesquad.repository.QuestionRepositoryImpl; | ||
| import codesquad.repository.UserRepositoryImpl; | ||
| import codesquad.repository.QuestionRepository; | ||
| import codesquad.repository.UserRepository; | ||
| import codesquad.service.QuestionService; | ||
| import codesquad.service.QuestionServiceImpl; | ||
| import codesquad.service.UserService; | ||
| import codesquad.service.UserServiceImpl; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
|
|
||
| @Configuration | ||
| public class AppConfig { | ||
|
|
||
| @Bean | ||
| public UserService userService() { | ||
| return new UserServiceImpl(userRepository()); | ||
| } | ||
|
|
||
| @Bean | ||
| public UserRepository userRepository() { | ||
| return new ArrayUserRepository(); | ||
| return new UserRepositoryImpl(); | ||
| } | ||
|
|
||
| @Bean | ||
| public QuestionService questionService() { | ||
| return new QuestionServiceImpl(questionRepository()); | ||
| } | ||
|
|
||
| @Bean | ||
| public QuestionRepository questionRepository() { | ||
| return new QuestionRepositoryImpl(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| package codesquad.controller; | ||
|
|
||
| import codesquad.AppConfig; | ||
| import codesquad.dto.question.QuestionRequestDto; | ||
| import codesquad.dto.question.QuestionResponseDto; | ||
| import codesquad.entity.QuestionEntity; | ||
| import codesquad.mapper.QuestionMapper; | ||
| import codesquad.service.QuestionService; | ||
| import org.springframework.context.ApplicationContext; | ||
| import org.springframework.context.annotation.AnnotationConfigApplicationContext; | ||
| import org.springframework.stereotype.Controller; | ||
| import org.springframework.ui.Model; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.PathVariable; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
|
|
||
| import java.util.List; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| @Controller | ||
| public class QuestionController { | ||
| ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); | ||
| QuestionService questionService = applicationContext.getBean("questionService", QuestionService.class); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. applicationcontext로부터 직접 빈을 가져오셔서 사용하신 이유가 궁금합니다!
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AppConfig에서 @componentscan 같은 Spring Bean을 자동으로 가져오기 위한 어노테이션을 사용하지 않았기에 직접 빈을 가져왔습니다!
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 스프링부트에서 생성자 주입을 하는 방법에 대해 검색해보시면 좋을 것 같아요
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
questionService는 다음과 같이 생성자를 통해 주입되었습니다. AppConfig @Bean
public QuestionService questionService() {
return new QuestionServiceImpl(questionRepository());
}
@Bean
public QuestionRepository questionRepository() {
return new QuestionRepositoryImpl();
}QuestionServiceImpl public QuestionServiceImpl(QuestionRepository questionRepository) {
this.questionRepository = questionRepository;
}생성자 주입을 한 경우, |
||
|
|
||
| @GetMapping("/questions/post") | ||
| public String getQuestionForm() { | ||
| return "qna/form"; | ||
| } | ||
|
|
||
| @PostMapping("/questions") | ||
| public String postQuestion(QuestionRequestDto questionRequestDto) { | ||
| QuestionEntity questionEntity = QuestionMapper.dtoToEntity(questionRequestDto); | ||
| questionService.postQuestion(questionEntity); | ||
| return "redirect:/questions"; | ||
| } | ||
|
|
||
| @GetMapping("/questions") | ||
| public String getQuestionList(Model model) { | ||
| List<QuestionResponseDto> questions = questionService.findQuestions().stream() | ||
| .map(questionEntity -> QuestionMapper.entityToDto(questionEntity)) | ||
| .collect(Collectors.toList()); | ||
|
|
||
| model.addAttribute("questions", questions); | ||
|
|
||
| return "qna/list"; | ||
| } | ||
|
|
||
| @GetMapping("/questions/{id}") | ||
| public String getQuestionShow(@PathVariable String id, Model model) { | ||
| QuestionResponseDto question = new QuestionResponseDto(questionService.findQuestion(id)); | ||
|
|
||
| model.addAttribute("writer", question.getWriter()); | ||
| model.addAttribute("title", question.getTitle()); | ||
| model.addAttribute("contents", question.getContents()); | ||
| model.addAttribute("date", question.getDate()); | ||
|
|
||
| return "qna/show"; | ||
| } | ||
|
|
||
| @GetMapping("/") | ||
| public String getHome(Model model) { | ||
| List<QuestionEntity> questionEntityList = questionService.findQuestions(); | ||
| if (questionEntityList.size() == 0) { | ||
| return "qna/list"; | ||
| } | ||
|
|
||
| List<QuestionResponseDto> questionResponseDtoList = questionService.findQuestions().stream() | ||
| .map(questionEntity -> QuestionMapper.entityToDto(questionEntity)) | ||
| .collect(Collectors.toList()); | ||
|
|
||
| model.addAttribute("questions", questionResponseDtoList); | ||
| return "qna/list"; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,18 +1,17 @@ | ||
| package codesquad.controller; | ||
|
|
||
| import codesquad.AppConfig; | ||
| import codesquad.dto.UserDto; | ||
| import codesquad.dto.user.UserDto; | ||
| import codesquad.dto.user.UserUpdateRequestDto; | ||
| import codesquad.entity.UserEntity; | ||
| import codesquad.mapper.UserMapper; | ||
| import codesquad.service.UserService; | ||
| import org.modelmapper.ModelMapper; | ||
| import org.springframework.context.ApplicationContext; | ||
| import org.springframework.context.annotation.AnnotationConfigApplicationContext; | ||
| import org.springframework.stereotype.Controller; | ||
| import org.springframework.ui.Model; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.PathVariable; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.*; | ||
|
|
||
| import java.util.List; | ||
| import java.util.stream.Collectors; | ||
|
|
@@ -39,7 +38,6 @@ public String registerUser(UserDto userDto) { | |
|
|
||
| @GetMapping() | ||
| public String getUserList(Model model) { | ||
| System.out.println("userService.findUsers().get(0) = " + userService.findUsers().get(0)); | ||
| List<UserDto> users = userService.findUsers().stream() | ||
| .map(userEntity -> modelMapper.map(userEntity, UserDto.class)).collect(Collectors.toList()); | ||
| model.addAttribute("users", users); | ||
|
|
@@ -57,4 +55,15 @@ public String getUserProfile(@PathVariable String userId, Model model) { | |
|
|
||
| return "user/profile"; | ||
| } | ||
|
|
||
| @GetMapping("/{userId}/form") | ||
| public String getProfileEditForm() { | ||
| return "user/update_form"; | ||
| } | ||
|
|
||
| @PutMapping("/{userId}/update") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 업데이트에는 보통 PUT과 PATCH가 사용됩니다. 이 둘의 차이는 무엇일까요?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
GOOD BAD GOOD |
||
| public String updateUserProfile(@PathVariable("userId") String userId, UserUpdateRequestDto requestDto) { | ||
| userService.updateUser(userId, UserMapper.dtoToEntity(requestDto)); | ||
| return "redirect:/users"; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package codesquad.dto.question; | ||
|
|
||
| import lombok.*; | ||
|
|
||
| @AllArgsConstructor | ||
| @Getter | ||
| @Setter | ||
| @Builder | ||
| public class QuestionRequestDto { | ||
| private String writer; | ||
| private String title; | ||
| private String contents; | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "QuestionDto{" + | ||
| "writer='" + writer + '\'' + | ||
| ", title='" + title + '\'' + | ||
| ", contents='" + contents + '\'' + | ||
| '}'; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package codesquad.dto.question; | ||
|
|
||
| import codesquad.entity.QuestionEntity; | ||
| import codesquad.mapper.QuestionMapper; | ||
| import lombok.*; | ||
|
|
||
| @AllArgsConstructor | ||
| @Getter | ||
| @Setter | ||
| @Builder | ||
| public class QuestionResponseDto { | ||
| private String writer; | ||
| private String title; | ||
| private String contents; | ||
| private String date; | ||
|
|
||
| public QuestionResponseDto(QuestionEntity questionEntity) { | ||
| writer = questionEntity.getWriter(); | ||
| title = questionEntity.getTitle(); | ||
| contents = questionEntity.getContents(); | ||
| date = QuestionMapper.localTimeToString(questionEntity.getCreatedDate()); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package codesquad.dto.user; | ||
|
|
||
| import lombok.Builder; | ||
|
|
||
| @Builder | ||
| public class UserUpdateRequestDto { | ||
| private String password; | ||
| private String name; | ||
| private String email; | ||
|
|
||
| public UserUpdateRequestDto(String password, String name, String email) { | ||
| this.password = password; | ||
| this.name = name; | ||
| this.email = email; | ||
| } | ||
|
|
||
| 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; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| package codesquad.entity; | ||
|
|
||
| import lombok.Getter; | ||
| import lombok.Setter; | ||
| import java.time.LocalDateTime; | ||
|
|
||
| @Getter | ||
| @Setter | ||
| public abstract class BaseTimeEntity { | ||
|
|
||
| private LocalDateTime createdDate; | ||
| private LocalDateTime modifiedDate; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package codesquad.entity; | ||
|
|
||
| import lombok.*; | ||
|
|
||
| @Setter | ||
| @Getter | ||
| @Builder | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| public class QuestionEntity extends BaseTimeEntity { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Entity 라는 postfix 를 붙이지 않아도 될 것 같습니다 ~
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @hyukjin-lee class명 말씀하실까요?? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 넵넵 QuestionEntity -> Question 을 말씀하시는 것 같아요~ |
||
|
|
||
| private String writer; | ||
| private String title; | ||
| private String contents; | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "QuestionEntity{" + | ||
| "writer='" + writer + '\'' + | ||
| ", title='" + title + '\'' + | ||
| ", contents='" + contents + '\'' + | ||
| '}'; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
컨트롤러는 @controller 어노테이션을 이용해 빈을 등록하고 계시는데, Service와 Repository는 Config 파일에서 빈을 따로 등록해주고 계시는 이유가 궁금합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
우선 의존성을 주입하여 코드/객체 간의 결합도를 낮추기 위해 Service와 Repository는 자바 코드로 직접 스프링 빈을 등록하였습니다. 이는 개발을 진행하다 Repository를 변경해야하는 상황일 때, Config에 등록된 Repository Bean만 수정하면 되기 때문입니다.
그럼 Controller의 역할을 생각해보겠습니다.
컨트롤러는 View와 Service를 이어주는 역할만 하고 비즈니스 로직을 가지고 있지 않습니다. 따라서 Repository가 변경되거나 비즈니스 로직이 변경되어도 Controller는 변경되지 않으므로 Config에서 등록하지 않았습니다.
ref: https://inf.run/SZEa -> 말 다듬는데 도움 받았습니다:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
의존성 주입은 스프링이 알아서 해주는 부분입니다 ~
스프링 부트의 DI 방식에 대해 알아보면 좋을 것 같아요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제어의 역전(IoC)가 무엇인지도 한 번 알아보시면 좋을 것 같습니다!