티스토리 뷰

0. 들어가기 앞서

   대학교 3학년 2학기에 박지웅 교수님의 <데이터베이스 프로그래밍> 수업을 들으면서 한 학기 동안 총 네 명의 팀원이 진행한 프로젝트이다. 해당 프로젝트의 전반적인 작업에 모두 참여하면서 온전한 서비스를 완성하기까지 정말 많은 공을 들였고 가장 애정이 가는 프로젝트이므로 블로그에 기록해보고자 한다.

 

데모 영상: https://www.youtube.com/watch?v=Rs0VtGXXfao

 

1. 프로젝트 소개

   기존 우리 학교 비교과 프로그램의 온라인 수업 출석 방식은 명확하게 정해져 있지 않고, 공식 출석 인증 플랫폼도 없기 때문에 대부분 채팅으로 진행한다. 채팅으로 출석을 진행할 경우 강의에 방해가 되기도 하고, 담당자는 채팅을 일일이 확인해야 하기 때문에 번거롭고 불편하다. 

 

   이러한 불편함을 해소하고자, 우리 학교 비교과 프로그램의 온라인 출석 인증 사이트를 제작하게 되었다. 내가 담당한 파트는 출석 담당자가 출석 인증 번호를 생성하는 파트로  출석 인증 사이트에서 가장 중요한 파트를 담당했다. 

 

  사용한 언어는 서버에 Node.js, 프론트에 HTML, CSS,  데이터 베이스는 MySQL을 사용했고, GitHub로 협업했다.  

 

2. 서비스 구현 방법

   해당 서비스를 구현하면서 가장 고민이 많았던 세 가지 경우가 있는데, 이를 해결한 방법을 소개해보고자 한다.

     (1) 10분이 지나서 출석 인증 번호가 폐기되야하는 경우     

     (2) 유효한 출석 인증 번호가 이미 존재할 경우 

     (3) 출석 번호의 '차시' 속성이 매 출석 번호마다 증가하도록 구현해야 하는 경우

 

 


 

(1) 10분이 지나서 출석 인증 번호가 폐기되어야 하는 경우

     Node.js를 처음 사용해서 익숙하지 않아 특별한 기능을 구현할 때 해당 언어가 어떤 유용한 라이브러리를 제공하는지 하나도 알지 못해서 일일이 검색해보고 찾아나갔다. 특히 이번 경우는 10분 타이머를 구현해야 하는데 이를 어떻게 만들어야 하는지 처음에 정말 막막했다. 열심히 검색해 본 결과(구글 최고..) Node.js는 타이머와 관련해 정말 유용한 매서드를 제공한다.

connection.query(//생성한 출석 정보 데이터에 삽입
	"INSERT INTO attendance_info(course_id, degree, attendance_num, attendance_date, attendance_time, att_valid) values(?,?,?,?,?,?); UPDATE course SET att_valid = 1 WHERE course_id = ? ",
		[id, att_degree, attendance_num, attendance_date, attendance_time, att_valid, id ],		
		function(err3, rows3){
			if(err3) throw err3;
			setTimeout(function(){ // 10분 후, 출석 종료 
				connection.query(
					"UPDATE course SET att_valid = 0 WHERE course_id = ?; UPDATE attendance_info SET att_valid = 0 WHERE attendance_num = ?",
					[id, attendance_num],
					function(err4, rows4){
						if(err4) throw err4;
						console.log('10분 후 출석 종료');
					}
				);
			},600000); 
								
			console.log("정보 삽입 성공");
			// res.write("<script>alert('Attendence Start')</script>");
			// res.write('<script>window.location="staff_main"</script>');
			res.redirect("/staff_attendance?id=" +req.body.course_id);		
		}
);

위 코드는 'Sunshine/routes/staff_att_start.js'의 일부로 전체 코드는 깃헙에서 확인할 수 있다.

 

