본문 바로가기
JSP/Java Script

2024_07_19_금 ⭐⭐⭐

by 알케니브 2024. 7. 19.

오늘의 코딩순서

(폴더: och11_sessionMember) ⭐⭐⭐MVC

  • loginForm.jsp + loginPro.jsp + memberDao.class + sessionMain.jsp + sessionLogout.jsp
    (>> 0718일지의 persom.jsp~subscribe.jsp의 연장선)

(폴더: och14) >> webapp 폴더에 sub1, sub2 폴더 만듬

(폴더: och14_sub1, och14_sub2, och14)

  • hello.jsp + SimpleFilter.Class (filter파일) + web.xml / + winner.jsp + LoginCheck.Class (filter파일) / login.jsp + check.jsp / SimpleFilter3.Class (filter파일)

(폴더: och15_ajax) >>js 폴더에 아래 세 파일 넣음 / 자카르타 파일 4개, och10의 context.xml 파일 넣음

httpRequest.js
0.00MB
jquery.js
0.27MB
Member.js
0.00MB

(폴더: och15_ajax_ch01)

  • hello.html + hello.jsp

오늘의 코딩 포인트

(폴더: och11_sessionMember)

  • loginForm.jsp >>로그인 창 만들기, MEMBER1 TBL에 있는 정보 일치할때 화면
<%@ 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>
<style type="text/css">
	table		{ background-color: pink;}
</style>
</head>
<body>
<h2>로그인</h2>
	<form action="loginPro.jsp">
		<table>
			<tr>
				<td>아이디</td>
				<td><input	type="text"		name="id"		required="required"></td>
			</tr>
			<tr>
				<td>비밀번호</td>
				<td><input	type="password"	name="password"	required="required"></td>
			</tr>
			<tr>
				<td><input type="submit" value="확인"></td>
				<td><input type="reset" value="취소"></td>
			</tr>
		</table>
	</form>
	<input type="button" value="회원가입" onclick="location.href='../session/person.jsp'">
	
</body>
</html>

MEMBER1 TBL에 있는 정보 일치할때 화면

  • loginPro.jsp (현장 HW1) >>로그인 로직 짜기
    Tip)  0718일지의 subscribe.jsp 참고하기
<%@page import="och11.MemberDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" errorPage="../error.jsp"%>	<!-- error코드 까먹지 말기! -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
	//현장 HW 1
	//1-1. id, password GET
	String id = request.getParameter("id");
	String password = request.getParameter("password");
	
	//1-2. MemberDao md Instance 생성
	MemberDao md = new MemberDao();
	int result = md.check(id, password);
	if (result ==1){
		session.setAttribute("id", id);
		response.sendRedirect("sessionMain.jsp");
	} else if (result == 0)	{		
		
%>
	<script type="text/javascript">
		alert("암호가 틀려! 누구냐!");
		history.go(-1);	//TBL에 있는 ID와는 일치하는데 비밀번호는 틀렸을때
	</script>
<%	} else { %>
	<script type="text/javascript">
		alert("넌 누구냐! 20년간 만두만 주고...");
		history.back();	//EMBER1 TBL에 없는 정보를 입력했을때 //해커 막을때 사용
	</script>
<%
	}
%>

</body>
</html>

ID는 맞는데 암호는 틀렸을때
ID랑 암호 전부 틀렸을때(MEMBER1 TBL에 없는 정보를 입력했을때)

  • memberDao.Class >> 성공+ 오류 MVC 짜기(0718일지의 memberDao에 추가한거 맞음!
    ∵0718의 데이터의 연장선이고 DAO는 완전히 다른 정보가 아닌 이상, 한곳에 몰아적는게 맞음)
    +++
    och15_ajax_ch03의 memberDao와는 달리 여기서는 Singleton을 사용하지 않고 DBCP만 사용함
    ∵ DBCP만 쓰는 회사도 있고, DBCP와 Singleton을 같이 사용하는 회사가 있기 때문에 다양한 케이스를 보여주심
