37일차 내용 정리

채공부·2025년 7월 15일

CSS

div.box

  • div라는 태그이면서 동시에 클래스가 box인 요소
<div class="box">

div .box

  • div 안에 있는 자손 요소 중에서 클래스가 box인 요소
<div>
	<p class="box">
</div>

선택자

가상 클래스 선택자

  • : 로 표시

hover

  • 요소 위에 마우스를 올리는 순간 :hover 상태가 된다
    ➜ 실제로 생기는 것이 아닌 가상 상태
.box:hover{
	background-color: yellow;
}

focus

  • 어떤 요소에 포커스가 향할 때
button:focus{
	color: red;
}

active

  • 요소를 클릭하고 있는 동안 적용
button:active{
	width: 100px;
	height: 100px;
}

<button p-class="focus active">

button:focus{
	color: red;
}

button:active{
	width: 100px;
	height: 100px;
}
  • 한 번도 방문하지 않은 링크
a:link{
	color: #000;
}

visited

  • 이미 방문했던 링크
a:visited{
	color: green;
}

가상 요소 선택자

  • 원래 정석으로는 :: 로 표시
  • 보이지 않는 콘텐츠를 생성할 때 사용

first-letter & first-line

p:first-letter{
	font-weight: bold;
	color: red;
}
#one:first-line{
	background-color: yellow;
}

before

  • 어떤 컨텐츠 바로 앞에
.quote:before{
	content:"'";
	color: red;
}

after

  • 어떤 컨텐츠 바로 뒤에
.quote:after{
	content:"'";
	color: blue;
}

position (위치)

static

  • 모든 요소의 default position 속성의 값
  • 위치 지정 불가, 문서의 흐름에 따라 위치가 결정
  • top, left, right, bottom 속성 무시

relative

  • 상대 좌표
    ➜ 원래 기본으로 표시되여야 하는 위치을 기준으로 상대 좌표 가능
⭐ 요소의 원래 위치는 그대로 유지 = 보이는 위치만 바뀌고 다른 요소에 영향이 없다
#one{
	position: relative;
	top: 150px;  ➜ 위에서 떨어진 거리 = y 좌표
	left: 150px; ➜ 왼쪽에서 떨어진 거리 = x 좌표
}

absolute

  • 특정 요소를 기준으로 절대 좌표에 배치하고자 할 때 사용
    특정 요소 = 부모 요소
  • 부모 요소 중에 position: relative, absolute, fixed, sticky가 처음 나오는 요소를 기준으로 배치 가능
    ➜ 없다면 body 기준

fixed

  • window 창 을 기준으로 절대 좌표에 배치 할 때 사용
  • 스크롤바를 움직여도 window 기준으로 항상 같은 위치에 존재
    ➜ 가장 많이 사용된다

부모 요소 & 자식 요소 배치

  • 부모 요소 안에서 자식 요소를 원하는 위치에 배치 가능
  • 부모 요소 relative , 자식 요소 absolute
<div class="wrapper">
	<div class="box" id="one">one</div>
	<div class="box" id="two">two</div>
	<div class="box" id="three">three</div>
	<div class="box" id="four">four</div>
	<div class="box" id="center">center</div>
	<div id="test">test</div>
</div>
.wrapper{
	position: relative;
	width: 500px;
	height: 500px;
	margin: 0 auto;
	border: 1px solid red
}
.box{
	position: absolute;
	width: 50px;
	height: 50px;
	background-color: yellow;
}

backdrop

어떤 영역을 덮어버리고 싶다면?

  • position을 absolute 로 한 후 top, left, right, bottom0 으로 설정
#test{
	background-color: #000;
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	color: #fff;
	opacity: 0.5;
	display: none;
}
⭐ opacity = 투명도 (0 ~ 1.0)

배치

float

  • 요소를 좌우로 띄워서 흐르게 한다
    ➜ 주로 이미지, 박스 정렬 등에 사용
#one{
	float: left;
}
#two{
	float: right;
}
⚠️ float 사용 후 레이아웃이 깨질 가능성이 존재
    clear 속성이 필요할 수 있다

display

  • 보이게 할지 말지 설정

none

  • 문서 객체는 만들어 졌지만 공간을 차지하지 않고 보이지 않게 한다

block

  • 한 줄 전체를 차지하는 요소
  • 자동으로 줄 바꿈된다
  • width, height 설정 가능

inline

  • width 와 height 를 지정 불가능
  • left & right margin, padding 을 가질 수 없다
  • top & bottom margin, padding 을 가질 수 없다
  • 왼쪽과 오른쪽에 다른 요소가 올 수 있다

