diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4f0d27e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,36 @@
+HELP.md
+target/
+.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+/.metadata/
+
+.class
\ No newline at end of file
diff --git a/.project b/.project
deleted file mode 100644
index e40ff58..0000000
--- a/.project
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
- Backend
-
-
-
-
-
-
-
-
diff --git a/README.md b/README.md
index 5e97794..bac0e4c 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,72 @@
-# Backend
\ No newline at end of file
+# BangBang Codeboy (정보처리기사/SQLD 스피드 퀴즈 플랫폼)
+
+## 1. 프로젝트 개요
+- 정보처리기사와 sqld를 공부의 범위가 방대하여 공부에 어려움을 겪는 자격증 준비생 혹은 SSAFY생을 위해 제작.
+- 각 자격증에서 배우는 내용을 쉽게 복습할 수 있는 시스템을 만든다.
+- 반 친구들과 스피드 퀴즈 대결을 하며 재미있게 학습한다.
+- 랭킹 기능을 제공하여 학습의 성취감을 얻는다.
+
+## 2. 핵심 기능
+- 정보처리기사와 sqld 관련 키워드를 활용한 4지선다 퀴즈 제공.
+- 퀴즈방 생성 및 최대 20명과 실시간 대결.
+- 오답노트 및 해설 제공.
+- 유저 제작 문제 생성/수정/삭제.
+- 리더보드 랭킹.
+- 유저가 직접 문제를 제작 가능.
+- 혹은 ChatGPT, Gemini로 문제를 자동으로 생성하고 해설을 제공.
+
+## 3. Tech Stack & 아키텍처
+
+
+
+ - Spring, MySQL, MyBatis, Fast API -> 백엔드 API 개발과 데이터베이스, 외부 LLM 호출 서버 제작을 맡고 있음.
+
+
+## 4. 시스템 설계 문서
+- [ERD]
+
+
+- [유즈케이스 다이어그램]
+
+
+- [기능 명세서 (구글 스프레드시트)](https://docs.google.com/spreadsheets/d/1pif1EVEQNDvyv444s-4GoqX6n816fivUlyM2uHmzNT8/edit?gid=0#gid=0)
+- [WBS & 일정관리(Notion)](https://pointy-harpymimus-0cb.notion.site/2a76fbddf57780169009ed2301511ee1)
+- [목업/화면 설계(Notion)](https://pointy-harpymimus-0cb.notion.site/2ab6fbddf57781839d13f9224dfa7a9c)
+
+
+## 5. API 시나리오 테스트
+### 테스트 시나리오
+1. 모든 테이블의 데이터들만 삭제.
+2. 회원가입 + 해당 유저의 점수 등록.
+3. 로그인(전단계에서 회원가입한 유저의 id와 password를 이용).
+4. 문제세트 전체조회.
+5. 로그인한 회원이 만든 유저제작문제세트 조회.
+6. 로그인한 회원이 유저제작문제 3개 추가.
+7. 로그인한 회원이 유저제작문제 하나 수정.
+8. 유저제작 문제의 댓글 조회.
+9. 로그인한 회원이 댓글 3개 작성.
+10. 로그인한 회원이 댓글 하나 수정.
+11. 로그인한 회원이 댓글 삭제.
+12. 로그인한 회원이 문제 세트 삭제.
+13. 모든 회원들의 점수 조회.
+14. 로그인한 회원 한명의 점수를 조회.
+15. 로그인한 회원 한명의 점수를 수정.
+16. 문제테이블(problem테이블) 에서 문제 전체 조회.
+17. 문제테이블(problem테이블) 에서 문제 전체 조회.
+18. 로그인한 회원의 오답노트에 문제 추가 후 로그인한 회원의 오답노트 안의 전체 문제 조회.
+19. 로그인한 회원의 오답노트에 있는 문제 삭제(problem과 user_problem테이블에 있는 문제도 삭제되면 안됨).
+20. 모든 퀴즈방 목록 조회.
+21. 로그인한 회원이 퀴즈방을 생성하고 방장이 됨(isHost = 1).
+22. 또 다른 mcp서버가 localhost:8082에서 가동되며 같은 DB 다른 회원을 가입하고 로그인 전체 퀴즈방들을 조회하여 조회된 퀴즈방에 들어가있는 회원들을 조회하고 isHost=0인 방장이 아닌 상태로 다른 방장이 만든 퀴즈방에 들어가기.
+23. 방장인 회원이 퀴즈방을 삭제.
+
+### 테스트 방법
+1. html에 자바스크립트를 작성 후 axios 통신을 통해 Vite 프록시 서버에 요청을 보낸 후 응답을 console.log로 출력.
+2. 테스트 결과를 testResultYYYYMMDDHH형식으로 다운로드.
+
+
+
+
+## 6. 향후 개선 계획
+- DeepseekOCR을 활용하여 개념요약 PDF -> 텍스트 -> 문제 제작 Flow 개발 / Fast API로 외부 LLM 호출하여 문제 생성 및 해설 기능 개발.
+- API 테스트 파이프라인 제작.
diff --git a/codeBoy_backend/.gitignore b/codeBoy_backend/.gitignore
index 667aaef..4f0d27e 100644
--- a/codeBoy_backend/.gitignore
+++ b/codeBoy_backend/.gitignore
@@ -31,3 +31,6 @@ build/
### VS Code ###
.vscode/
+/.metadata/
+
+.class
\ No newline at end of file
diff --git a/codeBoy_backend/mvnw b/codeBoy_backend/mvnw
old mode 100644
new mode 100755
diff --git a/codeBoy_backend/pom.xml b/codeBoy_backend/pom.xml
index aa498cf..29abeb6 100644
--- a/codeBoy_backend/pom.xml
+++ b/codeBoy_backend/pom.xml
@@ -29,57 +29,69 @@
17
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
- org.mybatis.spring.boot
- mybatis-spring-boot-starter
- 3.0.5
-
-
- org.springframework.boot
- spring-boot-devtools
- runtime
- true
-
-
- com.mysql
- mysql-connector-j
- runtime
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
- org.mybatis.spring.boot
- mybatis-spring-boot-starter-test
- 3.0.5
- test
-
-
- org.springdoc
- springdoc-openapi-starter-webmvc-ui
- 2.3.0
-
-
- org.springframework.boot
- spring-boot-starter
-
-
- org.projectlombok
- lombok
- true
-
-
+
+ com.mysql mysql-connector-j runtime
+
+ org.springframework.boot
+ spring-boot-starter-web
+
-
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 3.0.5
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.12.3
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.12.3
+ runtime
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ 0.12.3
+ runtime
+
+
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+ 2.3.0
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.42
+
+
+
+ org.flywaydb
+ flyway-core
+
+
+ org.flywaydb
+ flyway-mysql
+
+
+
+
+
+
org.springframework.boot
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/config/MyBatisConfig.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/config/MyBatisConfig.java
new file mode 100644
index 0000000..f657d4d
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/config/MyBatisConfig.java
@@ -0,0 +1,10 @@
+package com.codeboy.mvc.config;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@MapperScan("com.codeboy.mvc.model.dao")
+public class MyBatisConfig {
+
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/config/SecurityConfig.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/config/SecurityConfig.java
new file mode 100644
index 0000000..300ec84
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/config/SecurityConfig.java
@@ -0,0 +1,105 @@
+package com.codeboy.mvc.config;
+
+import com.codeboy.mvc.jwt.JWTFilter;
+import com.codeboy.mvc.jwt.JWTUtil;
+import com.codeboy.mvc.jwt.LoginFilter;
+import com.codeboy.mvc.model.service.CustomerUserDetailService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.CorsConfigurationSource;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+
+import java.util.List;
+
+@RequiredArgsConstructor
+@EnableWebSecurity
+@Configuration
+public class SecurityConfig {
+
+ private final CustomerUserDetailService customerUserDetailService;
+ private final JWTUtil jwtUtil;
+ private final com.fasterxml.jackson.databind.ObjectMapper objectMapper; //
+
+
+ @Bean
+ public BCryptPasswordEncoder bCryptPasswordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+ @Bean
+ public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
+ var builder = http.getSharedObject(org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.class);
+
+ builder
+ .userDetailsService(customerUserDetailService)
+ .passwordEncoder(bCryptPasswordEncoder());
+
+ return builder.build();
+ }
+
+ @Bean
+ public SecurityFilterChain securityFilterChain(HttpSecurity http,
+ AuthenticationManager authenticationManager) throws Exception {
+
+ http
+ .formLogin(AbstractHttpConfigurer::disable)
+ .httpBasic(AbstractHttpConfigurer::disable)
+ .csrf(AbstractHttpConfigurer::disable)
+ .cors(cors -> cors.configurationSource(corsConfigurationSource()));
+
+
+ http
+ .authorizeHttpRequests(auth -> auth
+ .requestMatchers("/", "/login", "/api/join", "/swagger-ui/**",
+ "/v3/api-docs/**",
+ "/api-docs/**",
+ "/swagger-resources/**").permitAll()
+ .requestMatchers("/admin/**").hasRole("ADMIN") // ✅ 보통 이렇게 씀
+ .anyRequest().authenticated()
+ );
+
+ http
+ .sessionManagement(session ->
+ session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ );
+
+ http.addFilterAt(
+ new LoginFilter(authenticationManager, jwtUtil, objectMapper),
+ UsernamePasswordAuthenticationFilter.class
+ );
+
+ http.addFilterBefore(
+ new JWTFilter(jwtUtil, customerUserDetailService),
+ UsernamePasswordAuthenticationFilter.class
+ );
+
+ return http.build();
+ }
+ @Bean
+ public CorsConfigurationSource corsConfigurationSource() {
+ CorsConfiguration configuration = new CorsConfiguration();
+
+ // 프론트 주소 허용
+ configuration.setAllowedOrigins(List.of("http://localhost:5173"));
+ // 모든 메서드 허용
+ configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
+ // 모든 헤더 허용
+ configuration.setAllowedHeaders(List.of("*"));
+ // 쿠키/Authorization 헤더 허용 (JWT 쓸 때 보통 true)
+ configuration.setAllowCredentials(true);
+
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ source.registerCorsConfiguration("/**", configuration);
+ return source;
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/AdminController.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/AdminController.java
new file mode 100644
index 0000000..e35b5da
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/AdminController.java
@@ -0,0 +1,13 @@
+package com.codeboy.mvc.controller;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class AdminController {
+
+ @GetMapping("/admin")
+ public String adminP() {
+ return "admin Controller";
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/CommentController.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/CommentController.java
new file mode 100644
index 0000000..2d29f62
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/CommentController.java
@@ -0,0 +1,169 @@
+package com.codeboy.mvc.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.codeboy.mvc.model.dto.CustomUserDetails;
+import com.codeboy.mvc.model.dto.request.CommentUpdateRequest;
+import com.codeboy.mvc.model.dto.response.ApiResponse;
+import jakarta.servlet.http.HttpSession;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.codeboy.mvc.model.dto.Comment;
+import com.codeboy.mvc.model.service.CommentService;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+@RestController
+@RequestMapping("/api/comments")
+@Tag(name="Comment RESTful API", description = "Comment CRUD를 할 수 있는 REST API")
+public class CommentController {
+ private final CommentService commentService;
+
+
+ @Autowired
+ public CommentController(CommentService commentService) {
+ this.commentService = commentService;
+ }
+
+
+ @GetMapping("{userProblemSetId}")
+ //숫자가 아닌 값이 userProblemSetId에 오면 스프링이 컨트롤러에 도달하기전에 400BAD_REQUEST를 보내줌
+ public ResponseEntity>> getAllCommentsById(@PathVariable("userProblemSetId") long userProblemSetId){
+ List comments = commentService.getAllCommentsById(userProblemSetId);
+
+ if (comments.isEmpty()) {
+ //댓글이 달리지 않은 경우
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success(HttpStatus.OK, "댓글이 없습니다.", new ArrayList()));
+ }
+ //댓글 조회에 성공한 경우
+ return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.success(HttpStatus.OK, "댓글 조회 성공", comments));
+
+ }
+
+ @PostMapping("{userProblemSetId}")
+ public ResponseEntity> addComment(@PathVariable long userProblemSetId,
+ @RequestBody Comment comment, @AuthenticationPrincipal CustomUserDetails loginUser) {
+ if (comment.getContent() == null || comment.getContent().isBlank()) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, "댓글 내용은 비어 있을 수 없습니다."));
+ }
+
+ Long memberId = loginUser.getMemberId();
+ if (memberId == null) {
+ // 인증 안 됨
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body(ApiResponse.failure(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다."));
+ }
+ comment.setMemberId(memberId);
+ int result = commentService.addComment(userProblemSetId, comment);
+
+ if (result == 0) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, "잘못된 요청. 댓글 추가 실패"));
+ }
+
+ return ResponseEntity.status(HttpStatus.CREATED)
+ .body(ApiResponse.success(HttpStatus.CREATED, "댓글 추가 성공", null));
+ }
+
+
+ //리소스의 일부(content)만 수정하므로 패치매핑
+ @PatchMapping("{commentId}")
+ public ResponseEntity> updateComment(
+ @PathVariable long commentId,
+ @RequestBody CommentUpdateRequest commentUpdateRequest,
+ @AuthenticationPrincipal CustomUserDetails loginUser) {
+
+ Long memberId = loginUser.getMemberId();
+ if (memberId == null) {
+ // 인증 안 됨
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body(ApiResponse.failure(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다."));
+ }
+ commentUpdateRequest.setMemberId(memberId);
+ if (!memberId.equals(commentUpdateRequest.getMemberId())) {
+ // 인가 실패
+ // 로그인 중인 회원이 자신이 작성한 댓글이 아닌 것을 수정하려할 때
+ return ResponseEntity.status(HttpStatus.FORBIDDEN)
+ .body(ApiResponse.failure(HttpStatus.FORBIDDEN, "본인의 댓글만 수정할 수 있습니다."));
+ }
+
+ //댓글이 비어있을 때
+ if (commentUpdateRequest.getContent() == null || commentUpdateRequest.getContent().isBlank()) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, "수정할 댓글 내용을 입력해주세요."));
+ }
+
+ Comment comment = new Comment();
+ comment.setContent(commentUpdateRequest.getContent());
+
+ int result = commentService.updateComment(commentId, comment);
+
+ if (result == 0) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND)
+ .body(ApiResponse.failure(HttpStatus.NOT_FOUND, "존재하지 않는 댓글입니다."));
+
+ }
+
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success(HttpStatus.OK, "댓글 수정 성공", null));
+ }
+
+
+ @DeleteMapping("{userProblemSetId}/{commentId}")
+ public ResponseEntity> deleteComment(@PathVariable long userProblemSetId,
+ @PathVariable long commentId,
+ @AuthenticationPrincipal CustomUserDetails loginUser) {
+
+ Long memberId = loginUser.getMemberId();
+
+ // 로그인 안한 상태
+ if (memberId == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body(ApiResponse.failure(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다."));
+ }
+
+ // DB에서 댓글 작성자 ID 조회
+ Long ownerId = commentService.getCommentOwnerId(commentId);
+
+ // 댓글ID가 존재하지 않는 경우
+ if (ownerId == null) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND)
+ .body(ApiResponse.failure(HttpStatus.NOT_FOUND, "존재하지 않는 댓글입니다."));
+ }
+
+ // 권한 없음 (본인 댓글 아님)
+ if (!memberId.equals(ownerId)) {
+ return ResponseEntity.status(HttpStatus.FORBIDDEN)
+ .body(ApiResponse.failure(HttpStatus.FORBIDDEN, "본인이 작성한 댓글만 삭제할 수 있습니다."));
+ }
+
+ // 삭제 실행
+ int result = commentService.deleteComment(commentId);
+
+ if (result == 0) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR, "댓글 삭제에 실패했습니다."));
+ }
+
+ // 삭제 실패 (DB 오류 등의 상황)
+
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success(HttpStatus.OK, "댓글 삭제 성공", null));
+ }
+
+
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/IncorrectNoteController.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/IncorrectNoteController.java
new file mode 100644
index 0000000..3bddc25
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/IncorrectNoteController.java
@@ -0,0 +1,74 @@
+package com.codeboy.mvc.controller;
+
+import com.codeboy.mvc.model.dto.CustomUserDetails;
+import com.codeboy.mvc.model.dto.request.IncorrectNoteRequest;
+import com.codeboy.mvc.model.dto.response.ApiResponse;
+import com.codeboy.mvc.model.dto.response.IncorrectNoteResponse;
+import com.codeboy.mvc.model.service.IncorrectNoteService;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpSession;
+
+import org.apache.ibatis.javassist.NotFoundException;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("api/incorrect-note")
+@Tag(name="Incorrect-note RESTful API", description = "Incorrect-note CRUD를 할 수 있는 REST API")
+public class IncorrectNoteController {
+
+ private final IncorrectNoteService incorrectNoteService;
+
+ public IncorrectNoteController(IncorrectNoteService incorrectNoteService) {
+ this.incorrectNoteService = incorrectNoteService;
+ }
+
+ //한 회원의 오답노트를 모두 조회
+ @GetMapping
+ public ResponseEntity>> getIncorrectNote( @AuthenticationPrincipal CustomUserDetails loginUser) {
+ try {
+ Long memberId = loginUser.getMemberId();
+ List incorrectNoteList = incorrectNoteService.getIncorrectNoteList(memberId);
+ return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.success(HttpStatus.OK, "오답노트가 성공적으로 조회되었습니다", incorrectNoteList));
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ } catch (NotFoundException e) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ApiResponse.failure(HttpStatus.NOT_FOUND, e.getMessage()));
+ }
+ }
+
+ //오답노트에 문제 넣기
+ @PostMapping
+ public ResponseEntity> addIncorrectNote(@RequestBody IncorrectNoteRequest incorrectNoteRequest, @AuthenticationPrincipal CustomUserDetails loginUser) {
+
+ Long memberId = loginUser.getMemberId();
+ Long problemId = incorrectNoteRequest.getProblemId();
+ Long userProblemId = incorrectNoteRequest.getUserProblemId();
+ Boolean isUserProblem = incorrectNoteRequest.getIsUserProblem();
+
+ try {
+ Long incorrectNoteId = incorrectNoteService.addIncorrectNote(memberId, problemId, userProblemId, isUserProblem);
+ return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(HttpStatus.CREATED, "오답노트를 성공적으로 생성하였습니다.", incorrectNoteId));
+
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+
+ }
+
+ @DeleteMapping("/{incorrectNoteId}")
+ public ResponseEntity> deleteIncorrectNote(@PathVariable long incorrectNoteId) {
+
+ try {
+ incorrectNoteService.deleteIncorrectNote(incorrectNoteId);
+ return ResponseEntity.ok(ApiResponse.success(HttpStatus.OK, "오답노트가 삭제되었습니다"));
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/JoinController.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/JoinController.java
new file mode 100644
index 0000000..c830a4d
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/JoinController.java
@@ -0,0 +1,28 @@
+package com.codeboy.mvc.controller;
+
+import com.codeboy.mvc.model.dto.request.JoinRequest;
+import com.codeboy.mvc.model.dto.response.ApiResponse;
+import com.codeboy.mvc.model.service.JoinService;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/join")
+@Tag(name="join RESTful API", description = "회원가입 REST API")
+public class JoinController {
+ private final JoinService joinService;
+ @PostMapping
+ public ResponseEntity> adminP(@RequestBody JoinRequest joinRequest) {
+ try {
+ Long memberId = joinService.joinProcess(joinRequest);
+ return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success( HttpStatus.CREATED, "회원가입에 성공했습니다.", memberId));
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/MainController.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/MainController.java
new file mode 100644
index 0000000..ce0a235
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/MainController.java
@@ -0,0 +1,13 @@
+package com.codeboy.mvc.controller;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class MainController {
+
+ @GetMapping("/")
+ public String adminP() {
+ return "admin Controller";
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/MemberController.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/MemberController.java
index 0a18715..11883d8 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/MemberController.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/MemberController.java
@@ -1,32 +1,134 @@
package com.codeboy.mvc.controller;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import com.codeboy.mvc.model.dto.CustomUserDetails;
import com.codeboy.mvc.model.dto.Member;
-
+import com.codeboy.mvc.model.dto.request.DuplicateCheckRequest;
+import com.codeboy.mvc.model.dto.request.LoginRequest;
+import com.codeboy.mvc.model.dto.request.MemberUpdateRequest;
+import com.codeboy.mvc.model.dto.response.ApiResponse;
+import com.codeboy.mvc.model.dto.response.DuplicateCheckResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpSession;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatusCode;
+
+import org.springframework.http.HttpStatus;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import com.codeboy.mvc.model.service.MemberService;
+
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.NoSuchElementException;
@RestController
-@RequestMapping("/api-member")
+@RequestMapping("/api/member")
@Tag(name="Member RESTful API", description = "Member CRUD를 할 수 있는 REST API")
public class MemberController {
-
-// @Autowired
-// private MemberService memberService;
-
-
- @PostMapping("/signup")
- public String signup(@ModelAttribute Member member){
- return "회원가입 성공?";
- }
-
- @GetMapping(){
-
- }
-
-
+ private final MemberService memberService;
+
+ @Autowired
+ public MemberController(MemberService memberService) {
+ this.memberService = memberService;
+ }
+
+ //회원 조회
+ @GetMapping
+ public ResponseEntity> getMemberInfo( @AuthenticationPrincipal CustomUserDetails loginUser) {
+ Long memberId = loginUser.getMemberId();
+ try {
+ Member member = memberService.getMemberById(memberId);
+ return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.success(HttpStatus.OK, "회원정보가 조회되었습니다", member));
+
+ } catch (NoSuchElementException e) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ApiResponse.failure(HttpStatus.NOT_FOUND, e.getMessage()));
+
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+ }
+//특정 회원 조회
+ @GetMapping("/{memberId}")
+ public ResponseEntity> getOneMemberInfo( @PathVariable Long memberId) {
+ try {
+ Member member = memberService.getMemberById(memberId);
+ return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.success(HttpStatus.OK, "회원정보가 조회되었습니다", member));
+
+ } catch (NoSuchElementException e) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ApiResponse.failure(HttpStatus.NOT_FOUND, e.getMessage()));
+
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+ }
+
+ //회원 탈퇴
+ @DeleteMapping
+ public ResponseEntity> deleteMember( @AuthenticationPrincipal CustomUserDetails loginUser) {
+ Long memberId = loginUser.getMemberId();
+ try {
+ memberService.deactivateMember(memberId);
+ return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.success(HttpStatus.OK, "회원이 성공적으로 삭제되었습니다."));
+
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ } catch (NoSuchElementException e) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ApiResponse.failure(HttpStatus.NOT_FOUND, e.getMessage()));
+ }
+ }
+
+ //회원 정보 업데이트
+ @PatchMapping
+ public ResponseEntity> updateMember(@RequestBody MemberUpdateRequest request, @AuthenticationPrincipal CustomUserDetails loginUser) {
+ Long memberId = loginUser.getMemberId();
+ try {
+ memberService.updateMember(memberId, request);
+ return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.success(HttpStatus.OK, "회원정보 업데이트에 성공했습니다."));
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ } catch (IllegalStateException e) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ApiResponse.failure(HttpStatus.NOT_FOUND, e.getMessage()));
+ }
+ }
+
+ //ID, 닉네임, 이메일 중복체크
+ @PostMapping("/check-id")
+ public ResponseEntity> checkId(@RequestBody DuplicateCheckRequest request) {
+ try {
+ boolean duplicated = memberService.checkIdDuplicate(request.getValue());
+ DuplicateCheckResponse response = new DuplicateCheckResponse(duplicated);
+ return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.success(HttpStatus.OK, "아이디 중복 확인 완료", response));
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+ }
+
+ @PostMapping("/check-email")
+ public ResponseEntity> checkEmail(@RequestBody DuplicateCheckRequest request) {
+ try {
+ boolean duplicated = memberService.checkEmailDuplicate(request.getValue());
+ DuplicateCheckResponse response = new DuplicateCheckResponse(duplicated);
+ return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.success(HttpStatus.OK, "이메일 중복 확인 완료", response));
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+ }
+
+ @PostMapping("/check-nickname")
+ public ResponseEntity> checkNickname(@RequestBody DuplicateCheckRequest request) {
+ try {
+ boolean duplicated = memberService.checkNicknameDuplicate(request.getValue());
+ DuplicateCheckResponse response = new DuplicateCheckResponse(duplicated);
+ return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.success(HttpStatus.OK, "닉네임 중복 확인 완료", response));
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+ }
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/ProblemController.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/ProblemController.java
new file mode 100644
index 0000000..4b1268c
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/ProblemController.java
@@ -0,0 +1,37 @@
+
+package com.codeboy.mvc.controller;
+
+import com.codeboy.common.Category;
+import com.codeboy.mvc.model.dto.response.ApiResponse;
+import com.codeboy.mvc.model.dto.Problem;
+import com.codeboy.mvc.model.service.ProblemServiceImpl;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/problem")
+@Tag(name="problem RESTful API", description = "problem을 조회할 수 있게하는 api")
+public class ProblemController {
+
+ @Autowired
+ private ProblemServiceImpl problemService;
+
+ @GetMapping
+// @RequestParam int limit,
+ public ResponseEntity>> getProblems( @RequestParam Category category) {
+ try {
+ List problems = problemService.getProblems(category);
+ return ResponseEntity.status(HttpStatus.OK).body(new ApiResponse<>(HttpStatus.OK, "문제가 성공적으로 반환되었습니다.", problems));
+
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ApiResponse<>(HttpStatus.BAD_REQUEST, e.getMessage(), null));
+ }
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/QuizRoomController.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/QuizRoomController.java
new file mode 100644
index 0000000..b101383
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/QuizRoomController.java
@@ -0,0 +1,123 @@
+package com.codeboy.mvc.controller;
+
+import com.codeboy.mvc.model.dto.*;
+import com.codeboy.mvc.model.dto.request.JoinQuizRoomRequest;
+import com.codeboy.mvc.model.dto.response.ApiResponse;
+import com.codeboy.mvc.model.dto.response.GetQuizRoomMembersResponse;
+import com.codeboy.mvc.model.service.QuizRoomService;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/quiz-room")
+@Tag(name="Quiz-room RESTful API", description = "Quiz-room CRUD를 할 수 있는 REST API")
+public class QuizRoomController {
+ private final QuizRoomService quizRoomService;
+
+ public QuizRoomController(QuizRoomService quizRoomService) {
+ this.quizRoomService = quizRoomService;
+ }
+
+ //호스트 - 퀴즈방 만들기
+ @PostMapping("/create")
+ public ResponseEntity> createQuizRoom(@AuthenticationPrincipal CustomUserDetails loginUser) {
+ try {
+ Long memberId = loginUser.getMemberId();
+ //새로운 채팅방 생성하기
+ Long quizRoomId = quizRoomService.createQuizRoom();
+ //3. QuizRoomMember 객체 생성
+// Long memberId = 1L;
+ QuizRoomMember quizRoomMember = new QuizRoomMember();
+ //4. setter로 객체 만들기
+ quizRoomMember.setMemberId(memberId);
+ quizRoomMember.setRoomId(quizRoomId);
+ quizRoomMember.setIsHost(true);
+
+ //5. 채팅방에 넣기
+ quizRoomService.joinQuizRoom(quizRoomMember);
+ return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(HttpStatus.CREATED, "퀴즈방이 성공적으로 생성되었습니다.", quizRoomId));
+
+ } catch (IllegalStateException | IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+ }
+
+ //채팅방 참여하기
+ @PostMapping("/join/{roomId}")
+ public ResponseEntity> joinQuizRoom(@PathVariable Long roomId, @AuthenticationPrincipal CustomUserDetails loginUser) {
+ Long memberId = loginUser.getMemberId();
+ try {
+ //QuizRoomMember 생성
+ QuizRoomMember quizRoomMember = new QuizRoomMember();
+ quizRoomMember.setIsHost(false);
+ quizRoomMember.setMemberId(memberId);
+ quizRoomMember.setRoomId(roomId);
+
+ //채팅방에 참가
+ quizRoomService.joinQuizRoom(quizRoomMember);
+ return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(HttpStatus.CREATED, "퀴즈방 입장에 성공하였습니다."));
+
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+ }
+
+ //채팅방 목록 보여주기
+ @GetMapping
+ public ResponseEntity>> getQuizRoomList() {
+ try {
+ List quizRooms = quizRoomService.getQuizRoomList();
+ return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.success(HttpStatus.OK, "퀴즈방 목록 조회 성공", quizRooms));
+
+ } catch (IllegalStateException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+ }
+
+
+ //현재 참가자 목록 보여주기
+ @GetMapping("/{roomId}/member")
+ public ResponseEntity>> getQuizRoomMembers(@PathVariable long roomId) {
+ try {
+ List memberList = quizRoomService.getOneQuizRoomMember(roomId);
+ return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.success(HttpStatus.OK, "멤버 리스트를 반환합니다.", memberList));
+ } catch (IllegalStateException | IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+ }
+
+ //채팅방 삭제하기
+ @DeleteMapping("/{roomId}")
+ public ResponseEntity> deleteQuizRoom(@PathVariable long roomId) {
+ try {
+ quizRoomService.deleteQuizRoom(roomId);
+ return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.success(HttpStatus.OK, "채팅방이 성공적으로 삭제되었습니다."));
+
+ } catch (IllegalStateException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+ }
+ //퀴즈방에서 나가기
+ // 퀴즈방에서 나가기
+ @DeleteMapping("/{roomId}/member")
+ public ResponseEntity> leaveQuizRoom(@PathVariable long roomId,
+ @AuthenticationPrincipal CustomUserDetails loginUser) {
+ Long memberId = loginUser.getMemberId();
+ try {
+ quizRoomService.leaveQuizRoom(roomId, memberId);
+ return ResponseEntity
+ .status(HttpStatus.OK)
+ .body(ApiResponse.success(HttpStatus.OK, "퀴즈방에서 성공적으로 나갔습니다."));
+ } catch (IllegalArgumentException | IllegalStateException e) {
+ return ResponseEntity
+ .status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/UserProblemController.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/UserProblemController.java
new file mode 100644
index 0000000..107eb59
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/UserProblemController.java
@@ -0,0 +1,163 @@
+package com.codeboy.mvc.controller;
+
+import com.codeboy.mvc.model.dto.CustomUserDetails;
+import com.codeboy.mvc.model.dto.UserProblem;
+import com.codeboy.mvc.model.dto.response.ApiResponse; // 실제 패키지에 맞게 수정
+import com.codeboy.mvc.model.service.UserProblemService;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpSession;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import javax.crypto.spec.PSource;
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/user-problems")
+@Tag(name="User-problems RESTful API", description = "User-problems CRUD를 할 수 있는 REST API")
+public class UserProblemController {
+
+
+ private final UserProblemService userProblemService;
+
+ public UserProblemController(UserProblemService userProblemService) {
+ this.userProblemService = userProblemService;
+ }
+
+ // 특정 문제세트 안의 모든 문제 조회
+ @GetMapping("/sets/{userProblemSetId}")
+ public ResponseEntity>> getProblemsByUserProblemSetId(
+ @PathVariable Long userProblemSetId
+ ) {
+ try {
+ List problems = userProblemService.getProblemsByUserProblemSetId(userProblemSetId);
+
+ if (problems == null || problems.isEmpty()) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND)
+ .body(ApiResponse.failure(HttpStatus.NOT_FOUND, "해당 문제세트에 등록된 문제가 없습니다."));
+ }
+
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success(HttpStatus.OK, "문제 목록 조회 성공", problems));
+
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류로 문제 목록을 조회하지 못했습니다."));
+ }
+ }
+
+ // user_problem테이블에 문제들 일괄 등록
+ @PostMapping("/sets/{userProblemSetId}")
+ public ResponseEntity> createUserProblems(
+ @PathVariable Long userProblemSetId,
+ @RequestBody List userProblems,
+ @AuthenticationPrincipal CustomUserDetails loginUser
+ ) {
+ System.out.println("문제세트 번호: "+ userProblemSetId);
+ Long memberId= loginUser.getMemberId();
+ if (memberId == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body(ApiResponse.failure(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다."));
+ }
+
+ try {
+ // 세트 ID 세팅
+ for (UserProblem p : userProblems) {
+ p.setUserProblemSetId(userProblemSetId);
+ }
+ System.out.println("디버깅1");
+
+ int inserted = userProblemService.addUserProblems(userProblems);
+ System.out.println("디버깅2");
+
+ if (inserted == 0) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, "문제 등록에 실패했습니다."));
+ }
+
+ return ResponseEntity.status(HttpStatus.CREATED)
+ .body(ApiResponse.success(HttpStatus.CREATED, "문제 등록 성공", null));
+
+ } catch (IllegalArgumentException e) {
+
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ } catch (Exception e) {
+ e.printStackTrace();
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류로 문제를 등록하지 못했습니다."));
+ }
+ }
+
+ // 문제 수정
+ @PutMapping("/{userProblemId}")
+ public ResponseEntity> updateUserProblem(
+ @PathVariable Long userProblemId,
+ @RequestBody UserProblem userProblem,
+ @AuthenticationPrincipal CustomUserDetails loginUser
+ ) {
+ Long memberId= loginUser.getMemberId();
+ if (memberId == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body(ApiResponse.failure(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다."));
+ }
+
+ try {
+ userProblem.setUserProblemId(userProblemId);
+
+ System.out.println("수정요청 받은 문제: " + userProblem);
+ int result = userProblemService.updateUserProblem(userProblem);
+ System.out.println("디버깅1");
+
+ if (result == 0) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND)
+ .body(ApiResponse.failure(HttpStatus.NOT_FOUND, "수정할 문제가 존재하지 않습니다."));
+ }
+
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success(HttpStatus.OK, "문제 수정 성공", null));
+
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류로 문제를 수정하지 못했습니다."));
+ }
+ }
+
+ // 문제 삭제
+ @DeleteMapping("/{userProblemId}")
+ public ResponseEntity> deleteUserProblem(
+ @PathVariable Long userProblemId,
+ @AuthenticationPrincipal CustomUserDetails loginUser
+ ) {
+ Long memberId= loginUser.getMemberId();
+ if (memberId == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body(ApiResponse.failure(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다."));
+ }
+
+ try {
+ int result = userProblemService.deleteUserProblem(userProblemId);
+
+ if (result == 0) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND)
+ .body(ApiResponse.failure(HttpStatus.NOT_FOUND, "삭제할 문제가 존재하지 않습니다."));
+ }
+
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success(HttpStatus.OK, "문제 삭제 성공", null));
+
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류로 문제를 삭제하지 못했습니다."));
+ }
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/UserProblemSetController.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/UserProblemSetController.java
new file mode 100644
index 0000000..b8f3ae5
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/UserProblemSetController.java
@@ -0,0 +1,149 @@
+package com.codeboy.mvc.controller;
+
+import com.codeboy.mvc.model.dto.CustomUserDetails;
+import com.codeboy.mvc.model.dto.UserProblemSet;
+import com.codeboy.mvc.model.dto.request.ProblemSetRequest;
+import com.codeboy.mvc.model.dto.response.ApiResponse; // 실제 패키지에 맞게 수정
+import com.codeboy.mvc.model.service.UserProblemSetService;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/user-problem-sets")
+@Tag(name="User-problems-sets RESTful API", description = "User-problems-sets CRUD를 할 수 있는 REST API")
+public class UserProblemSetController {
+
+
+ private final UserProblemSetService userProblemSetService;
+
+ public UserProblemSetController(UserProblemSetService userProblemSetService) {
+ this.userProblemSetService = userProblemSetService;
+ }
+
+ // 모든 문제 세트 조회
+ @GetMapping
+ public ResponseEntity>> getAllUserProblemSets() {
+ try {
+ List sets = userProblemSetService.getAllUserProblemSets();
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success(HttpStatus.OK, "유저 문제세트 전체 조회 성공", sets));
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류로 문제세트를 조회하지 못했습니다."));
+ }
+ }
+
+ // 마이페이지 - 내가 만든 문제세트 조회
+ @GetMapping("/me")
+ public ResponseEntity>> getMyUserProblemSet( @AuthenticationPrincipal CustomUserDetails loginUser) {
+ Long memberId = loginUser.getMemberId();
+ System.out.println(memberId);
+ if (memberId == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body(ApiResponse.failure(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다."));
+ }
+
+ try {
+ List set = userProblemSetService.getUserProblemSetByMemberId(memberId);
+
+ if (set == null) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND)
+ .body(ApiResponse.failure(HttpStatus.NOT_FOUND, "등록된 유저 문제세트가 없습니다."));
+ }
+
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success(HttpStatus.OK, "나의 유저 문제세트 조회 성공", set));
+
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류로 나의 문제세트를 조회하지 못했습니다."));
+ }
+ }
+
+ // 마이페이지 - 문제세트 생성
+ @PostMapping
+ public ResponseEntity> createMyUserProblemSet(@RequestBody ProblemSetRequest problemSetRequest , @AuthenticationPrincipal CustomUserDetails loginUser) {
+ Long memberId = loginUser.getMemberId();
+ if (memberId == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body(ApiResponse.failure(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다."));
+ }
+
+ try {
+ //문제 세트가 생성되기전에는 PK가 존재하질 않아서
+ //문제세트를 등록함과 동시에 이 PK값을 UserProblemController에도 넘겨줘야함.
+ //따라서 UserProblemSet 객체를 생성하여 memberId를 세팅해서 넘겨줌,
+ //프론트에서 이를 받아서 다시 문제 하나하나를 user_problem테이블에 저장 할 때 이 userProblemSetId를 같이 넘겨줘야함.
+ //이 부분은 프론트와 백엔드간의 협의가 필요.
+ //UserProblemSetMapper에도 generateKey를 추가해서 PK값을 set에 담을 수 있었다.
+ UserProblemSet set = new UserProblemSet();
+ set.setMemberId(memberId);
+ set.setCategory(problemSetRequest.getCategory());
+ set.setCreatedAt(problemSetRequest.getCreatedAt());
+ set.setProblemSetTitle(problemSetRequest.getProblemSetTitle());
+
+
+ int result = userProblemSetService.createUserProblemSet(set);
+ Long userProblemSetId = set.getUserProblemSetId();
+
+ if (result == 0) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, "유저 문제세트 생성에 실패했습니다."));
+ }
+
+ return ResponseEntity.status(HttpStatus.CREATED)
+ .body(ApiResponse.success(HttpStatus.CREATED, "유저 문제세트 생성 성공", userProblemSetId));
+
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류로 문제세트를 생성하지 못했습니다."));
+ }
+ }
+
+ // 마이페이지 - 문제세트 삭제
+ @DeleteMapping("/{userProblemSetId}")
+ public ResponseEntity> deleteUserProblemSet(
+ @PathVariable Long userProblemSetId,
+ @AuthenticationPrincipal CustomUserDetails loginUser
+ ) {
+ Long memberId= loginUser.getMemberId();
+ if (memberId == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body(ApiResponse.failure(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다."));
+ }
+
+ System.out.println("삭제할 문제 세트 id: "+ userProblemSetId);
+ // TODO: userProblemSetId가 memberId가 만든 세트인지 owner 체크 로직을 Service/Dao에 추가하면 더 안전함
+
+ try {
+ int result = userProblemSetService.deleteUserProblemSet(userProblemSetId);
+
+ if (result == 0) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND)
+ .body(ApiResponse.failure(HttpStatus.NOT_FOUND, "삭제할 유저 문제세트가 존재하지 않습니다."));
+ }
+
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success(HttpStatus.OK, "유저 문제세트 삭제 성공", null));
+
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류로 문제세트를 삭제하지 못했습니다."));
+ }
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/UserScoreController.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/UserScoreController.java
new file mode 100644
index 0000000..78cb89f
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/controller/UserScoreController.java
@@ -0,0 +1,160 @@
+package com.codeboy.mvc.controller;
+
+import java.util.List;
+
+import com.codeboy.mvc.model.dto.CustomUserDetails;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import com.codeboy.mvc.model.dto.UserScore;
+import com.codeboy.mvc.model.service.UserScoreService;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+import com.codeboy.mvc.model.dto.response.ApiResponse;
+
+import jakarta.servlet.http.HttpSession;
+
+@RestController
+@RequestMapping("api/scores")
+@Tag(name="User-score RESTful API", description = "User-score를 CRUD를 할 수 있게하는 api")
+public class UserScoreController {
+
+ private final UserScoreService userScoreService;
+
+ public UserScoreController(UserScoreService userScoreService) {
+ this.userScoreService = userScoreService;
+ }
+
+ // 점수 등록
+ @PostMapping
+ public ResponseEntity> createUserScore(
+ @RequestBody UserScore userScore,
+ @AuthenticationPrincipal CustomUserDetails loginUser
+ ) {
+ Long memberId = loginUser.getMemberId();
+ if (memberId == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body(ApiResponse.failure(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다."));
+ }
+
+ // 세션의 memberId를 강제로 DTO에 세팅 (신뢰할 수 있는 값)
+ userScore.setMemberId(memberId);
+
+ try {
+ int result = userScoreService.registerScore(userScore);
+
+ if (result == 0) {
+ // SQL은 정상 실행되었지만, 반영된 row가 없음
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, "SQL이 실행됐으나 row가 반영되지 않았습니다."));
+ }
+
+ return ResponseEntity.status(HttpStatus.CREATED)
+ .body(ApiResponse.success(HttpStatus.CREATED, "점수 등록 성공", null));
+
+ } catch (IllegalArgumentException e) {
+ // 파라미터/입력 문제
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+
+ } catch (Exception e) {
+ // 예기치 못한 DB 오류 / 서버 오류
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류로 점수를 등록하지 못했습니다."));
+ }
+ }
+
+ // 전체 유저 점수 조회
+ @GetMapping
+ public ResponseEntity>> getAllUserScores( @AuthenticationPrincipal CustomUserDetails loginUser) {
+ Long memberId = loginUser.getMemberId();
+ if (memberId == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body(ApiResponse.failure(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다."));
+ }
+
+ try {
+ List scores = userScoreService.getAllUserScores();
+
+ if (scores == null || scores.isEmpty()) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND)
+ .body(ApiResponse.failure(HttpStatus.NOT_FOUND, "점수 목록이 비어있습니다. UserScore테이블을 확인해주세요."));
+ }
+
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success(HttpStatus.OK, "점수 목록 조회 성공", scores));
+
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류로 점수 목록을 조회하지 못했습니다."));
+ }
+ }
+
+ // 특정 유저 점수 조회
+ @GetMapping("/member")
+ public ResponseEntity> getUserScore(
+ @AuthenticationPrincipal CustomUserDetails loginUser
+ ) {
+ Long memberId = loginUser.getMemberId();
+
+ try {
+ UserScore userScore = userScoreService.getUserScoreById(memberId);
+
+ if (userScore == null) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND)
+ .body(ApiResponse.failure(HttpStatus.NOT_FOUND, "해당 회원의 점수가 존재하지 않습니다."));
+ }
+
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success(HttpStatus.OK, "점수 조회 성공", userScore));
+
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류로 점수를 조회하지 못했습니다."));
+ }
+ }
+
+ // 점수 수정 HttpSession에서 memberId를 가져와 이 사람의 점수를 갱신하는거라 PathVariable이나 @RequestBody가 없다.
+ @PutMapping
+ public ResponseEntity> updateUserScore(
+ @RequestBody UserScore userScore,
+ @AuthenticationPrincipal CustomUserDetails loginUser
+ ) {
+ Long memberId = loginUser.getMemberId();
+ if (memberId == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body(ApiResponse.failure(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다."));
+ }
+
+ // 세션 기준으로 memberId 강제 세팅
+ userScore.setMemberId(memberId);
+
+ try {
+ int result = userScoreService.updateUser(userScore);
+
+ if (result == 0) {
+ // 수정할 row가 없거나, 업데이트 실패
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, "점수 수정에 실패했습니다."));
+ }
+
+ return ResponseEntity.status(HttpStatus.OK)
+ .body(ApiResponse.success(HttpStatus.OK, "점수 수정 성공", null));
+
+ } catch (IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(ApiResponse.failure(HttpStatus.BAD_REQUEST, e.getMessage()));
+
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(ApiResponse.failure(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류로 점수를 수정하지 못했습니다."));
+ }
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/jwt/JWTFilter.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/jwt/JWTFilter.java
new file mode 100644
index 0000000..ba60793
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/jwt/JWTFilter.java
@@ -0,0 +1,97 @@
+package com.codeboy.mvc.jwt;
+
+import com.codeboy.mvc.model.service.CustomerUserDetailService;
+import io.jsonwebtoken.ExpiredJwtException;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+import java.util.List;
+
+@RequiredArgsConstructor
+public class JWTFilter extends OncePerRequestFilter {
+
+ private final JWTUtil jwtUtil;
+ private final CustomerUserDetailService userDetailService;
+
+ // ❗ 실제 사용하는 URL에 맞게 수정해야 함
+ private static final List EXCLUDED_URLS = List.of(
+ "/login",// 스프링 시큐리티 로그인 엔드포인트
+ "/api/join",
+ "/member/login", // 커스텀 로그인 엔드포인트가 있다면
+ "/auth/login",
+ "/auth/signup",
+ "/member/join"
+ );
+
+ private boolean isExcluded(HttpServletRequest request) {
+ String path = request.getRequestURI();
+ return EXCLUDED_URLS.stream().anyMatch(path::startsWith);
+ }
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request,
+ HttpServletResponse response,
+ FilterChain filterChain)
+ throws ServletException, IOException {
+
+ // 0. 로그인/회원가입 등 공개 URL이면 토큰 검사 없이 그냥 패스
+ if (isExcluded(request)) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ // 1. Authorization 헤더 가져오기
+ String authorization = request.getHeader("Authorization");
+
+ // 2. 토큰이 없거나 Bearer 형식이 아니면 → 그냥 다음 필터로
+ if (authorization == null || !authorization.startsWith("Bearer ")) {
+ System.out.println("JWTFilter: 토큰 없음, 다음 필터로 패스");
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ // 3. "Bearer xxxxxx" 에서 실제 토큰 부분만 분리
+ String token = authorization.substring(7); // "Bearer " 길이 = 7
+
+ try {
+ // 4. 토큰 만료 여부 체크 (이 과정에서 ExpiredJwtException이 날 수 있음)
+ if (jwtUtil.isExpired(token)) {
+ throw new ExpiredJwtException(null, null, "Token expired");
+ }
+
+ // 5. 여기까지 왔으면 만료 안 된 토큰이므로 username 파싱
+ String username = jwtUtil.getUsername(token);
+
+ // 6. UserDetails 조회
+ UserDetails userDetails = userDetailService.loadUserByUsername(username);
+
+ // 7. Authentication 객체 생성해서 SecurityContext에 넣기
+ Authentication authToken = new UsernamePasswordAuthenticationToken(
+ userDetails,
+ null,
+ userDetails.getAuthorities()
+ );
+ SecurityContextHolder.getContext().setAuthentication(authToken);
+
+ // 8. 다음 필터 진행
+ filterChain.doFilter(request, response);
+
+ } catch (ExpiredJwtException e) {
+ // 9. 만료된 토큰일 때 401로 응답
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ response.setContentType("application/json;charset=UTF-8");
+ response.getWriter().write("""
+ {"code": "TOKEN_EXPIRED", "message": "토큰이 만료되었습니다. 다시 로그인 해주세요."}
+ """);
+ }
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/jwt/JWTUtil.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/jwt/JWTUtil.java
new file mode 100644
index 0000000..26d5e70
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/jwt/JWTUtil.java
@@ -0,0 +1,68 @@
+package com.codeboy.mvc.jwt;
+
+import io.jsonwebtoken.Jwts;
+import jakarta.annotation.PostConstruct;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+
+@Component
+public class JWTUtil {
+
+ private final SecretKey secretKey; // JWT 서명용 시크릿 키
+
+ // application.yml / properties 에 정의된 값 주입
+ // 예: spring.jwt.secret-key: my-jwt-secret-key...
+ public JWTUtil(@Value("${spring.jwt.secret-key}") String secret) {
+ this.secretKey = new SecretKeySpec(
+ secret.getBytes(StandardCharsets.UTF_8),
+ Jwts.SIG.HS256.key().build().getAlgorithm()
+ );
+ }
+
+
+ public String getUsername(String token) {
+ return Jwts.parser()
+ .verifyWith(secretKey)
+ .build()
+ .parseSignedClaims(token)
+ .getPayload()
+ .get("username", String.class);
+ }
+
+ public String getRole(String token) {
+ return Jwts.parser()
+ .verifyWith(secretKey)
+ .build()
+ .parseSignedClaims(token)
+ .getPayload()
+ .get("role", String.class);
+ }
+
+ public boolean isExpired(String token) {
+ Date expiration = Jwts.parser()
+ .verifyWith(secretKey)
+ .build()
+ .parseSignedClaims(token)
+ .getPayload()
+ .getExpiration();
+
+ return expiration.before(new Date());
+ }
+
+ public String createJwt(String username, String role, Long expiredMs) {
+ long now = System.currentTimeMillis();
+
+ return Jwts.builder()
+ .claim("username", username)
+ .claim("role", role)
+ .issuedAt(new Date(now))
+ .expiration(new Date(now + expiredMs))
+ .signWith(secretKey)
+ .compact();
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/jwt/LoginFilter.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/jwt/LoginFilter.java
new file mode 100644
index 0000000..fb40c5a
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/jwt/LoginFilter.java
@@ -0,0 +1,126 @@
+package com.codeboy.mvc.jwt;
+
+import com.codeboy.mvc.model.dto.CustomUserDetails;
+import com.codeboy.mvc.model.dto.request.LoginRequest;
+import com.codeboy.mvc.model.dto.response.ApiResponse;
+import com.codeboy.mvc.model.dto.response.LoginResponse;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+import java.io.IOException;
+
+@RequiredArgsConstructor
+public class LoginFilter extends UsernamePasswordAuthenticationFilter {
+
+ private final AuthenticationManager authenticationManager;
+ private final JWTUtil jwtUtil;
+ private final com.fasterxml.jackson.databind.ObjectMapper objectMapper; // ✅ 추가
+
+ {
+ // 인스턴스 초기화 블록 or 생성자에서 설정
+ setFilterProcessesUrl("/login"); // ✅ 이 URL로 오는 요청을 로그인으로 처리
+ }
+
+ /**
+ * 로그인 시도 시 호출되는 메서드
+ */
+ @Override
+ public Authentication attemptAuthentication(HttpServletRequest request,
+ HttpServletResponse response)
+ throws AuthenticationException {
+
+ LoginRequest loginRequest =
+ null;
+ try {
+ loginRequest = objectMapper.readValue(request.getInputStream(), LoginRequest.class);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ String username = loginRequest.getId();
+ String password = loginRequest.getPassword();
+
+ if (username == null) {
+ username = request.getParameter("username");
+ }
+ if (password == null) {
+ password = request.getParameter("password");
+ }
+
+
+
+ UsernamePasswordAuthenticationToken authRequest =
+ new UsernamePasswordAuthenticationToken(username, password);
+
+ return authenticationManager.authenticate(authRequest);
+ }
+
+ /**
+ * 로그인 성공 시 호출되는 메서드
+ * (JWT 발급 같은 작업을 여기서 하면 됨)
+ */
+ @Override
+ protected void successfulAuthentication(HttpServletRequest request,
+ HttpServletResponse response,
+ FilterChain chain,
+ Authentication authResult)
+ throws IOException, ServletException {
+
+ System.out.println("login success: " + authResult.getName());
+
+ // 1) 인증된 사용자 정보
+ CustomUserDetails principal = (CustomUserDetails) authResult.getPrincipal();
+ String username = principal.getUsername();
+ String role = principal.getAuthorities().iterator().next().getAuthority();
+
+ // 2) JWT 생성
+ String accessToken = jwtUtil.createJwt(username, role, 60 * 60 * 1000L);
+ String refreshToken = jwtUtil.createJwt(username, role, 7 * 24 * 60 * 60 * 1000L);
+
+
+ // 3) LoginResponse 생성
+ LoginResponse loginResponse = new LoginResponse(
+ accessToken,
+ refreshToken,
+ principal.getMemberId()
+ );
+
+ // 4) ApiResponse 생성
+ ApiResponse apiResponse =
+ ApiResponse.success(HttpStatus.OK, "로그인 성공", loginResponse);
+
+ // 5) JSON으로 내려주기
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setContentType("application/json;charset=UTF-8");
+ objectMapper.writeValue(response.getWriter(), apiResponse);
+ }
+
+
+ /**
+ * 로그인 실패 시 호출되는 메서드
+ */
+ @Override
+ protected void unsuccessfulAuthentication(HttpServletRequest request,
+ HttpServletResponse response,
+ AuthenticationException failed)
+ throws IOException, ServletException {
+
+ System.out.println("login fail: " + failed.getMessage());
+
+ ApiResponse apiResponse =
+ ApiResponse.failure(HttpStatus.UNAUTHORIZED, failed.getMessage()); // or failed.getMessage()
+
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ response.setContentType("application/json;charset=UTF-8");
+ objectMapper.writeValue(response.getWriter(), apiResponse);
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/CommentDao.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/CommentDao.java
index df05e7e..1f75116 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/CommentDao.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/CommentDao.java
@@ -2,14 +2,24 @@
import java.util.List;
+import org.apache.ibatis.annotations.Mapper;
+
import com.codeboy.mvc.model.dto.Comment;
+@Mapper
public interface CommentDao {
- public List selectAllByProblemId(long problemId);
-
- public void insertComment(Comment comment);
+ public List selectCommentsByuserProblemSetId(Long userProblemSetId);
+
+ //유저문제세트 id에다가 댓글을 달아야하므로 long userProblemSetId으로 지정
+ public int insertComment(Long userProblemSetId, Comment comment);
- public void updateComment(Comment comment);
+ //조회된 댓글의 id를 가져와서 수정하고 삭제함.
+ public int updateComment(Long commentId, Comment comment);
+
+ //조회된 댓글의 id를 가져와서 수정하고 삭제함.
+ public int deleteComment(Long commentId);
+
+ //댓글아이디로 댓글 작성자의 아이디를 가져옴
+ public Long selectCommentOwnerId(Long commentId);
- public void deleteComment(long commentId);
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/IncorrectNoteDao.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/IncorrectNoteDao.java
index 5a617b2..2782bb9 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/IncorrectNoteDao.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/IncorrectNoteDao.java
@@ -1,17 +1,32 @@
package com.codeboy.mvc.model.dao;
import java.util.List;
+import java.util.Map;
-import com.codeboy.mvc.model.dto.Problem;
+import com.codeboy.mvc.model.dto.response.IncorrectNoteResponse;
+import org.apache.ibatis.annotations.Mapper;
+@Mapper
public interface IncorrectNoteDao {
//유저의 아이디로 유저가 틀린 문제들의 모음을 조회
- public List selectIncorrectProblems(long memberId);
+ //sql의 관점에서
+ //
+ public List selectIncorrectProblems(Long memberId);
//유저가 자신의 오답노트 안에서 문제를 삭제
- public void deleteIncorrectProblem(long memberId, long problemId);
-
+ public int deleteIncorrectProblem(Long incorrectNoteId);
+
//오답노트에 문제 추가
- public void insertIncorrectProblem(long memberId, long problemId);
+ public void insertIncorrectProblem(Map params);
+
+ //문제 존재 여부 체크
+ boolean existsProblemById(Long problemId);
+
+ //유저 문제 존재 여부 체크
+ boolean existsUserProblemById(Long userProblemId);
+
+ //incorrectNoteId 존재 여부 체크
+ boolean existsIncorrectNoteById(Long incorrectNoteId);
+
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/MemberDao.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/MemberDao.java
index 6615b7c..464a799 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/MemberDao.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/MemberDao.java
@@ -1,18 +1,43 @@
package com.codeboy.mvc.model.dao;
import com.codeboy.mvc.model.dto.Member;
-import com.codeboy.mvc.model.dto.MemberUpdateRequest;
-
+import com.codeboy.mvc.model.dto.request.MemberUpdateRequest;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+@Mapper
public interface MemberDao {
- public void insertMember(Member member);
-
- public Member selectMember(String id, String password);
-
- //멤버 삭제 -> db에서는 status 변경
- public void delete(int memberId);
-
+ int insertMember(Member member);
+
+ Member selectMemberById(Long memberId);
+
+ //멤버 삭제 -> db에서는 status 변경
+ int deactivateMemberById(Long memberId);
+
//멤버 업데이트 -> db에서는 patch(nickname, email, id)
- public void updateMember(long memberId, MemberUpdateRequest memberUpdateRequest);
-
+ int updateMemberById(@Param("memberId") Long memberId, @Param("update") MemberUpdateRequest memberUpdateRequest);
+
+ //아이디 중복 체크
+ Boolean existsId(String id);
+
+ //닉네임 중복 체크
+ Boolean existsNickname(String nickname);
+
+ //이메일 중복 체크
+ Boolean existsEmail(String email);
+
+ //멤버가 활성화 상태인지 확인
+ Boolean isMemberActive(Long memberId);
+
+ // 회원 비활성화(탈퇴) - status, isDeleted 업데이트
+ int deleteMember(long memberId);
+ // 로그인 - ID와 password로 회원 조회
+ Member selectMemberByIdAndPassword(@Param("id") String id, @Param("password") String password);
+
+ //spring security
+ boolean existByUserId(String id);
+
+ Member findByUserId(String id);
+
+ String currentDatabase(); // 🔥 추가
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/ProblemDao.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/ProblemDao.java
index d98bc01..fe372e7 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/ProblemDao.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/ProblemDao.java
@@ -4,9 +4,12 @@
import com.codeboy.common.Category;
import com.codeboy.mvc.model.dto.Problem;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+@Mapper
public interface ProblemDao {
//문제 조회
- public List selectProblem(Category category);
-
+// @Param("limit") int limit
+ public List selectProblem( @Param("category") Category category);
}
\ No newline at end of file
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/QuizRoomDao.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/QuizRoomDao.java
index 67a7ce4..db92ead 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/QuizRoomDao.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/QuizRoomDao.java
@@ -4,28 +4,42 @@
import com.codeboy.mvc.model.dto.QuizRoom;
import com.codeboy.mvc.model.dto.QuizRoomMember;
+import com.codeboy.mvc.model.dto.response.GetQuizRoomMembersResponse;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+@Mapper
public interface QuizRoomDao {
-
//quiz_room 테이블. 퀴즈룸 생성. 생성된 퀴즈룸 id 반환
- public int insertQuizRoom();
-
- //quiz_room_member 테이블에 값 넣기 (퀴즈방 입장) - 참가자/호스트
- public void insertMemberToQuizRoom(QuizRoomMember quizRoomMember);
+ public void insertQuizRoom(QuizRoom room);
-
+ //quiz_room_member 테이블에 값 넣기 (퀴즈방 입장) - 참가자/호스트
+ public int insertMemberToQuizRoom(QuizRoomMember quizRoomMember);
//모든 퀴즈룸 조회하기
public List selectAllQuizRoom();
-
-
//하나의 퀴즈룸 조회(참가 멤버확인)
- public List selectOneQuizRoom(int roomId);
-
+ public List selectOneQuizRoom(Long roomId);
+
//퀴즈룸 수정
-
-
//퀴즈룸 삭제
- public void deleteQuizRoom(long roomId);
+ //TODO : 지금은 멤버가 전체 퀴즈방 테이블에 중복으로 들어가면 에러 터짐
+ //TODO : 채팅방이 끝나면 바로 삭제하는 로직 만들어야 함.
+
+ public boolean deleteQuizRoom(Long roomId);
+
+ //퀴즈룸 존재하는지 확인
+ public int existsQuizRoom(Long roomId);
+
+ //퀴즈룸에 특정 멤버가 있는지 확인
+ public int isDuplicatedMember(Long memberId);
+
+ QuizRoomMember selectQuizRoomMember(@Param("roomId") long roomId,
+ @Param("memberId") long memberId);
+ /**
+ * 퀴즈방 멤버 테이블에서 특정 멤버를 삭제 (퇴장)
+ */
+ int deleteQuizRoomMember(@Param("roomId") long roomId,
+ @Param("memberId") long memberId);
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/ScoreDao.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/ScoreDao.java
deleted file mode 100644
index 40a981a..0000000
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/ScoreDao.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.codeboy.mvc.model.dao;
-
-import java.util.List;
-
-import com.codeboy.mvc.model.dto.UserScore;
-
-public interface ScoreDao {
- //스코어 등록
- public void insertScore(UserScore userScore);
-
- //모든 스코어 조회
- public List selectAllUserScore();
-
- //한 멤버의 스코어 조회
- public int selectOneUserScore(int memberId);
-
- //멤버 스코어 업데이트
- public void updateUserScore(UserScore userScore);
-
-
-}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/UserIncorrectNoteDao.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/UserIncorrectNoteDao.java
deleted file mode 100644
index 537c5e1..0000000
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/UserIncorrectNoteDao.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.codeboy.mvc.model.dao;
-
-import java.util.List;
-
-import com.codeboy.mvc.model.dto.Problem;
-import com.codeboy.mvc.model.dto.UserProblem;
-
-public interface UserIncorrectNoteDao {
-
- //유저의 아이디로 유저가 틀린 문제들의 모음을 조회
- public List selectUserIncorrectProblems(long memberId);
-
- //유저가 자신의 오답노트 안에서 문제를 삭제
- public void deleteUserIncorrectProblem(long memberId, long userProblemId);
-
- //(중간자 테이블)오답노트에 문제 추가
- public void insertUserIncorrectProblem(long memberId, long userProblemId);
-}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/UserProblemDao.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/UserProblemDao.java
index b2ad1ff..61f7b11 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/UserProblemDao.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/UserProblemDao.java
@@ -3,23 +3,22 @@
import java.util.List;
import com.codeboy.common.Category;
-import com.codeboy.mvc.model.dto.Problem;
import com.codeboy.mvc.model.dto.UserProblem;
public interface UserProblemDao extends ProblemDao{
-
- //문제세트 조회
- public List selectUserProblem(Category category);
- //문제 생성하기
- public void insertUserProblem(UserProblem userProblem);
-
- //문제 세트 만들기
- public void insertUserProblemSet(List userProblemList);
-
- //문제 수정
- public void updateUserProblem(UserProblem userProblem);
-
- //문제 삭제
- public int deleteUserProblem(int id);
+
+ //유저제작 문제풀이 페이지에서 문제세트를 선택했을때, 그 문제세트에 속한문제들 조회
+ List selectProblemsByUserProblemSetId(Long userProblemSetId);
+
+ //문제 생성 시 문제세트를 등록함과 동시에 문제들을 전부 user_problem 테이블에 넣기
+ int insertUserProblemList(List userProblems);
+
+ //제작자 본인이 자신의 문제들을 수정하는 로직
+ int updateUserProblem(UserProblem userProblem);
+
+ //제작자 본인이 자신의 문제를 삭제하는 로직
+ int deleteUserProblemById(Long userProblemId);
+
+
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/UserProblemSetDao.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/UserProblemSetDao.java
new file mode 100644
index 0000000..1a0ffe6
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/UserProblemSetDao.java
@@ -0,0 +1,25 @@
+package com.codeboy.mvc.model.dao;
+
+import com.codeboy.mvc.model.dto.Problem;
+import com.codeboy.mvc.model.dto.UserProblem;
+import com.codeboy.mvc.model.dto.UserProblemSet;
+
+import java.util.List;
+
+public interface UserProblemSetDao {
+ //다른 사용자들이 만든 유저제작 문제세트들을 모두 조회
+ List selectUserProblemSets();
+
+
+ //마이페이지에서 자신이 제작한 문제세트 조회
+ List selectUserProblemSetByMemberId(long memberId);
+
+ //문제 세트 등록 memberId = 문제 제작자만 넘겨주고 문제들은 problemDao에서 insertUserProblem으로 넣음 (마이페이지에서 생성)
+ int insertUserProblemSet(UserProblemSet userProblemSet);
+
+ // 문제세트 삭제 (마이페이지에서 삭제)
+ int deleteUserProblemSetById(Long userProblemSetId);
+
+
+
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/UserScoreDao.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/UserScoreDao.java
new file mode 100644
index 0000000..4f67e0b
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dao/UserScoreDao.java
@@ -0,0 +1,21 @@
+package com.codeboy.mvc.model.dao;
+
+import java.util.List;
+
+import com.codeboy.mvc.model.dto.UserScore;
+
+public interface UserScoreDao {
+ //스코어 등록
+ public int insertScore(UserScore userScore);
+
+ //모든 스코어 조회
+ public List selectAllUserScores();
+
+ //한 멤버의 스코어 조회
+ public UserScore selectOneUserScore(Long memberId);
+
+ //멤버 스코어 업데이트
+ public int updateUserScore(UserScore userScore);
+
+
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/AIProblemDto.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/AIProblemDto.java
new file mode 100644
index 0000000..630a143
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/AIProblemDto.java
@@ -0,0 +1,15 @@
+package com.codeboy.mvc.model.dto;
+
+import java.util.List;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class AIProblemDto {
+
+ private String problemDescription; // 문제 본문
+ private List choices; // 보기 4개
+ private int answer; // 정답 인덱스 (0~3)
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/Comment.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/Comment.java
index 032ad95..bf7599c 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/Comment.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/Comment.java
@@ -13,7 +13,8 @@
@NoArgsConstructor
@Getter
@Setter
-public class Comment {
+public class
+Comment {
private long commentId;
private long memberId;
private String content;
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/CustomUserDetails.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/CustomUserDetails.java
new file mode 100644
index 0000000..a353a8b
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/CustomUserDetails.java
@@ -0,0 +1,66 @@
+package com.codeboy.mvc.model.dto;
+
+import io.micrometer.observation.annotation.Observed;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class CustomUserDetails implements UserDetails {
+ private final Member member;
+
+ public CustomUserDetails(Member member) {
+ this.member = member;
+ }
+
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ Collection collection = new ArrayList<>();
+
+ collection.add(new GrantedAuthority() {
+ @Override
+ public String getAuthority() {
+ return member.getRole();
+ }
+ });
+ return collection;
+ }
+ public String getNickname() {
+ return member.getNickname();
+ }
+
+
+ public Long getMemberId() {
+ return member.getMemberId(); // member 엔티티에 memberId 필드 있다고 가정
+ }
+
+ @Override
+ public String getPassword() {
+ return member.getPassword();
+ }
+
+ @Override
+ public String getUsername() {
+ return member.getId();
+ }
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/IncorrectNote.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/IncorrectNote.java
index f5d7ed0..288ba54 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/IncorrectNote.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/IncorrectNote.java
@@ -15,4 +15,7 @@ public class IncorrectNote {
private long incorrectNoteId;
private long memberId;
private long problemId;
+ private long userProblemId;
+ private Boolean isUserProblem;
+
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/Member.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/Member.java
index f657755..d87bfac 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/Member.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/Member.java
@@ -1,7 +1,9 @@
package com.codeboy.mvc.model.dto;
import java.sql.Timestamp;
+
import com.codeboy.common.Status;
+
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -20,7 +22,10 @@ public class Member {
private String nickname;
private String email;
private Timestamp signupDate;
- private Status status;
+ private Boolean isActive;
private Timestamp deletedDate;
+ private String role;
+
+
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/MemberUpdateRequest.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/MemberUpdateRequest.java
deleted file mode 100644
index eb94e12..0000000
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/MemberUpdateRequest.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.codeboy.mvc.model.dto;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-
-@AllArgsConstructor
-@NoArgsConstructor
-@Getter
-@Setter
-@Schema(description="유저 정보 수정 DTO")
-public class MemberUpdateRequest {
- private String nickName;
- private String id;
- private String email;
-}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/Problem.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/Problem.java
index e93caa9..605793f 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/Problem.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/Problem.java
@@ -20,7 +20,7 @@ public class Problem {
private String choice2;
private String choice3;
private String choice4;
- private String answer;
+ private int answerChoice;
private Category category;
-
+
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/QuizRoom.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/QuizRoom.java
index 059c4aa..01ca516 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/QuizRoom.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/QuizRoom.java
@@ -13,4 +13,6 @@
@Schema(description="퀴즈방 DTO")
public class QuizRoom {
private long roomId;
+
+
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/QuizRoomMember.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/QuizRoomMember.java
index d6cdd6e..8079a50 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/QuizRoomMember.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/QuizRoomMember.java
@@ -12,8 +12,34 @@
@Setter
@Schema(description="회원 퀴즈방 중간 DTO")
public class QuizRoomMember {
- private long quizRoomMemberId;
- private long memberId;
- private long roomId;
+ private Long quizRoomMemberId;
+ private Long memberId;
+ private Long roomId;
private Boolean isHost;
+ public Long getQuizRoomMemberId() {
+ return quizRoomMemberId;
+ }
+ public void setQuizRoomMemberId(long quizRoomMemberId) {
+ this.quizRoomMemberId = quizRoomMemberId;
+ }
+ public Long getMemberId() {
+ return memberId;
+ }
+ public void setMemberId(long memberId) {
+ this.memberId = memberId;
+ }
+ public Long getRoomId() {
+ return roomId;
+ }
+ public void setRoomId(long roomId) {
+ this.roomId = roomId;
+ }
+ public Boolean getIsHost() {
+ return isHost;
+ }
+ public void setIsHost(Boolean isHost) {
+ this.isHost = isHost;
+ }
+
+
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/UserProblem.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/UserProblem.java
index fa4f9b3..1a93309 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/UserProblem.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/UserProblem.java
@@ -14,14 +14,12 @@
@Getter
@Setter
public class UserProblem {
- private long userProblemId;
+ private Long userProblemId;
private String problemDescription;
- private Category category;
private String choice1;
private String choice2;
private String choice3;
private String choice4;
- private String answer;
- private int commentCount;
- private long userProblemSetId;
+ private int answerChoice;
+ private Long userProblemSetId;
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/UserProblemSet.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/UserProblemSet.java
index d460eb4..03f4931 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/UserProblemSet.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/UserProblemSet.java
@@ -1,17 +1,26 @@
package com.codeboy.mvc.model.dto;
+import com.codeboy.common.Category;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
+import lombok.ToString;
+
+import java.sql.Timestamp;
@Schema(description = "유저제작문제세트 DTO")
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
+@ToString
public class UserProblemSet {
- private long userProblemSetId;
- private long memberId;
+ private Long userProblemSetId;
+ private String problemSetTitle;
+ private Timestamp createdAt;
+ private Long memberId;
+ private Category category;
+ private int commentCount;
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/UserScore.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/UserScore.java
index e65a711..6a323ad 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/UserScore.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/UserScore.java
@@ -15,6 +15,4 @@
public class UserScore {
private long memberId;
private int score;
-
-
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/AIProblemRequest.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/AIProblemRequest.java
new file mode 100644
index 0000000..9c69b63
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/AIProblemRequest.java
@@ -0,0 +1,10 @@
+package com.codeboy.mvc.model.dto.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class AIProblemRequest {
+ private String category; // 정보처리기사 or SQLD
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/CommentUpdateRequest.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/CommentUpdateRequest.java
new file mode 100644
index 0000000..5614319
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/CommentUpdateRequest.java
@@ -0,0 +1,17 @@
+package com.codeboy.mvc.model.dto.request;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+public class CommentUpdateRequest {
+ //댓글을 업데이트할 때 content만 수정하니 수정할 content만 전달하는 DTO
+ private String content;
+ private long memberId;
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/DuplicateCheckRequest.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/DuplicateCheckRequest.java
new file mode 100644
index 0000000..8a366f4
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/DuplicateCheckRequest.java
@@ -0,0 +1,14 @@
+package com.codeboy.mvc.model.dto.request;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Getter
+@Setter
+public class DuplicateCheckRequest {
+ private String value;
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/IncorrectNoteRequest.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/IncorrectNoteRequest.java
new file mode 100644
index 0000000..ffc92f4
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/IncorrectNoteRequest.java
@@ -0,0 +1,14 @@
+package com.codeboy.mvc.model.dto.request;
+
+import lombok.*;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Getter
+@Setter
+@ToString
+public class IncorrectNoteRequest {
+ private Long problemId;
+ private Long userProblemId;
+ private Boolean isUserProblem;
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/JoinQuizRoomRequest.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/JoinQuizRoomRequest.java
new file mode 100644
index 0000000..4e0d70d
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/JoinQuizRoomRequest.java
@@ -0,0 +1,13 @@
+package com.codeboy.mvc.model.dto.request;
+
+import lombok.*;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Getter
+@Setter
+@ToString
+public class JoinQuizRoomRequest {
+ private long roomId;
+
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/JoinRequest.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/JoinRequest.java
new file mode 100644
index 0000000..e38606d
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/JoinRequest.java
@@ -0,0 +1,15 @@
+package com.codeboy.mvc.model.dto.request;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@NoArgsConstructor
+public class JoinRequest {
+ private String id;
+ private String password;
+ private String nickname;
+ private String email;
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/LoginRequest.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/LoginRequest.java
new file mode 100644
index 0000000..3ddd898
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/LoginRequest.java
@@ -0,0 +1,16 @@
+package com.codeboy.mvc.model.dto.request;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+@AllArgsConstructor
+@NoArgsConstructor
+@Setter
+@Getter
+public class LoginRequest {
+ //로그인을 할 때에는 id와 password만 사용하니 이를 간편하게 전달하기 위한 DTO
+ private String id;
+ private String password;
+
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/MemberUpdateRequest.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/MemberUpdateRequest.java
new file mode 100644
index 0000000..86afc67
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/MemberUpdateRequest.java
@@ -0,0 +1,17 @@
+package com.codeboy.mvc.model.dto.request;
+
+ import io.swagger.v3.oas.annotations.media.Schema;
+ import lombok.AllArgsConstructor;
+ import lombok.Getter;
+ import lombok.NoArgsConstructor;
+ import lombok.Setter;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+@Schema(description="유저 정보 수정 DTO")
+public class MemberUpdateRequest {
+ private String nickname;
+ private String email;
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/ProblemSetRequest.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/ProblemSetRequest.java
new file mode 100644
index 0000000..f3b6347
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/request/ProblemSetRequest.java
@@ -0,0 +1,21 @@
+package com.codeboy.mvc.model.dto.request;
+
+import com.codeboy.common.Category;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.sql.Timestamp;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+@Schema(description="유저 문제 세트 등록 DTO")
+public class ProblemSetRequest {
+ private String problemSetTitle;
+ private Timestamp createdAt;
+ private Category category;
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/ApiResponse.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/ApiResponse.java
new file mode 100644
index 0000000..c06d007
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/ApiResponse.java
@@ -0,0 +1,36 @@
+package com.codeboy.mvc.model.dto.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.http.HttpStatus;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ApiResponse {
+ private HttpStatus status;
+ private String message;
+ private T data;
+
+
+
+// public ApiResponse(HttpStatus status, String message, T data) {
+// super();
+// this.status = status;
+// this.message = message;
+// this.data = data;
+// }
+//
+ public static ApiResponse success(HttpStatus status, T data) {
+ return new ApiResponse<>(status, null, data);
+ }
+
+ public static ApiResponse success(HttpStatus status, String message, T data) {
+ return new ApiResponse<>(status, message, data);
+ }
+
+ public static ApiResponse failure(HttpStatus status, String message) {
+ return new ApiResponse<>(status, message, null);
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/DuplicateCheckResponse.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/DuplicateCheckResponse.java
new file mode 100644
index 0000000..17a6543
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/DuplicateCheckResponse.java
@@ -0,0 +1,15 @@
+package com.codeboy.mvc.model.dto.response;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+public class DuplicateCheckResponse {
+ private boolean duplicated;
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/GetQuizRoomMembersResponse.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/GetQuizRoomMembersResponse.java
new file mode 100644
index 0000000..9ec59ed
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/GetQuizRoomMembersResponse.java
@@ -0,0 +1,13 @@
+package com.codeboy.mvc.model.dto.response;
+
+import lombok.*;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+public class GetQuizRoomMembersResponse {
+ private Long memberId;
+ private String nickname;
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/IncorrectNoteResponse.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/IncorrectNoteResponse.java
new file mode 100644
index 0000000..f86a4c2
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/IncorrectNoteResponse.java
@@ -0,0 +1,20 @@
+package com.codeboy.mvc.model.dto.response;
+
+import com.codeboy.common.Category;
+import lombok.*;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+public class IncorrectNoteResponse {
+ private Long incorrectNoteId;
+ private String problemDescription;
+ private String choice1;
+ private String choice2;
+ private String choice3;
+ private String choice4;
+ private String answer;
+ private Category category;
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/LoginResponse.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/LoginResponse.java
new file mode 100644
index 0000000..4b076ae
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/dto/response/LoginResponse.java
@@ -0,0 +1,14 @@
+package com.codeboy.mvc.model.dto.response;
+
+// 예: com.codeboy.mvc.model.dto.response 패키지에 둔다
+import com.codeboy.mvc.model.dto.Member;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class LoginResponse {
+ private String accessToken;
+ private String refreshToken; // 추가
+ private Long memberId;
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/AIProblemService.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/AIProblemService.java
new file mode 100644
index 0000000..06b9a64
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/AIProblemService.java
@@ -0,0 +1,11 @@
+package com.codeboy.mvc.model.service;
+
+
+import com.codeboy.mvc.model.dto.AIProblemDto;
+import com.codeboy.mvc.model.dto.request.AIProblemRequest;
+
+import java.util.List;
+
+public interface AIProblemService {
+ List generateProblems(AIProblemRequest request);
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/CommentService.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/CommentService.java
index 962d5ec..d1b02dd 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/CommentService.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/CommentService.java
@@ -1,5 +1,24 @@
package com.codeboy.mvc.model.service;
-public class CommentService {
+import java.util.List;
+
+import com.codeboy.mvc.model.dto.Comment;
+
+public interface CommentService {
+ /**
+ * 유저제작 문제 세트Id로 조회
+ * @param userProblemSetId
+ * @return
+ */
+ public List getAllCommentsById(Long userProblemSetId);
+
+ //유저제작 문제 세트Id로 조회후 해당 세트에 댓글 작성
+ public int addComment(Long userProblemSetId, Comment comment);
+//
+ public int updateComment(Long commentId, Comment comment);
+//
+ public int deleteComment(Long commentId);
+
+ public Long getCommentOwnerId(Long commentId);
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/CommentServiceImpl.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/CommentServiceImpl.java
new file mode 100644
index 0000000..2d1dedd
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/CommentServiceImpl.java
@@ -0,0 +1,58 @@
+package com.codeboy.mvc.model.service;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.codeboy.mvc.model.dao.CommentDao;
+import com.codeboy.mvc.model.dto.Comment;
+
+@Service
+public class CommentServiceImpl implements CommentService {
+
+ private final CommentDao commentDao;
+
+ @Autowired
+ public CommentServiceImpl(CommentDao commentDao) {
+ this.commentDao = commentDao;
+ }
+
+
+
+ // 유저제작 문제 세트Id로 조회
+ @Override
+ public List getAllCommentsById(Long userProblemSetId) {
+ return commentDao.selectCommentsByuserProblemSetId(userProblemSetId);
+ }
+
+ @Override
+ public int addComment(Long userProblemSetId, Comment comment ) {
+
+ return commentDao.insertComment(userProblemSetId, comment);
+ }
+
+
+
+ @Override
+ public int updateComment(Long commentId, Comment comment) {
+ return commentDao.updateComment(commentId, comment);
+
+ }
+
+
+
+ @Override
+ public int deleteComment(Long commentId) {
+ return commentDao.deleteComment(commentId);
+
+ }
+
+
+ @Override
+ public Long getCommentOwnerId(Long commentId){
+ return commentDao.selectCommentOwnerId(commentId);
+ }
+
+
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/CustomerUserDetailService.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/CustomerUserDetailService.java
new file mode 100644
index 0000000..96b2b63
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/CustomerUserDetailService.java
@@ -0,0 +1,28 @@
+package com.codeboy.mvc.model.service;
+
+import com.codeboy.mvc.model.dao.MemberDao;
+import com.codeboy.mvc.model.dto.CustomUserDetails;
+import com.codeboy.mvc.model.dto.Member;
+import lombok.RequiredArgsConstructor;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class CustomerUserDetailService implements UserDetailsService {
+
+ private final MemberDao memberDao;
+
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+
+ Member userData = memberDao.findByUserId(username);
+
+ if (userData == null) {
+ throw new UsernameNotFoundException("User not found: " + username);
+ }
+ return new CustomUserDetails(userData);
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/IncorrectNoteService.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/IncorrectNoteService.java
index e8d653a..a3a64b2 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/IncorrectNoteService.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/IncorrectNoteService.java
@@ -1,5 +1,78 @@
package com.codeboy.mvc.model.service;
+import com.codeboy.mvc.model.dao.IncorrectNoteDao;
+import com.codeboy.mvc.model.dto.response.IncorrectNoteResponse;
+import org.apache.ibatis.javassist.NotFoundException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
public class IncorrectNoteService {
+ @Autowired
+ private IncorrectNoteDao incorrectNoteDao;
+
+ public Long addIncorrectNote(Long memberId, Long problemId, Long userProblemId, Boolean isUserProblem) {
+ if (!isUserProblem) {
+ boolean exists = incorrectNoteDao.existsProblemById(problemId);
+ if (!exists) {
+ throw new IllegalArgumentException("DB에 존재하지 않는 문제 ID입니다.:" + problemId);
+ }
+ } else {
+ boolean exists = incorrectNoteDao.existsUserProblemById(userProblemId);
+ if (!exists) {
+ throw new IllegalArgumentException("DB에 존재하지 않는 유저문제 ID입니다.:" + userProblemId);
+ }
+ }
+
+ //TODO : DB에 존재하는지 검증하는 로직 필요
+ if (memberId == null) {
+ throw new IllegalArgumentException("유효하지 않은 회원 ID입니다.: " + memberId);
+ }
+ if ((!isUserProblem && (problemId == null || userProblemId != null)) ||
+ (isUserProblem && (problemId != null || userProblemId == null))) {
+ throw new IllegalArgumentException("유효하지 않은 문제 ID 입니다.:" );
+ }
+
+ Map params = new HashMap<>();
+ params.put("memberId", memberId);
+ params.put("problemId", problemId);
+ params.put("userProblemId", userProblemId);
+ params.put("isUserProblem", isUserProblem);
+
+ params.put("incorrectNoteId", null);
+
+ incorrectNoteDao.insertIncorrectProblem(params);
+
+ BigInteger id = (BigInteger) params.get("incorrectNoteId");
+ return id != null ? id.longValue() : null;
+
+ }
+
+ public List getIncorrectNoteList(Long memberId) throws NotFoundException {
+ //TODO : DB에 존재하는지 검증하는 로직
+// if (memberId == null || !memberDao.existsById(memberId)) {
+// throw new IllegalArgumentException("유효하지 않은 회원 ID입니다.");
+// }
+ if (memberId == null) {
+ throw new IllegalArgumentException("유효하지 않은 회원 ID입니다.");
+ }
+ List list = incorrectNoteDao.selectIncorrectProblems(memberId);
+
+ if (list == null || list.isEmpty()) {
+ throw new NotFoundException("오답노트를 조회할 수 없습니다.");
+ }
+ return list;
+ }
+ public void deleteIncorrectNote(long incorrectNoteId) {
+ boolean exists = incorrectNoteDao.existsIncorrectNoteById(incorrectNoteId);
+ if (!exists) {
+ throw new IllegalArgumentException("DB에 존재하지 않는 오답노트ID 입니다.: " + incorrectNoteId);
+ }
+ incorrectNoteDao.deleteIncorrectProblem(incorrectNoteId);
+ }
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/JoinService.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/JoinService.java
new file mode 100644
index 0000000..cdd1dda
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/JoinService.java
@@ -0,0 +1,55 @@
+package com.codeboy.mvc.model.service;
+
+import com.codeboy.mvc.model.dao.MemberDao;
+import com.codeboy.mvc.model.dao.UserScoreDao;
+import com.codeboy.mvc.model.dto.Member;
+import com.codeboy.mvc.model.dto.UserScore;
+import com.codeboy.mvc.model.dto.request.JoinRequest;
+import com.codeboy.mvc.model.dto.request.LoginRequest;
+import lombok.RequiredArgsConstructor;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class JoinService {
+
+ private final MemberDao memberDao;
+ private final UserScoreDao userScoreDao;
+ private final BCryptPasswordEncoder bCryptPasswordEncoder;
+
+ public Long joinProcess(JoinRequest req) {
+
+ // 1) 중복 아이디 체크
+ Boolean exists = memberDao.existByUserId(req.getId());
+
+ if (Boolean.TRUE.equals(exists)) {
+ throw new IllegalArgumentException("이미 존재하는 아이디입니다.");
+ }
+
+ // 2) Member 매핑
+ Member member = new Member();
+ member.setId(req.getId());
+ member.setPassword(bCryptPasswordEncoder.encode(req.getPassword()));
+ member.setNickname(req.getNickname());
+ member.setEmail(req.getEmail());
+ member.setIsActive(true);
+ member.setRole("USER");
+
+ // 3) DB Insert
+ int rows = memberDao.insertMember(member);
+ if (rows != 1) {
+ throw new IllegalStateException("회원 가입에 실패했습니다. (insert rows = " + rows + ")");
+ }
+ //회원가입에 성공했다면 score에 0점 넣기
+ UserScore userScore = new UserScore();
+ userScore.setMemberId(member.getMemberId());
+ userScore.setScore(0);
+
+ int scoreRows = userScoreDao.insertScore(userScore);
+ if (scoreRows != 1) {
+ throw new IllegalStateException("초기 점수 등록에 실패했습니다");
+ }
+ return member.getMemberId();
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/MemberService.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/MemberService.java
index 90316ff..697bd31 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/MemberService.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/MemberService.java
@@ -1,19 +1,31 @@
package com.codeboy.mvc.model.service;
import com.codeboy.mvc.model.dto.Member;
-import com.codeboy.mvc.model.dto.MemberUpdateRequest;
-import com.codeboy.mvc.model.dto.MemberUpdateRequest;
+import com.codeboy.mvc.model.dto.request.MemberUpdateRequest;
public interface MemberService {
- //회원가입
- public void signupMember();
- //회원 정보 가져오기기
- public Member readMember(String id, String password);
+ // 회원정보 조회
+ Member getMemberById(Long memberId);
- //회원 탈퇴
- public void withdrawal(int memberId);
+ // 회원 탈퇴
+ void deactivateMember(Long memberId);
+
+ // 회원 정보 수정
+ void updateMember(Long memberId, MemberUpdateRequest memberUpdateRequest);
+
+ // 중복검사 (ID)
+ boolean checkIdDuplicate(String id);
+
+ // 중복검사 (Nickname)
+ boolean checkNicknameDuplicate(String nickname);
+
+ // 중복검사 (Email)
+ boolean checkEmailDuplicate(String email);
+
+ int signUp(Member member);
+
- //회원정보 수정-> db에서는 patch(nickname, email, id)
- public void updateMember(long memberId, MemberUpdateRequest memberUpdateRequest);
+ // 로그인
+ Member login(String id, String password);
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/MemberServiceImpl.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/MemberServiceImpl.java
new file mode 100644
index 0000000..7ff5bb0
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/MemberServiceImpl.java
@@ -0,0 +1,138 @@
+package com.codeboy.mvc.model.service;
+
+import com.codeboy.mvc.model.dao.MemberDao;
+import com.codeboy.mvc.model.dao.UserScoreDao;
+import com.codeboy.mvc.model.dto.Member;
+import com.codeboy.mvc.model.dto.UserScore;
+import com.codeboy.mvc.model.dto.request.MemberUpdateRequest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.NoSuchElementException;
+
+@Service
+public class MemberServiceImpl implements MemberService {
+ @Autowired
+ MemberDao memberDao;
+
+ @Autowired
+ UserScoreDao userScoreDao;
+
+ //회원 정보 가져오기기
+ public Member getMemberById(Long memberId) {
+ isMemberExist(memberId);
+
+ Member member = memberDao.selectMemberById(memberId);
+ if (member == null) {
+ throw new NoSuchElementException("Id에 해당하는 회원 정보를 찾을 수 없습니다. memberId:" + memberId);
+ }
+ return member;
+ };
+
+ //회원 탈퇴
+ public void deactivateMember(Long memberId){
+ isMemberExist(memberId);
+
+ int updatedRows = memberDao.deactivateMemberById(memberId);
+ if (updatedRows == 0) {
+ throw new IllegalStateException("회원 탈퇴 실패 : memberId: " + memberId);
+ }
+ }
+
+
+ public void updateMember(Long memberId, MemberUpdateRequest memberUpdateRequest) {
+ isMemberExist(memberId);
+
+ // 현재 DB에 저장된 회원 정보
+ Member current = memberDao.selectMemberById(memberId);
+ if (current == null) {
+ throw new IllegalStateException("회원 정보 수정 실패: 존재하지 않는 회원입니다. memberId: " + memberId);
+ }
+
+ String nickname = memberUpdateRequest.getNickname();
+ String email = memberUpdateRequest.getEmail();
+
+ // ✅ 내 현재 값과 비교해서, 실제로 바뀌는 필드만 중복체크
+ validateMemberUpdate(current, nickname, email);
+
+ int affectedRows = memberDao.updateMemberById(memberId, memberUpdateRequest);
+ if (affectedRows == 0) {
+ throw new IllegalStateException("회원 정보 수정에 실패하였습니다. memberId: " + memberId);
+ }
+ }
+
+ public boolean checkIdDuplicate(String id) {
+ if (id == null) {
+ throw new IllegalArgumentException("유효하지 않은 Id 입니다.");
+ }
+ return memberDao.existsId(id);
+ }
+
+ public boolean checkNicknameDuplicate(String nickname ) {
+ if (nickname == null) {
+ throw new IllegalArgumentException("유효하지 않은 Id 입니다.");
+ }
+ return memberDao.existsNickname(nickname);
+ }
+
+ public boolean checkEmailDuplicate(String email) {
+ if (email == null) {
+ throw new IllegalArgumentException("유효하지 않은 Id 입니다.");
+ }
+ return memberDao.existsEmail(email);
+ }
+
+ @Override
+ public int signUp(Member member) {
+ UserScore userScore = new UserScore(member.getMemberId(), 0);
+ userScoreDao.insertScore(userScore);
+ return memberDao.insertMember(member);
+ }
+
+ public void isMemberExist(Long memberId) {
+ if (memberId == null) {
+ throw new IllegalArgumentException("유효하지 않은 memberId입니다. memberId: " );
+ }
+
+ boolean isActive = memberDao.isMemberActive(memberId);
+ if (!isActive) {
+ throw new IllegalArgumentException("비활성화된 멤버 id 입니다. memberId: " + memberId);
+ }
+ }
+
+ // 최종 제출 시 전체 검증
+// 현재 회원 정보 + 변경 요청값 기준 검증
+ public void validateMemberUpdate(Member current, String nickname, String email) {
+
+ // 닉네임
+ if (nickname != null && !nickname.equals(current.getNickname())) {
+ if (memberDao.existsNickname(nickname)) {
+ throw new IllegalArgumentException("중복된 닉네임입니다.");
+ }
+ }
+
+ // 이메일
+ if (email != null && !email.equals(current.getEmail())) {
+ if (memberDao.existsEmail(email)) {
+ throw new IllegalArgumentException("중복된 이메일입니다.");
+ }
+ }
+ }
+
+
+ // 로그인
+ public Member login(String id, String password) {
+ if (id == null || password == null) {
+ throw new IllegalArgumentException("ID와 비밀번호를 입력해주세요.");
+ }
+
+ Member member = memberDao.selectMemberByIdAndPassword(id, password);
+ if (member == null) {
+ throw new IllegalArgumentException("ID 또는 비밀번호가 올바르지 않습니다.");
+ }
+
+ return member;
+ }
+
+
+};
\ No newline at end of file
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/ProblemService.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/ProblemService.java
index 959188b..1986fc6 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/ProblemService.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/ProblemService.java
@@ -1,5 +1,14 @@
package com.codeboy.mvc.model.service;
-public class ProblemService {
+import com.codeboy.common.Category;
+import com.codeboy.mvc.model.dto.Problem;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public interface ProblemService {
+
+ public List getProblems(Category category);
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/ProblemServiceImpl.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/ProblemServiceImpl.java
new file mode 100644
index 0000000..ad0265c
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/ProblemServiceImpl.java
@@ -0,0 +1,34 @@
+package com.codeboy.mvc.model.service;
+
+import com.codeboy.common.Category;
+import com.codeboy.mvc.model.dao.ProblemDao;
+import com.codeboy.mvc.model.dto.Problem;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class ProblemServiceImpl implements ProblemService{
+ @Autowired
+ private ProblemDao problemDao;
+
+ @Override
+ public List getProblems(Category category) {
+// if (limit <= 0) {
+// throw new IllegalArgumentException("limit의 수는 0이상이어야 합니다. limit: " + limit);
+// }
+ if (category == null) {
+ throw new IllegalArgumentException("category의 값은 null이 될 수 없습니다. : category: ");
+ }
+ List problems = problemDao.selectProblem(category);
+
+ //만약 요청 수보다 존재하는 문제 수가 적다면
+// if (limit > problems.size()) {
+// throw new IllegalArgumentException("limit의 값은 문제 수보다 클 수 없습니다. problems: " + problems.size());
+// }
+
+ return problems;
+ }
+
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/QuizRoomService.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/QuizRoomService.java
index cd3f65e..c66dde8 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/QuizRoomService.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/QuizRoomService.java
@@ -2,22 +2,108 @@
import java.util.List;
+import com.codeboy.mvc.model.dto.response.GetQuizRoomMembersResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.codeboy.mvc.model.dao.QuizRoomDao;
import com.codeboy.mvc.model.dto.QuizRoom;
+import com.codeboy.mvc.model.dto.QuizRoomMember;
+import org.springframework.stereotype.Service;
+
+@Service
+public class QuizRoomService{
+ @Autowired
+ private QuizRoomDao quizRoomDao;
+
+ public List getQuizRoomList() {
+ List quizRooms = quizRoomDao.selectAllQuizRoom();
+ if (quizRooms == null) {
+ throw new IllegalStateException("퀴즈방 정보를 가져오지 못했습니다");
+ }
+ return quizRooms;
+ }
+
+ public List getOneQuizRoomMember(long roomId) {
+ validateRoomId(roomId);
+
+ List memberList = quizRoomDao.selectOneQuizRoom(roomId);
+ if (memberList.isEmpty()) {
+ throw new IllegalStateException("퀴즈방에 참가자가 없습니다.");
+ }
+ return memberList;
+ }
+
+ public long createQuizRoom() {
+ QuizRoom room = new QuizRoom();
+ quizRoomDao.insertQuizRoom(room);
+
+ Long roomId = room.getRoomId();
+
+ validateRoomId(roomId);
+ return roomId;
+ }
+
+ public void joinQuizRoom(QuizRoomMember quizRoomMember) {
+ Long memberId = quizRoomMember.getMemberId();
+ Long roomId = quizRoomMember.getRoomId();
+ validateRoomId(roomId);
+ memberDuplicateCheck(memberId);
+
+ //멤버 id가 실제로 존재하는지 확인
+ if (memberId == null) {
+ throw new IllegalArgumentException("멤버 ID가 유효하지 않습니다. :" );
+ }
+ //TODO : 채팅방 참여 인원이 초과되었는지 검증하는 로직 추가
+ int rowAffected = quizRoomDao.insertMemberToQuizRoom(quizRoomMember);
+ if (rowAffected <= 0) {
+ throw new IllegalStateException("퀴즈방 입장에 실패하였습니다.");
+ }
+ }
+
+ public void deleteQuizRoom(long roomId) {
+ validateRoomId(roomId);
+ boolean deleted = quizRoomDao.deleteQuizRoom(roomId);
+ if (!deleted) {
+ throw new IllegalStateException("퀴즈방 삭제에 실패했습니다.");
+ }
+ }
+
+ private void validateRoomId(Long roomId) {
+ boolean existRoom = quizRoomDao.existsQuizRoom(roomId) > 0;
+ if (roomId == null || roomId <= 0 || !existRoom) {
+ throw new IllegalArgumentException("퀴즈방 ID가 유효하지 않습니다. : " + roomId);
+ }
+ }
+
+ private void memberDuplicateCheck(Long memberId) {
+ boolean duplicated = quizRoomDao.isDuplicatedMember(memberId) > 0;
+ if (duplicated) {
+ throw new IllegalArgumentException("한 멤버는 하나의 채팅방에만 들어갈 수 있습니다.");
+ }
+ }
+
+ public void leaveQuizRoom(long roomId, long memberId) {
+
+ // 1) 현재 방에 이 멤버가 실제로 있는지 확인
+ QuizRoomMember quizRoomMember = quizRoomDao.selectQuizRoomMember(roomId, memberId);
+
+ if (quizRoomMember == null) {
+ throw new IllegalArgumentException("해당 멤버는 이 퀴즈방에 참가 중이 아닙니다.");
+ }
+
+ // TODO: 호스트가 나갈 때의 정책이 따로 있다면 여기서 처리
+ // if (quizRoomMember.getIsHost()) { ... }
+
+ // 2) 퀴즈방 멤버 목록에서 삭제
+ int deleted = quizRoomDao.deleteQuizRoomMember(roomId, memberId);
+
+ if (deleted != 1) {
+ throw new IllegalStateException("퀴즈방 퇴장 처리에 실패했습니다.");
+ }
+
+ // TODO: 마지막 사람이 나가면 방 자체를 삭제할지 여부는 여기서 추가로 정책 결정 가능
+ // int remains = quizRoomDao.countMembersInRoom(roomId);
+ // if (remains == 0) { quizRoomDao.deleteQuizRoom(roomId); }
+ }
-public interface QuizRoomService {
-
- //퀴즈방 전체 조회
- public List getQuizRoomList();
-
- //퀴즈 방 만들기 -> 생성된 퀴즈방 id를 return
- //퀴즈방 생성하고 생성된 퀴즈방에 방장 id 넣기
- public int createQuizRoom(long memberId);
-
- //참가자 채팅방 입장
- public void joinQuizRoom(long memberId, long quizRoomId);
-
- //퀴즈룸 삭제
- public boolean deleteQuizRoom()
-
-
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/ScoreService.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/ScoreService.java
deleted file mode 100644
index 2b2aa4c..0000000
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/ScoreService.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.codeboy.mvc.model.service;
-
-public class ScoreService {
-
-}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserProblemService.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserProblemService.java
index c315c3b..2a25a51 100644
--- a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserProblemService.java
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserProblemService.java
@@ -1,5 +1,16 @@
package com.codeboy.mvc.model.service;
-public class UserProblemService {
+import com.codeboy.mvc.model.dto.UserProblem;
+import java.util.List;
+
+public interface UserProblemService {
+
+ List getProblemsByUserProblemSetId(Long userProblemSetId);
+
+ int addUserProblems(List userProblems);
+
+ int updateUserProblem(UserProblem userProblem);
+
+ int deleteUserProblem(Long userProblemId);
}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserProblemServiceImpl.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserProblemServiceImpl.java
new file mode 100644
index 0000000..e426773
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserProblemServiceImpl.java
@@ -0,0 +1,47 @@
+package com.codeboy.mvc.model.service;
+
+import com.codeboy.mvc.model.dao.UserProblemDao;
+import com.codeboy.mvc.model.dto.UserProblem;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class UserProblemServiceImpl implements UserProblemService {
+
+ private final UserProblemDao userProblemDao;
+
+ public UserProblemServiceImpl(UserProblemDao userProblemDao) {
+ this.userProblemDao = userProblemDao;
+ }
+
+ @Override
+ public List getProblemsByUserProblemSetId(Long userProblemSetId) {
+ return userProblemDao.selectProblemsByUserProblemSetId(userProblemSetId);
+ }
+
+ @Override
+ public int addUserProblems(List userProblems) {
+ if (userProblems == null || userProblems.isEmpty()) {
+ throw new IllegalArgumentException("등록할 문제가 하나 이상 있어야 합니다.");
+ }
+ return userProblemDao.insertUserProblemList(userProblems);
+ }
+
+ @Override
+ public int updateUserProblem(UserProblem userProblem) {
+ if (userProblem == null || userProblem.getUserProblemId() == null) {
+ throw new IllegalArgumentException("수정할 문제를 찾을 수 없습니다. 문제Id를 확인하세요.");
+ }
+ System.out.println("디버깅2");
+ return userProblemDao.updateUserProblem(userProblem);
+ }
+
+ @Override
+ public int deleteUserProblem(Long userProblemId) {
+ if (userProblemId == null) {
+ throw new IllegalArgumentException("삭제할 문제를 찾을 수 없습니다. 삭제할 문제 ID를 확인하세요.");
+ }
+ return userProblemDao.deleteUserProblemById(userProblemId);
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserProblemSetService.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserProblemSetService.java
new file mode 100644
index 0000000..ec15d55
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserProblemSetService.java
@@ -0,0 +1,15 @@
+package com.codeboy.mvc.model.service;
+
+import com.codeboy.mvc.model.dto.UserProblemSet;
+
+import java.util.List;
+
+public interface UserProblemSetService {
+ List getAllUserProblemSets();
+
+ List getUserProblemSetByMemberId(Long memberId);
+
+ int createUserProblemSet(UserProblemSet set);
+
+ int deleteUserProblemSet(Long userProblemSetId);
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserProblemSetServiceImpl.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserProblemSetServiceImpl.java
new file mode 100644
index 0000000..4135072
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserProblemSetServiceImpl.java
@@ -0,0 +1,49 @@
+package com.codeboy.mvc.model.service;
+
+import com.codeboy.mvc.model.dao.UserProblemSetDao;
+import com.codeboy.mvc.model.dto.UserProblemSet;
+import org.springframework.stereotype.Service;
+
+
+import java.util.List;
+
+@Service
+public class UserProblemSetServiceImpl implements UserProblemSetService {
+
+ private final UserProblemSetDao userProblemSetDao;
+
+ public UserProblemSetServiceImpl(UserProblemSetDao userProblemSetDao) {
+ this.userProblemSetDao = userProblemSetDao;
+ }
+
+ @Override
+ public List getAllUserProblemSets() {
+ return userProblemSetDao.selectUserProblemSets();
+ }
+
+ @Override
+ public List getUserProblemSetByMemberId(Long memberId) {
+ if (memberId == null) {
+ throw new IllegalArgumentException("회원 ID가 필요합니다.");
+ }
+ long memberIdl = memberId;
+ return userProblemSetDao.selectUserProblemSetByMemberId(memberIdl);
+ }
+
+ @Override
+ public int createUserProblemSet(UserProblemSet set) {
+ if (set.getMemberId() == null) {
+ throw new IllegalArgumentException("회원 ID가 필요합니다.");
+ }
+// long memberId = set.getMemberId();
+ return userProblemSetDao.insertUserProblemSet(set);
+ }
+
+ @Override
+ public int deleteUserProblemSet(Long userProblemSetId) {
+ if (userProblemSetId == null) {
+ throw new IllegalArgumentException("삭제할 문제세트 ID가 필요합니다.");
+ }
+ return userProblemSetDao.deleteUserProblemSetById(userProblemSetId);
+ }
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserScoreService.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserScoreService.java
new file mode 100644
index 0000000..2f07894
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserScoreService.java
@@ -0,0 +1,23 @@
+package com.codeboy.mvc.model.service;
+
+import java.util.List;
+
+import com.codeboy.mvc.model.dto.UserScore;
+
+public interface UserScoreService {
+
+
+ //회원가입 시 자동으로 리더보드에 보여줄 점수를 등록 디폴트는 0
+ int registerScore(UserScore userScore);
+
+ //리더보드에 모든 유저들의 점수정보들을 보여줌
+ List getAllUserScores();
+
+ //한 멤버의 스코어 조회
+ UserScore getUserScoreById(Long memberId);
+
+ //멤버 스코어 업데이트
+ //업데이트된 행 수 반환
+ int updateUser(UserScore userScore);
+
+}
diff --git a/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserScoreServiceImpl.java b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserScoreServiceImpl.java
new file mode 100644
index 0000000..1733b62
--- /dev/null
+++ b/codeBoy_backend/src/main/java/com/codeboy/mvc/model/service/UserScoreServiceImpl.java
@@ -0,0 +1,71 @@
+package com.codeboy.mvc.model.service;
+
+import java.util.List;
+
+import org.springframework.stereotype.Service;
+
+import com.codeboy.mvc.model.dao.UserScoreDao;
+import com.codeboy.mvc.model.dto.UserScore;
+
+
+@Service
+public class UserScoreServiceImpl implements UserScoreService {
+
+ private final UserScoreDao userScoreDao;
+
+ public UserScoreServiceImpl(UserScoreDao userScoreDao) {
+ this.userScoreDao = userScoreDao;
+ }
+
+ @Override
+ public int registerScore(UserScore userScore) {
+ // 1. 파라미터 유효성 검증 → IllegalArgumentException
+ if (userScore == null) {
+ throw new IllegalArgumentException("점수 정보가 비어 있습니다.");
+ }
+ if (userScore.getMemberId() <= 0) {
+ throw new IllegalArgumentException("유효하지 않은 회원 ID입니다.");
+ }
+ if (userScore.getScore() < 0) {
+ throw new IllegalArgumentException("점수는 0 이상이어야 합니다.");
+ }
+
+ // 2. DAO 호출 → 삽입된 row 수 반환
+ int result = userScoreDao.insertScore(userScore);
+ // result가 0인지 아닌지는 컨트롤러에서 판단
+ return result;
+ }
+
+ @Override
+ public List getAllUserScores() {
+ // 여기서는 그냥 DAO 결과를 그대로 반환하고
+ // 목록이 비었는지 여부는 컨트롤러에서 판단함.
+ return userScoreDao.selectAllUserScores();
+ }
+
+ @Override
+ public UserScore getUserScoreById(Long memberId) {
+ if (memberId == null || memberId <= 0) {
+ throw new IllegalArgumentException("유효하지 않은 회원 ID입니다.");
+ }
+
+ // 없으면 null 반환 → 컨트롤러에서 404 처리
+ return userScoreDao.selectOneUserScore(memberId);
+ }
+
+ @Override
+ public int updateUser(UserScore userScore) {
+ if (userScore == null) {
+ throw new IllegalArgumentException("점수 정보가 비어 있습니다.");
+ }
+ if (userScore.getMemberId() <= 0) {
+ throw new IllegalArgumentException("유효하지 않은 회원 ID입니다.");
+ }
+ if (userScore.getScore() < 0) {
+ throw new IllegalArgumentException("점수는 0 이상이어야 합니다.");
+ }
+
+ int result = userScoreDao.updateUserScore(userScore);
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/codeBoy_backend/src/main/resources/application.properties b/codeBoy_backend/src/main/resources/application.properties
index 603f194..598f3d5 100644
--- a/codeBoy_backend/src/main/resources/application.properties
+++ b/codeBoy_backend/src/main/resources/application.properties
@@ -9,9 +9,9 @@ spring.application.name=codeBoy_backend
#
#
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
-spring.datasource.url=jdbc:mysql://localhost:3306/ssafy_board?serverTimezone=UTC
-spring.datasource.username=ssafy
-spring.datasource.password=ssafy
+spring.datasource.url=jdbc:mysql://localhost:3306/board_test?serverTimezone=UTC
+spring.datasource.username=root
+spring.datasource.password=088alstmd!
#mybatis
#mapper
@@ -21,4 +21,12 @@ mybatis.mapper-locations=classpath:mappers/*.xml
mybatis.type-aliases-package=com.codeboy.mvc.model.dto
mybatis.configuration.map-underscore-to-camel-case=true
-debug=true
\ No newline at end of file
+debug=true
+
+#spring security
+spring.jwt.secret-key=_1234567890abcdefghijkmnkopqrstu
+
+spring.flyway.enabled=false
+
+logging.level.org.mybatis=DEBUG
+logging.level.org.springframework.jdbc.core=DEBUG
diff --git a/codeBoy_backend/src/main/resources/db/migration/DDL_schema.sql b/codeBoy_backend/src/main/resources/db/migration/DDL_schema.sql
new file mode 100644
index 0000000..1508fbf
--- /dev/null
+++ b/codeBoy_backend/src/main/resources/db/migration/DDL_schema.sql
@@ -0,0 +1,221 @@
+-- MySQL Script generated by MySQL Workbench
+-- Mon Nov 24 16:21:44 2025
+-- Model: New Model Version: 1.0
+-- MySQL Workbench Forward Engineering
+ DROP DATABASE IF EXISTS board_test;
+ CREATE DATABASE board_test;
+ USE board_test;
+
+SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
+SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
+SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
+
+
+CREATE SCHEMA IF NOT EXISTS `board_test` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci ;
+USE board_test;
+
+
+-- -----------------------------------------------------
+-- Table `board_test`.`member`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `board_test`.`member` (
+ `member_id` BIGINT AUTO_INCREMENT,
+ `ID` VARCHAR(30) NOT NULL,
+ `password` CHAR(64) NOT NULL,
+ `nickname` VARCHAR(30) NOT NULL,
+ `email` VARCHAR(30) NOT NULL,
+ `signup_date` TIMESTAMP NOT NULL,
+ `is_active` TINYINT NOT NULL,
+ `deleted_date` TIMESTAMP NULL DEFAULT NULL,
+ `role` VARCHAR(20) NOT NULL DEFAULT 'USER',
+ PRIMARY KEY (`member_id`))
+ENGINE = InnoDB
+DEFAULT CHARACTER SET = utf8mb4
+COLLATE = utf8mb4_0900_ai_ci;
+
+
+-- -----------------------------------------------------
+-- Table `board_test`.`user_problem_set`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `board_test`.`user_problem_set` (
+ `user_problem_set_id` BIGINT NOT NULL AUTO_INCREMENT,
+ `member_id` BIGINT NOT NULL,
+ `category` VARCHAR(50) NOT NULL,
+ `comment_count` INT NOT NULL DEFAULT 0,
+ `problem_set_title` VARCHAR(50) NOT NULL,
+ `created_at` TIMESTAMP NOT NULL DEFAULT NOW(),
+ PRIMARY KEY (`user_problem_set_id`),
+ INDEX `FK_member_TO_user_problem_set_1` (`member_id` ASC) VISIBLE,
+ CONSTRAINT `FK_member_TO_user_problem_set_1`
+ FOREIGN KEY (`member_id`)
+ REFERENCES `board_test`.`member` (`member_id`))
+
+ENGINE = InnoDB
+DEFAULT CHARACTER SET = utf8mb4
+COLLATE = utf8mb4_0900_ai_ci;
+
+
+-- -----------------------------------------------------
+-- Table `board_test`.`comment`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `board_test`.`comment` (
+ `comment_id` BIGINT NOT NULL AUTO_INCREMENT,
+ `content` VARCHAR(500) NOT NULL,
+ `comment_date` TIMESTAMP NOT NULL,
+ `member_id` BIGINT NOT NULL,
+ `user_problem_set_id` BIGINT NOT NULL,
+ PRIMARY KEY (`comment_id`),
+ INDEX `FK_member_TO_comment_1` (`member_id` ASC) VISIBLE,
+ INDEX `FK_user_problem_set_TO_comment_1` (`user_problem_set_id` ASC) VISIBLE,
+ CONSTRAINT `FK_member_TO_comment_1`
+ FOREIGN KEY (`member_id`)
+ REFERENCES `board_test`.`member` (`member_id`),
+ CONSTRAINT `FK_user_problem_set_TO_comment_1`
+ FOREIGN KEY (`user_problem_set_id`)
+ REFERENCES `board_test`.`user_problem_set` (`user_problem_set_id`))
+ENGINE = InnoDB
+DEFAULT CHARACTER SET = utf8mb4
+COLLATE = utf8mb4_0900_ai_ci;
+
+
+
+-- -----------------------------------------------------
+-- Table `board_test`.`problem`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `board_test`.`problem` (
+ `problem_id` BIGINT NOT NULL AUTO_INCREMENT,
+ `problem_description` VARCHAR(300) NOT NULL,
+ `choice_1` VARCHAR(255) NOT NULL,
+ `choice_2` VARCHAR(255) NOT NULL,
+ `choice_3` VARCHAR(255) NOT NULL,
+ `choice_4` VARCHAR(255) NOT NULL,
+ `answer_choice` TINYINT NOT NULL,
+ `category` VARCHAR(50) NOT NULL,
+ PRIMARY KEY (`problem_id`))
+ENGINE = InnoDB
+DEFAULT CHARACTER SET = utf8mb4
+COLLATE = utf8mb4_0900_ai_ci;
+
+-- -----------------------------------------------------
+-- Table `board_test`.`incorrect_note`
+-- -----------------------------------------------------
+-- DROP TABLE IF EXISTS incorrect_note;
+
+CREATE TABLE IF NOT EXISTS `board_test`.`incorrect_note` (
+ `incorrect_note_id` BIGINT NOT NULL AUTO_INCREMENT,
+ `member_id` BIGINT NOT NULL,
+ `problem_id` BIGINT,
+ `user_problem_id` BIGINT,
+ `is_user_problem` TINYINT NOT NULL,
+
+ PRIMARY KEY (`incorrect_note_id`),
+ INDEX `FK_member_TO_incorrect_note_1` (`member_id` ASC) VISIBLE,
+ INDEX `FK_problem_TO_incorrect_note_1` (`problem_id` ASC) VISIBLE,
+ INDEX `FK_user_problem_TO_incorrect_note_1` (`user_problem_id` ASC) VISIBLE,
+
+ CONSTRAINT `FK_member_TO_incorrect_note_1`
+ FOREIGN KEY (`member_id`)
+ REFERENCES `board_test`.`member` (`member_id`),
+
+ CONSTRAINT `FK_problem_TO_incorrect_note_1`
+ FOREIGN KEY (`problem_id`)
+ REFERENCES `board_test`.`problem` (`problem_id`),
+
+ CONSTRAINT `FK_user_problem_TO_incorrect_note_1`
+ FOREIGN KEY (`user_problem_id`)
+ REFERENCES `board_test`.`user_problem` (`user_problem_id`),
+
+ CHECK (
+ (is_user_problem= 0 AND problem_id IS NOT NULL AND user_problem_id IS NULL) OR
+ (is_user_problem= 1 AND user_problem_id IS NOT NULL AND problem_id IS NULL)
+ )
+) ENGINE = InnoDB
+ DEFAULT CHARACTER SET = utf8mb4
+ COLLATE = utf8mb4_0900_ai_ci;
+
+
+-- -----------------------------------------------------
+-- Table `board_test`.`quiz_room`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `board_test`.`quiz_room` (
+ `room_id` BIGINT NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`room_id`))
+ENGINE = InnoDB
+DEFAULT CHARACTER SET = utf8mb4
+COLLATE = utf8mb4_0900_ai_ci;
+
+-- -----------------------------------------------------
+-- Table `board_test`.`quiz_room_member`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `board_test`.`quiz_room_member` (
+ `quiz_room_member_id` BIGINT NOT NULL AUTO_INCREMENT,
+ `member_id` BIGINT NOT NULL,
+ `room_id` BIGINT NOT NULL,
+ `is_host` TINYINT(1) NULL DEFAULT NULL,
+ PRIMARY KEY (`quiz_room_member_id`),
+ INDEX `FK_member_TO_quiz_room_member_1` (`member_id` ASC) VISIBLE,
+ INDEX `FK_quiz_room_TO_quiz_room_member_1` (`room_id` ASC) VISIBLE,
+ UNIQUE INDEX `member_id_UNIQUE` (`member_id` ASC) VISIBLE,
+ CONSTRAINT `FK_member_TO_quiz_room_member_1`
+ FOREIGN KEY (`member_id`)
+ REFERENCES `board_test`.`member` (`member_id`),
+ CONSTRAINT `FK_quiz_room_TO_quiz_room_member_1`
+ FOREIGN KEY (`room_id`)
+ REFERENCES `board_test`.`quiz_room` (`room_id`))
+ENGINE = InnoDB
+DEFAULT CHARACTER SET = utf8mb4
+COLLATE = utf8mb4_0900_ai_ci;
+
+-- 퀴즈룸이 삭제되면 퀴즈룸멤버테이블에서 퀴즈룸아이디를 가지고있는 row가 연쇄적으로 삭제
+ALTER TABLE quiz_room_member
+DROP FOREIGN KEY FK_quiz_room_TO_quiz_room_member_1;
+
+ALTER TABLE quiz_room_member
+ADD CONSTRAINT FK_quiz_room_TO_quiz_room_member_1
+ FOREIGN KEY (room_id)
+ REFERENCES quiz_room (room_id)
+ ON DELETE CASCADE;
+
+-- -----------------------------------------------------
+-- Table `board_test`.`user_problem`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `board_test`.`user_problem` (
+ `user_problem_id` BIGINT NOT NULL AUTO_INCREMENT,
+ `problem_description` VARCHAR(300) NOT NULL,
+ `choice_1` VARCHAR(255) NOT NULL,
+ `choice_2` VARCHAR(255) NOT NULL,
+ `choice_3` VARCHAR(255) NOT NULL,
+ `choice_4` VARCHAR(255) NOT NULL,
+ `answer_choice` TINYINT NOT NULL,
+ `user_problem_set_id` BIGINT NOT NULL,
+ PRIMARY KEY (`user_problem_id`),
+ INDEX `FK_user_problem_set_TO_user_problem_1` (`user_problem_set_id` ASC) VISIBLE,
+ CONSTRAINT `FK_user_problem_set_TO_user_problem_1`
+ FOREIGN KEY (`user_problem_set_id`)
+ REFERENCES `board_test`.`user_problem_set` (`user_problem_set_id`)
+ ON DELETE CASCADE
+ )
+
+ENGINE = InnoDB
+DEFAULT CHARACTER SET = utf8mb4
+COLLATE = utf8mb4_0900_ai_ci;
+
+-- user_score테이블고유의 아이디를 가지고있도록 변경. member_id가 이전에는 pk역할을했엇음
+-- 로직에 맞게 member_id를 member테이블에서 외래키로 가져오도록 변경
+CREATE TABLE IF NOT EXISTS user_score (
+ user_score_id BIGINT NOT NULL AUTO_INCREMENT, -- 👉 점수 레코드 자체의 PK
+ member_id BIGINT NOT NULL, -- 👉 member 테이블 PK를 참조하는 FK
+ score INT NOT NULL,
+ PRIMARY KEY (user_score_id),
+ CONSTRAINT FK_member_TO_user_score_1
+ FOREIGN KEY (member_id)
+ REFERENCES member (member_id)
+ ON DELETE CASCADE
+);
+
+ALTER TABLE board_test.user_score
+ADD CONSTRAINT user_score_unique_member_id UNIQUE (member_id);
+
+SET SQL_MODE=@OLD_SQL_MODE;
+SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
+SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
diff --git a/codeBoy_backend/src/main/resources/db/migration/DML_schema.sql b/codeBoy_backend/src/main/resources/db/migration/DML_schema.sql
new file mode 100644
index 0000000..bfd1092
--- /dev/null
+++ b/codeBoy_backend/src/main/resources/db/migration/DML_schema.sql
@@ -0,0 +1,3 @@
+ USE board_test;
+
+ SELECT * FROM member;
\ No newline at end of file
diff --git a/codeBoy_backend/src/main/resources/mappers/CommentMapper.xml b/codeBoy_backend/src/main/resources/mappers/CommentMapper.xml
new file mode 100644
index 0000000..21c1d0f
--- /dev/null
+++ b/codeBoy_backend/src/main/resources/mappers/CommentMapper.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codeBoy_backend/src/main/resources/mappers/IncorrectNoteMapper.xml b/codeBoy_backend/src/main/resources/mappers/IncorrectNoteMapper.xml
new file mode 100644
index 0000000..cb57765
--- /dev/null
+++ b/codeBoy_backend/src/main/resources/mappers/IncorrectNoteMapper.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DELETE FROM incorrect_note
+ WHERE incorrect_note_id = #{incorrectNoteId}
+
+
+
+
+ INSERT INTO incorrect_note (member_id, problem_id, user_problem_id, is_user_problem)
+ VALUES (#{memberId}, #{problemId}, #{userProblemId}, #{isUserProblem})
+
+
+
\ No newline at end of file
diff --git a/codeBoy_backend/src/main/resources/mappers/MemberMapper.xml b/codeBoy_backend/src/main/resources/mappers/MemberMapper.xml
new file mode 100644
index 0000000..b4437ae
--- /dev/null
+++ b/codeBoy_backend/src/main/resources/mappers/MemberMapper.xml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+ UPDATE member
+ SET is_active = 0
+ WHERE member_id = #{memberId}
+
+
+
+ UPDATE member
+
+
+ nickname = #{update.nickname},
+
+
+
+ email = #{update.email}
+
+
+ WHERE member_id = #{memberId}
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO member (ID, password, nickname, email, is_active, signup_date, role)
+ VALUES (#{id}, #{password}, #{nickname}, #{email}, 1, NOW(), #{role});
+
+
+
+
+
+
+
+
+
+
diff --git a/codeBoy_backend/src/main/resources/mappers/ProblemMapper.xml b/codeBoy_backend/src/main/resources/mappers/ProblemMapper.xml
index b994f53..ff28a26 100644
--- a/codeBoy_backend/src/main/resources/mappers/ProblemMapper.xml
+++ b/codeBoy_backend/src/main/resources/mappers/ProblemMapper.xml
@@ -1 +1,14 @@
-
\ No newline at end of file
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/codeBoy_backend/src/main/resources/mappers/QuizRoomMapper.xml b/codeBoy_backend/src/main/resources/mappers/QuizRoomMapper.xml
index d5660c4..a89ba62 100644
--- a/codeBoy_backend/src/main/resources/mappers/QuizRoomMapper.xml
+++ b/codeBoy_backend/src/main/resources/mappers/QuizRoomMapper.xml
@@ -3,23 +3,24 @@
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
-
+
INSERT INTO
quiz_room()
VALUES();
-
+ parameterType="QuizRoomMember"
+ >
INSERT INTO
quiz_room_member(member_id, room_id, is_host)
- VALUES(#{memberId, roomId, isHost});
+ VALUES(#{memberId}, #{roomId}, #{isHost});
@@ -31,21 +32,57 @@
-
-
- DELETE FROM quiz_room_member
- WHERE room_id = #{roomId}
-
+
DELETE FROM quiz_room
WHERE room_id = #{roomId};
+
+
+
+
+
+
+
+
+
+
+
+ DELETE FROM quiz_room_member
+ WHERE room_id = #{roomId}
+ AND member_id = #{memberId}
+
+
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/codeBoy_backend/src/main/resources/mappers/ScoreMapper.xml b/codeBoy_backend/src/main/resources/mappers/ScoreMapper.xml
deleted file mode 100644
index b994f53..0000000
--- a/codeBoy_backend/src/main/resources/mappers/ScoreMapper.xml
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/codeBoy_backend/src/main/resources/mappers/UserMapper.xml b/codeBoy_backend/src/main/resources/mappers/UserMapper.xml
deleted file mode 100644
index b994f53..0000000
--- a/codeBoy_backend/src/main/resources/mappers/UserMapper.xml
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/codeBoy_backend/src/main/resources/mappers/UserProblemMapper.xml b/codeBoy_backend/src/main/resources/mappers/UserProblemMapper.xml
new file mode 100644
index 0000000..fecd538
--- /dev/null
+++ b/codeBoy_backend/src/main/resources/mappers/UserProblemMapper.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO user_problem
+ (problem_description, choice_1, choice_2, choice_3, choice_4, answer_choice, user_problem_set_id)
+ VALUES
+
+ (#{item.problemDescription},
+ #{item.choice1},
+ #{item.choice2},
+ #{item.choice3},
+ #{item.choice4},
+ #{item.answerChoice},
+ #{item.userProblemSetId})
+
+
+
+
+
+
+
+ UPDATE user_problem
+ SET problem_description = #{problemDescription},
+ choice_1 = #{choice1},
+ choice_2 = #{choice2},
+ choice_3 = #{choice3},
+ choice_4 = #{choice4},
+ answer_choice = #{answerChoice}
+ WHERE user_problem_id = #{userProblemId}
+
+
+
+
+ DELETE FROM user_problem
+ WHERE user_problem_id = #{userProblemId}
+
+
+
+
+
+
+
diff --git a/codeBoy_backend/src/main/resources/mappers/UserProblemSetMapper.xml b/codeBoy_backend/src/main/resources/mappers/UserProblemSetMapper.xml
new file mode 100644
index 0000000..eb7115f
--- /dev/null
+++ b/codeBoy_backend/src/main/resources/mappers/UserProblemSetMapper.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO user_problem_set (member_id, category, problem_set_title, created_at)
+ VALUES (#{memberId}, #{category}, #{problemSetTitle}, #{createdAt})
+
+
+
+
+ DELETE FROM user_problem_set
+ WHERE user_problem_set_id = #{userProblemSetId}
+
+
+
+
+
diff --git a/codeBoy_backend/src/main/resources/mappers/UserScoreMapper.xml b/codeBoy_backend/src/main/resources/mappers/UserScoreMapper.xml
new file mode 100644
index 0000000..3909667
--- /dev/null
+++ b/codeBoy_backend/src/main/resources/mappers/UserScoreMapper.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+ INSERT INTO user_score (member_id, score)
+ VALUES(#{memberId}, #{score})
+
+
+
+
+
+
+
+ UPDATE user_score
+ SET score = #{score}
+ WHERE member_id = #{memberId}
+
+
+