diff --git a/src/main/java/id/ac/ui/cs/advprog/tutorial0/controller/CourseController.java b/src/main/java/id/ac/ui/cs/advprog/tutorial0/controller/CourseController.java new file mode 100644 index 0000000000000000000000000000000000000000..ce9f54e776b5d002960c39a62a8d05d5d80918d3 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/tutorial0/controller/CourseController.java @@ -0,0 +1,45 @@ +package id.ac.ui.cs.advprog.tutorial0.controller; + +import id.ac.ui.cs.advprog.tutorial0.exception.EmptyCourseName; +import id.ac.ui.cs.advprog.tutorial0.model.Course; +import id.ac.ui.cs.advprog.tutorial0.service.CourseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Controller +@RequestMapping("/course") +public class CourseController { + + @Autowired + private CourseService courseService; + + @GetMapping("/list") + public String courseListPage(Model model){ + List<Course> allCourses = courseService.findAll(); + model.addAttribute("courses", allCourses); + return "courseList"; + } + + @GetMapping("/create") + public String createCoursePage(Model model){ + Course course = new Course(); + model.addAttribute("course", course); + return "createCourse"; + } + + @PostMapping("/create") + public String createCoursePost(@ModelAttribute Course course, Model model){ + try { + courseService.create(course); + } catch (EmptyCourseName e){ + model.addAttribute("error", e); + model.addAttribute("course", course); + return "createCourse"; + } + return "redirect:list"; + } +} diff --git a/src/main/java/id/ac/ui/cs/advprog/tutorial0/controller/StudentController.java b/src/main/java/id/ac/ui/cs/advprog/tutorial0/controller/StudentController.java new file mode 100644 index 0000000000000000000000000000000000000000..80fa1a675092f6437f9705df9aa911ad70523d45 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/tutorial0/controller/StudentController.java @@ -0,0 +1,46 @@ +package id.ac.ui.cs.advprog.tutorial0.controller; + +import id.ac.ui.cs.advprog.tutorial0.exception.DuplicateStudentNameException; +import id.ac.ui.cs.advprog.tutorial0.model.Student; +import id.ac.ui.cs.advprog.tutorial0.service.StudentService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Controller +@RequestMapping("/student") +public class StudentController { + + @Autowired + private StudentService service; + + @GetMapping("/list") + public String studentListPage(Model model){ + List<Student> allStudents = service.findAll(); + model.addAttribute("students", allStudents); + System.out.println(""); + return "studentList"; + } + + @GetMapping("/create") + public String createStudentPage(Model model){ + Student student = new Student(); + model.addAttribute("student", student); + return "createStudent"; + } + + @PostMapping("/create") + public String createStudentPost(@ModelAttribute Student student, Model model){ + try{ + service.create(student); + } catch(DuplicateStudentNameException e){ + model.addAttribute("error", e); + model.addAttribute("student", student); + return "createStudent"; + } + return "redirect:list"; + } +} diff --git a/src/main/java/id/ac/ui/cs/advprog/tutorial0/exception/DuplicateStudentNameException.java b/src/main/java/id/ac/ui/cs/advprog/tutorial0/exception/DuplicateStudentNameException.java new file mode 100644 index 0000000000000000000000000000000000000000..1f9adfdf6396cb90d7729810c431824c390cf7e5 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/tutorial0/exception/DuplicateStudentNameException.java @@ -0,0 +1,8 @@ +package id.ac.ui.cs.advprog.tutorial0.exception; + +public class DuplicateStudentNameException extends RuntimeException{ + + public DuplicateStudentNameException(String studentName){ + super(String.format("The student name %s is a duplicate!", studentName)); + } +} diff --git a/src/main/java/id/ac/ui/cs/advprog/tutorial0/exception/EmptyCourseName.java b/src/main/java/id/ac/ui/cs/advprog/tutorial0/exception/EmptyCourseName.java new file mode 100644 index 0000000000000000000000000000000000000000..82e427b18961e2b86b64795d003e3eb9d3c37b13 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/tutorial0/exception/EmptyCourseName.java @@ -0,0 +1,7 @@ +package id.ac.ui.cs.advprog.tutorial0.exception; + +public class EmptyCourseName extends RuntimeException{ + public EmptyCourseName(){ + super("Course Name cannot be empty"); + } +} diff --git a/src/main/java/id/ac/ui/cs/advprog/tutorial0/model/Course.java b/src/main/java/id/ac/ui/cs/advprog/tutorial0/model/Course.java new file mode 100644 index 0000000000000000000000000000000000000000..33ed68070b716674690d69c7236031e43753360f --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/tutorial0/model/Course.java @@ -0,0 +1,11 @@ +package id.ac.ui.cs.advprog.tutorial0.model; + +import lombok.Getter; +import lombok.Setter; + +@Getter @Setter +public class Course { + private String courseId; + private String courseName; + private Boolean vacancyStatus = true; +} diff --git a/src/main/java/id/ac/ui/cs/advprog/tutorial0/model/Student.java b/src/main/java/id/ac/ui/cs/advprog/tutorial0/model/Student.java new file mode 100644 index 0000000000000000000000000000000000000000..98026586b72d3c5c2063699a9d77cb73a8343be5 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/tutorial0/model/Student.java @@ -0,0 +1,12 @@ +package id.ac.ui.cs.advprog.tutorial0.model; + +import lombok.Getter; +import lombok.Setter; + +@Getter @Setter +public class Student { + private String name; + private String npm; + private String address; + +} diff --git a/src/main/java/id/ac/ui/cs/advprog/tutorial0/repository/CourseRepository.java b/src/main/java/id/ac/ui/cs/advprog/tutorial0/repository/CourseRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..b217c4d2d5b19f8d7f2ab2cef809c662957408be --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/tutorial0/repository/CourseRepository.java @@ -0,0 +1,24 @@ +package id.ac.ui.cs.advprog.tutorial0.repository; + +import id.ac.ui.cs.advprog.tutorial0.model.Course; +import org.springframework.stereotype.Repository; +import org.springframework.web.servlet.support.JstlUtils; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +@Repository +public class CourseRepository { + + List<Course> courseInMemory = new ArrayList<>(); + + public Course create(Course course){ + courseInMemory.add(course); + return course; + } + + public Iterator<Course> findAll(){ + return courseInMemory.iterator(); + } +} diff --git a/src/main/java/id/ac/ui/cs/advprog/tutorial0/repository/StudentRepository.java b/src/main/java/id/ac/ui/cs/advprog/tutorial0/repository/StudentRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..88aa444e7b85d03d714bb0568e0670f945b1820e --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/tutorial0/repository/StudentRepository.java @@ -0,0 +1,23 @@ +package id.ac.ui.cs.advprog.tutorial0.repository; + +import id.ac.ui.cs.advprog.tutorial0.model.Student; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +@Repository +public class StudentRepository { + + private List<Student> studentsInMemory = new ArrayList<>(); + + public Student create(Student student){ + studentsInMemory.add(student); + return student; + } + + public Iterator<Student> findAll(){ + return studentsInMemory.iterator(); + } +} diff --git a/src/main/java/id/ac/ui/cs/advprog/tutorial0/service/CourseService.java b/src/main/java/id/ac/ui/cs/advprog/tutorial0/service/CourseService.java new file mode 100644 index 0000000000000000000000000000000000000000..53b8a76bd0f50814492bd0c3caaaaf61448abaa1 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/tutorial0/service/CourseService.java @@ -0,0 +1,11 @@ +package id.ac.ui.cs.advprog.tutorial0.service; + +import id.ac.ui.cs.advprog.tutorial0.model.Course; +import org.springframework.stereotype.Service; +import java.util.List; + +public interface CourseService { + + public Course create(Course course); + public List<Course> findAll(); +} diff --git a/src/main/java/id/ac/ui/cs/advprog/tutorial0/service/CourseServiceImpl.java b/src/main/java/id/ac/ui/cs/advprog/tutorial0/service/CourseServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..aaff896bd2ed6821c30a14efea579a8df34628e6 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/tutorial0/service/CourseServiceImpl.java @@ -0,0 +1,49 @@ +package id.ac.ui.cs.advprog.tutorial0.service; + +import id.ac.ui.cs.advprog.tutorial0.exception.EmptyCourseName; +import id.ac.ui.cs.advprog.tutorial0.model.Student; +import id.ac.ui.cs.advprog.tutorial0.repository.CourseRepository; +import id.ac.ui.cs.advprog.tutorial0.repository.StudentRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import id.ac.ui.cs.advprog.tutorial0.model.Course; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +@Service +public class CourseServiceImpl implements CourseService{ + + @Autowired + private CourseRepository courseRepository; + + public Course create(Course course){ + generateCourseId(course); + validateEmptyName(course); + courseRepository.create(course); + return course; + } + + public void validateEmptyName(Course course){ + if(course.getCourseName().equals("")) + throw new EmptyCourseName(); + } + + private void generateCourseId(Course course) { + StringBuilder stringBuilder = new StringBuilder(); + for (char letter: course.getCourseName().toCharArray()) { + stringBuilder.append(String.valueOf((int)letter)); + } + String courseId = stringBuilder.toString(); + course.setCourseId(courseId); + } + + @Override + public List<Course> findAll() { + Iterator<Course> courseIterator = courseRepository.findAll(); + List<Course> allCourses = new ArrayList<>(); + courseIterator.forEachRemaining(allCourses::add); + return allCourses; + } +} diff --git a/src/main/java/id/ac/ui/cs/advprog/tutorial0/service/StudentService.java b/src/main/java/id/ac/ui/cs/advprog/tutorial0/service/StudentService.java new file mode 100644 index 0000000000000000000000000000000000000000..b1dd4617ef7c27b1d793c8d8500970f2b07e82ad --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/tutorial0/service/StudentService.java @@ -0,0 +1,11 @@ +package id.ac.ui.cs.advprog.tutorial0.service; + +import id.ac.ui.cs.advprog.tutorial0.model.Student; +import org.springframework.stereotype.Service; +import java.util.List; + +public interface StudentService { + + public Student create(Student student); + public List<Student> findAll(); +} diff --git a/src/main/java/id/ac/ui/cs/advprog/tutorial0/service/StudentServiceImpl.java b/src/main/java/id/ac/ui/cs/advprog/tutorial0/service/StudentServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..5f0eb8f5dbe33ed66bd254103d071886850e528b --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/tutorial0/service/StudentServiceImpl.java @@ -0,0 +1,53 @@ +package id.ac.ui.cs.advprog.tutorial0.service; + +import id.ac.ui.cs.advprog.tutorial0.repository.StudentRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import id.ac.ui.cs.advprog.tutorial0.model.Student; +import id.ac.ui.cs.advprog.tutorial0.exception.DuplicateStudentNameException; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +@Service +public class StudentServiceImpl implements StudentService{ + + @Autowired + private StudentRepository studentRepository; + + @Override + public Student create(Student student) { + validateName(student); + generateNPM(student); + studentRepository.create(student); + return student; + } + + private void validateName(Student student) { + List<Student> allStudents = findAll(); + for(Student dbStudent: allStudents) { + if(dbStudent.getName().equals(student.getName())) { + throw new DuplicateStudentNameException(student.getName()); + } + } + + } + + private void generateNPM(Student student) { + StringBuilder stringBuilder = new StringBuilder(); + for (char letter: student.getName().toCharArray()) { + stringBuilder.append(String.valueOf((int)letter)); + } + String npm = stringBuilder.toString(); + student.setNpm(npm); + } + + @Override + public List<Student> findAll() { + Iterator<Student> studentIterator = studentRepository.findAll(); + List<Student> allStudents = new ArrayList<>(); + studentIterator.forEachRemaining(allStudents::add); + return allStudents; + } +} diff --git a/src/main/resources/templates/courseList.html b/src/main/resources/templates/courseList.html new file mode 100644 index 0000000000000000000000000000000000000000..ff5db832c04acdf9e7b189946cf886abeeae845c --- /dev/null +++ b/src/main/resources/templates/courseList.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html lang="en" xmlns:th="http://www.thymeleaf.org"> +<head> + <meta charset="UTF-8"> + <title>Course List</title> + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> +</head> +<body> + +<h2>Course' List</h2> +<a th:href="@{/course/create}" class="btn btn-primary btn-sm mb-3" >Create course</a> + +<table class="table"> + <thead> + <tr> + <th scope="col">CourseId</th> + <th scope="col">CourseName</th> + <th scope="col">Status</th> + </tr> + </thead> + <tbody th:each="course: ${courses}"> + <tr> + <td th:text="${course.courseId}"></td> + <td th:text="${course.courseName}"></td> + <td th:text="${course.vacancyStatus}"></td> + </tr> + + </tbody> +</table> + + +<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> +</body> +</html> \ No newline at end of file diff --git a/src/main/resources/templates/createCourse.html b/src/main/resources/templates/createCourse.html new file mode 100644 index 0000000000000000000000000000000000000000..a971bc4a8bfd60c4b625698d8713c8425d9d49d0 --- /dev/null +++ b/src/main/resources/templates/createCourse.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html lang="en" xmlns:th="http://www.thymeleaf.org"> +<head> + <meta charset="UTF-8"> + <title>Create new Course</title> + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> +</head> +<body> +<h3>Create new Course</h3> +<div th:if="${error!=null}" class="alert alert-danger" role="alert"> + Empty course name! +</div> +<form th:action="@{/course/create}" th:object="${course}" method="post"> + <div class="form-group"> + <label for="nameInput">Course Name</label> + <input th:field="*{courseName}" type="text" class="form-control" id="nameInput" aria-describedby="nameHelp" placeholder="Enter course' name"> + <small id="nameHelp" class="form-text text-muted">Please enter course name.</small> + </div> + <div class="form-group"> + <label for="vacancyStatusInput">Check Here</label> + <input type="checkbox" th:field="*{vacancyStatus}" id="vacancyStatusInput" value="0"></input> + </div> + <button type="submit" class="btn btn-primary">Submit</button> +</form> +<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> +</body> +</html> \ No newline at end of file diff --git a/src/main/resources/templates/createStudent.html b/src/main/resources/templates/createStudent.html new file mode 100644 index 0000000000000000000000000000000000000000..a42294a504b6819a3fef004156e824b92bd4a1a7 --- /dev/null +++ b/src/main/resources/templates/createStudent.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html lang="en" xmlns:th="http://www.thymeleaf.org"> +<head> + <meta charset="UTF-8"> + <title>Create new Student</title> + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> +</head> +<body> +<h3>Create new Student</h3> +<div th:if="${error!=null}" class="alert alert-danger" role="alert"> + Duplicate student name +</div> +<form th:action="@{/student/create}" th:object="${student}" method="post"> + <div class="form-group"> + <label for="nameInput">Name</label> + <input th:field="*{name}" type="text" class="form-control" id="nameInput" aria-describedby="nameHelp" placeholder="Enter student' name"> + <small id="nameHelp" class="form-text text-muted">Please enter unique name.</small> + </div> + <div class="form-group"> + <label for="addressTextarea">Address</label> + <textarea th:field="*{address}" class="form-control" id="addressTextarea" rows="3"></textarea> + </div> + <button type="submit" class="btn btn-primary">Submit</button> +</form> +<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> +</body> +</html> \ No newline at end of file diff --git a/src/main/resources/templates/studentList.html b/src/main/resources/templates/studentList.html new file mode 100644 index 0000000000000000000000000000000000000000..84ab6ad54e0980ae984cb2585ad00f446513b60c --- /dev/null +++ b/src/main/resources/templates/studentList.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html lang="en" xmlns:th="http://www.thymeleaf.org"> +<head> + <meta charset="UTF-8"> + <title>Student List</title> + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> +</head> +<body> + +<h2>Student' List</h2> +<a th:href="@{/student/create}" class="btn btn-primary btn-sm mb-3" >Create student</a> + +<table class="table"> + <thead> + <tr> + <th scope="col">Name</th> + <th scope="col">NPM</th> + <th scope="col">Address</th> + </tr> + </thead> + <tbody th:each="student: ${students}"> + <tr> + <td th:text="${student.name}"></td> + <td th:text="${student.npm}"></td> + <td th:text="${student.address}"></td> + </tr> + + </tbody> +</table> + + +<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> +</body> +</html> \ No newline at end of file