diff --git a/src/main/java/com/example/smartair/controller/homecontroller/HomeController.java b/src/main/java/com/example/smartair/controller/homecontroller/HomeController.java new file mode 100644 index 0000000..24c3eb9 --- /dev/null +++ b/src/main/java/com/example/smartair/controller/homecontroller/HomeController.java @@ -0,0 +1,32 @@ +package com.example.smartair.controller.homecontroller; + +import ch.qos.logback.core.model.Model; +import com.example.smartair.dto.TrackProgressDto; +import com.example.smartair.service.TrackService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +import java.util.List; + +@Controller +@RequiredArgsConstructor +public class HomeController { + + private final TrackService trackService; + + @GetMapping("/home") + public String showMyProgress(Model model) { // 1. Model 객체를 파라미터로 추가 + // TODO: 추후 Spring Security 등과 연동하여 실제 로그인한 사용자 ID를 가져와야 함 + Long currentStudentId = 1L; // 2. 테스트용 임시 학생 ID 사용 + + // 3. 학생의 이수 현황을 계산하는 새로운 서비스 메서드 호출 + List progressData = trackService.calculateTrackProgress(currentStudentId); + + // 4. 조회된 데이터를 "progressData"라는 이름으로 모델에 추가 + //model.addAttribute("progressData", progressData); + + // 5. 데이터를 표시할 뷰(html)의 이름을 반환 + return "home"; + } +} diff --git a/src/main/java/com/example/smartair/dto/CourseDto.java b/src/main/java/com/example/smartair/dto/CourseDto.java new file mode 100644 index 0000000..133278a --- /dev/null +++ b/src/main/java/com/example/smartair/dto/CourseDto.java @@ -0,0 +1,17 @@ +package com.example.smartair.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +/** + * 교과목 정보를 담는 DTO + */ +@Getter +@Setter +@AllArgsConstructor // 모든 필드를 인자로 받는 생성자 자동 생성 +public class CourseDto { + + private String courseName; // 현재 과목명 + private String courseAlias; // 과거 과목명 (없으면 null) +} diff --git a/src/main/java/com/example/smartair/dto/TrackProgressDto.java b/src/main/java/com/example/smartair/dto/TrackProgressDto.java new file mode 100644 index 0000000..1528031 --- /dev/null +++ b/src/main/java/com/example/smartair/dto/TrackProgressDto.java @@ -0,0 +1,22 @@ +package com.example.smartair.dto; + +import lombok.Getter; +import lombok.Setter; +import java.util.List; + +/** + * 하나의 트랙에 대한 학생의 이수 진행 현황 정보를 담는 DTO + */ +@Getter +@Setter +public class TrackProgressDto { + + private String trackName; // 트랙 이름 (예: "AI 콘텐츠") + private String department; // 소속 학과 + private int completedCount; // 이수한 과목 수 + private int requiredCount; // 이수 필요 과목 수 (예: 6) + private boolean isCompleted; // 트랙 이수 완료 여부 + + private List completedCourses; // 이수한 과목 목록 + private List remainingCourses; // 이수해야 할 남은 과목 목록 +} diff --git a/src/main/java/com/example/smartair/entity/StudentCourse.java b/src/main/java/com/example/smartair/entity/StudentCourse.java new file mode 100644 index 0000000..0624742 --- /dev/null +++ b/src/main/java/com/example/smartair/entity/StudentCourse.java @@ -0,0 +1,17 @@ +package com.example.smartair.entity; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.Getter; + +@Entity +@Getter +public class StudentCourse { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private Long studentId; // 학생 ID (로그인 연동) + private String courseName; +} diff --git a/src/main/java/com/example/smartair/entity/Track.java b/src/main/java/com/example/smartair/entity/Track.java new file mode 100644 index 0000000..124ddbb --- /dev/null +++ b/src/main/java/com/example/smartair/entity/Track.java @@ -0,0 +1,25 @@ +package com.example.smartair.entity; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter @Setter +public class Track { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String name; + private String department; + + @OneToMany(mappedBy = "track", cascade = CascadeType.ALL) + private List courses = new ArrayList<>(); +// public void addCourse(TrackCourse course) { +// courses.add(course); +// course.setTrack(this); +// } +} diff --git a/src/main/java/com/example/smartair/entity/TrackCourse.java b/src/main/java/com/example/smartair/entity/TrackCourse.java new file mode 100644 index 0000000..968b5cd --- /dev/null +++ b/src/main/java/com/example/smartair/entity/TrackCourse.java @@ -0,0 +1,19 @@ +package com.example.smartair.entity; + +import jakarta.persistence.*; +import lombok.Getter; + +@Entity +@Getter +public class TrackCourse { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String courseName; // 현재 과목명 + private String courseAlias; // 구(과거) 과목명 + + @ManyToOne + @JoinColumn(name = "track_id") + private Track track; + // Getters and Setters +} diff --git a/src/main/java/com/example/smartair/repository/StudentCourseRepository.java b/src/main/java/com/example/smartair/repository/StudentCourseRepository.java new file mode 100644 index 0000000..2f9daac --- /dev/null +++ b/src/main/java/com/example/smartair/repository/StudentCourseRepository.java @@ -0,0 +1,15 @@ +package com.example.smartair.repository; + +import com.example.smartair.entity.StudentCourse; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +public interface StudentCourseRepository extends JpaRepository { + + List findByStudentId(Long studentId); + + @Transactional + void deleteByStudentId(Long studentId); // 학생 ID로 이수과목 한번에 삭제 +} diff --git a/src/main/java/com/example/smartair/repository/TrackCourseRepository.java b/src/main/java/com/example/smartair/repository/TrackCourseRepository.java new file mode 100644 index 0000000..e5e2d1c --- /dev/null +++ b/src/main/java/com/example/smartair/repository/TrackCourseRepository.java @@ -0,0 +1,7 @@ +package com.example.smartair.repository; + +import com.example.smartair.entity.TrackCourse; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TrackCourseRepository extends JpaRepository { +} diff --git a/src/main/java/com/example/smartair/repository/TrackRepository.java b/src/main/java/com/example/smartair/repository/TrackRepository.java new file mode 100644 index 0000000..3269a91 --- /dev/null +++ b/src/main/java/com/example/smartair/repository/TrackRepository.java @@ -0,0 +1,12 @@ +package com.example.smartair.repository; + +import com.example.smartair.entity.Track; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import java.util.List; + +public interface TrackRepository extends JpaRepository { + + @Query("SELECT DISTINCT t FROM Track t LEFT JOIN FETCH t.courses") + List findAllWithCourses(); +} diff --git a/src/main/java/com/example/smartair/service/TrackService.java b/src/main/java/com/example/smartair/service/TrackService.java new file mode 100644 index 0000000..baba871 --- /dev/null +++ b/src/main/java/com/example/smartair/service/TrackService.java @@ -0,0 +1,92 @@ +package com.example.smartair.service; + +import com.example.smartair.dto.CourseDto; +import com.example.smartair.dto.TrackProgressDto; +import com.example.smartair.entity.StudentCourse; +import com.example.smartair.entity.Track; +import com.example.smartair.entity.TrackCourse; +import com.example.smartair.repository.StudentCourseRepository; +import com.example.smartair.repository.TrackRepository; +import org.springframework.stereotype.Service; +import lombok.RequiredArgsConstructor; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class TrackService { + + private final TrackRepository trackRepository; + private final StudentCourseRepository studentCourseRepository; // 기존 기능 + + // ... (기존의 saveStudentCoursesFromExcel, calculateTrackProgress 메서드) ... + + /** + * 모든 트랙 정보를 학과별로 그룹화하여 반환하는 메서드 + */ + public Map> getAllTracksGroupedByDepartment() { + // 1. DB에서 모든 트랙과 관련 과목들을 한번에 조회 + List allTracks = trackRepository.findAllWithCourses(); + + // 2. 조회된 트랙 리스트를 '학과' 이름으로 그룹화하여 Map으로 변환 후 반환 + return allTracks.stream() + .collect(Collectors.groupingBy(Track::getDepartment)); + } + + public List calculateTrackProgress(Long studentId) { + // 1. 학생의 이수 과목 목록 조회 + Set completedCourseNames = studentCourseRepository.findByStudentId(studentId) + .stream() + .map(StudentCourse::getCourseName) + .collect(Collectors.toSet()); + + // 2. 모든 트랙 정보 조회 + List allTracks = trackRepository.findAllWithCourses(); + + List progressList = new ArrayList<>(); + + // 3. 각 트랙별로 진행 현황 계산 + for (Track track : allTracks) { + + // 현재 트랙에서 완료한 과목과 남은 과목을 담을 리스트 초기화 + List completedInThisTrack = new ArrayList<>(); + List remainingInThisTrack = new ArrayList<>(); + + // 현재 트랙에 속한 모든 교과목을 하나씩 확인 + for (TrackCourse trackCourse : track.getCourses()) { + + // 학생이 해당 과목을 이수했는지 확인 (현재 이름 또는 과거 이름으로 체크) + if (completedCourseNames.contains(trackCourse.getCourseName()) || + (trackCourse.getCourseAlias() != null && completedCourseNames.contains(trackCourse.getCourseAlias()))) { + // 이수한 경우: 완료 리스트에 추가 + completedInThisTrack.add(new CourseDto(trackCourse.getCourseName(), trackCourse.getCourseAlias())); + } else { + // 이수하지 않은 경우: 남은 과목 리스트에 추가 + remainingInThisTrack.add(new CourseDto(trackCourse.getCourseName(), trackCourse.getCourseAlias())); + } + } + + // 최종 결과를 담을 DTO 객체 생성 및 데이터 세팅 + TrackProgressDto progressDto = new TrackProgressDto(); + progressDto.setTrackName(track.getName()); + progressDto.setDepartment(track.getDepartment()); + + int completedCount = completedInThisTrack.size(); + progressDto.setCompletedCount(completedCount); + progressDto.setRequiredCount(6); // 트랙 이수 요구 과목 수는 6개 + progressDto.setCompleted(completedCount >= 6); // 6개 이상이면 true + + progressDto.setCompletedCourses(completedInThisTrack); + progressDto.setRemainingCourses(remainingInThisTrack); + + // 완성된 DTO를 최종 결과 리스트에 추가 + progressList.add(progressDto); + } + + return progressList; + } +}