package och11;

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

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class MemberDao {	//MVC 짜기, person.jsp용 짜기
	
	//여기서는 Singleton을 사용하지 않고 DBCP만 사용함
	private Connection getConnection() throws SQLException	{
		Connection conn = null;

		try {
			Context ctx = new InitialContext();	//surround try catch로 감싸주기
			DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/OracleDB");
			conn = ds.getConnection();
			
		} catch (NamingException e) {
			// TODO Auto-generated catch block
			System.out.println("e.getMessage()->"+e.getMessage());
		}
		
		return conn;
	}
	
	public int insert(MemberDto member) throws SQLException {
		Connection conn = null;
		int result = 0;
		PreparedStatement pstmt = null;
		String sql = "insert into member1 values(?,?,?,sysdate)";
		try	{
			conn = getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, member.getId());
			pstmt.setString(2, member.getPassword());
			pstmt.setString(3, member.getName());
			result = pstmt.executeUpdate();
		}catch(Exception e)	{ System.out.println(e.getMessage());
		}finally {
			if	(pstmt != null) pstmt.close();
			if	(conn != null) conn.close();
			
		}
		return result;
	}
	
	//loginForm.jsp용 로직추가
	//현장 HW 2 (DB의 MEMBER TBL 데이터활용)
	//2-1. RESULT 1	:	id, password TBL에 등록해둔 내용과 일치할 때 
	//2-2. RESULT 0 :	id는 맞는데, password가 틀렸을때 
	//2-3. RESULT -1 :	id가 없을때(해커 유입 방지용)
	public int check(String id, String password) throws SQLException	{
		Connection conn = null;
		int result = 0;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = "select password from member1 where id=?";
		try	{
			conn = getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, id);
			rs = pstmt.executeQuery();
			if	(rs.next())	{
				String dbPassword = rs.getString(1);
				if	(dbPassword.equals(password)) 
					result = 1;
				else
					result = 0;				
			} else result = -1; 
		}catch(Exception e)	{
			System.out.println(e.getMessage());
		}finally {
			if	(rs != null) rs.close();
			if	(pstmt != null) 
				pstmt.close();
			if	(conn != null) 
				conn.close();
		}
		return result;
	}
	
	
}

 

  • sessionMain.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>
<%	//로그인 성공시 나오는 화면
	String id = (String)session.getAttribute("id");
	if	(id == null || id =="")	{
		response.sendRedirect("loginForm.jsp");	//로그인창에 잘못 입력시 처음으로 되돌아감
	}
%>
<%=id %>님 격하게 환영합니다.<p>
	
	<input type="button" value="로그아웃" onclick="location.href='sessionLogout.jsp'">
	<!-- 로그아웃으로 가는 버튼 + 이동되는 창 만들기 -->
</body>
</html>

  • sessionLogout.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>
<% 
	String id = (String)session.getAttribute("id");
	System.out.println("Logout session id->"+id);
	//session이 살아있는지 확인용 두 줄

	session.invalidate();	//원래는 이거 한 줄만 코딩해도 작동함
%>
<script type="text/javascript">		//로그아웃 버튼 눌렀을때 반응
	alert("로그아웃 됐습니다");
	location.href="sessionMain.jsp";	
	//로그아웃하고 sessionMain으로 가자마자 loginForm으로 이동하여, 결과적으로 맨 처음으로 이동함
</script>
</body>
</html>

 



(폴더: och13)

  • uploadForm.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>
<h2>jsp로 파일 업로드</h2>
	<form action="upload.jsp" method="post" enctype="multipart/form-data">
		<label for="name">작성자</label>
				<input type="text" name="name"			required="required">
		제목 :	<input type="text" name="title"			required="required">
		파일명 : <input type="file" name="uploadFile"	required="required">
		<input type="submit" value="확인">
	</form>
</body>
</html>
    • upload.jsp
      Tip)
      • MultipartRequest
        • HTTP 프로토콜에서 여러 개의 데이터 파트를 한 번에 서버로 전송할 수 있도록 하는 요청 형식
        • 주로 파일 업로드와 같은 경우에 사용되며, 웹 애플리케이션에서 클라이언트가 서버에 파일이나 데이터를 전송할 때 많이 활용됨
        • 클라이언트와 서버 간의 복합 데이터 전송을 효율적으로 처리할 수 있게 해줌
        • MultipartRequest는 여러 부분으로 구성되며, 각 부분은 고유한 헤더와 데이터 본문을 가질 수 있음
        • 파일 업로드: 사용자가 웹 애플리케이션에서 파일을 서버로 업로드할 때 주로 사용됨
        • 복합 데이터 전송: 하나의 요청에서 여러 종류의 데이터를 전송해야 하는 경우, 예를 들어 텍스트와 이미지를 함께 전송할 때 유용함
      • DefaultFileRenamePolicy()
        • 파일 업로드 시 파일 이름이 충돌하지 않도록 자동으로 파일 이름을 변경해주는 정책을 제공하는 클래스
        • 주로 파일 업로드 기능을 처리하는 서블릿이나 다른 서버 측 코드에서 사용됨
        • 주로 Java 웹 애플리케이션에서 파일 업로드 기능을 구현할 때, 특히 Apache Commons FileUpload 라이브러리나 similar한 라이브러리와 함께 사용됨
        • 파일 이름 충돌 방지같은 이름의 파일이 이미 서버에 존재할 경우, 새로운 파일의 이름을 자동으로 변경하며, 기본적으로 숫자를 붙여서 새로운 파일 이름을 생성함
        • 장점
          • 자동 파일 이름 관리: 개발자가 별도로 파일 이름 충돌을 처리하는 로직을 작성하지 않아도 됨
          • 안정성: 파일 이름 충돌로 인한 데이터 덮어쓰기 문제를 방지할 수 있음
          • 간편성: DefaultFileRenamePolicy를 사용하면 복잡한 파일 이름 관리 로직을 단순화할 수 있음
