46일차 내용 정리

채공부·2025년 7월 28일

CSS & BootStrap

is-valid & is-invalid

  • 특정 클래스 추가
.classList.add("클래스명")
  • 특정 클래스 제거
.classList.remove("클래스명")
  • 클래스 제어 = 명시한 클래스가 없으면 추가, 있으면 제거
.classList.toggle("클래스명")

폼 유효성 검증 상태 표시

  1. 아이디
<div class="mb-3">
	<label for="userName" class="form-label">아이디</label>
	<input type="text" id="userName" class="form-control" />
	<div class="invalid-feedback">5글자 이상 입력하세요</div>
	<div class="valid-feedback">사용 가능한 아이디입니다</div>
</div>
// userName 입력란의 참조값
const userNameInput = document.querySelector("#userName");

userNameInput.addEventListener("input", ()=>{
	// 입력한 userName 을 읽어온다
	const userName = userNameInput.value;
	// 입력한 값을 검증한다
	const userNameValid = userName.length >= 5 ? true : false;
	// 일단 모든 클래스를 제거하고
	userNameInput.classList.remove("is-valid", "is-invalid");
	// 검증 결과에 맞는 클래스를 추가한다
	userNameInput.classList.add(userNameValid ? "is-valid":"is-invalid");
});
  1. 비밀번호

regular expression 정규 표현식을 사용하면 더 간단하게 가능

<div class="mb-3">
	<label for="pwd" class="form-label">비밀번호</label>
	<input type="password" id="pwd" class="form-control" />
	<div class="form-text text-muted">
		비밀번호는 8글자 이상 입력하세요
	</div>
	<div class="invalid-feedback">비밀번호를 확인하세요</div>
	<div class="valid-feedback">사용 가능한 비밀번호입니다</div>
</div>
// pwd 입력란의 참조값
const pwdInput = document.querySelector("#pwd");

	pwdInput.addEventListener("input", ()=>{
	// 입력한 pwd 을 읽어온다
	const pwd = pwdInput.value;
	// 입력한 값을 검증한다
	const pwdValid = pwd.length >= 8 ? true : false;
	// 일단 모든 클래스를 제거하고
	pwdInput.classList.remove("is-valid", "is-invalid");
	// 검증 결과에 맞는 클래스를 추가한다
	pwdInput.classList.add(pwdValid ? "is-valid":"is-invalid");
});
  1. 비밀번호 확인
<div class="mb-3">
	<label for="pwd2" class="form-label">비밀번호 확인</label>
	<input type="password" id="pwd2" class="form-control" />
	<div class="invalid-feedback">비밀번호가 일치하지 않습니다</div>
	<div class="valid-feedback">비밀번호가 일치합니다</div>
</div>
// pwd2 입력란의 참조값
const pwd2Input = document.querySelector("#pwd2");

pwd2Input.addEventListener("input", ()=>{
	 pwdEqualValidate();
});

function pwdEqualValidate(){
	// 입력한 2개의 비밀번호를 읽어와서
	const pwd = pwd2Input.value;
	const pwd2 = pwdInput.value;
	// 일단 모든 클래스를 제거하고
	pwd2Input.classList.remove("is-valid", "is-invalid");
	// 두 비밀번호가 같은지 확인해서 적절한 클래스를 추가한다
	pwd2Input.classList.add(pwd == pwd2 ? "is-valid" : "is-invalid");
}
  • pwd 에도 해당 함수 추가
 pwdEqualValidate();

JAVA & JSP

게시판

대댓글

  • view.jsp 코드 추가
<div class="d-none form-div">
	<form action="save-comment.jsp" method="post">
		<!-- 원글의 글번호, 댓글 대상자의 userName, 댓글의 그룹번호도 같이 전송해야 한다 -->
		<input type="hidden" name="parentNum" value="<%=dto.getNum()%>"/>
		<input type="hidden" name="targetWriter" value="<%= tmp.getWriter()%>"/>
		<input type="hidden" name="groupNum" value="<%=getGroupNum()%>"/>
		<textarea name="content" class="form-control mb-2" rows="2" 
				                                placeholder="댓글을 입력하세요"></textarea>
		<button type="submit" class="btn btn-sm btn-outline-primary">등록</button>
		<button type="reset" class="btn btn-sm btn-outline-secondary cancel-reply-btn">취소</button>
	</form>
</div>
⭐ 댓글의 글번호가 안 넘어오면 댓글, 넘어오면 대댓글
  • save-comment.jsp 코드 추가
