diff --git a/resource-server/src/main/java/com/example/config/SwaggerConfig.java b/resource-server/src/main/java/com/example/config/SwaggerConfig.java index 661448a..76101f9 100644 --- a/resource-server/src/main/java/com/example/config/SwaggerConfig.java +++ b/resource-server/src/main/java/com/example/config/SwaggerConfig.java @@ -119,4 +119,21 @@ public GroupedOpenApi getPlayerApi() { .pathsToMatch("/api/player/**", "/api/queue/**") .build(); } + + @Bean + public GroupedOpenApi getQnAAPI() { + return GroupedOpenApi.builder() + .group("질문 및 답변 관련") + .pathsToMatch("/api/questions/**", "/api/responses/**") + .build(); + } + + @Bean + public GroupedOpenApi getTestProgressAPI() { + return GroupedOpenApi.builder() + .group("진행 상황 및 참여 인원 관련") + .pathsToMatch("/api/test-progress/**", "/api/participants/**") + .build(); + } + } diff --git a/resource-server/src/main/java/com/example/web/QnAController.java b/resource-server/src/main/java/com/example/web/QnAController.java new file mode 100644 index 0000000..e278a9d --- /dev/null +++ b/resource-server/src/main/java/com/example/web/QnAController.java @@ -0,0 +1,69 @@ +package com.example.web; + +import com.example.web.qna.domain.Question; +import com.example.web.qna.domain.Answer; +import com.example.web.qna.dto.AnswerDTO; +import com.example.web.qna.dto.QuestionDTO; +import com.example.web.qna.usecase.QnAService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +@RestController +@RequestMapping("/api/questions") +public class QnAController { + + @Autowired + private QnAService qnAService; + + @Operation( + summary = "랜덤 질문 가져오기", + description = "데이터베이스에서 무작위로 선택된 질문을 제공합니다." + ) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "성공적으로 랜덤 질문 반환", + content = @Content(schema = @Schema(implementation = QuestionDTO.class))), + @ApiResponse(responseCode = "404", description = "질문 데이터 없음", + content = @Content(schema = @Schema(example = "{\"status\": 404, \"message\": \"질문 데이터가 없습니다.\"}"))), + }) + @GetMapping("/") + public ResponseEntity getRandomQuestion() { + QuestionDTO question = qnAService.getRandomQuestion(); + if (question == null) { + return ResponseEntity.status(404).body(Map.of( + "status", 404, + "message", "질문 데이터가 없습니다." + )); + } + return ResponseEntity.ok(question); + } + + @Operation( + summary = "답변 저장하기", + description = "사용자가 작성한 답변을 저장합니다." + ) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "답변 저장 완료", + content = @Content(schema = @Schema(implementation = AnswerDTO.class))), + @ApiResponse(responseCode = "400", description = "잘못된 요청", + content = @Content(schema = @Schema(example = "{\"status\": 400, \"message\": \"잘못된 요청입니다.\"}"))), + }) + @PostMapping("/responses") + public ResponseEntity saveAnswer(@RequestBody Answer answer) { + if (answer == null || answer.getContent() == null || answer.getContent().isEmpty()) { + return ResponseEntity.badRequest().body(Map.of( + "status", 400, + "message", "잘못된 요청입니다. 답변 내용을 입력해주세요." + )); + } + AnswerDTO savedAnswer = qnAService.saveAnswer(answer); + return ResponseEntity.ok(savedAnswer); + } +} diff --git a/resource-server/src/main/java/com/example/web/TestProgressController.java b/resource-server/src/main/java/com/example/web/TestProgressController.java new file mode 100644 index 0000000..c6e1b4b --- /dev/null +++ b/resource-server/src/main/java/com/example/web/TestProgressController.java @@ -0,0 +1,35 @@ +package com.example.web; + +import com.example.web.progress.dto.ParticipantCountDTO; +import com.example.web.progress.usecase.TestProgressService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/test-progress") +public class TestProgressController { + + @Autowired + private TestProgressService testProgressService; + + @Operation( + summary = "참여 인원 카운팅", + description = "이 테스트에 총 몇 명이 참여했는지 반환합니다." + ) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "참여 인원 수 반환", + content = @Content(schema = @Schema(implementation = ParticipantCountDTO.class))) + }) + @GetMapping("/participants/count") + public ResponseEntity getParticipantCount() { + long count = testProgressService.getParticipantCount(); + ParticipantCountDTO response = new ParticipantCountDTO((int) count); + return ResponseEntity.ok(response); + } +} diff --git a/resource-server/src/main/java/com/example/web/progress/domain/Participant.java b/resource-server/src/main/java/com/example/web/progress/domain/Participant.java new file mode 100644 index 0000000..ff2ff70 --- /dev/null +++ b/resource-server/src/main/java/com/example/web/progress/domain/Participant.java @@ -0,0 +1,47 @@ +package com.example.web.progress.domain; + +import jakarta.persistence.*; + +@Entity +public class Participant { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String participantName; + + @ManyToOne + @JoinColumn(name = "test_progress_id") + private TestProgress testProgress; + + // 기본 생성자 + public Participant() {} + + // 생성자 + public Participant(String participantName, TestProgress testProgress) { + this.participantName = participantName; + this.testProgress = testProgress; + } + + // Getter 및 Setter + public Long getId() { + return id; + } + + public String getParticipantName() { + return participantName; + } + + public void setParticipantName(String participantName) { + this.participantName = participantName; + } + + public TestProgress getTestProgress() { + return testProgress; + } + + public void setTestProgress(TestProgress testProgress) { + this.testProgress = testProgress; + } +} diff --git a/resource-server/src/main/java/com/example/web/progress/domain/TestProgress.java b/resource-server/src/main/java/com/example/web/progress/domain/TestProgress.java new file mode 100644 index 0000000..efd0972 --- /dev/null +++ b/resource-server/src/main/java/com/example/web/progress/domain/TestProgress.java @@ -0,0 +1,46 @@ +package com.example.web.progress.domain; + +import jakarta.persistence.*; +import java.util.List; + +@Entity +public class TestProgress { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String testName; + + @OneToMany(mappedBy = "testProgress") + private List participants; + + // 기본 생성자 + public TestProgress() {} + + // 생성자 + public TestProgress(String testName) { + this.testName = testName; + } + + // Getter 및 Setter + public Long getId() { + return id; + } + + public String getTestName() { + return testName; + } + + public void setTestName(String testName) { + this.testName = testName; + } + + public List getParticipants() { + return participants; + } + + public void setParticipants(List participants) { + this.participants = participants; + } +} diff --git a/resource-server/src/main/java/com/example/web/progress/dto/ParticipantCountDTO.java b/resource-server/src/main/java/com/example/web/progress/dto/ParticipantCountDTO.java new file mode 100644 index 0000000..567539e --- /dev/null +++ b/resource-server/src/main/java/com/example/web/progress/dto/ParticipantCountDTO.java @@ -0,0 +1,23 @@ +package com.example.web.progress.dto; + +public class ParticipantCountDTO { + + private int participantCount; + + // 기본 생성자 + public ParticipantCountDTO() {} + + // 생성자 + public ParticipantCountDTO(int participantCount) { + this.participantCount = participantCount; + } + + // Getter 및 Setter + public int getParticipantCount() { + return participantCount; + } + + public void setParticipantCount(int participantCount) { + this.participantCount = participantCount; + } +} diff --git a/resource-server/src/main/java/com/example/web/progress/repository/ParticipantRepository.java b/resource-server/src/main/java/com/example/web/progress/repository/ParticipantRepository.java new file mode 100644 index 0000000..62b951b --- /dev/null +++ b/resource-server/src/main/java/com/example/web/progress/repository/ParticipantRepository.java @@ -0,0 +1,8 @@ +package com.example.web.progress.repository; + +import com.example.web.progress.domain.Participant; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ParticipantRepository extends JpaRepository { + // 추가적인 쿼리 메서드가 필요하면 여기에 정의합니다. +} diff --git a/resource-server/src/main/java/com/example/web/progress/repository/TestProgressRepository.java b/resource-server/src/main/java/com/example/web/progress/repository/TestProgressRepository.java new file mode 100644 index 0000000..325aa0e --- /dev/null +++ b/resource-server/src/main/java/com/example/web/progress/repository/TestProgressRepository.java @@ -0,0 +1,8 @@ +package com.example.web.progress.repository; + +import com.example.web.progress.domain.TestProgress; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TestProgressRepository extends JpaRepository { + // 추가적인 쿼리 메서드가 필요하면 여기에 정의합니다. +} diff --git a/resource-server/src/main/java/com/example/web/progress/usecase/TestProgressService.java b/resource-server/src/main/java/com/example/web/progress/usecase/TestProgressService.java new file mode 100644 index 0000000..a0d621c --- /dev/null +++ b/resource-server/src/main/java/com/example/web/progress/usecase/TestProgressService.java @@ -0,0 +1,16 @@ +package com.example.web.progress.usecase; + +import com.example.web.progress.repository.ParticipantRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class TestProgressService { + + @Autowired + private ParticipantRepository participantRepository; + + public long getParticipantCount() { + return participantRepository.count(); + } +} diff --git a/resource-server/src/main/java/com/example/web/qna/domain/Answer.java b/resource-server/src/main/java/com/example/web/qna/domain/Answer.java new file mode 100644 index 0000000..a5db67a --- /dev/null +++ b/resource-server/src/main/java/com/example/web/qna/domain/Answer.java @@ -0,0 +1,23 @@ +package com.example.web.qna.domain; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Getter +@Setter +@Table(name = "answers") +public class Answer { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private String content; + + @ManyToOne + @JoinColumn(name = "question_id", nullable = false) + private Question question; +} diff --git a/resource-server/src/main/java/com/example/web/qna/domain/Question.java b/resource-server/src/main/java/com/example/web/qna/domain/Question.java new file mode 100644 index 0000000..11184e0 --- /dev/null +++ b/resource-server/src/main/java/com/example/web/qna/domain/Question.java @@ -0,0 +1,20 @@ +package com.example.web.qna.domain; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Getter +@Setter +@Table(name = "questions") +public class Question { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private String content; + +} diff --git a/resource-server/src/main/java/com/example/web/qna/dto/AnswerDTO.java b/resource-server/src/main/java/com/example/web/qna/dto/AnswerDTO.java new file mode 100644 index 0000000..5abffaf --- /dev/null +++ b/resource-server/src/main/java/com/example/web/qna/dto/AnswerDTO.java @@ -0,0 +1,25 @@ +package com.example.web.qna.dto; + +public class AnswerDTO { + private Long id; + private String content; + private Long questionId; + + public AnswerDTO(Long id, String content, Long questionId) { + this.id = id; + this.content = content; + this.questionId = questionId; + } + + public Long getId() { + return id; + } + + public String getContent() { + return content; + } + + public Long getQuestionId() { + return questionId; + } +} diff --git a/resource-server/src/main/java/com/example/web/qna/dto/QuestionDTO.java b/resource-server/src/main/java/com/example/web/qna/dto/QuestionDTO.java new file mode 100644 index 0000000..628e1db --- /dev/null +++ b/resource-server/src/main/java/com/example/web/qna/dto/QuestionDTO.java @@ -0,0 +1,19 @@ +package com.example.web.qna.dto; + +public class QuestionDTO { + private Long id; + private String content; + + public QuestionDTO(Long id, String content) { + this.id = id; + this.content = content; + } + + public Long getId() { + return id; + } + + public String getContent() { + return content; + } +} diff --git a/resource-server/src/main/java/com/example/web/qna/repository/AnswerRepository.java b/resource-server/src/main/java/com/example/web/qna/repository/AnswerRepository.java new file mode 100644 index 0000000..91b8161 --- /dev/null +++ b/resource-server/src/main/java/com/example/web/qna/repository/AnswerRepository.java @@ -0,0 +1,10 @@ +package com.example.web.qna.repository; + +import com.example.web.qna.domain.Answer; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface AnswerRepository extends JpaRepository { + +} diff --git a/resource-server/src/main/java/com/example/web/qna/repository/QuestionRepository.java b/resource-server/src/main/java/com/example/web/qna/repository/QuestionRepository.java new file mode 100644 index 0000000..b149bec --- /dev/null +++ b/resource-server/src/main/java/com/example/web/qna/repository/QuestionRepository.java @@ -0,0 +1,10 @@ +package com.example.web.qna.repository; + +import com.example.web.qna.domain.Question; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface QuestionRepository extends JpaRepository { + +} diff --git a/resource-server/src/main/java/com/example/web/qna/usecase/QnAService.java b/resource-server/src/main/java/com/example/web/qna/usecase/QnAService.java new file mode 100644 index 0000000..a3ad4d2 --- /dev/null +++ b/resource-server/src/main/java/com/example/web/qna/usecase/QnAService.java @@ -0,0 +1,36 @@ +package com.example.web.qna.usecase; + +import com.example.web.qna.domain.Answer; +import com.example.web.qna.domain.Question; +import com.example.web.qna.dto.AnswerDTO; +import com.example.web.qna.dto.QuestionDTO; +import com.example.web.qna.repository.AnswerRepository; +import com.example.web.qna.repository.QuestionRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class QnAService { + + @Autowired + private QuestionRepository questionRepository; + + @Autowired + private AnswerRepository answerRepository; + + public QuestionDTO getRandomQuestion() { + List questions = questionRepository.findAll(); + if (questions.isEmpty()) { + return null; + } + Question randomQuestion = questions.get((int) (Math.random() * questions.size())); + return new QuestionDTO(randomQuestion.getId(), randomQuestion.getContent()); + } + + public AnswerDTO saveAnswer(Answer answer) { + Answer savedAnswer = answerRepository.save(answer); + return new AnswerDTO(savedAnswer.getId(), savedAnswer.getContent(), savedAnswer.getQuestion().getId()); + } +}