<%@page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy"%>
<%@page import="javax.swing.text.DefaultTextUI"%>
<%@page import="com.oreilly.servlet.MultipartRequest"%>
<%@ 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>
<%
	int maxSize = 5 * 1024 * 1024;	//5M(메가바이트)
	String fileSave = "/fileSave";
	
	String realPath = getServletContext().getRealPath(fileSave);	//Meta Data
	System.out.println("realPath->" + realPath);

	MultipartRequest multi = 
			new MultipartRequest(request, realPath, maxSize, "utf-8", new DefaultFileRenamePolicy());
	//MultipartRequest: 이미지를 호출하는 객체, cos.jar을 넣어야 만들기 가능
	//DefaultFileRenamePolicy(): 회사 정책


%>
</body>
</html>

(폴더: och14_sub1)

  • hello.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>
	<h2>안뇽! 컴 동지들 !!!!</h2>
</body>
</html>
  • SimpleFilter.Class(filter파일)
    Tip)
    • init는 한번 실행됨
    • filter는 여러 번 실행 됨

package och14;

import java.io.IOException;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;

//@WebFilter("/sub1/*")		
//sub1에서 돌아가는 모든 것은 이 SimpldFilter 필터를 거쳐서 실행되라는 뜻
public class SimpleFilter implements Filter {
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		System.out.println("SimpleFilter init...");
		Filter.super.init(filterConfig);
	}
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// TODO Auto-generated method stub
		System.out.println("Filter 시작");
		//또 다른 Filter 수행
		chain.doFilter(request, response);
		System.out.println("Filter 끝");


	}

}

 

  • web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://jakarta.ee/xml/ns/jakartaee" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" id="WebApp_ID" version="6.0">
  <display-name>och14</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    <welcome-file>default.htm</welcome-file>
  </welcome-file-list>
  
  <filter>
  	<filter-name>simple-filter</filter-name>
  	<filter-class>och14.SimpleFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>simple-filter</filter-name>
  	<url-pattern>/sub1/*</url-pattern>
  </filter-mapping>
  
</web-app>

(폴더: och14_sub2)

  • winner.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>
<h2>당첨자 명단</h2>
	1등	냉장고 끈<p>
	2등	TV 램<p>
	3등	자동차 권리

</body>
</html>
  • LoginCheck.Class (filter파일) >> 권한을 부여할때 만드는 페이지
    Tip)
    • webfilter
    • HttpServletRequest
    • ServletRequest

package och14;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;


/**
 * Servlet Filter implementation class LoginCheck
 */
@WebFilter("/sub/*")
public class LoginCheck extends HttpFilter implements Filter {
	//filter를 상속받아서 쓰는 방법도 가능함
       
    /**
     * @see HttpFilter#HttpFilter()
     */
    public LoginCheck() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see Filter#destroy()
	 */
	public void destroy() {
		// TODO Auto-generated method stub
	}

	/**
	 * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		// TODO Auto-generated method stub
		System.out.println("LoginCheck doFilter ...");	//확인을 위한 로직

		// pass the request along the filter chain
		//chain.doFilter(request, response);
		
		//request.getsession이 없기 때문에 아래 형전환을 하여 사용함
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		HttpServletResponse httpServletResponse = (HttpServletResponse) response;
		
		HttpSession session = httpServletRequest.getSession();	//session 도출 방법
		System.out.println("LoginCheck doFilter ...");	//확인을 위한 로직
		
		if	(session == null || session.equals(""))	{
			httpServletResponse.sendRedirect("../login.jsp");
		}
		System.out.println("doFilter session != null");	//확인을 위한 로직
		String id = (String)session.getAttribute("id");
		System.out.println("doFilter session id->"+id);	//확인을 위한 로직
		
		if	(id == null || id.equals(""))	{	//이중체크를 위해 if를 한번 더 걸기
			httpServletResponse.sendRedirect("../login.jsp");
		}
		System.out.println("doFilter session id not Null->"+id);	//확인을 위한 로직
		
		chain.doFilter(request, response);	//chain으로 가라
		
	}

	/**
	 * @see Filter#init(FilterConfig)
	 */
	public void init(FilterConfig fConfig) throws ServletException {
		// TODO Auto-generated method stub
	}

}

(폴더: och14)

  • login.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>
<h2>로그인</h2>
	<form action="check.jsp">
		<label for="id">아이디</label>
			<input type="text" name="id" id="id"><p>
		<label for="pass">비밀번호</label>
			<input type="password" name="pass" id="pass"><p>
		<input type="submit" value="확인"><p>
			
	</form>

</body>
</html>
  • check.jsp
    Tip) ID를 kk, 비번을 1234로 입력했을 경우에만 체크가 가능하도록 만든 페이지
