공부의 기록/자바 풀 스택 : 수업내용정리

자바 풀 스택 1/22 오전 기록 043-1

파티피플지선 2025. 1. 22. 13:18

9:15 경 학원 도착

 

 

<9:30 1교시>

javascript 의 배열에 점 찍어서 사용하는 메소드 (함수를 전달하는 함수)

배열.forEach((item, index)=>{ });

배열.map(item=>{

       return    newItem

 });  기존 배열에 저장된 아이템을 이용해서 새로운 배열을 얻어낼 때 사용

배열.map(item => newItem); 이라는 람다식으로도 쓸 수 있다.

 

 

 

 

배열.concat(  )  :   배열에, 전달된 새로운 아이템을 추가한 새로운 배열을 얻음

마찬가지로 ...names로 배열을 spread 해놓고 추가할 수도 있음

 

 

 

 

배열.filter();   : 아이템을 조건에 따라 필터해서 리턴된 값이 true면 아이템을 남기고 리턴된 값이 false 면 제거해서 새로운 배열을 만듦

    <script>
            const names=["친구1","친구2","친구3"];
            const result1=names.concat("친구4");
            const result2=names.concat("친구4", "친구5")

            //concat() 함수를 대신할 수 있는 표현식
            const result3=[...names, "친구4"];
    </script>

이 또한 람다식으로 쓸 수 있다고 한다.

 

 

람다식을 쓸 수 있는 조건이 궁금해졌다. 알것 같기도 한데, 나중에 질문해봐야지.

 

 

정규표현식을 사용해서 filter를 사용할 수도 있다.

정규표현식을 제대로 쓰는게 중요하다. 처음에 ^시작과 $끝 안넣고 했음

    <script>
        const nums = [-10, 20, 30, -5, -21, 43, 16];
       
        const result1 = nums.filter(item=>{
            console.log("호출됨!");
            return item >0;
        });
        const result2=nums.filter(item=>item<0);

        const msgs= ["hi", "bye", "안녕", "잘가", "hello"];
        //msgs 배열에서 영문자로만 구성된 새로운 배열 얻어내기
        const result3=msgs.filter(item=>{
            const reg_msgs = /^[a-zA-Z]+$/;
            return reg_msgs.test(item);
        })

        const reg_msgs = /^[a-zA-Z]+$/;
        const result4=msgs.filter(msg=>reg.test(msg));
    </script>

 

 

 

    <script>
        const nums = [-10, 20, 30, -5, -21, 43, 16];
       
        const result1 = nums.filter(item=>{
            console.log("호출됨!");
            return item >0;
        });
        const result2=nums.filter(item=>item<0);

        const msgs= ["hi", "bye", "안녕", "잘가", "hello"];
        //msgs 배열에서 영문자로만 구성된 새로운 배열 얻어내기
        const result3=msgs.filter(item=>{
            const reg_msgs = /^[a-zA-Z]+$/;
            return reg_msgs.test(item);
        })

        const reg_msgs = /^[a-zA-Z]+$/;
        const result4=msgs.filter(msg=>reg_msgs.test(msg));

        const phones = [
            { name: "iPhone 14", price: 999 },
            { name: "Samsung Galaxy S23", price: 899 },
            { name: "Google Pixel 8", price: 799 },
            { name: "OnePlus 11", price: 729 },
            { name: "Xiaomi Mi 13", price: 599 },
            { name: "Sony Xperia 1 V", price: 1199 },
            { name: "Huawei P60 Pro", price: 899 },
            { name: "Asus ROG Phone 7", price: 999 },
            { name: "Oppo Find X6 Pro", price: 849 },
            { name: "Motorola Edge 40", price: 699 },
        ];

        //phones 배열에서 전화기 가격이 800달러 이상인 전화기 정보만 담긴 새로운 배열얻어내보기
        const result5=phones.filter(item=>{
            return item.price>800
        });

        const result6=phones.filter(phone=>phone.price >=800)
    </script>

 

 

배열.sort() : 새로운 배열을 만들지 않고 바로 그 배열의 아이템을 오름차순/내림차순 정렬하기

    <script>
        const nums=[20,30,10,5,7];
        const result1 = nums.sort((one, two)=>one-two);
        //새로운 배열을 만들지 않고 바로 그 배열의 아이템을 오름차순 정렬
   
        const nums2=[20,30,10,5,7];
        const result2 = nums2.sort((one, two)=>two-one);
        //새로운 배열을 만들지 않고 바로 그 배열의 아이템을 내림차순 정렬
    </script>

 

 

 

 

 

