diff --git a/build.gradle b/build.gradle index c2a742ef..5d51539f 100755 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,6 @@ buildscript { } apply plugin: 'java' -apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' @@ -23,7 +22,7 @@ repositories { } dependencies { - implementation 'org.junit.jupiter:junit-jupiter:5.9.0' + implementation 'org.junit.jupiter:junit-jupiter:5.3.2' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-devtools' @@ -37,6 +36,11 @@ dependencies { implementation 'org.modelmapper:modelmapper:3.0.0' implementation 'org.springdoc:springdoc-openapi-ui:1.6.11' implementation 'com.h2database:h2' + implementation 'org.mapstruct:mapstruct:1.5.2.Final' + implementation 'org.mockito:mockito-core:2.22.0' + implementation 'org.mockito:mockito-junit-jupiter:2.22.0' + annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.2.Final' + annotationProcessor 'org.projectlombok:lombok:1.18.24' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.assertj:assertj-core:3.23.1' } \ No newline at end of file diff --git a/src/main/java/codesquad/AppConfig.java b/src/main/java/codesquad/AppConfig.java index 57293795..b083159e 100644 --- a/src/main/java/codesquad/AppConfig.java +++ b/src/main/java/codesquad/AppConfig.java @@ -1,7 +1,11 @@ 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; @@ -9,7 +13,7 @@ @Configuration public class AppConfig { - + @Bean public UserService userService() { return new UserServiceImpl(userRepository()); @@ -17,6 +21,16 @@ public UserService userService() { @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(); } } diff --git a/src/main/java/codesquad/controller/QuestionController.java b/src/main/java/codesquad/controller/QuestionController.java new file mode 100644 index 00000000..ebab5d22 --- /dev/null +++ b/src/main/java/codesquad/controller/QuestionController.java @@ -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); + + @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 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 questionEntityList = questionService.findQuestions(); + if (questionEntityList.size() == 0) { + return "qna/list"; + } + + List questionResponseDtoList = questionService.findQuestions().stream() + .map(questionEntity -> QuestionMapper.entityToDto(questionEntity)) + .collect(Collectors.toList()); + + model.addAttribute("questions", questionResponseDtoList); + return "qna/list"; + } +} \ No newline at end of file diff --git a/src/main/java/codesquad/controller/UserController.java b/src/main/java/codesquad/controller/UserController.java index 8caa905a..a7b732b4 100644 --- a/src/main/java/codesquad/controller/UserController.java +++ b/src/main/java/codesquad/controller/UserController.java @@ -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 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") + public String updateUserProfile(@PathVariable("userId") String userId, UserUpdateRequestDto requestDto) { + userService.updateUser(userId, UserMapper.dtoToEntity(requestDto)); + return "redirect:/users"; + } } diff --git a/src/main/java/codesquad/dto/question/QuestionRequestDto.java b/src/main/java/codesquad/dto/question/QuestionRequestDto.java new file mode 100644 index 00000000..e0fa4a30 --- /dev/null +++ b/src/main/java/codesquad/dto/question/QuestionRequestDto.java @@ -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 + '\'' + + '}'; + } +} diff --git a/src/main/java/codesquad/dto/question/QuestionResponseDto.java b/src/main/java/codesquad/dto/question/QuestionResponseDto.java new file mode 100644 index 00000000..53b2f511 --- /dev/null +++ b/src/main/java/codesquad/dto/question/QuestionResponseDto.java @@ -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()); + } +} \ No newline at end of file diff --git a/src/main/java/codesquad/dto/UserDto.java b/src/main/java/codesquad/dto/user/UserDto.java similarity index 70% rename from src/main/java/codesquad/dto/UserDto.java rename to src/main/java/codesquad/dto/user/UserDto.java index 3d2bbee9..b38a8e61 100644 --- a/src/main/java/codesquad/dto/UserDto.java +++ b/src/main/java/codesquad/dto/user/UserDto.java @@ -1,13 +1,11 @@ -package codesquad.dto; +package codesquad.dto.user; import codesquad.entity.UserEntity; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @NoArgsConstructor -@AllArgsConstructor @Getter @Setter public class UserDto { @@ -23,22 +21,6 @@ public UserDto(UserEntity userEntity) { email = userEntity.getEmail(); } - public String getUserId() { - return userId; - } - - public String getPassword() { - return password; - } - - public String getName() { - return name; - } - - public String getEmail() { - return email; - } - @Override public String toString() { return "UserDto{" + diff --git a/src/main/java/codesquad/dto/user/UserUpdateRequestDto.java b/src/main/java/codesquad/dto/user/UserUpdateRequestDto.java new file mode 100644 index 00000000..8bb30c0e --- /dev/null +++ b/src/main/java/codesquad/dto/user/UserUpdateRequestDto.java @@ -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; + } +} diff --git a/src/main/java/codesquad/entity/BaseTimeEntity.java b/src/main/java/codesquad/entity/BaseTimeEntity.java new file mode 100644 index 00000000..5e801d65 --- /dev/null +++ b/src/main/java/codesquad/entity/BaseTimeEntity.java @@ -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; +} diff --git a/src/main/java/codesquad/entity/QuestionEntity.java b/src/main/java/codesquad/entity/QuestionEntity.java new file mode 100644 index 00000000..f0b9b169 --- /dev/null +++ b/src/main/java/codesquad/entity/QuestionEntity.java @@ -0,0 +1,24 @@ +package codesquad.entity; + +import lombok.*; + +@Setter +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class QuestionEntity extends BaseTimeEntity { + + private String writer; + private String title; + private String contents; + + @Override + public String toString() { + return "QuestionEntity{" + + "writer='" + writer + '\'' + + ", title='" + title + '\'' + + ", contents='" + contents + '\'' + + '}'; + } +} diff --git a/src/main/java/codesquad/entity/UserEntity.java b/src/main/java/codesquad/entity/UserEntity.java index cbe5e70f..ba7dcdc9 100644 --- a/src/main/java/codesquad/entity/UserEntity.java +++ b/src/main/java/codesquad/entity/UserEntity.java @@ -1,24 +1,14 @@ package codesquad.entity; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import lombok.*; @Setter @Getter +@Builder @AllArgsConstructor @NoArgsConstructor -@Entity public class UserEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) private String userId; private String password; private String name; @@ -33,4 +23,20 @@ public String toString() { ", email='" + email + '\'' + '}'; } + + public boolean isSameId(UserEntity user, String userId) { + return userId.equals(user.getUserId()); + } + + public void updatePassword(String password) { + this.password = password; + } + + public void updateName(String name) { + this.name = name; + } + + public void updateEmail(String email) { + this.email = email; + } } diff --git a/src/main/java/codesquad/mapper/QuestionMapper.java b/src/main/java/codesquad/mapper/QuestionMapper.java new file mode 100644 index 00000000..0eb4a3f6 --- /dev/null +++ b/src/main/java/codesquad/mapper/QuestionMapper.java @@ -0,0 +1,45 @@ +package codesquad.mapper; + +import codesquad.dto.question.QuestionRequestDto; +import codesquad.dto.question.QuestionResponseDto; +import codesquad.entity.QuestionEntity; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class QuestionMapper { + + public static QuestionEntity dtoToEntity(QuestionRequestDto questionRequestDto) { + if (questionRequestDto == null){ + return null; + } + + QuestionEntity.QuestionEntityBuilder questionEntity = QuestionEntity.builder(); + + questionEntity.writer(questionRequestDto.getWriter()); + questionEntity.title(questionRequestDto.getTitle()); + questionEntity.contents(questionRequestDto.getContents()); + + return questionEntity.build(); + } + + public static QuestionResponseDto entityToDto(QuestionEntity questionEntity) { + if (questionEntity == null) { + return null; + } + + QuestionResponseDto.QuestionResponseDtoBuilder questionResponseDto = QuestionResponseDto.builder(); + + questionResponseDto.writer(questionEntity.getWriter()); + questionResponseDto.title(questionEntity.getTitle()); + questionResponseDto.contents(questionEntity.getContents()); + questionResponseDto.date(localTimeToString(questionEntity.getCreatedDate())); + + return questionResponseDto.build(); + } + + public static String localTimeToString(LocalDateTime localDateTime) { + String stringLocalTime = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); + return stringLocalTime; + } +} diff --git a/src/main/java/codesquad/mapper/UserMapper.java b/src/main/java/codesquad/mapper/UserMapper.java new file mode 100644 index 00000000..2e264818 --- /dev/null +++ b/src/main/java/codesquad/mapper/UserMapper.java @@ -0,0 +1,20 @@ +package codesquad.mapper; + +import codesquad.dto.user.UserUpdateRequestDto; +import codesquad.entity.UserEntity; + +public class UserMapper { + public static UserEntity dtoToEntity(UserUpdateRequestDto userUpdateRequestDto) { + if (userUpdateRequestDto == null) { + return null; + } + + UserEntity.UserEntityBuilder userEntity = UserEntity.builder(); + + userEntity.userId(userUpdateRequestDto.getPassword()); + userEntity.name(userUpdateRequestDto.getName()); + userEntity.email(userUpdateRequestDto.getEmail()); + + return userEntity.build(); + } +} \ No newline at end of file diff --git a/src/main/java/codesquad/repository/QuestionRepository.java b/src/main/java/codesquad/repository/QuestionRepository.java new file mode 100644 index 00000000..76e3cdbc --- /dev/null +++ b/src/main/java/codesquad/repository/QuestionRepository.java @@ -0,0 +1,13 @@ +package codesquad.repository; + +import codesquad.entity.QuestionEntity; + +import java.util.List; + +public interface QuestionRepository { + void post(QuestionEntity questionEntity); + + List findAll(); + + void setBaseTime(QuestionEntity questionEntity); +} diff --git a/src/main/java/codesquad/repository/QuestionRepositoryImpl.java b/src/main/java/codesquad/repository/QuestionRepositoryImpl.java new file mode 100644 index 00000000..3cdfebde --- /dev/null +++ b/src/main/java/codesquad/repository/QuestionRepositoryImpl.java @@ -0,0 +1,26 @@ +package codesquad.repository; + +import codesquad.entity.QuestionEntity; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +public class QuestionRepositoryImpl implements QuestionRepository { + private final List questions = new ArrayList<>(); + + @Override + public void post(QuestionEntity questionEntity) { + questions.add(questionEntity); + } + + @Override + public List findAll() { + return questions; + } + + @Override + public void setBaseTime(QuestionEntity questionEntity) { + questionEntity.setCreatedDate(LocalDateTime.now()); + } +} diff --git a/src/main/java/codesquad/repository/UserRepository.java b/src/main/java/codesquad/repository/UserRepository.java index 9ae0e05d..b73cc5b8 100644 --- a/src/main/java/codesquad/repository/UserRepository.java +++ b/src/main/java/codesquad/repository/UserRepository.java @@ -7,6 +7,8 @@ public interface UserRepository { void register(UserEntity userEntity); + void update(String userId, UserEntity userEntity); + UserEntity findById(String userId); List findAll(); diff --git a/src/main/java/codesquad/repository/ArrayUserRepository.java b/src/main/java/codesquad/repository/UserRepositoryImpl.java similarity index 57% rename from src/main/java/codesquad/repository/ArrayUserRepository.java rename to src/main/java/codesquad/repository/UserRepositoryImpl.java index f7531941..02eaf8b4 100644 --- a/src/main/java/codesquad/repository/ArrayUserRepository.java +++ b/src/main/java/codesquad/repository/UserRepositoryImpl.java @@ -6,7 +6,7 @@ import java.util.ArrayList; import java.util.List; -public class ArrayUserRepository implements UserRepository { +public class UserRepositoryImpl implements UserRepository { private final List users = new ArrayList<>(); @Override @@ -14,10 +14,21 @@ public void register(UserEntity userEntity) { users.add(userEntity); } + @Override + public void update(String userId, UserEntity userEntity) { + for (UserEntity user : users) { + if (user.isSameId(user, userId)) { + user.updatePassword(userEntity.getPassword()); + user.updateName(userEntity.getName()); + user.updateEmail(userEntity.getEmail()); + } + } + } + @Override public UserEntity findById(String userId) { for (UserEntity user : users) { - if (userId.equals(user.getUserId())) { + if (user.isSameId(user, userId)) { return user; } } diff --git a/src/main/java/codesquad/service/QuestionService.java b/src/main/java/codesquad/service/QuestionService.java new file mode 100644 index 00000000..01b78595 --- /dev/null +++ b/src/main/java/codesquad/service/QuestionService.java @@ -0,0 +1,13 @@ +package codesquad.service; + +import codesquad.entity.QuestionEntity; + +import java.util.List; + +public interface QuestionService { + void postQuestion(QuestionEntity questionEntity); + + List findQuestions(); + + QuestionEntity findQuestion(String id); +} diff --git a/src/main/java/codesquad/service/QuestionServiceImpl.java b/src/main/java/codesquad/service/QuestionServiceImpl.java new file mode 100644 index 00000000..88eefb7f --- /dev/null +++ b/src/main/java/codesquad/service/QuestionServiceImpl.java @@ -0,0 +1,30 @@ +package codesquad.service; + +import codesquad.entity.QuestionEntity; +import codesquad.repository.QuestionRepository; + +import java.util.List; + +public class QuestionServiceImpl implements QuestionService { + private final QuestionRepository questionRepository; + + public QuestionServiceImpl(QuestionRepository questionRepository) { + this.questionRepository = questionRepository; + } + + @Override + public void postQuestion(QuestionEntity questionEntity) { + questionRepository.post(questionEntity); + questionRepository.setBaseTime(questionEntity); + } + + @Override + public List findQuestions() { + return questionRepository.findAll(); + } + + @Override + public QuestionEntity findQuestion(String id) { + return questionRepository.findAll().get(Integer.parseInt(id) - 1); + } +} diff --git a/src/main/java/codesquad/service/UserService.java b/src/main/java/codesquad/service/UserService.java index 5b7e20e8..1945d606 100644 --- a/src/main/java/codesquad/service/UserService.java +++ b/src/main/java/codesquad/service/UserService.java @@ -7,6 +7,8 @@ public interface UserService { void registerUser(UserEntity userEntity); + void updateUser(String userId, UserEntity userEntity); + UserEntity findUser(String userId); List findUsers(); diff --git a/src/main/java/codesquad/service/UserServiceImpl.java b/src/main/java/codesquad/service/UserServiceImpl.java index 23c46f8c..553e0772 100644 --- a/src/main/java/codesquad/service/UserServiceImpl.java +++ b/src/main/java/codesquad/service/UserServiceImpl.java @@ -18,6 +18,11 @@ public void registerUser(UserEntity user) { userRepository.register(user); } + @Override + public void updateUser(String userId, UserEntity userEntity) { + userRepository.update(userId, userEntity); + } + @Override public UserEntity findUser(String userId) { return userRepository.findById(userId); diff --git a/src/main/java/codesquad/utils/handlebars/IndexHelper.java b/src/main/java/codesquad/utils/handlebars/IndexHelper.java index 929f4969..c578aec7 100644 --- a/src/main/java/codesquad/utils/handlebars/IndexHelper.java +++ b/src/main/java/codesquad/utils/handlebars/IndexHelper.java @@ -4,7 +4,10 @@ @HandlebarsHelper public class IndexHelper { - public int setStartingIndexNumber(int index) { + public int setStartingIndexNumberIs1(int index) { + return index + 1; + } + public int setStartingIndexNumberIs3(int index) { return index + 3; } } \ No newline at end of file diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index ed14d9ff..e9570a39 100755 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -119,7 +119,6 @@ -
@@ -134,7 +133,7 @@
diff --git a/src/main/resources/templates/layout/navigation.html b/src/main/resources/templates/layout/navigation.html index a0d5b601..341671f2 100644 --- a/src/main/resources/templates/layout/navigation.html +++ b/src/main/resources/templates/layout/navigation.html @@ -1,7 +1,7 @@