<%@ 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>
<%
	String id = request.getParameter("id");
	String pass = request.getParameter("pass");
	
	//DB는 갔다 왔다고 가정하고 아래 작성하기
	if	(id.equals("kk") && pass.equals("1234"))	{
		session.setAttribute("id", id);	
		//당첨자명단을 로그인한 사람만 보여주기 위해 작성
	} else {
		session.invalidate();
	}
%>
<a href="sub2/winner.jsp">당첨자 보기</a>

</body>
</html>

 

  • SimpleFilter3.Class
package och14;

import java.io.IOException;

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;

@WebFilter("/sub2/*")
public class SimpleFilter3 implements Filter {

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// TODO Auto-generated method stub
		System.out.println("Filter 시작");
		//또 다른 Filter 수행
		chain.doFilter(request, response);
		System.out.println("Filter 끝");
	}

}


(폴더: och15_ajax)

    • hello.html 
      Tip)
      • check  함수
        • JSP에서 "check" 함수는 일반적으로, Java 코드를 포함하여 다양한 작업을 수행할 수 있는 사용자 정의 함수로 구현할 수 있음
        • 주로 유효성 검사를 위해 사용됨
          • 입력 데이터의 유효성을 위해 사용하며, 유효하지 않은 입력에 대해서는 오류 메시지를 출력함
          • 유효성 검사를 서블릿으로 분리하여 JSP 페이지와의 역할을 분리할 수도 있음
          • 이를 통해 웹 애플리케이션의 코드 구조를 더 깔끔하고 유지보수하기 쉽게 만들 수 있
      • callback함수: Ajax 요청이 완료된 후 실행되는 함수로, 서버로부터 받은 데이터를 처리하는 역할을 함
        Ajax 요청의 성공 여부에 따라 서버로부터 받은 데이터를 처리함
        • result: result는 이 callback 함수에 전달되는 서버의 응답 데이터임
      • readyState
        • XMLHttpRequest 객체의 속성으로, Ajax 요청의 현재 상태를 나타냄. 
        • Ajax 요청의 상태와 결과를 확인하는 데 중요한 역할을 함
        • readyState의 다섯 가지 속성
          1. 0 (UNSENT): XMLHttpRequest 객체가 생성되었으나, 아직 초기화되지 않은 상태.
          2. 1 (OPENED): open() 메서드가 호출되어 요청이 초기화된 상태.
          3. 2 (HEADERS_RECEIVED): send() 메서드가 호출되어 서버로 요청이 전송된 상태. 이 시점에서 응답 헤더가 수신되었음을 의미.
          4. 3 (LOADING): 요청한 데이터를 수신 중인 상태.
          5. 4 (DONE): 요청이 완료되어 모든 데이터를 수신한 상태
      • status
        • 서버로부터의 HTTP 응답 상태 코드를 나타내며, 일반적으로 이 코드를 통해 요청이 성공적으로 처리되었는지 여부를 확인할 수 있음
        • Ajax 요청의 상태와 결과를 확인하는 데 중요한 역할을 함
        • 주요 상태 코드
          1. 200 (OK): 요청이 성공적으로 완료되어 서버가 요청한 리소스를 반환함
          2. 404 (Not Found): 요청한 리소스를 찾을 수 없음
          3. 500 (Internal Server Error): 서버에서 오류가 발생하여 요청을 처리할 수 없음
    • indexOf
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="../js/httpRequest.js"></script>	<!-- Ajax선언 -->
<script type="text/javascript">
function chk()	{
	var params="name="+encodeURIComponent(frm.name.value);
	
	//sendRequest(url(server PGM), params, callback함수, method)
	sendRequest("hello.jsp",		params, result, "POST");
	//위를 실행하고 성공해야 아래로 감
	
}

function result()	{
	//readyState속성을 로직화
	if	(httpRequest.readyState == 4)
		if	(httpRequest.status == 200)	{
			//서버가 문제가 없으면 아래를 실행시키라는 로직
			
			var text1 = httpRequest.responseText;
			alert("responseText->"+text1);
			
			start = text1.indexOf("<body>");	//창에서 보고 싶은 문자의 첫 부분, 이를 위해 indexOf를 걸어줌
			end = text1.indexOf("</body>");		//창에서 보고 싶은 문자의 끝 부분
			var text2 = text1.substring(start+6,end);
			//alert(text1);
			alert(text2);
		} else alert("Server 오류");
	
}


</script>
</head>
<body>
<h2>이름을 입력하세요</h2>
	<form name="frm" action="">
		<input type="text" name="name"><p>
		<input type="button" value="확인" onclick="chk()">	
									<!-- onsubmit가 아님! -->
	</form>
</body>
</html>
  • hello.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>
<%
	//request.setCharacterEncoding("utf-8");
	String name = request.getParameter("name");
%>
<body>
	와우! 방가방가 <%=name %>님
</body>
</html>

alert(text1);와 alert(text2); 둘 다 작동할 때

 

alert(text2);만 남겼을 때


질문목록

1. 괄호 안의 (String)는 무엇을 뜻하는가?

↳  sessionMain.jsp의 String id = (String)session.getAttribute("id");를 예시로 들어보자