inline-block

  • width, height, margin, padding 모두 가능
  • 왼쪽과 오른쪽에 다른 요소가 올 수 있다
  • inline 처럼 줄 안에 배치되지만 block 처럼 크기 지정 가능
    ➜ 버튼이나 아이콘 정렬에 자주 사용

BootStrap

data-bs-theme = dark

  • 기본값은 light, 어두운 배경에서는 dark로 지정해 흰색 글씨 사용

JSP

JSP 구성

resource.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- /WEB-INF/include/resource.jsp -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-LN+7fdVzj6u52u30Kp6M/trliBMCMKTyK833zpbD+pXdCLuTusPj697FH4R/5mcr" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/js/bootstrap.bundle.min.js" integrity="sha384-ndDqU0Gzau9qJ1lfW4pNLlhNTkCfHzAVBReH9diLvGRem5+R9g2FzA8ZGN954O5Q" crossorigin="anonymous"></script>

footer.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- /WEB-INF/include/footer.jsp -->
<footer class="bg-success text-white py-4 mt-5">
    <div class="container d-flex justify-content-between align-items-center flex-wrap">
        <div>
            <h5 class="mb-0">MyBrand</h5>
        </div>
        <div>
            <a href="#" class="text-white me-3">
                <i class="bi bi-facebook"></i>
            </a>
            <a href="#" class="text-white me-3">
                <i class="bi bi-twitter-x"></i>
            </a>
            <a href="#" class="text-white">
                <i class="bi bi-instagram"></i>
            </a>
        </div>
    </div>
</footer>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- /WEB-INF/include/navbar.jsp -->
<nav class="navbar navbar-expand-md bg-success" data-bs-theme="dark">
    <div class="container">
        <a class="navbar-brand" href="${pageContext.request.contextPath}/">Acorn</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav">
                <li class="nav-item">
                    <a class="nav-link" href="${pageContext.request.contextPath}/member/list.jsp">Member</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="${pageContext.request.contextPath}/book/list.jsp">Book</a>
                </li>
            </ul>
        </div>
    </div>
</nav>

active 처리

  • 피 include 되는 jsp 페이지에 임의로 요청 파라미터를 전달할 수 있다
<jsp:include page="/WEB-INF/include/navbar.jsp">
	<jsp:param value="index" name="thisPage"/>
    					⤷ 파라미터 값	⤷ 파라미터명
</jsp:include>
request.getParameter("thisPage")
navbar.jsp 페이지에서 이런식으로 파라미터를 읽어낼 수 있다
  • navbar.jsp 에 java 코드 추가
<%
	// navbar.jsp 페이지가 어떤 페이지에 include 되었는지 파라미터 읽어오기
	String thisPage = request.getParameter("thisPage");
	// "index" or "member" or "book"
%>
  • 삼항 연산자로 조건을 부여해 탭 메뉴 강조에 사용
<div class="collapse navbar-collapse" id="navbarNav">
    <ul class="navbar-nav">
        <li class="nav-item">
            <a class="nav-link <%= thisPage.equals("member") ? "active" : "" %>" 
               href="${pageContext.request.contextPath}/member/list.jsp">Member</a>
        </li>
        <li class="nav-item">
            <a class="nav-link <%= thisPage.equals("book") ? "active" : "" %>" 
               href="${pageContext.request.contextPath}/book/list.jsp">Book</a>
        </li>
    </ul>
</div>

삭제 이벤트 처리

<td><a href="javascript:" id="deleteLink" data-num="<%=tmp.getNum()%>">삭제</a></td>

<script>
	document.querySelector("#deleteLink").addEventListener("click", (e)=>{});
</script>

⚠️ 오류 상태 : 현재는 가장 a 첫번째 요소에만 이벤트가 발생

  • 반복문으로 행 하나당 각각 이벤트 리스너 등록해주기
<td><a href="javascript:" class="delete-link" data-num="<%=tmp.getNum()%>">삭제</a></td>

<script>
	document.querySelectorAll(".delete-link").forEach(item=>{
		// item 은 클린한 a 요소의 참조값
		item.addEventListener("click", (e)=>{
			// e.target 은 이벤트가 발생한 바로 그 요소의 참조값이다
			// click 이벤트가 발생한 a 요소에 data-num 속성의 value 를 읽어오기
			const num=e.target.getAttribute("data-num");
			const isDelete=confirm(num+" 번 회원을 삭제 하시겠습니까?");
			if(isDelete){
				// delete.jsp 페이지로 이동하게 하면서 삭젷할 회원의 번호도 같이 전달되도록 한다
				location.href="${pageContext.request.contextPath }/member/delete.jsp?num="+num;
				// 결과적으로 delete.jsp?num=X
			}
		});
	});