setTimeout (myFunc, ms) :  첫 번째 인자로 일정한 시간 뒤에 실행할 함수, 두 번째 인자로 타임 아웃 시간(밀리초 단위)을 받는다. 해당 메서드를 현재 경우에 적용해보면, 출석 인증 정보 생성 후 10분이 지나면 출석 인증 정보가 폐기될 수 있도록 출석 인증 정보 테이블의 'att_valid(유효성)' 속성을 false로 업데이트해주는 매서드를 첫 번째 인자로 넣어주고, 두 번째 인자로 10분(600000 ms)을 삽입해준 setTimeout 매서드를 출석 인증 정보 생성 코드에 삽입해주면 된다. (setTImeout 함수에 대한 자세한 내용은 아래 Node.js의 공식 문서를 확인해보자) 

https://nodejs.org/ko/docs/guides/timers-in-node/

 

Node.js의 Timers | Node.js

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

nodejs.org

 

 

 

(2) 유효한 출석 인증 번호가 이미 존재할 경우 

    담당자는 메인 화면에서 자신이 관리하는 강의들 목록을 확인할 수 있는데 여기서 출석 인증을 진행할 강의를 선택하면,

출석 담당자 메인 화면

 

선택한 강의의 현재 유효한 출석 번호가 없을 경우 아래와 같이 비어 있는 화면이 나타나고

유효한 출석 인증 번호가 없을 경우: 빈 화면

 

유효한 출석 인증 번호가 존재할 경우, 위와 같은 빈 화면이 출력돼서는 안되고, 해당 유효한 출석 인증 번호를 화면에 불러와야 한다.

유효한 출석 인증 번호가 있을 경우: 해당 정보 불러오기

 

처음에 각각의 경우를 어떻게 다르게 뜨도록 구현해야할지 정말 많은 고민이 있었다. 이는 attendance_info(출석 인증 정보) 테이블과 course(강의) 테이블에 att_valid 속성을 삽입하는 방식으로 해결했다. att_valid는 Boolean 타입 속성으로 1(유효 0), 0(유효 X) 두 가지 값을 가질 수 있다. 

 

//강의 정보 띄워주기
connection.query(
	"SELECT date_format(course_date, '%Y-%m-%d') AS course_date, course_name, course_num FROM course WHERE course_id=?;",
	[queryData.id],
	function(err1, rows1){
		if(err1){
			throw err1;
		}
		var context1 = [rows1[0].course_name, rows1[0].course_date, rows1[0].course_num];	
		const context2 = [];												
							
		//[1]유효한 정보가 있는지 확인하는 코드
		connection.query(
			"SELECT att_valid FROM course WHERE course_id=?",
			[queryData.id],
			function(err2, rows2){
				if(err2){
					throw err2;
				}
									
				var valid = rows2[0].att_valid;

				if(valid){//[2]-1: 유효한 인증 번호가 있을 경우
					connection.query( 
						"SELECT course_id, date_format(attendance_date, '%Y년 %m월 %d일 ') AS att_date, degree, attendance_personnel AS atts, attendance_num AS att_num, date_format(attendance_time, '%H시 %i분 %s초') AS att_time FROM attendance_info WHERE course_id=? AND att_valid = 1 ",
						[queryData.id],
						function(err3,rows3){
							if(err3){
								throw err3;
							}
							if(rows3){//[3]유효한 인증 번호 불러서 띄워주기
								//끝나는 시각 계산
								var endHour = parseInt((rows3[0].att_time).substring(0,2));    
								var endMin = parseInt((rows3[0].att_time).substring(4,6)) + 10;
								var endSec = parseInt((rows3[0].att_time).substring(8,10));
                                
								if (endMin > 60) { //끝나는 시각이 새로운 시로 변경되는 경우
									endMin = endMin - 60;
									endHour = endHour + 1;
								}
								var endTime = endHour + "시 " + endMin + "분 " + endSec + "초";
								var context2 = [rows3[0].att_num, ''.concat(rows3[0].degree, '차시'), rows3[0].att_date, rows3[0].att_time, rows3[0].course_id, endTime];
								res.render("staff_attendance", {data: context, course: context1, att: context2 });
							}
						}
					);									
				}
				else{ //[2]-2: 유효한 인증 번호가 없을 경우 빈화면 띄워주기 
					connection.query(
						"SELECT max(degree) as max FROM attendance_info WHERE course_id=?",
						[queryData.id],
						function(err4,rows4){
							if(err4) throw err4;
							var degree = rows4[0].max + 1;
							console.log("불러온 차시: "+degree);
							var context2 = ["인증 번호를 생성하세요", ''.concat(degree, '차시'), "", "", queryData.id];
							res.render("staff_attendance", {data: context, course: context1, att: context2 });
						}
					);
				}
			}
		);
	}
);