session.getAttribute() 메서드는 세션 객체에서 특정 속성의 값을 가져오는 메서드이다. 이 메서드의 반환 타입은 'object'이므로 우리가 필요한 값에 맞게 형변환(casting)을 해야한다. 반환된 값을 사용할 때 원래의 데이터 타입으로 캐스팅을 해주어야 하기 때문에 (String)를 사용한 것이다.

 

여기서 앞에서 쓴 String 을 한 번 더 쓴 이유는 두 가지이다

  1. 형변환: session.getAttribute("id")의 반환 값이 'object' 형태이지만, 실제로 session에 저장된 값은 'String'일 수 있다. 따라서 '(String)'을 사용하여 명시적으로 형 변환을 수행한다. 이는 컴파일러에게 반환 값을 String으로 취급하도록 지시하는 역할을 한다. 이외에도 위와 같은 session.getAttribute()형태에서 형변환을 하면 왼쪽의 값을 따라 괄호 안에 넣도록 한다
  2. 타입 안정성 보장: 형변환을 통해 컴파일러가 반환 값의 타입을 알 수 있게 되므로, 잘못된 형 변환으로 인한 오류를 방지할 수 있다. 실제로, 만약 session의 값 "id"라는 속성이 존재하지 않거나 형 변환이 불가능한 객체가 저장되어 있으면 ClassCastException이 발생할 수 있다

따라서 '(String)'을 사용하여 session에서 가져온 값을 명시적으로 'String'으로 변환하는 것은 Java에서 타입 안정성을 유지하고, 코드의 신뢰성을 높이는 중요한 방법이다.

 

+++여기서 발생한 추가 질문

1. 형변환(casting)?

  • 데이터 타입을 다른 데이터 타입으로 변환하는 과정을 뜻함
  • Casting은 상위 클래스와 하위 클래스 간에 발생하고 구현 클래스와 인터페이스 간에도 발생하며, 이러한 관계가 아니라면 클래스는 다른 타입으로 변환할 수 없음
  • 사용하는 이유
    • 데이터 타입끼리 호환되지 않는 경우가 많기 때문에 데이터 타입을 변환해야 할 때 사용함
    • 다형성: 오버라이딩된 함수를 분리해서 활용할 수 있음
      • 2. 다형성?: 동일 Interface 서로 다르게 응답할 수 있는 특성 연관 Class위한 일관된 매개체를 개발하는 수단
      • 3. 오버라이딩?: 부모 메소드의 방식을 자식 메소드가 받고 재정의 하는 것
    • 상속: 캐스팅을 통해 범용적인 프로그래밍이 가능함
      • 4. 상속?: 기존의 클래스를 재사용해서 새로운 클래스를 작성
        (자세한 것은 0529일지 상속부분 참고)
  •  종류
    • 업캐스팅
      • 작은 크기의 데이터 타입을 큰 크기의 데이터 타입으로 자동 반환하는 것을 말함
      • 데이터 손실없이 수행되며 암시적 캐스팅이라고도 할 수 있음
      • 자바에서 자식 클래스는 부모 클래스의 모든 특성을 상속받기 때문에 자식 클래스는 부모 클래스로 취급될 수 있음. 즉, 부모 클래스의 참조변수가 자식 클래스로 객체화된 인스턴스를 가리킬 수 있게 됨
    • 다운캐스팅
      • 큰 크기의 데이터 타입을 작은 크기의 데이터 타입으로 변환하는 것을 말함
      • 업캐스팅 된 것을 다시 원래대로 돌리는 것. 즉, 자신의 고유한 특성을 잃은 자식 클래스의 객체를 복구시키는 것
      • 데이터 손실이 발생할 수 있으므로, 명시적으로 변환을 진행하고 괄호 안에 변환할 타입을 명시함
        때문에 명시적 캐스팅이라고도 함

2. memberDao.Class는 왜 null 값인가?

null을 넣는 이유는 변수 conn을 초기화하기 위함이다. null로 설정되어 Null 상태가 된 참조 변수는 아무 객체도 참조하지 않는 상태가 된다

 

의문점 1. 초기화?: 해당 변수를 기본값으로 돌리는 것을 말한다. Java에서 변수를 선언할 때, 해당 변수를 초기화하지 않으면 해당 변수는 자동으로 기본값으로 초기화된다. 

 

