44일차 내용 정리

채공부·2025년 7월 24일

CSS & BootStrap

반응형 레이아웃

flex-row : 가로 방향으로 자식 컨텐츠를 정렬
flex-column : 새로 방향으로 자식 컨텐츠를 정렬
align-self-center : main 축에 따라 가운데 배치

<div class="container">
    <h1>댓글 출력 레이아웃 sample</h1>

    <div class="card mb-3">
        <div class="card-body d-flex">
            <img class="rounded-circle me-3" src="images/1.jpg" alt="프로필 이미지">
            <div class="flex-grow-1">
                <div class="d-flex justify-content-between">
                    <div>
                        <strong>작성자: 유재석</strong>
                        <span>수신자: 전체</span>
                    </div>
                    <small>25.07.25 12:00</small>
                </div>
                <pre>첫번째 댓글입니다</pre>
                <button class="btn btn-sm btn-outline-primary show-reply-btn">댓글</button>  
                <!-- 댓글 입력 폼 (처음에는 숨김) -->
                <div class="d-none form-div">
                    <form action="comment-save.jsp" method="post">
                        <textarea class="form-control mb-2" rows="2" 
                            placeholder="댓글을 입력하세요..."></textarea>
                        <button type="submit" class="btn btn-sm btn-success">등록</button>
                        <button type="reset" class="btn btn-sm btn-secondary cancel-reply-btn">취소</button>
                    </form>
                </div>
            </div>
        </div>
    </div>

    <div class="card mb-3">
        <div class="card-body d-flex flex-column flex-sm-row">
            <img class="rounded-circle me-3 align-self-center" src="images/1.jpg" alt="프로필 이미지">
            <div class="flex-grow-1">
                <div class="d-flex justify-content-between">
                    <div>
                        <strong>작성자: 유재석</strong>
                        <span>수신자: 전체</span>
                    </div>
                    <small>25.07.25 12:05</small>
                </div>
                <pre>첫번째 댓글입니다</pre>
                <button class="btn btn-sm btn-outline-primary show-reply-btn">댓글</button>  
                <!-- 댓글 입력 폼 (처음에는 숨김) -->
                <div class="d-none form-div">
                    <form action="comment-save.jsp" method="post">
                        <textarea class="form-control mb-2" rows="2" 
                            placeholder="댓글을 입력하세요..."></textarea>
                        <button type="submit" class="btn btn-sm btn-success">등록</button>
                        <button type="reset" class="btn btn-sm btn-secondary cancel-reply-btn">취소</button>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

Forms

floating

<div class="container">
    <h3>로그인 폼</h3>
    <form action="login.jsp" method="post">
        <div class="form-floating mb-3">
            <input type="email" class="form-control" id="floatingInput" placeholder="name@example.com">
            <label for="floatingInput">Email address</label>
        </div>
        <div class="form-floating">
            <input type="password" class="form-control" id="floatingPassword" placeholder="Password">
            <label for="floatingPassword">Password</label>
        </div>
        <button class="btn btn-primary" type="submit">로그인</button>
    </form>
</div>

Validation

  • 유효성 검증

is-valid : 입력값이 유효성 검사를 통과했을 때 input 요소에 적용
is-invalid : 입력값이 유효성 검사를 실패했을 때 input 요소에 적용

<div class="container">
    <h3>폼 유효성 검증 상태 표시하기</h3>
    <form action="">
        <div>
            <label class="form-label" for="id">아이디</label>
            <input class="form-control is-valid" type="text" id="id">
            <div class="valid-feedback">형식에 맞게 입력했습니다</div>
            <div class="invalid-feedback">영문자 소문자로 시작하세요</div>
        </div>
        <div>
            <label class="form-label" for="pwd">비밀번호</label>
            <input class="form-control is-invalid" type="text" id="pwd">
        </div>
        <button type="submit" class="btn btn-primary">가입</button>
    </form>
</div>

JAVA & JSP

게시판

댓글

  • CommentDao 에 SelectList 메소드 수정
public List<CommentDto> selectList(int parentNum) {
    List<CommentDto> list = new ArrayList<>();
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;

    try {
        conn = new DbcpBean().getConn();
        String sql = """
            SELECT comments.num, writer, targetWriter, content, deleted, groupNum,
                   comments.createdAt, profileImage
            FROM comments
            INNER JOIN users ON comments.writer = users.userName
            WHERE parentNum = ?
            ORDER BY groupNum ASC, num ASC
            """;
        pstmt = conn.prepareStatement(sql);
        pstmt.setInt(1, parentNum);
        rs = pstmt.executeQuery();

        while (rs.next()) {
            CommentDto dto = new CommentDto();
            dto.setNum(rs.getInt("num"));
            dto.setWriter(rs.getString("writer"));
            dto.setTargetWriter(rs.getString("targetWriter"));
            dto.setContent(rs.getString("content"));
            dto.setParentNum(parentNum);
            dto.setGroupNum(rs.getInt("groupNum"));
            dto.setDeleted(rs.getString("deleted"));
            dto.setCreatedAt(rs.getString("createdAt"));
            dto.setProfileImage(rs.getString("profileImage"));

            list.add(dto);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (rs != null) rs.close();
            if (pstmt != null) pstmt.close();
            if (conn != null) conn.close();
        } catch (Exception e) {
        }
    }
    return list;
}