<%
	// 댓글의 그룹번호가 넘어오는지 읽어와 본다 (null 이면 원글의 댓글 저장 요청이다)
	String strGroupNum = request.getParameter("groupNum");
	// 댓글의 그룹번호를 담을 변수를 미리 만들고
	int groupNum = 0;
	// 만일 댓글의 그룹번호가 넘어 온다면 (댓글의 댓글이라면)
	if(strGroupNum != null){
		groupNum   = Integer.parseInt(strGroupNum);
	}
    
    // 만일 원글의 댓글이면
	if(groupNum == 0){
		dto.setGroupNum(num); // 원글의 댓글은 자신의 글번호가 댓글의 글번호이다
	} else{
		dto.setGroupNum(groupNum); // 대댓글은 전송된 그룹번호가 댓글의 그룹 번호이다
	}
%>
  • view.jsp 코드 수정 & 추가
<div class="comments">
	<%for(CommentDto tmp : commentList) {%>
		<!-- 대댓글은 자신의 글번호와 댓글의 그룹번호가 다르다, 그런 경우 왼쪽 마진을 부여 -->
		<div class="card mb-3 <%=tmp.getNum() == tmp.getGroupNum() ? "":"ms-5"%>">
			<%if(tmp.getDeleted().equals("yes")) {%>
				<!--  삭제된 댓글 -->
				<div class="card-body bg-light text-muted rounded">삭제된 댓글입니다</div>
					<%}else {%>
						<!-- 삭제되지 않은 댓글 -->
						<div class="card-body d-flex flex-column flex-sm-row position-relative">
			            	<%if(tmp.getNum() != tmp.getGroupNum()){ %>
		            			<i class="bi bi-arrow-return-right position-absolute" style="top:0;left:-30px"></i>
		            		<%} %> 
  					.
          			.
          			.   
</div>
⭐ 원글의 댓글을 자신의 num 과 groupNum 이 같지만
    댓글의 댓글은 자신의 num 과 groupNum 이 다르다
    ➜ groupNum이 모두 같다

권한 설정

  • login.jsp 코드 추가
<%
// role 정보도 저장한다
session.setAttribute("role", dto.getRole());
%>
  • logout.jsp 코드 축가
<%
	// 세션 영역에 저장된 모든 정보 삭제
	session.invalidate();
%>
  • SecurityFilter 클래스에 isAuthorized 메소드 추가
// role 정보 얻어오기
String role = (String)session.getAttribute("role");
// 권한 체크
// 만일 Authorized() 메소드가 false 를 리턴한다면 (접근 불가하다고 판정이 된다면)
if(!isAuthorized(path, role)) {
	// 금지된 요청이라고 응답하고
	res.sendError(HttpServletResponse.SC_FORBIDDEN, "접근 권한이 없습니다");
	return; // 메소드를 여기서 끝낸다
}
// 역할 기반 권한 검사
// 클라이언트의 요청 경로와 role 정보를 넣어서 접근 가능한지 여부를 리턴하는 메소드
private boolean isAuthorized(String path, String role) {
	if ("ROLE_ADMIN".equals(role)) {
		return true; // 모든 경로 접근 허용
	} else if ("ROLE_STAFF".equals(role)) {
		// "/admin/" 하위 경로를 제외한 모든 경로 접근 허용
		return !path.startsWith("/admin/");
	} else if ("ROLE_USER".equals(role)) {
		// "/admin/" 하위와 "/staff/" 하위를 제외한 모든 경로 접근 허용
		return !path.startsWith("/admin/") && !path.startsWith("/staff/");
	}
	return false; // unknown role
}
⚠️ webapp 폴더 안에 admin, staff 폴더 생성
  • admin 폴더에서 index.jsp 파일 생성
<div class="container">
	<h1>관리자 인덱스 페이지</h1>
	<p>role이 <strong>ROLE_ADMIN</strong> 인 사용자만 이 페이지를 볼 수 있습니다</p>
</div>
  • staff 폴더에서 index.jsp 파일 생성
<div class="container">
	<h1>직원 인덱스 페이지</h1>
  	<p>
		role이 <strong>ROLE_STAFF</strong> 또는
		<strong>ROLE_ADMIN</strong> 인 사용자만 이 페이지를 볼 수 있습니다
	</p>
</div>
  • index.jsp 링크 추가
<ul>
	<li><a href="${pageContext.request.contextPath}/admin/index.jsp">관리자</a></li>
	<li><a href="${pageContext.request.contextPath}/staff/index.jsp">직원</a></li>
</ul>
  • 'superman' 으로 회원가입 후 cmd 에서 role 변경
UPDATE users
SET role='ROLE_ADMIN'
WHERE userName='superman';
  • 'batman' 으로 회원가입 후 cmd 에서 role 변경
UPDATE users
SET role='ROLE_STAFF'
WHERE userName='batman';
⭐ 관리자 페이지는 role 이 ROLE_ADMIN 인 사용자만 볼 수 있고
    직원 페이지는 role 이 ROLE_ADMIN, ROLE_STAFF 인 사용자가 볼 수 있다
profile
학원 공부 내용 정리

0개의 댓글