Professional Documents
Culture Documents
------------
Nhóm : 09
Nhóm BTL : 17
Page | 1
LỜI CẢM ƠN
Em xin gửi lời cảm ơn chân thành đến thầy giáo Dương Trần Đức - giảng viên
môn Lập trình Web tại Học Viện Công Nghệ Bưu Chính Viễn Thông đã trang bị giúp
nhóm em những kỹ năng cần thiết và những kiến thức cơ bản để hoàn thành được bài
tập lớn trong môn học này.
Tuy nhiên, trong quá trình hoàn thiện bài tập lớn, do kiến thức chuyên ngành của
nhóm em còn tồn tại một số hạn chế nên không thể tránh khỏi một vài thiếu sót khi xây
dựng phần mềm và đánh giá các vấn đề tồn tại. Rất mong nhận được sự góp ý, hướng
dẫn của thầy để đề tài của nhóm em sẽ hoàn thiện hơn.
Page | 2
Mục lục
I. Đặc tả hệ thống..............................................................................4
1. Đặc tả...........................................................................................4
2. Các chức năng chính.....................................................................4
II. Thiết kế hệ thống........................................................................... 4
1. Thiết kế data.......................................................................................4
2. Thiết kế view.......................................................................................9
3. Thiết kế controller...............................................................................10
III. Kiến trúc hệ thống..........................................................................13
1. Mô hình...............................................................................................13
2. Công nghệ áp dụng.............................................................................13
3. Database.............................................................................................13
IV. Kiểm thử, triển khai ......................................................................14
1. Chạy thử trên local..............................................................................14
2. Deploy ................................................................................................27
V. Phân công công việc.......................................................................27
Page | 3
Đặc tả hệ thống
Mô tả
Hệ thống kiểm tra online dùng để tạo môi trường chung để giúp giảng viên và
sinh viên có thể thực hiện các tác vụ cơ bản với nhau cũng như : Tham khảo , xem
thông tin , đánh giá và kiểm tra .
Thiết kế hệ thống
Thiết kế data
User
Đây là thực thể dùng tham gia vào phiên đăng nhập của trang
web.
Với các thuộc tính: tài khoản, mật khẩu, vai trò.
Mật khẩu của người dùng được lưu dưới dạng mã hoá (bởi lớp
PasswordEncoder)
@Data
@Entity
@NoArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull(message = "Bạn phải có tài khoản")
@Column(nullable = false, unique = true)
private String username;
@NotNull(message = "Bạn cần mật khẩu để đăng nhập")
@Size(min=6, message = "Mật khẩu của bạn cần phải có 6 ký
tự")
@Column(nullable = false)
private String password;
private String role;
}
Page | 4
Student
Thực thể này đại diện cho học sinh, bao gồm các thông tin cơ bản:
họ và tên, email, ngày sinh, địa chỉ, số điện thoại.
Thực thể này liên kết 1 – 1 với User
@Data
@Entity
@NoArgsConstructor
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull(message = "Bạn phải có tài khoản")
@OneToOne(targetEntity = User.class)
@OnDelete(action = OnDeleteAction.CASCADE)
private User user;
private String email;
@NotNull(message = "Bạn phải đặt tên")
@Column(nullable = false)
private String name;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dateOfBirth;
private String address;
private String phoneNumber;
}
Teacher
Thực thể này đại diện cho giảng viên, bao gồm các thông tin cơ
bản: họ và tên, email, ngày sinh, địa chỉ, số điện thoại.
Thực thể này liên kết 1 – 1 với User
@Data
@Entity
@NoArgsConstructor
public class Teacher{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull(message = "Bạn phải có tài khoản")
@OneToOne(targetEntity = User.class)
@OnDelete(action = OnDeleteAction.CASCADE)
private User user;
private String email;
@NotNull(message = "Bạn phải đặt tên")
@Column(nullable = false)
private String name;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dateOfBirth;
private String address;
private String phoneNumber;
}
Page | 5
Course
Thực thể này đại diện cho lớp học, mỗi lớp học sẽ có các thông tin
như tên lớp, mã mời, giảng viên, danh sách sinh viên.
Thực thể này liên kết nhiều – 1 với giảng viên, liên kết nhiều –
nhiều với học sinh.
Một giảng viên có thể mở nhiều lớp học, nhưng 1 lớp học chỉ
được quản lý bởi 1 giảng viên.
Một sinh viên có thể join nhiều lớp, và một lớp cũng có nhiều sinh
viên.
@Data
@Entity
@NoArgsConstructor
public class Course {
private static final String CHARACTERS =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull(message = "Lớp học cần phải có tên")
private String name;
@Column(unique = true)
private String code;
@ManyToMany(fetch = FetchType.EAGER, targetEntity =
Student.class)
private List<Student> studentList;
@ManyToOne(targetEntity = Teacher.class)
@OnDelete(action = OnDeleteAction.CASCADE)
@NotNull(message = "Lớp học cần có giảng viên")
private Teacher teacher;
@PrePersist
void code(){
Random random = new Random();
StringBuilder sb = new StringBuilder(8);
for (int i = 0; i < 8; i++) {
int randomIndex =
random.nextInt(CHARACTERS.length());
char randomChar = CHARACTERS.charAt(randomIndex);
sb.append(randomChar);
}
this.code=sb.toString();
}
}
Page | 6
Examination
Thực thể này đại diện cho bài kiểm tra. Gồm có các thông tin cơ
bản của bài kiểm tra như: tên bài, mô tả, ngày bắt đầu, ngày kết
thúc, thời gian làm, điểm số, hiện cho sinh viên ….
Thực thể này liên kết nhiều – 1 với giảng viên
Thuộc tính isVisible sẽ cho phép sinh viên được thấy bài kiểm tra
hoặc không.
public class Examination {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title = "Chưa đặt tên";
@Column(length = 500)
private String description = "Bài kiểm tra";
@ManyToOne(targetEntity = Course.class)
@OnDelete(action = OnDeleteAction.CASCADE)
@NotNull(message = "Bài kiểm tra phải có lớp")
private Course course;
@NotNull(message = "Hãy thêm ngày bắt đầu")
@Column(nullable = false)
private Date startDate;
@NotNull(message = "Hãy thêm ngày kết thúc")
@Column(nullable = false)
private Date endDate;
@NotNull
private Long totalTime = (long) 600; // in seconds
@Column(nullable = false)
@NotNull(message = "Bài kiểm tra phải có điểm")
private Float points;
private Boolean isVisible = false;
}
Question
Đây là thực thể đại diện cho câu hỏi. Mỗi câu hỏi sẽ có các thông
tin như: đề bài, đáp án, đáp án đúng.
Để đơn giản việc lưu trữ, các đáp án sẽ được join lại bởi chuỗi
“#~~~#”
Thực thể này liên kết nhiều – 1 với Examination
@Data
@Entity
@NoArgsConstructor
public class Question {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(targetEntity = Examination.class)
Page | 7
@OnDelete(action = OnDeleteAction.CASCADE)
@NotNull(message = "Câu hỏi phải nằm trong bài kiểm tra")
private Examination examination;
Result
Thực thể này đại diện cho kết quả của sinh viên sau khi hoàn
thành bài kiểm tra
Thực thể này liên kết nhiều – 1 với Examination và nhiều – 1 với
Student.
@Entity
@Data
@NoArgsConstructor
public class Result {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(targetEntity = Student.class)
@OnDelete(action = OnDeleteAction.CASCADE)
@NotNull
private Student student;
@ManyToOne(targetEntity = Examination.class)
@OnDelete(action = OnDeleteAction.CASCADE)
@NotNull
private Examination examination;
private Date startTime;
private Integer numberOfCorrectAnswers = 0;
private Boolean done = false;
@PrePersist
void startTime(){
this.startTime = new Date();
}
}
Page | 8
Thiết kế view
Page
404.html (không tìm thấy), 500.html (lỗi server), 403.html(không có
quyền), login.html, registration.html, success_registration.html,
hometeacher.html, homestudent.html, course_student.html,
course_teacher.html, profile.html, examination.html, results.html,
profile.html, reset-password.html
Với mọi Controller: nếu session không có dữ liệu đăng nhập thì
redirect về login.
Đối với API Controller: nếu không có dữ liệu hoặc truy cập sai
cách thì trả về code 404 hoặc 403
1 navbar, chứa 1 nút home (ở đầu navbar) và, 1 nút profile (ở cuối
navbar)
login.html
1 form gồm 3 input (tài khoản, mật khẩu, lưu đăng nhập), 1 link dẫn
tới registration.html (nếu chưa có tk), 1 button đăng nhập
Sau khi ấn đăng nhập, nếu oke thì return home.html, nếu không thì
return login.html kèo error message.
registration.html
1 form gồm 5 input: Họ và tên, email đăng nhập, mật khẩu, nhập lại
mật khẩu, Select gồm 2 option vai trò: sinh viên hoặc giảng viên; 1
link dẫn tới login.html (nếu đã có tk); 1 button đăng ký.
Sau khi ấn button đăng ký, nếu oke thì trả về
success_registration.html với nội dung là đăng kí thành công và 1
nút trở về home.html kèm theo variable role=student hoặc
role=teacher.
Nếu lỗi thì trả lại registration.html kèm error message và vẫn giữ
nguyên value các input.
home.html
Chung:
Xin chào …
Danh sách lớp học dạng bảng, Gồm: id, tên lớp, tên giảng
viên, số sinh viên. khi ấn vào tên sẽ dẫn sang course.html
Nếu là sinh viên:
Có 1 input để nhập mã mời vào lớp học. Nhập xong sẽ call
API. nếu không tồn tại thì báo lỗi.
Nếu là giảng viên:
Sẽ có thêm 1 form tạo course, khi ấn vào sẽ gửi API, nếu
succes reload lại
course.html
Chung:
tên lớp
Page | 9
tên giảng viên
1 bảng hiện danh sách sinh viên, chiều cao cố định,
overflow-y: scroll
1 danh sách bài kiểm tra bao gồm tên, trạng thái, số học
sinh đã tham gia. Click vào tên sẽ vào examination.html
Nếu là giảng viên:
Thêm 1 danh sách các sinh viên đang chờ phê duyệt bao
gồm: tên sinh viên, email, bên cạnh là nút đồng ý hoặc huỷ.
call API. Nếu đồng ý và thành công thì xoá khỏi hàng chờ và
thêm vào danh sách sv. Nếu huỷ và thành công thì chỉ xóa
khỏi hàng chờ.
Thêm input thêm bài kiểm tra, gồm các thông tin cơ bản.
Nếu là sinh viên: Danh sách bài kiểm tra chỉ hiện những bài có
thuộc tính isVisible = true
examination.html
Thông tin bài kiểm tra
Nếu là giảng viên:
Hiện danh sách các câu hỏi.
Input thêm câu hỏi, bao gồm mô tả, các đáp án. nút
thêm. Sau khi ấn, nếu thành công thì clear input và
append câu vào danh sách. Nếu không thì báo lỗi.
Nếu là sinh viên:
o Nếu đã nộp bài thì hiện kết quả danh sách các sinh viên đã
hoàn thành.
o Nếu chưa nộp bài, và bài kiểm tra đang trong quá trình diễn
ra. Hiện nút bắt đầu làm.
o Nếu chưa nộp bài và đã bắt đầu, hiện nút tiếp tục.
Sau khi ấn nút bắt đầu/tiếp tục. valid xem sinh viên còn đủ điều
kiện tham gia không. Nếu có thì hiện danh sách bài kiểm tra kèm
đồng hồ đếm ngược.
profile.html
Hiện các thông tin cở bản của người dùng dưới dạng input form. Có nút
update để cập nhật thông tin
reset-password.html:
Gồm 3 form mật khẩu cũ, mật khẩu mới, nhập lại mật khẩu để người
dùng có thể cập nhật
Thiết kế controller
Login, Register
Login:
o Nếu đăng nhập rồi thì redirect về home
o Khi POST sẽ valid tài khoản mật khẩu, lỗi sẽ trả lại trang kèm lỗi.
Thành công redirect về home
Page | 10
Register:
o Nếu đăng nhập rồi thì redirect về home
o Khi POST sẽ valid thông tin người dùng, lỗi sẽ trả lại trang kèm lỗi.
Thành công thì gửi về trang thành công
Home
- Gồm có 2 phương thức
+ Phương thức xử lý trang home cho học sinh.
Nếu người dùng chưa đăng nhập sẽ chuyển đến trang đăng nhập
Lấy danh sách lớp học có chứa học từ trong cơ sở dữ liệu rồi lưu vào
model để hiện thị ra bên frontend.
+ Phương thức xử lý home dành cho giáo viên.
Nếu người dùng chưa đăng nhập sẽ chuyển đến trang đăng nhập
Lấy danh sách lớp học mà giáo viên đã tạo trong cơ sở dữ liệu rồi lưu
vào model để hiển thị ra phía frontend.
Course
- Gồm có 2 phương thức
+ Phương thức xử lý trang course cho học sinh.
Tìm lớp học theo id trên url.
Nếu lớp học mà sinh viên đăng nhập chưa tham gia sẽ hiển thị lỗi.
Tìm kiếm các bài kiểm tra có trong lớp học và có thuộc tính isVisible =
true.
Lưu các biến cần hiển thị ở frontend vào model.
+ Phương thức xử lý trang course cho giáo viên.
Tìm lớp học theo id trên url.
Nếu lớp học mà không phải giáo viên đăng nhập sẽ hiển thị lỗi.
Tím kiếm các bài kiểm tra có trong lớp học mà giáo viên đã tạo.
Lưu các biến cần hiển thi ở frontend vào model
Examination
/examination/id: Khi có yêu cầu GET, kiểm tra xem quyền người dùng là
giảng viên hay sinh viên.
o Nếu là giảng viên: trả về danh sách các câu hỏi đã thêm từ trước.
Lúc này giao diện sẽ hiện các form để thao tác API với
QuestionApi
o Nếu là học sinh: trả về thời gian làm bài còn lại, trạng thái bài
kiểm tra. Lúc này giao diện sẽ hiện trạng thái bài kiểm tra cho sinh
viên. Nếu sinh viên có thể làm bài thì có thể click vào để chuyển
sang trang process để thực hiện bài kiểm tra.
/examination/id/process:
Page | 11
o Chỉ cho phép sinh viên
o GET:
Khởi tạo một Result cho sinh viên với done = false nếu
chưa có.
Check xem sinh viên còn đủ điều kiện làm bài không. Nếu
không sẽ trả về fobidden.
Nếu có sẽ trả về thời gian làm bài còn lại kèm các câu hỏi.
o POST: khi sinh viên bấm submit sẽ post form lên server
Đối chiếu kết quả với đáp án đúng và lưu kết quả của sinh
viên với done = true.
/examination/id/results:
o Nếu isvisble = false thì chỉ hiện cho giảng viên đã tạo ra bài này
o Kiểm tra xem sinh viên và giảng viên có ở trong lớp có bài kiểm tra
hay không. Nếu không trả về forbidden.
o Trả về danh sách các bài làm đã hoàn thành của sinh viên trong
lớp.
API:
o GET: kiểm tra quyền, đối với sinh viên thì chỉ trả những bài có
isVisible = true
o POST: kiểm tra quyền, thêm bài kiểm tra vào lớp học.
o DELETE: kiểm tra quyền, xoá bài theo id
o PUT: kiểm tra quyền, sửa bài theo requestbody
o Thành công sẽ trả về object Examination (trừ delete), thất bại sẽ
trả về Forbidden hoặc Notfound code.
Question(API):
POST: kiểm tra quyền, thêm câu hỏi vào bài kiểm tra.
PUT: kiểm tra quyền, sửa câu hỏi.
DELETE: kiểm tra quyền, xoá câu hỏi.
Profile
GET: gửi về thông tin của người dùng.
POST: valid thông tin, nếu hợp lệ sẽ lưu thông tin mới của người dùng,
nếu không sẽ trả về lỗi.
ChangePassword: Kiểm tra mã hash của mật khẩu cũ có trùng với mật
khẩu hiện tại. Đồng thời mật khẩu mới phải có ít nhất 6 kí tự.
Database
Dự án sử dụng hệ quản trị cơ sở dữ liệu Mysql để lưu trữ
Page | 13
Kiểm thử, vận hành
Chạy trên local
Giao diện chung
- Giao diện login
Page | 14
- Giao diện đăng ký thành công
Page | 15
- Giao diện thay đổi thông tin
Page | 16
Giao diện dành cho giáo viên.
- Trang chủ
Page | 17
- Giao diện trang chủ sau khi thêm lớp học
- Giao diện xóa lớp học thành công ấn ok thì sẽ load lại trang và lớp học sẽ mất
Page | 18
- Giao diện lớp học.
Page | 19
- Giao diện sau khi thêm thông tin bài kiểm tra
Page | 20
- Giao diện bài kiểm tra
Page | 21
- Giao diện sau khi thêm câu hỏi
- Giao diện hiển thị danh sách kết quả của sinh viên làm bài
Page | 22
Giao diện dành cho sinh viên.
- Giao diện trang chủ.
Page | 23
- Giao diện bài kiểm tra
Page | 24
- Giao diện kết quả
Page | 25
Giao diện bài kiểm tra chưa bắt đầu.
Deloy
Hiện tại hệ thống đang được host trên: https://ac61-14-177-236-241.ngrok-
free.app/
Page | 26
i) Deploy
Page | 27