↳  memberDao.jsp의 Connection conn = null;을 예시로 들어보자. 여기서 변수 conn은 참조 타입이기 때문에 초기값은 'null'이다. 만약 Connection conn; 으로만 선언하면 변수 conn은 자동으로 null로 초기화 된다. 기본적으로 null값이기 때문에 '=null' 선언을 하지 않아도 문법적으로 문제는 없으며 반드시 해야하는 것도 아니고, 프로젝트 팀이나 개발자 개인의 선호 차이다. 하지만 이는 다음과 같은 세 가지 이유 때문에 명시적으로 습관을 들이는 것이 좋다

  1. 가독성 및 명확성: 코드를 읽는 사람이나 코드 리뷰어가 변수의 초기값을 명확하게 파악할 수 있게 하기 위함이다. 게다가 초기화하지 않고 선언만 한 참조 변수는 자동적으로 null로 설정될 수 있기 때문에 명시적으로 표현하는 것이 좋다
  2. 초기화 의도 명시: 변수를 선언만 하고 초기화하지 않은 상태로 남겨두면, 이 변수가 의도적으로 'null'일 수 있다는 것을 나타내기 어렵고, 때문에 그 의도를 전달하기 어려워진다. 따라서 이 변수를 초기화한다는 코드의 의도를 명확하게 전달하기 위해 초기화 선언을 하는 것이 좋다
  3. 코드 안정성: 참조 타입 변수가 null일 때의 처리를 명확하게 알 수 있다. 위의 예시를 사용해서 들어보면, conn변수를 사용하기 전에 'null' 체크를 하여 NullPointerException(NPE) 예외 처리를 방지할 수 있다

 의문점2. 초기화하지 않은 참조 변수란, 변수가 선언은 되었지만 명시적으로 초기화되지 않은 상태를 말한다
Java에서 모든 지역 변수(local bariablee)는 사용하기 전에 반드시 초기화되어야 한다. 초기화되지 않은 변수를 사용하려고 하면 컴파일 오류가 난다. 아래는 그 오류이다

  1. 컴파일 오류: Java는 초기화되지 않은 지역 변수를 사용하려고 하면 컴파일 오류를 발생시킴
    하지만 클래스 멤버 변수(static 변수 or instance 변수)는 자동으로 기본값으로 초기화되긴 함
  2. 의도하지 않은 동작: 변수가 의도하지 않은 기본값으로 초기화되어서 예상치 못한 동작을 일으킬 수 있다
    ex) int 변수가 기본값인 '0'으로 초기화되어 원하지 않는 계산 결과가 나올 수 있다
  3. NullPointerException: 참조 타입의 변수가 초기화되지 않고 'null' 상태로 남아있을 경우, 해당 변수를 사용하여 객체의 메서드를 호출하거나 인스턴스 변수에 접근하려고 할 때 발생하는 예외 오류
  4. 값의 무결성 보장이 어려움: 변수가 초기화되지 않은 상태에서는 변수에 예상치 못한 값이 들어갈 수 있으며, 이로 인해 프로그램의 데이터 무결성이 보장되지 않을 수 있음

∴ 위의 'conn'변수는 참조 타입이기 때문에 초기값이 'null' 이므로 =null선언을 하지 않아도 되지만, 위에 기재한 세 가지 이유 때문에 선언하는 것이 좋다

 

+++여기서 발생한 추가 질문

1. 참조 타입(Reference Type)

  • Java에서 객체(object)를 참조하는 변수 타입. Java에서 모든 객체는 참조 타입에 의해 사용된다
  • Java의 대부분의 타입(Class, interface 등)은 참조타입이다
  • Java에서는 객체 지향 프로그래밍을 지원하며, 객체 간의 상호작용은 주로 참조 변수를 통해 이루어진다
  • 기본 타입과의 차이: 기본 데이터 타입(primitive types)은 직접적인 값을 변수에 저장하지만, 참조 타입은 객체가 저장된 메모리의 위치(주소)를 변수에 저장한다. 예시로는 String, Object, 사용자가 정의한 클래스 등이 있다
  • 객체 생성과 초기화: 참조 타입을 사용할 때는 객체를 생성하고, 그 객체에 대한 참조(주소)를 변수에 할당해야 한다.
    ex) String str = new String("Hello");에서 str은 String객체를 참조하는 변수이다
  • 메모리 관리: 객체는 heap 메모리에 저장되며, 참조 변수는 해당 객체의 위치를 가리킨다. Java의 가비지 컬렉터는 더 이상 사용되지 않는 객체를 자동으로 삭제하여 메모리를 관리한다.
  • Null 값: 참조 변수는 객체를 참조하지 않는 경우에는 'null'을 가질 수 있다. 이때 'null'은 아무 객체도 참조하지 않는 상태를 나타낸다
  • 메서드 호출: 참조 변수를 사용하면 객체의 메서드를 호출하거나, 인스턴스 변수에 접근할 수 있다.
    ex) Str.length()는 str이 참조하는 String 객체의 길이를 반환한다

2. 초기값과 기본값의 차이

  • 기본값(default value)
    • Java에서 기본 데이터 타입(primitive types)의 변수는 선언만 하고 초기화를 하지 않았을 때, 컴파일러에 의해 자동으로 기본값으로 초기화됨
    • 초기값 예시
      int:0, double: 0.0, boolean: false, 참조타입 변수:null
  • 초기값(initial value)
    • 변수를 처음으로 선언할 떄 명시적으로 할당하는 값, 이 값을 변수에 직접 지정할 수 있음
    • 초기값을 지정하지 않으면 변수는 해당 데이터 타입의 기본값으로 초기화됨
    • ex) int num = 10; 에서 10은 변수 num의 초기값

 