</script>

회원가입

  • 테이블 & 시퀸스 생성
CREATE TABLE users(
	num NUMBER PRIMARY KEY, -- 회원의 고유번호
	userName VARCHAR2(20) UNIQUE, -- 아이디
	password VARCHAR2(100) NOT NULL, -- 비밀번호
	email VARCHAR2(50) UNIQUE, -- 이메일
	profileImage VARCHAR2(100), -- 프로필 이미지 정보 (처음 가입 시 NULL)
	role VARCHAR2(10) DEFAULT 'ROLE_USER', -- 역할 ROLE_USER(일반 사용자) | ROLE_STAFT(직원) | ROLE_ADMIN(최고 권한 관리자)
	updatedAt DATE, -- 수정 날짜 
	createdAt DATE -- 가입 날짜
);

CREATE SEQUENCE users_seq;
  • 바로가기 링크 생성
<li><a href="${pageContext.request.contextPath}/user/signup-form.jsp">회원가입</a></li>
  • 회원가입 폼 생성
<div class="container">
	<h1>회원가입 양식</h1>
	<form action="signup.jsp" method="post">
		<div>
			<label for="userName">아이디</label>
			<input type="text" name="userName" id="userName" />
		</div>
		<div>
			<label for="password">비밀번호</label>
			<input type="text" name="password" id="password" />
		</div>
		<div>
			<label for="email">이메일</label>
			<input type="text" name="email" id="email" />
		</div>
		<button type="submit">가입</button>
	</form>
</div>
  • UserDto 생성
public class UserDto {
	private long num;
	private String userName;
	private String password;
	private String email;
	private String profileImage;
	private String role;
	private String updatedAt;
	private String createdAt;
	
	// 생성자
	public UserDto() {
		
	}

	// setter, getter 메소드
	public long getNum() {
		return num;
	}

	public void setNum(long num) {
		this.num = num;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getProfileImage() {
		return profileImage;
	}

	public void setProfileImage(String profileImage) {
		this.profileImage = profileImage;
	}

	public String getRole() {
		return role;
	}

	public void setRole(String role) {
		this.role = role;
	}

	public String getUpdatedAt() {
		return updatedAt;
	}

	public void setUpdatedAt(String updateAt) {
		this.updatedAt = updatedAt;
	}

	public String getCreatedAt() {
		return createdAt;
	}

	public void setCreatedAt(String createdAt) {
		this.createdAt = createdAt;
	}
}
  • UserDao 의 insert 생성 : 회원정보 추가
public boolean insert(UserDto dto) {
	Connection conn = null;
	PreparedStatement pstmt = null;
	int rowCount = 0;
	try {
		conn = new DbcpBean().getConn();
		String sql = """
				INSERT INTO users
				(num, userName, password, email, updatedAt, createdAt)
				VALUES(users_seq.NEXTVAL, ?, ?, ?, SYSDATE, SYSDATE)
				""";
		pstmt = conn.prepareStatement(sql);
		pstmt.setString(1,dto.getUserName());
		pstmt.setString(2, dto.getPassword());
		pstmt.setString(3, dto.getEmail());
		rowCount = pstmt.executeUpdate();
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		try {
			if (pstmt != null)
				pstmt.close();
			if (conn != null)
				conn.close();
		} catch (Exception e) {
		}
	}
	if (rowCount > 0) {
		return true;
	} else {
		return false;
	}
}
  • sign.jsp
<%
	String userName = request.getParameter("userName");	
	String password = request.getParameter("password");
	String email = request.getParameter("email");
	
	// 사용자가 입력한 비밀번호를 암호화한 비밀번호를 얻어낸다
	String hashed = BCrypt.hashpw(password, BCrypt.gensalt());
	System.out.println("암호화된 비밀번호"+hashed);
	
	// dto 에 담아서
	UserDto dto = new UserDto();
	dto.setUserName(userName);
	dto.setPassword(hashed);
	dto.setEmail(email);
	
	// dao 객체를 이용해서 DB 에 저장하고
	boolean isSuccess = new UserDao().insert(dto);
	