<10:30 2교시>

로그인 폼 만들기

login-form.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<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="submit">로그인</button>
		</form>
	</div>
</body>
</html>

 

 

 

getData 메소드가 여러번 정의되어 있다 오버로딩 되어 있다.

 

 

 

코딩 팁 : 코딩하다가 잘 안되면 주석으로 논리부터 작성한 다음에 논리에 맞게 코딩을 작성한다.

 

 

로그인된 user 정보를 session 영역에 담는데 이외에도 프라이머리키, userName, role 정도를 담아두는 편이다.

그래서 SessionDto를 하나 더 만든다.

package test.user.dto;

public class SessionDto {
	private long num;
	private String userName;
	private String role;
	public SessionDto() {}
	public SessionDto(long num, String userName, String role) {
		super();
		this.num = num;
		this.userName = userName;
		this.role = role;
	}
	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 getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	};
}

 

 

상태가 2가지니까 불리언으로 상태값을 관리하려고 상태를 관리할 변수를 선언을 해줌.

 

login.jsp

<%@page import="test.user.dto.SessionDto"%>
<%@page import="test.user.dao.UserDao"%>
<%@page import="test.user.dto.UserDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%
	// 1. 폼 전송되는 userName, password 를 읽어와서
	String userName=request.getParameter("userName");
	String password=request.getParameter("password");
	//2. 아이디에 해당하는 회원정보를 userdao 객체를 이용해서 얻어와서
	UserDto dto = UserDao.getInstance().getData(userName);
	//3. 실제로 존재하는 아이디이고, 존재한다면 비밀번호도 일치하는지 비교해서
	boolean isLoginSuccess=false;
	if(dto!=null){
		//비밀 번호 확인 해서 
		if(dto.getPassword().equals(password)){//비밀번호까지 일치한다면 
			//로그인 처리를 한다(로그인된 user 정보를 session 영역에 담는다 * 이외에도 프라이머리키, userName, role 정도를 담아두는 편이다.)
			SessionDto sessionDto=new SessionDto();
			sessionDto.setNum(dto.getNum());
			sessionDto.setUserName(dto.getUserName());
			sessionDto.setRole(dto.getRole());
			//로그인 처리 해주기
			session.setAttribute("sessionDto", sessionDto);
			isLoginSuccess=true;
		}
	}
	//일치하면 로그인 처리 후 응답, 일치하지 않으면 일치하지 않는다고 응답

%>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div class="container">
		<%if(isLoginSuccess){%>
		<p><strong><%=dto.getUserName() %></strong>님 로그인 되었습니다.</p>
		<a href="${pageContext.request.contextPath}/">확인</a>
		<%}else{ %>
		<p>아이디 또는 비밀번호가 일치하지 않습니다.</p>
		<a href="${pageContext.request.contextPath}/user/login-form.jsp">다시 입력</a>
		<%} %>
	</div>
</body>
</html>

 

 

login-form.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	//Get 방식 파라미터 url 이라는 이름으로 전달되는 값이 있는지 읽어와 보기
	String url=request.getParameter("url");
	//만일 넘어오는 값이 없다면
	if(url==null){
		//로그인 후에는 인덱스 페이지로 갈 수 있도록 한다.
		String cPath=request.getContextPath();
		url=cPath+"/index.jsp";
	}
	
%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div class="container">
		<h1>로그인 폼</h1>
		<form action="login.jsp" method="post">
		<input type="hidden" name=url value=<%=url %> />
			<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="submit">로그인</button>
		</form>
	</div>
</body>
</html>



 

 

로그아웃 페이지까지

logout.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	//1. 세션 초기화
	session.invalidate();
	//2. 응답
%>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<script>
		alert("로그아웃되었습니다");
		//자바스크립트로 페이지 이동시키기
		location.href="${pageContext.request.contextPath}/";
		
	</script>
	