3. 지역 변수, static 변수, instance 변수 >>> 0529 일지 참고

 


3. LoginCheck.java의 null값은 무엇을 뜻하는가?

if	(session == null || session.equals(""))	{
			httpServletResponse.sendRedirect("../login.jsp");

여기서 null은 세션 객체가 null인지 확인하는 기능을 함. 세션이  null인 경우 사용자가 로그인되지 않았음을 의미하므로 로그인 페이지로 리다이렉트함

String id = (String)session.getAttribute("id");
if	(id == null || id.equals(""))	{	//이중체크를 위해 if를 한번 더 걸기
			httpServletResponse.sendRedirect("../login.jsp");
		}

여기서 null은 세션의 'id'속성이 null인지 확인하는 기능을 함. 'id'가 null인 경우 사용자가 로그인되지 않았거나 유효하지 않은 세션임을 의미하므로, 로그인 페이지로 리다이렉트 함

 

즉, 이 페이지에서 null은 사용자가 유효한 세션을 가지고 있는지, 다시 말해, 로그인 상태인지를 확인하는데 사용된다. null이 아닌 경우에만 Filter 체인의 다음 단계로 요청을 전달하게 된다. 이러한 null 체크는 웹 애플리케이션에서 인증 및 권한 부여 로직을 구현할 때 매우 중요하다


수업교재

17. 필터와 래퍼

1. 필터

1. 정의

  • 글자 그대로, 여과기 역할을 하는 프로그램
  • 필터는 자바 클래스 형태로 그현해야 하며, 이; 클래스를 필터 클래스(filter class)라고 함
    필터 클래스 ==(인스턴스화)==> 필터 객체 ==(초기화)==> 필터
  • 초기화된 필터는 웹 브라우저와 웹 컴포넌트 사이에 위치함
  • 웹 브라우저가 웹 컴포넌트를 호출하면 필터가 대신 호출되고, 필터는 사전 작업을 수행한 다음에 웹 컴포넌트를 호출함
  • 웹 컴포넌트가 할 일을 끝내면 실행의 제어는 다시 필터로 돌아가고, 필터는 사후 작업을 수행한 후 웹 브라우저로 응답을 보냄
  • 필터를 이용하면 필터 체인이 향하는 방향을 바꿀 수도 있음
    ex) 웹 브라우저에서 사용자의 로그인을 체크하는 필터가 로그인한 회원만 사용할 수 있는 웹 컴포넌트로 향하던 방향을, 로그인을 하지 않은 사용자에게 로그인을 유도하는 웹 페이지로 유도하도록 바꿀 수 있음

