Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,52 +1,51 @@
package raisetech.student.management.controller;

import jakarta.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import raisetech.student.management.controller.request.SearchStudentRequest;
import raisetech.student.management.data.ApplicationStatus;
import raisetech.student.management.domain.ApplicationStatusType;
import raisetech.student.management.domain.StudentDetail;
import raisetech.student.management.exception.ResourceNotFoundException;
import raisetech.student.management.service.StudentService;
import raisetech.student.management.validation.CreateValidationGroup;
import raisetech.student.management.validation.UpdateValidationGroup;

/**
* 受講生の検索や登録、更新などを置こうなREST APIを受け付ける実行されるControllerです。
* 受講生の検索や登録、更新などを行うREST APIを受け付ける実行されるControllerです。
*/

@RestController
public class StudentController {

private StudentService service;


@Autowired
public StudentController(StudentService service) {
this.service = service;
}


/**
* 受講生詳細一覧検索。 全件検索を行うので、条件指定は行いません。* @return 受講生詳細一覧(全件)
* 受講生検索(ID指定)。
* RESTful: GET /students/{id}
* @param id 受講生ID
* @return 受講生
*/
@GetMapping("/studentList")
public List<StudentDetail> getStudentList() {
return service.searchStudentList();
}

/**
* 受講生詳細の検索。 IDに基づく任意の受講生情報取得を行います。
*
* @param id 受講生ID @return 受講生
*/
@GetMapping("/student/{id}")
@GetMapping("/students/{id}")
public StudentDetail getStudent(@PathVariable @NotNull Integer id) {
StudentDetail student = service.searchStudent(id);
if (student == null) {
Expand All @@ -55,31 +54,72 @@ public StudentDetail getStudent(@PathVariable @NotNull Integer id) {
return student;
}

/**
* 受講生を条件で検索します。
* RESTful: GET /students?name=...&age=...
* @param request 検索条件を保持するDTO
* @return 検索結果の受講生詳細一覧
*/
@GetMapping("/students")
public List<StudentDetail> searchStudentList(@ModelAttribute SearchStudentRequest request) {
return service.searchStudentList(request.toSearchCondition());
}

/**
* 受講生詳細の登録。
*
* @ param studentDetail 受講生詳細
* @ return 実行結果
* RESTful: POST /students
*/
@PostMapping("/registerStudent")
@PostMapping("/students")
public ResponseEntity<StudentDetail> registerStudent(
@RequestBody @Validated(CreateValidationGroup.class)
StudentDetail studentDetail) {
@RequestBody @Validated(CreateValidationGroup.class)
StudentDetail studentDetail) {
StudentDetail responseStudentDetail = service.registerStudent(studentDetail);
return ResponseEntity.ok(responseStudentDetail);
}

/**
* 受講生詳細の更新を行います。キャンセルフラグの更新もここで行います(理論削除)
*
* @ param studentDetail 受講生詳細
* @ return 実行結果
* 受講生詳細の更新を行います。
* RESTful: PUT /students
*/
@PutMapping("/updateStudent")
@PutMapping("/students")
public ResponseEntity<String> updateStudent(
@RequestBody @Validated(UpdateValidationGroup.class)
StudentDetail studentDetail) {
@RequestBody @Validated(UpdateValidationGroup.class)
StudentDetail studentDetail) {
service.updateStudent(studentDetail);
return ResponseEntity.ok("success updating");
}
}


/**
* 申し込み状況の選択肢一覧を取得します。
* RESTful: GET /application-statuses/options
* @return 申し込み状況の日本語名リスト
*/
@GetMapping("/application-statuses/options")
public List<String> getApplicationStatusOptions() {
return Arrays.stream(ApplicationStatusType.values())
.map(ApplicationStatusType::getJapaneseName)
.collect(Collectors.toList());
}

/**
* 全てのコースの申し込み状況一覧を取得します。
* RESTful: GET /application-statuses
* @return 申し込み状況一覧
*/
@GetMapping("/application-statuses")
public List<ApplicationStatus> getApplicationStatusList() {
return service.searchApplicationStatusList();
}

/**
* IDに紐づくコースの申し込み状況を取得します。
* RESTful: GET /application-statuses/{id}
* @param id 申し込み状況ID
* @return 申し込み状況
*/
@GetMapping("/application-statuses/{id}")
public ApplicationStatus getApplicationStatus(@PathVariable @NotNull Integer id) {
return service.searchApplicationStatus(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,52 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
import raisetech.student.management.data.ApplicationStatus;
import raisetech.student.management.data.Student;
import raisetech.student.management.data.StudentCourse;
import raisetech.student.management.domain.StudentDetail;

/*
* 受講生詳細を受講生と受講生コース情報、もしくはその逆の変換を行うコンバーターです
* */
@Component
public class StudentConverter {

/*
* 受講生に紐づく受講生コース情報をマッピングする。
* 受講生コース情報は受講生に対して複数存在するので、ループをまわして受講生詳細情報を組み立てる。
*
* @param students 受講生一覧
* @param StudentCourses 受講生コース情報のリスト
* @return 受講生詳細情報のリスト
* */
public List<StudentDetail> convertStudentDetails(List<Student> students, List<StudentCourse> studentCours) {
List<StudentDetail> studentDetails = new ArrayList<>();
students.forEach(student -> {
StudentDetail studentDetail = new StudentDetail();
studentDetail.setStudent(student);

List<StudentCourse> convertStudentCours = studentCours.stream()
.filter(studentCourse -> student.getId().equals(studentCourse.getStudentId()))
.collect(Collectors.toList());
studentDetail.setStudentCourseList(convertStudentCours);
studentDetails.add(studentDetail);
});
return studentDetails;
}
}
public List<StudentDetail> convertStudentDetails(List<Student> students, List<StudentCourse> studentCourses,
List<ApplicationStatus> applicationStatuses) {
List<StudentDetail> studentDetails = new ArrayList<>();

// 重複する courseId がある場合、最初に見つかった ApplicationStatus を優先 (後のものを破棄) するマージ関数を追加
Map<Integer, ApplicationStatus> applicationStatusMap = applicationStatuses.stream()
.filter(as -> as.getCourseId() != null)
.collect(Collectors.toMap(
ApplicationStatus::getCourseId,
Function.identity(),
(existing, replacement) -> existing // マージ関数: 既存の値を保持
));

students.forEach(student -> {
StudentDetail studentDetail = new StudentDetail();
studentDetail.setStudent(student);

// courseId と applicationIdは 1:1 対応で重複することはないが、念のため重複対応
List<StudentCourse> convertStudentCourse = studentCourses.stream()
.filter(studentCourse -> student.getId().equals(studentCourse.getStudentId()))
.map(studentCourse -> {
ApplicationStatus status = applicationStatusMap.get(studentCourse.getId());

if (status != null) {
studentCourse.setApplicationStatus(status);
}

return studentCourse;
})
.collect(Collectors.toList());

studentDetail.setStudentCourseList(convertStudentCourse);
studentDetails.add(studentDetail);
});
return studentDetails;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package raisetech.student.management.controller.request;

import lombok.Getter;
import lombok.Setter;
import raisetech.student.management.data.Student;

@Getter
@Setter
public class SearchStudentRequest {
// Studentの検索に使用するフィールドを定義
private Integer id;
private String name;
private String kanaName;
private String nickname;
private String email;
private String area;
private Integer age;
private String sex;
// isDeleted は検索条件として不適切なので省略(必要であれば追加)

/**
* リクエストDTOを検索条件として使用するデータオブジェクトに変換するヘルパーメソッド。
* Service層以下で利用する Student オブジェクトに変換します。
* @return 検索条件として設定された Student オブジェクト
*/
public Student toSearchCondition() {
Student student = new Student();
student.setId(this.id);
student.setName(this.name);
student.setKanaName(this.kanaName);
student.setNickname(this.nickname);
student.setEmail(this.email);
student.setArea(this.area);
student.setAge(this.age);
student.setSex(this.sex);
// isDeletedなど、Requestにないフィールドはデフォルト値のまま
return student;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package raisetech.student.management.data;

import java.time.LocalDateTime;
import lombok.Getter;
import lombok.Setter;

/**
* コースの申込状況を扱うオブジェクトです。
*/
@Getter
@Setter
public class ApplicationStatus {

private Integer id;
private Integer courseId;
private String status;
private LocalDateTime createAt;
private LocalDateTime updateAt;
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ public class StudentCourse {
private String courseName;
private LocalDateTime courseStartAt;
private LocalDateTime courseEndAt;

private ApplicationStatus applicationStatus;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package raisetech.student.management.domain;

/**
* コースの申し込み状況を定義するEnum
* (仮申込、本申込、受講中、受講終了の4種類)
*/
public enum ApplicationStatusType {

TEMPORARY_APPLICATION("仮申込"),
FULL_APPLICATION("本申込"),
IN_PROGRESS("受講中"),
COMPLETED("受講終了");

private final String japaneseName;

ApplicationStatusType(String japaneseName) {
this.japaneseName = japaneseName;
}

/**
* 日本語名を取得します。
*/
public String getJapaneseName() {
return japaneseName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,4 @@ public class StudentDetail {

@Valid
private List<StudentCourse> studentCourseList = new ArrayList<>();

}
Loading