</body>
</html>

 

 

 

 

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div class="class">
		<c:choose>
			<c:when test="${empty sessionScope.sessionDto}">
				<p>
					<a href="${pageContext.request.contextPath}/user/login-form.jsp">로그인</a>
					<a href="${pageContext.request.contextPath}/user/signup-form.jsp">회원가입</a>				
				</p>
			</c:when>
			<c:otherwise>
				<p>
					<strong>${sessionDto.userName}</strong>님 로그인 중...
					<a href="${pageContext.request.contextPath}/user/logout.jsp">로그아웃</a>
				</p>
			</c:otherwise>
		</c:choose>
	
		<h1>인덱스 페이지입니다.</h1>	
		<ul>
			<li><a href="${pageContext.request.contextPath}/jstl/hello.jsp">jstl 테스트</a></li>
			<li><a href="${pageContext.request.contextPath}/user/signup-form.jsp">회원가입</a></li>
			<li><a href="${pageContext.request.contextPath}/user/login-form.jsp">로그인</a></li>
		</ul>
	</div>
</body>
</html>

 

 



 

<11:30 3교시>

로그인 된 사람만 사용할 수 있는 페이지 만들기

1. 일단 그 페이지 만드는데, 이 아래 같은 페이지면 로그인 안 한 사람도 사용할 수 있는 상태임

2. 해야할 것 : 로그인 안 한 사람은 로그인 필터링으로 로그인폼 페이지를 리다이렉트 해야 함 -> jsp로 요청하기 전에 필터로 확인해서 그 다음에 리다이렉트 하기

 

 

 

jakarta.servlet 의 필터 인터페이스를 구현하기

 

override

 

 

memberonly 하위의 경로의 모든 요청에 대해 응답하는 필터.

저 이외에도 staff만 접근할 수 있는 페이지나 admin만 참고할 수 있는 페이지도 있을 수 있다.

 

 

session은 request를 통해서 세션객체를 직접 코딩해서 얻는다.

 

 

 

리다이렉트 : 클라이언트로 하여금 특정 경로로 요청을 다시 하라고 응답을 줌 -> 웹브라우저가 응답을 다시 클라이언트에게 보여줘서 클라이언트로 하여금 다시 특정 경로로 요청을 하게 함

포워드 : 응답을 위임

 

 

아 3교시부터 엄청 졸았다... 일단 위에 올렸던거 다 조금씩 고치는 거 같았어서 일단 최종으로 된 거 코드 백업...

<12:30 4교시>

기능 추가한거까지 일단 코드 업로드....ㅠㅠ 야자해야할듯? ㅠㅠ

더보기

login-form.jsp

package test.filter;

import java.io.IOException;
import java.net.URLEncoder;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import test.user.dto.SessionDto;


@WebFilter({"/member-only/*"})
public class LoginFilter implements Filter{
	
	//@WebFilter()에 명시한 패턴의 요청을 하면 아래의 메소드가 호출된다
	@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
		//매개변수에 전달된 객체를 이용해서 부모타입을 자식타입으로 캐스팅하여 객체의 참조값을 얻어낸다.
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        //session 영역에서 로그인된 정보를 얻어내기 위한 객체
        HttpSession session = req.getSession();
        //세션 영역에 sessionDto 라는 키값으로 저장된 세션 값이 있으면 얻어내서 원래 type으로 캐스팅
        SessionDto dto = (SessionDto) session.getAttribute("sessionDto");
        //만일 로그인하지 않았다면
        if (dto == null) { 
        	//로그인 페이지로 리다이렉트 시키는 메소드를 호출해서 리다이렉트 시킴
            redirectToLogin(req, res);
            //메소드를 여기서 끝내기
            return;
        }   
        // Role-based authorization : role을 확인해서 /admin/*, /staff/* 요청도 필터링 해주는 역할
        String role = dto.getRole();
        String requestURI = req.getRequestURI();
       
        if (requestURI.startsWith(req.getContextPath() + "/admin") && !"ADMIN".equals(role)) {
        	//금지된 요청이라고 응답한다(관리자만 쓰는거니까 에러페이지를 굳이 쓸 필요는 없음)
        	res.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied.");
            return;
        }

        if (requestURI.startsWith(req.getContextPath() + "/staff") && !"STAFF".equals(role) && !"ADMIN".equals(role)) {
            //금지된 요청이라고 응답한다(직원이 쓸 수 있는거)
        	res.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied.");
            return;
        }

