본문 바로가기
카테고리 없음

241101 2차 프로젝트 개발

by SSONG1521 2024. 11. 1.

오늘도 개발을 시작해보려고 한다.

 

우선 어제 엄마 지인 개발자를 통해 들었던 내용을 정리하자면,

나는 옛날 방식의 웹 개발을 주로 공부하였고 요즘은 앱 개발이 주를 이룬다고 해서 그 부분을 공부해보면 좋을 것 같다고 했다.

 

그래서 gpt에 검색해 나온 우선적인 답변이다.

 

 

웹 개발을 이미 배우셨다면, 앱 개발로 넘어가면서 유용한 기술과 도구가 몇 가지 있습니다. 다음을 고려해보세요:

  1. 모바일 앱 개발 프레임워크:
    • React Native: 자바스크립트를 사용하여 iOS와 Android 앱을 동시에 개발할 수 있습니다.
    • Flutter: 구글에서 개발한 UI 툴킷으로, Dart 언어를 사용하여 네이티브 앱을 만듭니다.
  2. 백엔드 기술:
    • 이미 자바 스프링을 알고 계시니, 스프링 부트와 같은 프레임워크를 사용해 RESTful API를 구축하는 것도 좋습니다. 모바일 앱과 서버 간의 통신을 위해 매우 유용합니다.
  3. 데이터베이스:
    • Firebase와 같은 클라우드 데이터베이스를 공부하면 모바일 앱에서 쉽게 데이터 관리를 할 수 있습니다. SQL과 NoSQL 모두에 대한 이해가 필요합니다.
  4. 버전 관리와 협업 도구:
    • Git과 GitHub 사용법을 익혀 팀 프로젝트에서 협업할 수 있는 능력을 키우세요.
  5. UX/UI 디자인:
    • 기본적인 UX/UI 원칙을 이해하면 사용자 경험을 개선하는 데 도움이 됩니다. Figma와 같은 도구를 사용해보세요.
  6. DevOps 및 배포:
    • 앱 배포와 관리를 위한 CI/CD 도구에 대해 배우는 것도 중요합니다.

이런 방향으로 공부하면 앱 개발에 좋은 기반이 될 것입니다. 필요한 기술들을 하나씩 익혀보세요!

 

 

열심히 해야지!! (오늘 집 가서 이력서 다 쓰고 자야겠다. 그러니 학원에서 진짜 열심히 할 예정)

 

코딩 시작

 

어제 아작스로 해 놓으 것들 잘 모르겠는 부분 하나하나 체크해봐야 겠다.

 

<script type="text/javascript">
	$(document).ready(function () {
		$('#lctrWeekSelect').change(function() {
			let lctr_weeks = $(this).val();
			
			$.ajax({
				url: "<%=request.getContextPath()%>/hs/lecWeekProf",
				type: "POST",
				dataType: "JSON",
				data: {lctr_weeks : lctr_weeks},
				success:function(lctrWeekRes) {
					console.log(lctrWeekRes);
					
					// 기존 출결 데이터 초기화
					$('tbody#attendList').empty();
					
					// 서버에서 받은 데이터로 새로운 행 추가
					$.each(lctrWeekRes.attendList, function(index, student) {
						let row = `
							<tr>
								<td>${hs_attend.unq_num}</td>
								<td>${hs_attend.stdnt_nm}</td>
								<td>
									<input type="radio" class="btn-check" name="atndc_type_${student.unq_num}" id="option100_${student.unq_num}" autocomplete="off" value="100">
									<label class="btn btn-outline-primary btn-sm" for="option100_${student.unq_num}">출석</label>
									
									<input type="radio" class="btn-check" name="atndc_type_${student.unq_num}" id="option110_${student.unq_num}" autocomplete="off" value="110">
									<label class="btn btn-outline-primary btn-sm" for="option110_${student.unq_num}">지각</label>
									
									<input type="radio" class="btn-check" name="atndc_type_${student.unq_num}" id="option120_${student.unq_num}" autocomplete="off" value="120">
									<label class="btn btn-outline-primary btn-sm" for="option120_${student.unq_num}">결석</label>
								</td>
							</tr>
						`;
						$('tbody#attendList').append(row);
					});
				}, 
				error: function(xhr, status, error) {
					console.error('Error fetching data:', error);
				}
			})
		})
	})