	// 응답한다
%>
<div class="container">
	<%if(isSuccess) { %>
		<p>
			<strong><%=userName %></strong> 님 회원가입 되었습니다
			<a href="loginform.jsp">로그인 하러 가기</a>
		</p>
	<%} else{ %>
		<p>
			가입 실패
			<a href="signup-form.jsp">다시 가입하기</a>
		</p>
	<%} %>
</div>

로그인

<a href="loginform.jsp">로그인 하러 가기</a>
  • 로그인 폼 생성
<div class="container">
	<h1>로그인 양식</h1>
	<form action="login.jsp" method="post">
		<div>
			<label for="userName">아이디</label>
			<input type="text" name="userName" id="userName" />
		</div>
		<div>
			<label for="password">비밀번호</label>
			<input type="password" name="password" id="password" />
		</div>
		<button type="submt">로그인</button>
	</form>
</div>
  • UserDao 의 select 생성 : 회원 로그인
// userName 을 이용해서 회원 한 명의 정보를 리턴해주는 메소드
public  UserDto getByUserName(String userName) {
	UserDto dto =  null;
	Connection conn = null;
	PreparedStatement pstmt = null;
	ResultSet rs = null;
	try {
		conn = new DbcpBean().getConn();
		String sql = """
				SELECT num, userName, password, email, profileImage, role, updatedAt, createdAt
				FROM users
				WHERE userName = ?
				""";
		pstmt = conn.prepareStatement(sql);
		pstmt.setString(1, userName);
		rs = pstmt.executeQuery();
		// select 되는 userName은 unique 속성을 가지기에 if 로도 가능
		if (rs.next()) {
			// UserDto 객체를 생성해서
			dto = new UserDto();
			// select 된 정보를 담는다
			dto.setNum(rs.getLong("num"));
			dto.setUserName(userName);
			dto.setPassword(rs.getString("password"));
            dto.setEmail(rs.getString("email"));
            dto.setProfileImage(rs.getString("profileImage"));
			dto.setRole(rs.getString("role"));
			dto.setUpdateAt(rs.getString("updatedAt"));
			dto.setCreatedAt(rs.getString("createdAt"));
		}
	} 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 dto;
}
  • login.jsp
<%
	// 폼 전송되는 아이디와 비밀번호 추출하기
	String userName = request.getParameter("userName");
	String password = request.getParameter("password");
	
	// 아이디 비밀번호가 유효한 정보인지 여부
	boolean isValid = false;
	
	// DB 에서 userName 을 이용해서 select 되는 정보가 있는지 select 해 본다
	UserDto dto = new UserDao().getByUserName(userName);
	// 만일 select 된 정보가 있다면 (최소한 userName 은 존재한다는 것)
	if(dto != null){
		// raw 비밀번호와 DB 에 저장된 암호화된 비밀번호를 비교해서 일치하는지 확인
		// BCrypt.checkpw(입력한 비밀번호, 암호화된 비밀번호)
		isValid = BCrypt.checkpw(password, dto.getPassword());
	}
	
	/* 만일 입력한 아이디와 비밀번호가 유효한 정보라면 로그인 처리를 한다
	   jsp 에서 기본 제공해주는 HttpSession 객체에 userName 을 저장
	   HttpSession 객체에 저장하면 응답을 한 이후에 다음번 요청에서 HttpSession 객체에 저장된 정보를 읽어올 수 있다
	   세션 객체에 담긴 정보는 어떤 요청도 하지 않고 일정 시간이 흐르면 자동 삭제된다
	   필요하다면 (로그아웃이 요청되면) 강제로 세션 객체에 담긴 정보를 삭제할 수도 있다
	   세션 객체에 담긴 로그인 정보를 삭제하는 것이 "로그아웃"
	   세션 객체에 로그인 정보(userName)를 저장하는 것이 "로그인"
	*/
	if(isValid){
		// HttpSession 객체에 "userName" 이라는 키값으로 userName 을 저장
		session.setAttribute("userName", userName);
		// 세션 유지시간 설정 (초단위)
		session.setMaxInactiveInterval(60*10); // 설정하지 않으면 기본 30분
	}
%>
<div class="container">
	<%if(isValid) {%>
		<p>
			<strong><%=userName%></strong> 회원님 로그인 되었습니다
		</p>
	<%} else {%>
		<p>
			아이디 혹은 비밀번호가 틀립니다
			<a href="loginform.jsp">다시 로그인</a>
		</p>
	<%} %>
</div>
  • index.jsp 에 추가
<%
	// 세션에 "userName" 이라는 키값으로 저장된 값이 있는지 읽어와 본다
	String userName = (String)session.getAttribute("userName");
%>
<%if(userName != null) {%>
	<strong><%=userName%></strong> 님 로그인 중
<%} %>
profile
학원 공부 내용 정리

0개의 댓글