        // 여기까지 실행의 흐름이 넘어오면 요청의 흐름을 계속 이어간다(필터를 하지 않겠다는 것)Allow access for USER, STAFF, ADMIN
        chain.doFilter(request, response);
    }

	
	//리다이렉트로 응답하는 메소드(요청을 새로운 경로로 다시 하라는 응답)
    private void redirectToLogin(HttpServletRequest req, HttpServletResponse res) throws IOException {
        //원래 요청 url을 읽어온다
    	String url = req.getRequestURI();
    	//혹시 뒤에 query parameter가 있다면 걔 역시 읽어온다. ?num=xxx&count=ccc
        String query = req.getQueryString();
        String encodedUrl = query == null ? URLEncoder.encode(url, "UTF-8") : URLEncoder.encode(url + "?" + query, "UTF-8");
        //로그인 페이지로 리다이렉트 이동하면서 원래 가려던 목적지 정보도 같이 넘겨줌.
        res.sendRedirect(req.getContextPath() + "/user/login-form.jsp?url=" + encodedUrl);
    }

}

 

login.jsp

<%@page import="java.net.URLEncoder"%>
<%@page import="test.user.dto.SessionDto"%>
<%@page import="test.user.dao.UserDao"%>
<%@page import="test.user.dto.UserDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%
	// 1. 폼 전송되는 userName, password 를 읽어와서
	String userName=request.getParameter("userName");
	String password=request.getParameter("password");
	//2. 아이디에 해당하는 회원정보를 userdao 객체를 이용해서 얻어와서
	UserDto dto = UserDao.getInstance().getData(userName);
	//3. 실제로 존재하는 아이디이고, 존재한다면 비밀번호도 일치하는지 비교해서
	boolean isLoginSuccess=false;
	if(dto!=null){
		//비밀 번호 확인 해서 
		if(dto.getPassword().equals(password)){//비밀번호까지 일치한다면 
			//로그인 처리를 한다(로그인된 user 정보를 session 영역에 담는다 * 이외에도 프라이머리키, userName, role 정도를 담아두는 편이다.)
			SessionDto sessionDto=new SessionDto();
			sessionDto.setNum(dto.getNum());
			sessionDto.setUserName(dto.getUserName());
			sessionDto.setRole(dto.getRole());
			//로그인 처리 해주기
			session.setAttribute("sessionDto", sessionDto);
			isLoginSuccess=true;
		}
	}
	//로그인 후 가야할 목적지 정보
	String url=request.getParameter("url");
	//로그인 실패를 대비해서 목적지 정보를 인코딩한 결과도 준비한다
	String encodedUrl=URLEncoder.encode(url, "UTF-8");
	
	//일치하면 로그인 처리 후 응답, 일치하지 않으면 일치하지 않는다고 응답

%>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div class="container">
		<%if(isLoginSuccess){%>
		<p><strong><%=dto.getUserName() %></strong>님 로그인 되었습니다.</p>
		<a href="<%=url%>">확인</a>
		<%}else{ %>
		<p>아이디 또는 비밀번호가 일치하지 않습니다.</p>
		<a href="${pageContext.request.contextPath}/user/login-form.jsp?url=<%=encodedUrl%>">다시 입력</a>
		<%} %>
	</div>
</body>
</html>

 

 UserDao.java

package test.user.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import test.user.dto.UserDto;
import test.util.DbcpBean;

public class UserDao {
	//자신의 참조값을 저장할 static 필드
	private static UserDao dao;
	//static 초기화 블럭 (이클래스가 최초로 사용될때 오직 한번만 수행된다)
	static {
		//객체를 생성해서 static 필드에 담는다.
		dao=new  UserDao();
	}
	//외부에서 객체 생성하지 못하도록 생성자의 접근 지정자를 private 로 설정
	private  UserDao() {}
		
	//static 필드에 저장된 GuestDao 의 참조값을 리턴해주는 static 메소드
	public static  UserDao getInstance() {
		return dao;
	}
	