</script>

 

 (1) jQuery 의 $.each( ... ) 함수 : attendList를 반복한다

 each문 옆에 function에 있는 값은 객체이다. index는 서버쪽에서 순서를 위한 것이고, student 는 dto 명이다.

따라서 내가 쓰는 dto로 바꿔주면 된다.

 

 (2) ajax로 주차별로 출석 현황을 불러와준다.
 (3) each가 for문처럼 쓰여진다.

 (4) 마지막으로 append(row)로 

 

 

ajax에서 each 내에 list를 불러오기 위해 사용하려면, javascript에서는 EL 표기법이 안 먹기 때문에

`+ +` 안에 넣어주어야 한다....... 이걸로 몇시간 잡아 먹었다. ${ }가 아니라 `+ +`로 되어야 한다.

 

 

 

그리고 이번엔 이 값들은 update form 으로 넘겨주는 방식을 또 jQuery로 처리해야한다.

// 폼 제출 시 데이터 수집
        $('#attendFormUpd').on('submit', function(event) {
            event.preventDefault(); // 기본 제출 방지

            let attendanceData = [];
            $('tbody#attendList tr').each(function() {
                let studentId = $(this).find('td:nth-child(2)').text();
                let attendanceType = $(this).find('input[type="radio"]:checked').val();
                attendanceData.push({ unq_num: studentId, atndc_type: attendanceType });
            });

            // 데이터를 JSON 문자열로 변환
            $('<input>').attr({
                type: 'hidden',
                name: 'attendanceData',
                value: JSON.stringify(attendanceData)
            }).appendTo('#attendFormUpd');

            // 폼 제출
            this.submit();
        });

 

(1) 우선 변경된 함수가 let 배열 함수에 담아서 빈 배열을 생성합니다.

 

이 값들을 하나하나 서버로 옮기려고 합니다.

 

