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

Feat: Answer 기능 구현 #21

Merged
merged 4 commits into from
Dec 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 5 additions & 5 deletions server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.mapstruct:mapstruct:1.5.3.Final'
implementation 'com.google.code.gson:gson'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5
annotationProcessor 'org.projectlombok:lombok'
implementation 'org.mapstruct:mapstruct:1.5.3.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final'
implementation 'org.springframework.boot:spring-boot-starter-validation'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5
}

tasks.named('test') {
Expand Down
23 changes: 23 additions & 0 deletions server/src/main/java/seb4141preproject/Member.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package seb4141preproject;

import lombok.Getter;
import lombok.Setter;
import net.bytebuddy.dynamic.loading.InjectionClassLoader;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
* Answer CRUD 테스트를 위한 목업 데이터
*/

@Getter
@Setter
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
}
21 changes: 21 additions & 0 deletions server/src/main/java/seb4141preproject/Question.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package seb4141preproject;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
* Answer CRUD 테스트를 위한 목업 데이터
*/
@Getter
@Setter
@Entity
public class Question {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package seb4141preproject.answer.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import seb4141preproject.answer.dto.AnswerDto;
import seb4141preproject.answer.entity.Answer;
import seb4141preproject.answer.mapper.AnswerMapper;
import seb4141preproject.answer.service.AnswerService;
import seb4141preproject.dto.MultiResponseDto;
import seb4141preproject.dto.PageInfo;
import seb4141preproject.dto.SingleResponseDto;

import javax.validation.Valid;
import javax.validation.constraints.Positive;
import java.util.List;

/**
* - AnswerController_v1
* - Member/Question 연결 필요
* - getAnswers 응답 구조 테스트 필요
*/

@RestController
@RequestMapping("/answer")
@Validated
@Slf4j
public class AnswerController {
private final AnswerService answerService;
private final AnswerMapper mapper;

public AnswerController(AnswerService answerService, AnswerMapper mapper) {
this.answerService = answerService;
this.mapper = mapper;
}

@PostMapping
public ResponseEntity postAnswer(@Valid @RequestBody AnswerDto.Post requestBody) {
Answer answer = mapper.answerPostToAnswer(requestBody);

Answer createdAnswer = answerService.createAnswer(answer);
AnswerDto.Response response = mapper.answerToAnswerResponse(createdAnswer);

return new ResponseEntity<>(
new SingleResponseDto<>(response),
HttpStatus.CREATED);
}

@PatchMapping("/{answer-id}")
public ResponseEntity patchAnswer(
@PathVariable("answer-id") @Positive long answerId,
@Valid @RequestBody AnswerDto.Patch requestBody) {
Answer answer =
answerService.updateAnswer(mapper.answerPatchToAnswer(requestBody));
AnswerDto.Response response = mapper.answerToAnswerResponse(answer);

return new ResponseEntity<>(
new SingleResponseDto<>(response), HttpStatus.OK);
}

@GetMapping("/{answer-id}")
public ResponseEntity getAnswer(
@PathVariable("answer-id") @Positive long answerId) {
Answer answer = answerService.findAnswer(answerId);
AnswerDto.Response response = mapper.answerToAnswerResponse(answer);
return new ResponseEntity<>(
new SingleResponseDto<>(response), HttpStatus.OK);
}

@GetMapping
public ResponseEntity getAnswers(@Positive @RequestParam int page,
@Positive @RequestParam int size,
@Positive @RequestParam long questionId) {
Page<Answer> answers = answerService.findAnswers(page - 1, size, questionId);
List<Answer> answerList = answers.getContent();

return new ResponseEntity<>(
new MultiResponseDto<>(mapper.answersToAnswerResponses(answerList),answers),
HttpStatus.OK);
}

@DeleteMapping("/{answer-id}")
public ResponseEntity deleteAnswer(
@PathVariable("answer-id") @Positive long answerId) {
answerService.deleteAnswer(answerId);

return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}

}
45 changes: 45 additions & 0 deletions server/src/main/java/seb4141preproject/answer/dto/AnswerDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package seb4141preproject.answer.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;

import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;

public class AnswerDto {
@Getter
@AllArgsConstructor
public static class Post {

private long memberId;

private long questionId;
@NotBlank
private String description;
}

@Getter
@AllArgsConstructor
public static class Patch {
@NotBlank
private String description;
}

@Getter
@AllArgsConstructor
public static class Response {

private long answerId;
private long memberId;
private long questionId;
private String description;

private LocalDateTime createAt;

private LocalDateTime modifiedAt;


}


}
45 changes: 45 additions & 0 deletions server/src/main/java/seb4141preproject/answer/entity/Answer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package seb4141preproject.answer.entity;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import seb4141preproject.Member;
import seb4141preproject.Question;

import javax.persistence.Entity;
import javax.persistence.*;
import java.time.LocalDateTime;

/**
* H2로 테스트
*/


@Entity
@Getter
@Setter
@NoArgsConstructor
public class Answer {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long answerId;

// 글자 수 지정
@Column(nullable = false)
private String description;

@Column
private LocalDateTime createdAt;

@Column
private LocalDateTime modifiedAt;

// 테스트를 위해 목업 데이터 클래스 연결
@ManyToOne
@JoinColumn(name = "QUESTION_ID")
private Question question;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package seb4141preproject.answer.mapper;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
import seb4141preproject.answer.dto.AnswerDto;
import seb4141preproject.answer.entity.Answer;

import java.util.List;

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface AnswerMapper {
Answer answerPostToAnswer(AnswerDto.Post requestBody);
Answer answerPatchToAnswer(AnswerDto.Patch requestBody);
@Mapping(target = "memberId", source = "member.id")
@Mapping(target = "questionId", source = "question.id")
AnswerDto.Response answerToAnswerResponse(Answer answer);
List<AnswerDto.Response> answersToAnswerResponses(List<Answer> answers);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package seb4141preproject.answer.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import seb4141preproject.answer.entity.Answer;
import seb4141preproject.dto.PageInfo;

import java.util.Optional;

public interface AnswerRepository extends JpaRepository<Answer, Long> {
//TODO : query 확인 필요
@Query(value = "select a from Question a where a.id = :questionId")
Page<Answer> findByQuestionId(long questionId, PageRequest pageRequest);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package seb4141preproject.answer.service;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import seb4141preproject.Member;
import seb4141preproject.Question;
import seb4141preproject.answer.entity.Answer;
import seb4141preproject.answer.repository.AnswerRepository;

import java.util.Optional;

/**
* - Service 목업 데이터로 테스트 (H2 콘솔에서 데이터 삽입 후)
* - 검증 기능 구현
*/

@Service
public class AnswerService {
private final AnswerRepository answerRepository;

public AnswerService(AnswerRepository answerRepository) {
this.answerRepository = answerRepository;
}

public Answer createAnswer(Answer answer) {
// Member, Question 연결 전 목업 데이터 사용 세팅
Member member = new Member();
member.setId(1L);

Question question = new Question();
question.setId(1L);

answer.setMember(member);
answer.setQuestion(question);

//TODO: 존재하는 회원, 존재하는 질문 검증 필요
// verifiedMember(answer.getMember().getId());
// verifiedQuestion(answer.getQuestion().getId());

Answer savedanswer = answerRepository.save(answer);

return savedanswer;
}

public Answer updateAnswer(Answer answer) {
Answer findAnswer = findVerifiedAnswer(answer.getAnswerId());

Optional.ofNullable(answer.getDescription())
.ifPresent(description -> findAnswer.setDescription(description));

return answerRepository.save(findAnswer);
}

public Answer findAnswer(long answerId) {
return findVerifiedAnswer(answerId);
}

public Page<Answer> findAnswers(int page, int size, long questionId) {
return answerRepository.findByQuestionId(questionId, PageRequest.of(page, size,
Sort.by("answerId").descending()));
}

public void deleteAnswer(long answerId) {
Answer findAnswer = findVerifiedAnswer(answerId);

answerRepository.delete(findAnswer);
}

public Answer findVerifiedAnswer(long answerId) {
Optional<Answer> optionalAnswer =
answerRepository.findById(answerId);
Answer findAnswer =
optionalAnswer.orElseThrow(() ->
new IllegalArgumentException("답변을 찾을 수 없습니다."));
return findAnswer;
}

// public Member verifiedMember(long memberId) {
// Optional<Member> optionalMember =
// memberRepository.findById(memberId);
// Member findMember =
// optionalMember.orElseThrow(() ->
// new IllegalArgumentException("회원을 찾을 수 없습니다."));
// return findMember;
// }
//
// public Question verifiedQuestion(long questionId) {
// Optional<Question> optionalQuestion =
// questionRepository.findById(questionId);
// Question findQuestion =
// optionalQuestion.orElseThrow(()->
// new IllegalArgumentException("질문을 찾을 수 없습니다."));
// return findQuestion;
// }
}
Loading