	public UserDto getData(String userName) {
		UserDto dto=null;
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			//Connection Pool 로 부터 Connection 객체 하나 가져오기 
			conn = new DbcpBean().getConn();
			//실행할 sql 문 작성
			String sql = """
				SELECT num, password, email, role, profileImage, createdAt, updatedAt
				FROM users
				WHERE userName=?
			""";
			pstmt = conn.prepareStatement(sql);
			// ? 에 값 바인딩할게 있으면 여기서 하기
			pstmt.setString(1, userName);
			//sql 문 실행하고 결과를 ResultSet 객체로 리턴받기
			rs = pstmt.executeQuery();
			if (rs.next()) {
				dto=new UserDto();
				dto.setNum(rs.getLong("num"));
				dto.setUserName(userName);
				dto.setPassword(rs.getString("password"));
				dto.setEmail(rs.getString("email"));
				dto.setRole(rs.getString("role"));
				dto.setProfileImage(rs.getString("profileImage"));
				dto.setCreatedAt(rs.getString("createdAt"));
				dto.setUpdatedAt(rs.getString("updatedAt"));
			}
		} 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;
	}
	
	public UserDto getData(long num) {
		UserDto dto=null;
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			//Connection Pool 로 부터 Connection 객체 하나 가져오기 
			conn = new DbcpBean().getConn();
			//실행할 sql 문 작성
			String sql = """
				SELECT userName, password, email, role, profileImage, createdAt, updatedAt
				FROM users
				WHERE num=?
			""";
			pstmt = conn.prepareStatement(sql);
			// ? 에 값 바인딩할게 있으면 여기서 하기
			pstmt.setLong(1, num);
			//sql 문 실행하고 결과를 ResultSet 객체로 리턴받기
			rs = pstmt.executeQuery();
			if (rs.next()) {
				dto=new UserDto();
				dto.setNum(num);
				dto.setUserName(rs.getString("userName"));
				dto.setPassword(rs.getString("password"));
				dto.setEmail(rs.getString("email"));
				dto.setRole(rs.getString("role"));
				dto.setProfileImage(rs.getString("profileImage"));
				dto.setCreatedAt(rs.getString("createdAt"));
				dto.setUpdatedAt(rs.getString("updatedAt"));
			}
		} 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;
	}
	
	public boolean insert(UserDto dto) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		int rowCount = 0;
		try {
			conn = new DbcpBean().getConn();
			// 실행할 SQL 문 작성
	        String sql = """
	            INSERT INTO users 
	            (num, userName, password, email)
	            VALUES (users_seq.NEXTVAL, ?, ?, ?)
	        """;
	        pstmt = conn.prepareStatement(sql);
	        // ? 에 값을 여기서 바인딩한다.
	        pstmt.setString(1, dto.getUserName());
	        pstmt.setString(2, dto.getPassword());
	        pstmt.setString(3, dto.getEmail());
			// sql 문 실행하고 변화된 row 의 갯수 리턴받기
			rowCount = pstmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (conn != null)
					conn.close();
				if (pstmt != null)
					pstmt.close();
			} catch (Exception e) {
			}
		}
		if (rowCount > 0) {
			return true;
		} else {
			return false;
		}
	}
	
	public boolean update(UserDto dto) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		int rowCount = 0;
		try {
			conn = new DbcpBean().getConn();
			//실행할 미완성의 sql 문
			String sql = """
				UPDATE users
				SET email=?, profileImage=?, updatedAt=SYSDATE
				WHERE num=?		
			""";
			pstmt = conn.prepareStatement(sql);
			// ? 에 값을 여기서 바인딩한다.
			pstmt.setString(1, dto.getEmail());
			pstmt.setString(2, dto.getProfileImage());
			pstmt.setLong(3, dto.getNum());
			// sql 문 실행하고 변화된 row 의 갯수 리턴받기
			rowCount = pstmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (conn != null)
					conn.close();
				if (pstmt != null)
					pstmt.close();
			} catch (Exception e) {
			}
		}
		if (rowCount > 0) {
			return true;
		} else {
			return false;
		}
	}
	
	public boolean updatePassword(UserDto dto) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		int rowCount = 0;
		try {
			conn = new DbcpBean().getConn();
			//실행할 미완성의 sql 문
			String sql = """
				UPDATE users
				SET password=?, updatedAt=SYSDATE
				WHERE num=?
			""";
			pstmt = conn.prepareStatement(sql);
			// ? 에 값을 여기서 바인딩한다.
			pstmt.setString(1, dto.getPassword());
			pstmt.setLong(2, dto.getNum());
			// sql 문 실행하고 변화된 row 의 갯수 리턴받기
			rowCount = pstmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (conn != null)
					conn.close();
				if (pstmt != null)
					pstmt.close();
			} catch (Exception e) {
			}
		}
		if (rowCount > 0) {
			return true;
		} else {
			return false;
		}
	}
	public boolean updateRole(UserDto dto) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		int rowCount = 0;
		try {
			conn = new DbcpBean().getConn();
			//실행할 미완성의 sql 문
			String sql = """
				UPDATE users
				SET role=?, updatedAt=SYSDATE
				WHERE num=?
			""";
			pstmt = conn.prepareStatement(sql);
			// ? 에 값을 여기서 바인딩한다.
			pstmt.setString(1, dto.getRole());
			pstmt.setLong(2, dto.getNum());
			// sql 문 실행하고 변화된 row 의 갯수 리턴받기
			rowCount = pstmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (conn != null)
					conn.close();
				if (pstmt != null)
					pstmt.close();
			} catch (Exception e) {
			}
		}
		if (rowCount > 0) {
			return true;
		} else {
			return false;
		}
	}
	
	public boolean delete(long num) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		int rowCount = 0;
		try {
			conn = new DbcpBean().getConn();
			//실행할 미완성의 sql 문
			String sql = """
				DELETE FROM users
				WHERE num=?
			""";
			pstmt = conn.prepareStatement(sql);
			// ? 에 값을 여기서 바인딩한다.
			pstmt.setLong(1, num);
			// sql 문 실행하고 변화된 row 의 갯수 리턴받기
			rowCount = pstmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (conn != null)
					conn.close();
				if (pstmt != null)
					pstmt.close();
			} catch (Exception e) {
			}
		}
		if (rowCount > 0) {
			return true;
		} else {
			return false;
		}
	}
}

 

 

 SessionDto.java