(2) $('tbody#attendList tr').each(function() {...} 는 tbody 안의 각 tr 요소에 대해 반복한다.

(3) let 함수 중 student Id에 $(this).find('td:nth-child(2)').text(); 로 현재 tr의 두 번째  td를 찾아서 그 텍스트 값을 가져온다.

(4) let attendanceType = $(this).find('input[type="radio"]:checked').val() 여기는 현재 tr에서 선택된 radio 값을 가져온다.

(5) attendanceData.push({ unq_num: studentId, atndc_type: attendanceType }) 여기는 배열 값에 push로 넣어준다.

 

(6) 그리고 새로 숨겨진 input을 추가해준다는 attr은 속성이다.

그리고 appendTo로 해당 id가 있는 form에 추가해주고

 (7) submit을 해준다.

 

** dto로 넘기는 것이 편하기 때문에, dto에 담아서 넘겨준다. (즉 dto에 추가해준다. 배열속성을)

 

 

진짜 오류 파티이다.

json 형태가 포함된 data를 보낼 시, post 방식은 지원이 안되는 것 같다. 그저 get 방식만 가능한가보다.

그런데 또 페이지는 오류가 뜨는데, data는 변경이 되어있네 뭐 어쩌라는걸까./..ㅎ

 

그래도 오늘 출석 update 까지는 완료했따. 뿌듯 ㅎㅎㅎ

// 교수 출석체크 update Form
	@RequestMapping(value = "/AttendUpdate")
	public String lecProfAttUpd (Hs_Attend attend, Model model) {
		System.out.println("HsController lecProfAttUpd Start...");
		System.out.println("HsController lecProfAttUpd attend(list로 불러온 값)->"+attend);
		
		String attendanceData = attend.getAttendanceData();
		
		try {
	        // JSON 문자열을 List<Hs_Attend>로 변환
	        ObjectMapper objectMapper = new ObjectMapper();
	        List<Hs_Attend> attendList = objectMapper.readValue(attendanceData, new TypeReference<List<Hs_Attend>>() {});

	        // 각 Hs_Attend 객체의 unq_num과 atndc_type을 출력
	        for (Hs_Attend attendL : attendList) {
	        	attendL.setLctr_weeks(attend.getLctr_weeks());
	        	attendL.setLctr_num(24151513);
	            
	            // 출결 상태가 null이 아닐 경우에만 로그 출력 및 DB 업데이트
	            if (attendL.getAtndc_type() != null) {
	                System.out.println("학번: " + attendL.getUnq_num() + ", 출결상태: " + attendL.getAtndc_type() + ", 주차: " + attendL.getLctr_weeks());
	                // 교수가 강의 출결 등록
	                int updateCount = hss.updateAttProf(attendL);
	            } else {
	                System.out.println("학번: " + attendL.getUnq_num() + "의 출결상태가 null입니다. 업데이트 생략.");
	            }
	        }
	    } catch (Exception e) {
	    	System.out.println("HsController lecProfAttUpd e.getMessage()-> "+e.getMessage());
	        e.printStackTrace();
	    }
		
		System.out.println("HsController lecProfAttUpd End...");
		return "forward:/hs/lecProfAttend";
	}

 

view단에서 json을 string 형태로 보내고, 다시 json 형태로 변환시켜서 하나하나 값을 넣었다.

지난번에 공유일정 추가에서 참석자 불러오는 것과 비슷한 로직이다. 그래도 이번에는

로직하나하나 이해해보려고 노력중이다. 처음 보는 로직이어도 하나하나 분석중이다.

 

lecProfAttend.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>출석입력(교수용)</title>

<style type="text/css">
	body {
        width: 1920px !important; /* body 폭 설정 */
        margin: 0; /* 기본 여백 제거 */
        padding: 0; /* 기본 패딩 제거 */
        box-sizing: border-box; /* 박스 모델 설정 */
    }
    
	.container1 {
        display: grid;
        grid-template-columns: 410px 1180px; /* 왼쪽 메뉴와 오른쪽 콘텐츠 영역 비율 */
        grid-gap: 15px; /* 좌우 간격 */
        width: 1700px; /* 콘텐츠 영역 폭 */
        margin: 50px auto; /* 가운데 정렬 및 상단 여백 */
    }
    
    .main {
        width: 1180px; /* 오른쪽 콘텐츠 영역 폭 */
    }
	
	a {
		color: black;	/* 글자 색상 설정 */
		text-decoration: none;	/* 밑줄제거 */
	}
	
	a:hover {
		font-weight: bold;
	}
</style>
</head>
<header>
	<%@ include file="../header.jsp" %>
</header>
<script type="text/javascript">
	// 아작스로 주차 별 list 불러오기
	$(document).ready(function () {
		$('#lctrWeekSelect').change(function() {
			let lctr_weeks = $(this).val();
			$('#lctrWeeksHidden').val(lctr_weeks); // 선택된 주차를 hidden input에 설정
			
			$.ajax({
				url: "<%=request.getContextPath()%>/hs/lecWeekProf",
				type: "POST",
				dataType: "JSON",
				data: {lctr_weeks : lctr_weeks},
				success:function(lecWeekAttend) {
					console.log('AJAX 호출 성공:', lecWeekAttend);
					
					// 기존 출결 데이터 초기화
					$('tbody#attendList').empty();
					
					// 서버에서 받은 데이터로 새로운 행 추가
					$.each(lecWeekAttend, function(index, hs_attend) {
						console.log('현재 처리 중인 학생: ',hs_attend);	//속성 확인
						console.log('학번:', hs_attend.unq_num, '이름:', hs_attend.stdnt_nm);
						console.log('학번 타입:', typeof hs_attend.unq_num); // 타입 확인
						
						let studentId = hs_attend.unq_num;
			            let studentName = hs_attend.stdnt_nm;
			            let atndc_type = hs_attend.atndc_type; // 출결 상태
			            let index1 = index+1;
			            console.log('each 학번:', studentId, 'each 이름:', studentName);
						console.log('index', index);
						let row = `
							<tr>
								<td>`+index1+`</td>
								<td>`+studentId+`</td>
								<td>`+studentName+`</td>
								<td>
									<input type="radio" class="btn-check" name="atndc_type_`+studentId+`" id="option100_`+studentId+`" autocomplete="off" value="100" ` + (atndc_type === "100" ? 'checked' : '') + `>
									<label class="btn btn-outline-primary btn-sm" for="option100_`+studentId+`">출석</label>
									
									<input type="radio" class="btn-check" name="atndc_type_`+studentId+`" id="option110_`+studentId+`" autocomplete="off" value="110" ` + (atndc_type === "110" ? 'checked' : '') + `>
									<label class="btn btn-outline-primary btn-sm" for="option110_`+studentId+`">지각</label>
									
									<input type="radio" class="btn-check" name="atndc_type_`+studentId+`" id="option120_`+studentId+`" autocomplete="off" value="120" ` + (atndc_type === "120" ? 'checked' : '') + `>
									<label class="btn btn-outline-primary btn-sm" for="option120_`+studentId+`">결석</label>
								</td>
							</tr>
						`;
						
						// 130이면 100 체크
				        /* if (atndc_type === "130") {
				            row = row.replace(`value="100"`, `value="100" checked`);
				        } */
						
						console.log('추가된 행 :', row);	//추가된 행 확인
						$('tbody#attendList').append(row);
					});
				}, 
				error: function(xhr, status, error) {
					console.error('Error fetching data:', error);
				}
			});
		});
		
		// 폼 제출 시 데이터 수집
        $('#attendFormUpd').on('submit', function(event) {
            event.preventDefault(); // 기본 제출 방지

            let attendanceData = [];
            
            $('tbody#attendList tr').each(function() {
                let studentId = $(this).find('td:nth-child(2)').text();
                let attendanceType = $(this).find('input[type="radio"]:checked').val();
                attendanceData.push({ unq_num: studentId, atndc_type: attendanceType });
            });
			
            if ($('#attendFormUpd input[name="lctr_weeks"]').length === 0) {
            
	         	// lctr_weeks 값을 추가
	            $('<input>').attr({
	                type: 'hidden',
	                name: 'lctr_weeks',
	                value: $('#lctrWeeksHidden').val() // 현재 hidden input의 값을 사용
	            }).appendTo('#attendFormUpd');
            }
            
            // 데이터를 JSON 문자열로 변환
            $('<input>').attr({
                type: 'hidden',
                name: 'attendanceData',
                value: JSON.stringify(attendanceData)
            }).appendTo('#attendFormUpd');
            
            // 폼 제출
            this.submit();
        });
	})
</script>
<body>
	<div class="container1">
		<div class="sideLeft">
			<%@ include file="../sidebarLctr.jsp" %>
		</div>
		<div class="main">
		<form action="AttendUpdate" id="attendFormUpd">
			<h1>출결관리</h1>
			<table>
				<tr>
					<th>
						<select class="form-select" id="lctrWeekSelect" aria-label="Default select example">
							<option>주차 선택</option>
							<c:forEach var="hs_attend" items="${weekList }">
								<option value="${hs_attend.lctr_weeks }"
								<c:if test="${hs_attend.lctr_weeks == defaultWeek}">selected</c:if>>
									${hs_attend.lctr_weeks } 주차 (${hs_attend.lctr_ymd })
								</option>
							</c:forEach>
						</select>
					</th>
					<th></th>
					<th></th>
				</tr>
				<tr list="lctr_weeks"></tr>
				<tr>
					<th></th>
					<th>학번</th>
					<th>이름</th>
					<th>출결상태</th>
				</tr>
				<tbody id="attendList"><!-- 출결 목록이 여기에 동적으로 추가됩니다. --></tbody>
			</table>
			<input type="hidden" id="lctrWeeksHidden" name="lctr_weeks" value="">
			<button type="submit" class="btn btn-outline-secondary">등록</button>
		</form>
		</div>
	</div>
</body>
<footer>
	<%@ include file="../footer.jsp" %>
</footer>
</html>

 

 

하.... 오늘 하루종일 이거 하나 했다...

ajax... 어렵다.....ㅠㅠㅠ

 

 

그리고 아 이건 프론트단이긴 한데, sidebar에서 해당 페이지에서 active 시키는거 구현했따.물론 GPT도움이지만

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>사이드바 내강의실</title>
<link rel="stylesheet" type="text/css" href="/css/sidebarLctr.css">
<script type="text/javascript">
	window.onload = function() {
	    const links = document.querySelectorAll('.list a div');
	    const currentPath = window.location.pathname;
	
	    links.forEach(link => {
	        if (link.parentElement.getAttribute('href') === currentPath) {
	            link.classList.add('active');
	        }
	    });
	};
</script>
</head>
<body>
<div class="body">
    <div class="main-container"> <!-- 리스트와 콘텐츠를 감싸는 컨테이너 -->
        <div class="list">
        <%-- <c:if test="${lgn.unq_num.startWith('1') }"> --%>
            <a href="/hs/lecSchedule"><div class="<%= request.getRequestURI().equals("/hs/lecSchedule") ? "active" : "" %>">강의계획서</div></a>
            <a href="/hs/lecAttendance"><div class="<%= request.getRequestURI().equals("/hs/lecAttendance") ? "active" : "" %>">출석확인</div></a>
            <a href="/hs/lecAssignment"><div class="<%= request.getRequestURI().equals("/hs/lecAssignment") ? "active" : "" %>">과제제출</div></a>
            <a href="/hs/lecTest"><div class="<%= request.getRequestURI().equals("/hs/lecTest") ? "active" : "" %>">시험</div></a>
            <a href="/hb/courseEval"><div class="<%= request.getRequestURI().equals("/courseEval") ? "active" : "" %>">평가</div></a>
            <a href="/hb/showResult"><div class="<%= request.getRequestURI().equals("/showResult") ? "active" : "" %>">성적확인</div></a>
        <%-- </c:if>
        
        <c:if test="${lgn.unq_num.startWith('2') }"> --%>
            <a href="/hs/lecProfAttend"><div class="<%= request.getRequestURI().equals("/hs/lecProfAttend") ? "active" : "" %>">출석입력(교수용)</div></a>
            <a href="/hs/lecAssignWrite"><div class="<%= request.getRequestURI().equals("/hs/lecAssignWrite") ? "active" : "" %>">과제입력(교수)</div></a>
            <a href="/hs/lecProfConfirmAssign"><div class="<%= request.getRequestURI().equals("/hs/lecProfConfirmAssign") ? "active" : "" %>">학생과제제출물(교수)</div></a>
            <a href="/hs/lecTestWrite"><div class="<%= request.getRequestURI().equals("/hs/lecTestWrite") ? "active" : "" %>">시험입력(교수)</div></a>
            <a href="/hb/showFinalResult"><div class="<%= request.getRequestURI().equals("/hs/lecTestRead") ? "active" : "" %>">성적입력(교수)</div></a>
            <a href="/hs/lecTestRead"><div class="<%= request.getRequestURI().equals("/hs/lecTestRead") ? "active" : "" %>">학생시험결과(교수)</div></a>
        <%-- </c:if> --%>
        </div>
    </div>
</div>
</body>
</html>

 

 

사이드바 진호씨가 만든거 되게 잘 만들어서 잘 활용중이다 좋다!.!