위 코드는 'Sunshine/routes/staff_attendance.js'의 일부로 전체 코드는 깃헙에서 확인할 수 있다.

 

현재 선택된 강의의 유효한 출석 인증 정보가 있는지 확인하기 위해 [1] 파트에서 SELECT 문을 사용해서 course 테이블의  att_valid값을 가져온다. 이후 가져온 값을 if문에 넣어 유효한 출석 정보가 있다면 [2]-1, 없다면 [2]-2가 실행된다.

[2]-1에서는 유효한 출석 인증 정보를 불러와야하기 때문에 attendance_info 테이블에서 'att_valid == 1'인 출석 인증 정보를 불러오도록 SELECT문을 구성하고, 불러온 정보를 화면에 띄워준다. [2]-2에서는 유효한 인증 정보가 없으므로 빈 화면을 띄워주는데, 해당 강의에서 다음에 생성할 출석 인증 정보의 '차시' 속성을 화면에 띄워주도록 했다. 이와 관련된 구현법은 아래 3번에서 자세히 설명하겠다.

 

 

 

3. 출석 번호의 '차시' 속성이 매 출석 번호마다 증가하도록 구현해야 하는 경우

하나의 강의는 여러 날에 걸쳐 진행할 수 있고, 출석 인증은 같은 날에도 여러 번 진행할 수 있다. 각각을 구분하기 위해 여러 날에 걸쳐 진행하는 하나의 강의더라도 다른 강의로 두고 구분했다. 예를 들면 개발자 진로 특강이 1일 차와 2일 차 이틀에 걸쳐 진행된다면 두 강의는 서로 다른 'course_id' 즉, 기본키를 갖도록 해서 다른 강의로 구분했다. 

하루에 여러 번 출석을 진행할 경우는 출석 인증 정보 테이블의 기본키인 '차시(degree)' 속성을 사용해서 하나의 강의에 대해 서로 다른 차시 속성을 가지도록 해 구분했다. 

else{ //[2]-2: 유효한 인증 번호가 없을 경우 빈화면 띄워주기 
	connection.query(
		"SELECT max(degree) as max FROM attendance_info WHERE course_id=?",
		[queryData.id],
		function(err4,rows4){
			if(err4) throw err4;
			var degree = rows4[0].max + 1;
			console.log("불러온 차시: "+degree);
			var context2 = ["인증 번호를 생성하세요", ''.concat(degree, '차시'), "", "", queryData.id];
			res.render("staff_attendance", {data: context, course: context1, att: context2 });
		}
	);
}

위 코드는 'Sunshine/routes/staff_attendance.js'의 일부로 전체 코드는 깃헙에서 확인할 수 있다.

 

그럼 [2]-2 코드를 다시 확인해보자. SELECT max를 구문을 사용해서 attendance_info 테이블에서 차시의 최댓값을 구해온다. 차시는 하나씩 생성할 때마다 1씩 증가하는 정수 값을 가지기 때문에 다음에 생성할 차시는 max degree 값에 1을 더한 값이다. 이를 render에 인자로 삽입해 빈 화면에 다음 출석 인증 정보를 띄워주는 것이다.

 

 


그럼 저는 또 다른 프로젝트를 들고 오겠습니다. 궁금한 점은 댓글 남겨주세요! 

읽어주셔서 감사합니다 :)

 

*협업 GitHub Link: https://github.com/Databaseprogramming-Sunshine/Sunshine

 

 

GitHub - Databaseprogramming-Sunshine/Sunshine: 교내 특강 스마트출석 시스템 웹사이트

교내 특강 스마트출석 시스템 웹사이트. Contribute to Databaseprogramming-Sunshine/Sunshine development by creating an account on GitHub.

github.com

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함