package test.user.dto;

public class SessionDto {
	private long num;
	private String userName;
	private String role;
	public SessionDto() {}
	public SessionDto(long num, String userName, String role) {
		super();
		this.num = num;
		this.userName = userName;
		this.role = role;
	}
	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 getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	};
	
	
}

 

 

 

logout.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	//1. 세션 초기화
	session.invalidate();
	//2. 응답
%>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<script>
		alert("로그아웃되었습니다");
		//자바스크립트로 페이지 이동시키기
		location.href="${pageContext.request.contextPath}/";
		
	</script>
	
</body>
</html>

 

 index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div class="class">
		<c:choose>
			<c:when test="${empty sessionScope.sessionDto}">
				<p>
					<a href="${pageContext.request.contextPath}/user/login-form.jsp">로그인</a>
					<a href="${pageContext.request.contextPath}/user/signup-form.jsp">회원가입</a>				
				</p>
			</c:when>
			<c:otherwise>
				<p>
					<a href="${pageContext.request.contextPath}/user/protected/info.jsp"><strong>${sessionDto.userName}</strong>님 로그인 중...</a>
					<a href="${pageContext.request.contextPath}/user/logout.jsp">로그아웃</a>
				</p>
			</c:otherwise>
		</c:choose>
	
		<h1>인덱스 페이지입니다.</h1>	
		<ul>
			<li><a href="${pageContext.request.contextPath}/jstl/hello.jsp">jstl 테스트</a></li>
			<li><a href="${pageContext.request.contextPath}/user/signup-form.jsp">회원가입</a></li>
			<li><a href="${pageContext.request.contextPath}/user/login-form.jsp">로그인</a></li>
			<li><a href="${pageContext.request.contextPath}/member-only/play.jsp">놀러가기</a></li>
		</ul>
	</div>
</body>
</html>

 

 

 play.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div class="container">
		<h1>로그인된 회원 전용 공간</h1>
		<p>
			<strong>${sessionDto.userName }</strong>님의 로그인 페이지 입니다.
			<a href="${pageContext.request.contextPath}/">인덱스로 돌아가기</a>
		</p>
	
	</div>
</body>
</html>

 

 LoginFilter.java

package test.filter;

import java.io.IOException;
import java.net.URLEncoder;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import test.user.dto.SessionDto;


@WebFilter({"/member-only/*", "/staff/*", "/admin/*","/user/protected.jsp"})
public class LoginFilter implements Filter{
	