2. 작성 규칙

  1. 필터 클래스를 작성할 때는 서블릿 규격서에 정해져 있는 규칙을 지켜야 함
    가장 중요한 규칙은 javax.servlet.Filter 인터페이스를 구현해야 한다는 것
  2. Filter 인터페이스에는 세 개의 메서드가 있음
    1. doFilter: 웹 브라우저가 웹 컨테이너로 요청을 보냈을 때 호출되는 메서드
      • doFilter 메서드의 첫 번째와 두 번째 파라미터는 요청 객체와 응답 객체이다. 만약 필터가 없었더라면 이 두 객체는 웹 컨테이너가 웹 컴포넌트로 직접 넘겨주었을 것이다
      • chain.doFilter(request, response);
        doFilter 메서드 안에서 세 번째 파라미터는 필터 체인을 표현하는 FilterChain 객체임
        doFilter 메서드 안에서 세 번째 파라미터에 대해  doFilter라는 이름의 메서드를 호출하면서, doFilter 메서드가 받은 첫 번째와 두 번째 파라미터를 넘겨주면 필터 체인의 다음번 멤버가 호출됨
    2. init: 웹 컨테이너가 필터 객체를 초기화할 때 호출되는 메서드
    3. destroy: 웹 컨테이너가 필터 객체를 제거하기 직전에 호출되는 메서드
  3. Filter 클래스를 작성한 다음 해야 할일
    1. 필터 클래스를 컴파일한다
    2. 컴파일 결과물을 웹 컨테이너에 설치한다
    3. 필터 클래스를 wdb.xml 파일에 등록한다
  4. web.xml 파일에 등록하는 법
    : 루트 엘리먼트인 <web-app>의 아래에 <filter>와 <filter-mapping>이라는 두 개의 엘리먼트를 추가해야함
    혹은, <servlet-name>과 <url-pattern> 도 가능, 하지만 위와 아래 중 하나의 서브엘리먼트를 써야함
    1. <filter>: 필터를 등록하는 엘리먼트
      • 이 안에는 <filter-name>과 <filter-class>라는 두 개의 서브엘리먼트를 써야 하며, 이 둘은 각각 필터 이름과 필터 클래스 이름을 포함하는 역할을 함
      • <filter-name> 안에는 <filter> 엘리먼트 안에 썼던 것과 동일한 필터 이름을 써야함
    2. <filter-mapping>: 필터를 적용할 웹 컴포넌트를 지정하는 엘리먼트
      • 필터를 여러 개의 웹 컴포넌트에 한꺼번에 적용하고자 할 때는 <url-pattern> 서브엘리먼트에 해당 웹 컴포넌트들의 URL 패턴을 쓰면 됨
      • <filter-mapping> 안에 엘리먼트 안에 여러 개의 <url-pattern> 서브엘리먼트를 쓸 수도 있음
        ex) URL 경로명이 /sub1/ 또는 /sub2/로 시작하는 모든 웹 컴포넌트에 필터를 적용함
      • <filter-mapping> 안에 엘리먼트 안에 여러 개의 <servlet-name> 엘리먼트를 쓸 수도 있고, <servlet-name> <url-pattern> 엘리먼트를 혼용해서 쓸 수도 있음
        ex) URL 경로명이 /sub1/ 또는 /sub2/로 시작하는 웹 컴포넌트와 이름이 hello-servlet인 서블릿에 필터를 적용
    3. <url-pattern>
      • 필터를 같은 웹 애플리케이션 디렉터리 내에 있는 모든 웹 컴포넌트에 적용하려면 <url-pattern>엘리먼트 안에 /*라고 쓰면 됨 => /*란?: 같은 웹 애플리케이션 디렉터리에 있는 모든 웹 컴포넌트를 가리키는 URL 패턴
      • 필터를 같은 웹 애플리케이션 디렉터리 내에 있는 모든 JSP 페이지에 적용하려면 <url-pattern> 엘리먼트 안에 *.jsp라고 쓰면 됨 => *.jsp란?: 필터를 같은 웹 애플리케이션 디렉터리 내에 있는 모든 JSP 페이지에 적용
      • <url-pattern> 엘리먼트 안에 계층적인 URL 경로명을 쓸 수도 있음
        이 경로명은 웹 애플리케이션 디렉터리의 루트 디렉터리를 의미하는 슬래시(/) 문자로 시작함ㅋ
        ex) <url-pattern> /sub1/*    <url-pattern> : /sub1/ 이라는 URL 경로명으로 시작하는 모든 웹 컴포넌트를 가리키는 URL 패턴
      • <url-pattern> 엘리먼트 안에 계층적인 URL 경로명을 쓸 때는 와일드카드(*)문자와 파일 확장자를 함께 쓰면 안됨
        ex) <url-pattern> /sub1/*.jsp    <url-pattern> ==> 잘못된 URL pattern
      •  
    4. <servlet-name><url-pattern>: 필터를 특정한 웹 컨포넌트에만 적용하고자 할 때는 < servlet-name> 서브엘리먼트에 해당 웹 컴포넌트의 이름을 지정하면 됨

3. filter 클래스의 메서드

  1. init 메서드
    • 필터의 초기화 파라미터란 필터 클래스에서 사용한 데이터를 web.xml 파일 안에 이름-값 쌍으로 지정해 놓은 것을 말함
    • 필터의 초기화 파라미터는 <filter> 엘리먼트 안에 <init-param> 서브엘리먼트를 추가하고, 그 안에 다시 <param-name>과 <param-value> 서브 엘리먼트를 추가해서 등록할 수 있음
      <param-name>: 초기화 파라미터의 이름
      <param-value>: 초기화 파라미터의 값
  2. getInitParameter: 초기화 파라미터의 값을 가져오는 메서드  
    : 필터 클래스의 init 메서드 안에서 필터의 초기화 파라미터를 읽어오려면 FilterConfig 파라미터에 대해 getInitParameter 메서드를 호출하면 됨
    ex) String filename = config.getInitParameter( “FILE_NAME ”);
  3. getRemoteAddr: 클라이이언트의 IP 주소를 가져오는 메서드
    • 요청 메시지와 응답 메시지에 포함된 정보 조회할 때 사용함
    • 필터 클래스의 doFilter 메서드 안에서 웹 브라우저의 IP 주소를 가져오기 위해서는 ServletRequest 파라미터에 대해 getRemoteAddr 메서드를 호출하면 됨
  4. getContentType: 응답 메시지에 포함된 컨텐트 타입을 가져오는 메서드
    : 필터 클래스의 doFilter 메서드 안에서 웹 자원의 컨텐트 타입을 가져오기 위해서는 ServletResponse 파라미터에 대해 getContentType 메서드를 호출하면 됨

 

 


오늘의 숙제

'JSP > Java Script' 카테고리의 다른 글

2024_07_23_화~ 07_24_수  (0) 2024.07.23
2024_07_22_월  (0) 2024.07.22
2024_07_18_목  (0) 2024.07.18
2024_07_17_수  (0) 2024.07.17
2024_07_16_화  (0) 2024.07.16