Open mohammad-fahs opened 2 months ago
I will only show the relevant code snippets after task 3. For the full project, you can download it here: task4-student-ms.zip
package com.dgpad.task4_student_ms.controller;
import com.dgpad.task4_student_ms.DTO.request.CreateStudentDTO;
import com.dgpad.task4_student_ms.DTO.request.UpdateStudentDTO;
import com.dgpad.task4_student_ms.DTO.response.ApiResponse;
import com.dgpad.task4_student_ms.model.Student;
import com.dgpad.task4_student_ms.service.StudentService;
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/students")
public class StudentController {
@Autowired
private StudentService studentService;
@PostMapping
public ResponseEntity<ApiResponse<Student>> createStudent(@RequestBody CreateStudentDTO student) {
try {
Student savedStudent = studentService.saveStudent(student);
return ResponseEntity.ok(new ApiResponse<>(true, savedStudent, "Student created successfully", HttpStatus.OK.value()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to create Student: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
@GetMapping
public ResponseEntity<ApiResponse<List<Student>>> getAllStudents() {
try {
List<Student> students = studentService.getAllStudents();
return ResponseEntity.ok(new ApiResponse<>(true, students, "Students retrieved successfully", HttpStatus.OK.value()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to retrieve Students: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
@GetMapping("/{id}")
public ResponseEntity<ApiResponse<Student>> getStudentById(@PathVariable Long id) {
try {
Student student = studentService.getStudentById(id);
return ResponseEntity.ok(new ApiResponse<>(true, student, "Student retrieved successfully", HttpStatus.OK.value()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to retrieve Student: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
@PutMapping("/{id}")
public ResponseEntity<ApiResponse<Student>> updateStudent(@PathVariable Long id, @RequestBody UpdateStudentDTO student) {
try {
Student updatedStudent = studentService.updateStudent(id, student);
return ResponseEntity.ok(new ApiResponse<>(true, updatedStudent, "Student updated successfully", HttpStatus.OK.value()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to update Student: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
@DeleteMapping("/{id}")
public ResponseEntity<ApiResponse<Void>> deleteStudent(@PathVariable Long id) {
try {
studentService.deleteStudent(id);
return ResponseEntity.ok(new ApiResponse<>(true, null, "Student deleted successfully", HttpStatus.OK.value()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to delete Student: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
}
package com.dgpad.task4_student_ms.controller;
import com.dgpad.task4_student_ms.DTO.request.CreateCourseDTO;
import com.dgpad.task4_student_ms.DTO.request.UpdateCourseDTO;
import com.dgpad.task4_student_ms.DTO.response.ApiResponse;
import com.dgpad.task4_student_ms.model.Course;
import com.dgpad.task4_student_ms.service.CourseService;
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/courses")
public class CourseController {
@Autowired
private CourseService courseService;
@PostMapping
public ResponseEntity<ApiResponse<Course>> createCourse(@RequestBody CreateCourseDTO course)
{
try
{
Course savedCourse = courseService.saveCourse(course);
return ResponseEntity.ok(new ApiResponse<>(true, savedCourse, "Course created successfully", HttpStatus.OK.value()));
}
catch (Exception e)
{
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to create Course: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
@GetMapping
public ResponseEntity<ApiResponse<List<Course>>> getAllCourses()
{
try
{
List<Course> courses = courseService.getAllCourses();
return ResponseEntity.ok(new ApiResponse<>(true, courses, "Courses retrieved successfully", HttpStatus.OK.value()));
}
catch (Exception e)
{
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to retrieve Courses: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
@GetMapping("/{id}")
public ResponseEntity<ApiResponse<Course>> getCourseById(@PathVariable Long id)
{
try
{
Course course = courseService.getCourseById(id);
return ResponseEntity.ok(new ApiResponse<>(true, course, "Course retrieved successfully", HttpStatus.OK.value()));
}
catch (Exception e)
{
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to retrieve Course: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
@PutMapping("/{id}")
public ResponseEntity<ApiResponse<Course>> updateCourse(@PathVariable Long id, @RequestBody UpdateCourseDTO course)
{
try
{
Course updatedCourse = courseService.updateCourse(id, course);
return ResponseEntity.ok(new ApiResponse<>(true, updatedCourse, "Course updated successfully", HttpStatus.OK.value()));
}
catch (Exception e)
{
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to update Course: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
@DeleteMapping("/{id}")
public ResponseEntity<ApiResponse<Void>> deleteCourse(@PathVariable Long id)
{
try
{
courseService.deleteCourse(id);
return ResponseEntity.ok(new ApiResponse<>(true, null, "Course deleted successfully", HttpStatus.OK.value()));
}
catch (Exception e)
{
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to delete Course: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
}
package com.dgpad.task4_student_ms.controller;
import com.dgpad.task4_student_ms.DTO.request.CreateEnrollmentDTO;
import com.dgpad.task4_student_ms.DTO.request.UpdateEnrollmentDTO;
import com.dgpad.task4_student_ms.DTO.response.ApiResponse;
import com.dgpad.task4_student_ms.DTO.response.EnrollmentResponseDTO;
import com.dgpad.task4_student_ms.service.EnrollmentService;
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")
public class EnrollmentController {
@Autowired
private EnrollmentService enrollmentService;
@PostMapping("/enrollments")
public ResponseEntity<ApiResponse<EnrollmentResponseDTO>> createEnrollment(@RequestBody CreateEnrollmentDTO enrollmentDTO) {
try {
EnrollmentResponseDTO enrollmentDetails = enrollmentService.saveEnrollment(enrollmentDTO);
return ResponseEntity.ok(new ApiResponse<>(true, enrollmentDetails, "Enrollment created successfully", HttpStatus.CREATED.value()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to create enrollment: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
@GetMapping("/enrollments")
public ResponseEntity<ApiResponse<List<EnrollmentResponseDTO>>> getAllEnrollments() {
try {
List<EnrollmentResponseDTO> enrollments = enrollmentService.getAllEnrollments();
return ResponseEntity.ok(new ApiResponse<>(true, enrollments, "Enrollments retrieved successfully", HttpStatus.OK.value()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to retrieve enrollments: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
@GetMapping("/students/{studentId}/enrollments")
public ResponseEntity<ApiResponse<List<EnrollmentResponseDTO>>> getEnrollmentsForStudent(@PathVariable Long studentId) {
try {
List<EnrollmentResponseDTO> enrollments = enrollmentService.getEnrollmentsForStudent(studentId);
return ResponseEntity.ok(new ApiResponse<>(true, enrollments, "Enrollments for student retrieved successfully", HttpStatus.OK.value()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to retrieve enrollments for student: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
@GetMapping("/courses/{courseId}/enrollments")
public ResponseEntity<ApiResponse<List<EnrollmentResponseDTO>>> getEnrollmentsForCourse(@PathVariable Long courseId) {
try {
List<EnrollmentResponseDTO> enrollments = enrollmentService.getEnrollmentsForCourse(courseId);
return ResponseEntity.ok(new ApiResponse<>(true, enrollments, "Enrollments for course retrieved successfully", HttpStatus.OK.value()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to retrieve enrollments for course: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
@PutMapping("/enrollments/{id}")
public ResponseEntity<ApiResponse<EnrollmentResponseDTO>> updateEnrollment(@PathVariable Long id, @RequestBody UpdateEnrollmentDTO enrollmentDTO) {
try {
EnrollmentResponseDTO updatedEnrollment = enrollmentService.updateEnrollment(id, enrollmentDTO);
return updatedEnrollment != null
? ResponseEntity.ok(new ApiResponse<>(true, updatedEnrollment, "Enrollment updated successfully", HttpStatus.OK.value()))
: ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ApiResponse<>(false, null, "Enrollment not found", HttpStatus.NOT_FOUND.value()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to update enrollment: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
@DeleteMapping("/enrollments/{id}")
public ResponseEntity<ApiResponse<Void>> deleteEnrollment(@PathVariable Long id) {
try {
enrollmentService.deleteEnrollment(id);
return ResponseEntity.ok(new ApiResponse<>(true, null, "Enrollment deleted successfully", HttpStatus.NO_CONTENT.value()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>(false, null, "Failed to delete enrollment: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}
}
package com.dgpad.task4_student_ms.repository;
import com.dgpad.task4_student_ms.model.Student;
import org.springframework.data.jpa.repository.JpaRepository;
public interface StudentRepository extends JpaRepository<Student, Long> {
}
package com.dgpad.task4_student_ms.repository;
import com.dgpad.task4_student_ms.model.Course;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CourseRepository extends JpaRepository<Course, Long> {
}
package com.dgpad.task4_student_ms.repository;
import com.dgpad.task4_student_ms.model.Enrollment;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface EnrollmentRepository extends JpaRepository<Enrollment, Long> {
List<Enrollment> findByStudentId(Long studentId);
List<Enrollment> findByCourseId(Long courseId);
}
package com.dgpad.task4_student_ms.service;
import com.dgpad.task4_student_ms.DTO.request.CreateStudentDTO;
import com.dgpad.task4_student_ms.DTO.request.UpdateStudentDTO;
import com.dgpad.task4_student_ms.model.Enrollment;
import com.dgpad.task4_student_ms.model.Student;
import com.dgpad.task4_student_ms.repository.EnrollmentRepository;
import com.dgpad.task4_student_ms.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class StudentService {
@Autowired
private StudentRepository studentRepository;
@Autowired
private EnrollmentRepository enrollmentRepository;
public Student saveStudent(CreateStudentDTO studentDTO)
{
Student student = new Student(studentDTO.getFirstName(), studentDTO.getLastName(), studentDTO.getEmail(), studentDTO.getAge());
return studentRepository.save(student);
}
public List<Student> getAllStudents()
{
return studentRepository.findAll();
}
public Student getStudentById(Long id)
{
return studentRepository.findById(id).orElse(null);
}
public Student updateStudent(Long id, UpdateStudentDTO updatedStudentDTO)
{
Optional<Student> existingStudentOptional = studentRepository.findById(id);
if (existingStudentOptional.isPresent())
{
Student existingStudent = existingStudentOptional.get();
existingStudent.setFirstName(updatedStudentDTO.getFirstName());
existingStudent.setLastName(updatedStudentDTO.getLastName());
existingStudent.setEmail(updatedStudentDTO.getEmail());
existingStudent.setAge(updatedStudentDTO.getAge());
return studentRepository.save(existingStudent);
}
else
{
return null;
}
}
public void deleteStudent(Long id)
{
studentRepository.deleteById(id);
}
public int getTotalCredits(Long studentId)
{
List<Enrollment> enrollments = enrollmentRepository.findByStudentId(studentId);
return enrollments.stream()
.mapToInt(enrollment -> enrollment.getCourse().getCredits())
.sum();
}
}
package com.dgpad.task4_student_ms.service;
import com.dgpad.task4_student_ms.DTO.request.CreateCourseDTO;
import com.dgpad.task4_student_ms.DTO.request.UpdateCourseDTO;
import com.dgpad.task4_student_ms.model.Course;
import com.dgpad.task4_student_ms.repository.CourseRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class CourseService {
@Autowired
private CourseRepository courseRepository;
public Course saveCourse(CreateCourseDTO courseDTO)
{
Course course = new Course(courseDTO.getName(), courseDTO.getCode(), courseDTO.getInstructor(), courseDTO.getCredits());
return courseRepository.save(course);
}
public List<Course> getAllCourses()
{
return courseRepository.findAll();
}
public Course getCourseById(Long id)
{
return courseRepository.findById(id).orElse(null);
}
public Course updateCourse(Long id, UpdateCourseDTO updatedCourseDTO)
{
Optional<Course> existingCourseOptional = courseRepository.findById(id);
if (existingCourseOptional.isPresent())
{
Course existingCourse = existingCourseOptional.get();
existingCourse.setCourseName(updatedCourseDTO.getName());
existingCourse.setCourseCode(updatedCourseDTO.getCode());
existingCourse.setInstructor(updatedCourseDTO.getInstructor());
existingCourse.setCredits(updatedCourseDTO.getCredits());
return courseRepository.save(existingCourse);
}
else
{
return null;
}
}
public void deleteCourse(Long id)
{
courseRepository.deleteById(id);
}
}
package com.dgpad.task4_student_ms.service;
import com.dgpad.task4_student_ms.DTO.request.CreateEnrollmentDTO;
import com.dgpad.task4_student_ms.DTO.request.UpdateEnrollmentDTO;
import com.dgpad.task4_student_ms.DTO.response.EnrollmentResponseDTO;
import com.dgpad.task4_student_ms.model.Course;
import com.dgpad.task4_student_ms.model.Enrollment;
import com.dgpad.task4_student_ms.model.Student;
import com.dgpad.task4_student_ms.repository.CourseRepository;
import com.dgpad.task4_student_ms.repository.EnrollmentRepository;
import com.dgpad.task4_student_ms.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
public class EnrollmentService {
@Autowired
private EnrollmentRepository enrollmentRepository;
@Autowired
private StudentRepository studentRepository;
@Autowired
private CourseRepository courseRepository;
@Autowired
private StudentService studentService;
private static final int MAX_CREDITS = 17;
public EnrollmentResponseDTO saveEnrollment(CreateEnrollmentDTO enrollmentDTO)
{
Optional<Student> studentOptional = studentRepository.findById(enrollmentDTO.getStudentId());
Optional<Course> courseOptional = courseRepository.findById(enrollmentDTO.getCourseId());
if (studentOptional.isPresent() && courseOptional.isPresent()) {
Student student = studentOptional.get();
Course course = courseOptional.get();
int totalCredits = studentService.getTotalCredits(student.getId());
if (totalCredits + course.getCredits() > MAX_CREDITS) {
throw new IllegalArgumentException("Student cannot exceed the maximum allowed credits.");
}
Enrollment enrollment = new Enrollment();
enrollment.setStudent(student);
enrollment.setCourse(course);
enrollment.setEnrollmentDate(enrollmentDTO.getEnrollmentDate());
enrollment.setGrade(enrollmentDTO.getGrade());
Enrollment savedEnrollment = enrollmentRepository.save(enrollment);
return new EnrollmentResponseDTO(
savedEnrollment.getId(),
savedEnrollment.getEnrollmentDate(),
savedEnrollment.getGrade(),
savedEnrollment.getStudent(),
savedEnrollment.getCourse()
);
}
return null;
}
public List<EnrollmentResponseDTO> getAllEnrollments() {
List<Enrollment> enrollments = enrollmentRepository.findAll();
return enrollments.stream()
.map(enrollment -> new EnrollmentResponseDTO(
enrollment.getId(),
enrollment.getEnrollmentDate(),
enrollment.getGrade(),
enrollment.getStudent(),
enrollment.getCourse()
))
.collect(Collectors.toList());
}
public List<EnrollmentResponseDTO> getEnrollmentsForStudent(Long studentId) {
List<Enrollment> enrollments = enrollmentRepository.findByStudentId(studentId);
return enrollments.stream()
.map(enrollment -> new EnrollmentResponseDTO(
enrollment.getId(),
enrollment.getEnrollmentDate(),
enrollment.getGrade(),
enrollment.getStudent(),
enrollment.getCourse()
))
.collect(Collectors.toList());
}
public List<EnrollmentResponseDTO> getEnrollmentsForCourse(Long courseId) {
List<Enrollment> enrollments = enrollmentRepository.findByCourseId(courseId);
return enrollments.stream()
.map(enrollment -> new EnrollmentResponseDTO(
enrollment.getId(),
enrollment.getEnrollmentDate(),
enrollment.getGrade(),
enrollment.getStudent(),
enrollment.getCourse()
))
.collect(Collectors.toList());
}
public EnrollmentResponseDTO updateEnrollment(Long id, UpdateEnrollmentDTO enrollmentDTO) {
Optional<Enrollment> existingEnrollmentOptional = enrollmentRepository.findById(id);
if (existingEnrollmentOptional.isPresent()) {
Enrollment existingEnrollment = existingEnrollmentOptional.get();
existingEnrollment.setGrade(enrollmentDTO.getGrade());
existingEnrollment.setEnrollmentDate(enrollmentDTO.getEnrollmentDate());
Enrollment updatedEnrollment = enrollmentRepository.save(existingEnrollment);
return new EnrollmentResponseDTO(
updatedEnrollment.getId(),
updatedEnrollment.getEnrollmentDate(),
updatedEnrollment.getGrade(),
updatedEnrollment.getStudent(),
updatedEnrollment.getCourse()
);
}
return null;
}
public void deleteEnrollment(Long id) {
enrollmentRepository.deleteById(id);
}
}
Task: Create an Advanced Student Management System Using Spring Boot, MySQL Database, and REST APIs
Objective:
Your task is to create an advanced Student Management System using Spring Boot, MySQL, and RESTful APIs. This system will manage not only students but also courses and enrollments. You will create a relational database structure that includes multiple entities and relationships between them. This exercise will help you understand how to build a more complex CRUD application with multiple entities and relationships using Spring Boot, JPA, and MySQL.
user this discussion for help:
https://github.com/dgPadBootcamps/Java-Bootcamp-2024/discussions/195
Make Sure to use the best practice architecture discussed in the latest sessions
Requirements:
student_management
.application.properties
(orapplication.yml
) file, configure the connection to the MySQL database, including the database URL, username, and password.Entity Classes:
a. Student:
id
: Primary key, auto-generated.firstName
: String, not null.lastName
: String, not null.email
: String, not null, unique.age
: Integer.enrollments
: One-to-Many relationship with theEnrollment
entity.b. Course:
id
: Primary key, auto-generated.courseName
: String, not null.courseCode
: String, not null, unique.credits
: Integer.instructor
: String, not null.enrollments
: One-to-Many relationship with theEnrollment
entity.c. Enrollment:
id
: Primary key, auto-generated.student
: Many-to-One relationship with theStudent
entity.course
: Many-to-One relationship with theCourse
entity.enrollmentDate
: Date of enrollment.grade
: String, grade received in the course.@OneToMany
,@ManyToOne
, and@JoinColumn
.StudentRepository
,CourseRepository
, andEnrollmentRepository
should extendJpaRepository
.StudentService
,CourseService
, andEnrollmentService
.Controller Layer:
a. Student Endpoints:
POST /api/students
GET /api/students
GET /api/students/{id}
id
(the student's ID).PUT /api/students/{id}
id
(the student's ID).DELETE /api/students/{id}
id
(the student's ID).b. Course Endpoints:
POST /api/courses
GET /api/courses
GET /api/courses/{id}
id
(the course's ID).PUT /api/courses/{id}
id
(the course's ID).DELETE /api/courses/{id}
id
(the course's ID).c. Enrollment Endpoints:
POST /api/enrollments
studentId
,courseId
,enrollmentDate
, andgrade
.GET /api/enrollments
GET /api/students/{studentId}/enrollments
studentId
.GET /api/courses/{courseId}/enrollments
courseId
.PUT /api/enrollments/{id}
id
(the enrollment's ID).DELETE /api/enrollments/{id}
id
(the enrollment's ID).email
field in theStudent
entity is unique and follows a valid email format.courseCode
field in theCourse
entity is unique.grade
field in theEnrollment
entity follows a specific format (e.g.,A
,B
,C
, etc.).Student
,Course
, andEnrollment
) are correctly handled in both the database and the application.The task is submitted using Postman collection and code snippets as usual in addition to screenshots from the database