	//@WebFilter()에 명시한 패턴의 요청을 하면 아래의 메소드가 호출된다
	@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
		//매개변수에 전달된 객체를 이용해서 부모타입을 자식타입으로 캐스팅하여 객체의 참조값을 얻어낸다.
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        //session 영역에서 로그인된 정보를 얻어내기 위한 객체
        HttpSession session = req.getSession();
        //세션 영역에 sessionDto 라는 키값으로 저장된 세션 값이 있으면 얻어내서 원래 type으로 캐스팅
        SessionDto dto = (SessionDto) session.getAttribute("sessionDto");
        //만일 로그인하지 않았다면
        if (dto == null) { 
        	//로그인 페이지로 리다이렉트 시키는 메소드를 호출해서 리다이렉트 시킴
            redirectToLogin(req, res);
            //메소드를 여기서 끝내기
            return;
        }   
        // Role-based authorization : role을 확인해서 /admin/*, /staff/* 요청도 필터링 해주는 역할
        String role = dto.getRole();
        String requestURI = req.getRequestURI();
       
        if (requestURI.startsWith(req.getContextPath() + "/admin") && !"ADMIN".equals(role)) {
        	//금지된 요청이라고 응답한다(관리자만 쓰는거니까 에러페이지를 굳이 쓸 필요는 없음)
        	res.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied.");
            return;
        }

        if (requestURI.startsWith(req.getContextPath() + "/staff") && !"STAFF".equals(role) && !"ADMIN".equals(role)) {
            //금지된 요청이라고 응답한다(직원이 쓸 수 있는거)
        	res.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied.");
            return;
        }

        // 여기까지 실행의 흐름이 넘어오면 요청의 흐름을 계속 이어간다(필터를 하지 않겠다는 것)Allow access for USER, STAFF, ADMIN
        chain.doFilter(request, response);
    }

	
	//리다이렉트로 응답하는 메소드(요청을 새로운 경로로 다시 하라는 응답)
    private void redirectToLogin(HttpServletRequest req, HttpServletResponse res) throws IOException {
        //원래 요청 url을 읽어온다
    	String url = req.getRequestURI();
    	//혹시 뒤에 query parameter가 있다면 걔 역시 읽어온다. ?num=xxx&count=ccc
        String query = req.getQueryString();
        String encodedUrl = query == null ? URLEncoder.encode(url, "UTF-8") : URLEncoder.encode(url + "?" + query, "UTF-8");
        //로그인 페이지로 리다이렉트 이동하면서 원래 가려던 목적지 정보도 같이 넘겨줌.
        res.sendRedirect(req.getContextPath() + "/user/login-form.jsp?url=" + encodedUrl);
    }

}

 

 

info.jsp

<%@page import="test.user.dao.UserDao"%>
<%@page import="test.user.dto.UserDto"%>
<%@page import="test.user.dto.SessionDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%
	//session 영역에서 SessionDto 객체를 얻어낸다.
	SessionDto sessionDto=(SessionDto)session.getAttribute("sessionDto");
	//회원 번호를 이용해서 UserDto 정보 얻어내기
	UserDto dto=UserDao.getInstance().getData(sessionDto.getNum());
	//el 에서 dto 를 사용가능하게 request 영역에 담는다.
	request.setAttribute("dto", dto);
	
	//아래에서 가입정보를 응답한다 
%>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/user/protected/info.jsp</title>
<style>
	#profileImage{
		width: 100px;
		height: 100px;
		border: 1px solid #cecece;
		border-radius: 50%;
	}
</style>
</head>
<body>
	<div class="container">
		<h1>가입 정보 입니다</h1>
		<table>
			<tr>
				<th>아이디</th>
				<td>${dto.userName }</td>
			</tr>
			<tr>
				<th>비밀번호</th>
				<td>
					<a href="pwd-update-form.jsp">수정하기</a>
				</td>
			</tr>
			<tr>
				<th>프로필 이미지</th>
				<td>
					<c:choose>
						<c:when test="${empty dto.profileImage }">
							<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16">
								<path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/>
								<path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1z"/>
							</svg>						
						</c:when>
						<c:otherwise>
							<img id="profileImage" src="${pageContext.request.contextPath }/upload/${dto.profileImage}" alt="프로필 이미지">
						</c:otherwise>
					</c:choose>
				</td>
			</tr>
			<tr>
				<th>이메일</th>
				<td>${dto.email }</td>
			</tr>
			<tr>
				<th>가입일</th>
				<td>${dto.createdAt }</td>
			</tr>
			<tr>
				<th>수정일</th>
				<td>${dto.updatedAt }</td>
			</tr>
		</table>
	</div>
</body>
</html>