➜ 최신 댓글은 아래로

댓글 출력

  • view.jsp 코드 추가
<%
	// 댓글 목록 DB 에서 읽어오기
    List<CommentDto> commentList = CommentDao.getInstance().selectList(num);
    // 로그인 했는지 여부를 알아내기
    boolean isLogin = userName == null ? false : true;
%>
<div class="comments">
    <%for(CommentDto tmp : commentList) {%>
        <div class="card mb-3">
            <div class="card-body d-flex flex-column flex-sm-row">
                <%if(tmp.getProfileImage() ==  null) {%>    
                    <i style="font-size:50px;" class="bi bi-person-circle me-3 align-self-center"></i>    
                <%} else{%>
                    <img class="rounded-circle me-3 align-self-center"
                        src="${pageContext.request.contextPath}/upload/<%=tmp.getProfileImage() %>"
                        alt="프로필 이미지"
                        style="width:50px; height:50px;">
                <%} %>
                <div class="flex-grow-1">
                    <div class="d-flex justify-content-between">
                        <div>
                            <strong><%=tmp.getWriter()%></strong>
                            <span>@<%=tmp.getTargetWriter()%></span>
                        </div>
                        <small><%=tmp.getCreatedAt()%></small>
                    </div>
                    <pre><%=tmp.getContent()%></pre>
                    <pre><%=tmp.getContent()%></pre>
		                    
		                    <%if(tmp.getWriter().equals(userName)) {%>
		                    
		                    <%} else{%>
		                    	<button class="btn btn-sm bg-primary-subtle btn-outline-secondary show-reply-btn">댓글</button>  
			                    <!-- 댓글 입력 폼 (처음에는 숨김) -->
			                    <div class="d-none form-div">
			                        <form action="comment-save.jsp" method="post">
			                            <textarea 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>
		                    <%} %>
                    <button class="btn btn-sm bg-primary-subtle btn-outline-secondary show-reply-btn">댓글</button>  
                    <!-- 댓글 입력 폼 (처음에는 숨김) -->
                    <div class="d-none form-div">
                        <form action="comment-save.jsp" method="post">
                            <textarea 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>
                </div>
            </div>
        </div>    
    <%} %>
</div>
// 클라이언트가 로그인 했는지 여부
const isLogin = <%=isLogin%>;

document.querySelector("#commentContent").addEventListener("input", () => {
    // 원글의 댓글 입력란에 입력했을 때 만일 로그인 하지 않았다면
    if (!isLogin) {
        alert("댓글 작성을 위해 로그인이 필요합니다!");
        location.href =
            "${pageContext.request.contextPath}/user/loginform.jsp?url=${pageContext.request.contextPath}/board/view.jsp?num=<%=num%>";
    }
});

// 모든 댓글 버튼에 이벤트 등록
document.querySelectorAll(".show-reply-btn").forEach(item => {
    // 매개변수에 전달된 item 은 댓글 button 의 참조값이다 
    item.addEventListener("click", () => {
        // 클릭한 버튼의 다음 형제요소의 class 목록에서 d-none 을 제거 
      
      // 댓글 버튼을 눌렀을 때 만일 로그인 하지 않았다면
       if(!isLogin){
			alert("댓글 작성을 위해 로그인이 필요합니다!");
			location.href = 
              "${pageContext.request.contextPath}/user/loginform.jsp?url=${pageContext.request.contextPath}/board/view.jsp?num=<%=num%>";
		}
        item.nextElementSibling.classList.remove("d-none");
        // 클릭한 버튼의 class 목록에 d-none 을 추가
        item.classList.add("d-none");
    });
});

document.querySelectorAll(".cancel-reply-btn").forEach(item => {
    item.addEventListener("click", () => {
        // 가장 가까운 부모 요소중에 클래스 속성이 form-div 인요소  
        const formDiv = item.closest(".form-div");
        // formDiv 에 d-none 클래스 추가해서 안보이게 하고
        formDiv.classList.add("d-none");
        // formDiv 의 이전 형제요소(댓글버튼)에 d-none 클래스 제거해서 보이게 한다  
        formDiv.previousElementSibling.classList.remove("d-none");
    });
});
profile
학원 공부 내용 정리

0개의 댓글