YJ의 새벽

JDBC 활용 연습용. ( 이메일 받아서 정보출력 ) 본문

SelfStudy/JDBC

JDBC 활용 연습용. ( 이메일 받아서 정보출력 )

YJDawn 2023. 3. 24. 01:18

 

 

 

 

 

 community  Dynamic Web Project 생성.

 

 

 community server 생성.

serve modules without publishing 체크

 

 

오라클 넘어와서  .  community 계정생성

CREATE USER community IDENTIFIED BY 1234;

GRANT CONNECT, RESOURCE TO community;

ALTER USER community DEFAULT TABLESPACE SYSTEM QUOTA UNLIMITED ON SYSTEM;

 

 

테스트용 테이블 생성.

CREATE TABLE "MEMBER" ( 
   "MEMBER_NO"   NUMBER   PRIMARY KEY,
   "MEMBER_EMAIL"   VARCHAR2(50) NOT NULL,
   "MEMBER_PW"   VARCHAR2(30) NOT NULL,
   "MEMBER_NICK"   VARCHAR2(30) NOT NULL,
   "MEMBER_TEL"   CHAR(11) NOT NULL,
   "MEMBER_ADDR"   VARCHAR2(500),
   "PROFILE_IMG"   VARCHAR2(200),
   "ENROLL_DT"   DATE DEFAULT SYSDATE ,
   "SECESSION_FL"   CHAR(1)   DEFAULT 'N'
);

COMMENT ON COLUMN "MEMBER"."MEMBER_NO" IS '회원 번호';
COMMENT ON COLUMN "MEMBER"."MEMBER_EMAIL" IS '회원 이메일(아이디)';
COMMENT ON COLUMN "MEMBER"."MEMBER_PW" IS '회원 비밀번호';
COMMENT ON COLUMN "MEMBER"."MEMBER_NICK" IS '회원 닉네임(중복x)';
COMMENT ON COLUMN "MEMBER"."MEMBER_TEL" IS '전화번호(- 미포함)';
COMMENT ON COLUMN "MEMBER"."MEMBER_ADDR" IS '회원 주소';
COMMENT ON COLUMN "MEMBER"."PROFILE_IMG" IS '회원 프로필 이미지';
COMMENT ON COLUMN "MEMBER"."ENROLL_DT" IS '회원 가입일';
COMMENT ON COLUMN "MEMBER"."SECESSION_FL" IS '탈퇴여부(Y:탈퇴, N:미탈퇴)';

-- 회원 번호 시퀀스
CREATE SEQUENCE SEQ_MEMBER_NO;

INSERT INTO MEMBER
VALUES(SEQ_MEMBER_NO.NEXTVAL, 'user01@kh.or.kr', 'pass01!', 
    '유저일', '01011111111', '04540,,서울시 중구 남대문로 120,,2층 A강의장',
     NULL, DEFAULT, DEFAULT);
    
INSERT INTO MEMBER
VALUES(SEQ_MEMBER_NO.NEXTVAL, 'user02@kh.or.kr', 'pass02!', 
    '유저이', '01022222222', '10004, 서울시 종로구 통인동',
     NULL, DEFAULT, DEFAULT);
    
INSERT INTO MEMBER
VALUES(SEQ_MEMBER_NO.NEXTVAL, 'user03@kh.or.kr', 'pass03!', 
    '유저삼', '01033333333', '25746, 서울시 성북구 정릉3동',
     NULL, DEFAULT, DEFAULT);
    
INSERT INTO MEMBER
VALUES(SEQ_MEMBER_NO.NEXTVAL, 'user04@kh.or.kr', 'pass04!', 
    '유저사', '01044444444', '94564, 인천시 부평구 산곡동',
     NULL, DEFAULT, DEFAULT);

    
COMMIT;

-- 인증 테이블 생성
 -- 한 이메일로 발급 받은 인증번호가 계속 업데이트
CREATE TABLE CERTIFICATION (
   EMAIL VARCHAR2(50) PRIMARY KEY,
   C_NUMBER CHAR(6) NOT NULL,
   ISSUE_DT DATE DEFAULT SYSDATE
);

 

 

Servers/context.xml 들어가서

추가하기.

<Resource 
      name="jdbc/oracle" 
      auth="Container"
      type="javax.sql.DataSource" 
      driverClassName="oracle.jdbc.OracleDriver"
      url="jdbc:oracle:thin:@localhost:1521:xe"
      username="community" 
      password="1234" 
      maxTotal="50"      
      maxIdle="10"
      maxWaitMillis="-1"
    />
    <!-- 
       name : JNDI 이름 Context의 lookup()을 사용하여 자원을 찾을때 사용한다. java:comp/env 디렉터리에서 찾을 수 있다.
       auth : 자원 관리 주체 지정(Application 또는 Container)
       type : Resource의 타입 지정
       driverClassName : JDBC 드라이버 클래스 이름.
       maxTotal : DataSource 에서 유지할 수 있는 최대 커넥션 수    
       maxIdle : 사용되지 않고 풀에 저장될 수 있는 최대 커넥션의 개수. 음수일 경우 제한이 없음
       maxWaitMillis : 커넥션 반납을 기다리는 시간(-1은 반환될 때 까지 기다림)
     -->

 

 

 

JDBCTemplate.class  작성     ( Connection pool ) 

public class JDBCTemplate {

	// DB 연결 
	//( Connection 생성) , 자동커밋 off , 트랜잭션제어 , JDBC 객체 자동반환
	// 반복사용되는 코드를 모아둔 클래스
	//모든 필드, 메서드가 static ,  클래스명.메서드명 호출할수있도록.

	private static Connection conn = null;
	
	/** DB 연결정보를 담고있는 Connection 생성 및 반환메서드
	 * @return conn
	 */
	public static Connection getConnection() {	
		try {
			
			// JNDI ( Java Naming and Directory Interface API )
			Context initContext = new InitialContext();
			
			// servers -> context.xml 파일 찾기.
			Context envContext = (Context)initContext.lookup("java:/comp/env");
			
			// DBCP 세팅의 <Resource> 태그를 찾아서 DataSource 형식의 객체로 얻어오기
			// DataSource : Connection Pool 을 구현하는객체 ( 만들어둔 Connection 얻어오기 가능)
			DataSource ds = (DataSource)envContext.lookup("jdbc/oracle");
			conn = ds.getConnection();
			
			conn.setAutoCommit(false);   // 자동커밋 비활성화
			
		}catch(Exception e) {
			System.out.println("[Connection 생성중 예외 발생]");
			e.printStackTrace();
		}
		return conn;
	}

	
	
	/** Connection 객체 자원 반환메서드
	 * @param conn
	 */
	public static void close(Connection conn) {
		try {
			if(conn != null && !conn.isClosed())  conn.close();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	/** Statement 객체 자원 반환메서드 ( PreparedStatement(자식) 
	 * 다형성/ 동적바인딩
	 * @param stmt
	 */
	public static void close(Statement stmt) {
		try {
			if(stmt != null && !stmt.isClosed())  stmt.close();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	/** ResultSet 객체 자원 반환메서드
	 * @param rs
	 */
	public static void close(ResultSet rs) {
		try {
			if(rs != null && !rs.isClosed())  rs.close();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	/** 트랜잭션 Commit 메서드
	 * @param conn
	 */
	public static void commit(Connection conn) {
		try {
			if(conn != null && !conn.isClosed()) conn.commit();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	/** 트랜잭션 Rollback 메서드
	 * @param conn
	 */
	public static void rollback(Connection conn) {
		try {
			if(conn != null && !conn.isClosed()) conn.rollback();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
}

 

 

EncodingFilter.class 작성 

//     ' / '   ==  /community  ==  최상위주소
 //      ' /* '  == 최상위 주소 하위 모든. == 모든요청
@WebFilter(filterName = "encodingFilter", urlPatterns = "/*")
public class EncodingFilter extends HttpFilter implements Filter{
	
	// 서버 실행시 or 필터 코드 변경시
	// 필터 객체가 자동 생성되는데 
	// 그때, 필터에 필요한 내용을 초기화하는 메서드
	public void init(FilterConfig fConfig) throws ServletException{
		System.out.println("문자 인코딩 필터 초기화");
	}
	
	// 서버 실행중 필터 코드가 변경되어
	// 기존 필터를 없애야 할 때 수행되는 메서드
	public void destroy() {
		System.out.println("문자 인코딩 필터 파괴");
	}
	
	// 필터 역할을 수행하는 메서드
	public void doFilter(ServletRequest request,ServletResponse response, FilterChain chain) throws IOException, ServletException {
		
		// ServletRequest == HttpServletRequest 의 부모타입
		// ServletResponse == HttpServletResponse 의 부모타입 .   필요시 다운캐스팅.
		
		// 모든 요청의 문자 인코딩을 UTF-8 로 설정.
		request.setCharacterEncoding("UTF-8");
		
		// 모든 응답의 문자 인코딩을 UTF-8 로 설정.
		response.setCharacterEncoding("UTF-8");
		
		//-----------------------------------------
		
		//application scope 로 최상위 경로 얻어올수 있는 값 세팅
		//  1) application 내장객체 얻어오기
		ServletContext application = request.getServletContext();
		
		//  2) 최상위 주소 얻어오기
		String contextPath = ( (HttpServletRequest)request).getContextPath();
		
		//  3) 세팅
		application.setAttribute("contextPath",contextPath);
		
		// 연결된 다음 필터 수행 ( 없으면 Servlet 수행 )
		chain.doFilter(request, response);
	}
}

 

 

Member.class

public class Member {
	private int memberNo;
	private String memberEmail;
	private String memberPw;
	private String memberNickname;
	private String memberTel;
	private String memberAddress;
	private String profileImage;
	private String enrollDate;
	private String secessionFlag;
	
	public Member() {	}

	public Member(int memberNo, String memberEmail, String memberPw, String memberNickname, String memberTel,
			String memberAddress, String profileImage, String enrollDate, String secessionFlag) {
		this.memberNo = memberNo;
		this.memberEmail = memberEmail;
		this.memberPw = memberPw;
		this.memberNickname = memberNickname;
		this.memberTel = memberTel;
		this.memberAddress = memberAddress;
		this.profileImage = profileImage;
		this.enrollDate = enrollDate;
		this.secessionFlag = secessionFlag;
	}
	public int getMemberNo() {
		return memberNo;
	}
	public void setMemberNo(int memberNo) {
		this.memberNo = memberNo;
	}
	public String getMemberEmail() {
		return memberEmail;
	}
	public void setMemberEmail(String memberEmail) {
		this.memberEmail = memberEmail;
	}
	public String getMemberPw() {
		return memberPw;
	}
	public void setMemberPw(String memberPw) {
		this.memberPw = memberPw;
	}
	public String getMemberNickname() {
		return memberNickname;
	}
	public void setMemberNickname(String memberNickname) {
		this.memberNickname = memberNickname;
	}
	public String getMemberTel() {
		return memberTel;
	}
	public void setMemberTel(String memberTel) {
		this.memberTel = memberTel;
	}
	public String getMemberAddress() {
		return memberAddress;
	}
	public void setMemberAddress(String memberAddress) {
		this.memberAddress = memberAddress;
	}
	public String getProfileImage() {
		return profileImage;
	}
	public void setProfileImage(String profileImage) {
		this.profileImage = profileImage;
	}
	public String getEnrollDate() {
		return enrollDate;
	}
	public void setEnrollDate(String enrollDate) {
		this.enrollDate = enrollDate;
	}
	public String getSecessionFlag() {
		return secessionFlag;
	}
	public void setSecessionFlag(String secessionFlag) {
		this.secessionFlag = secessionFlag;
	}
	@Override
	public String toString() {
		return "Member [memberNo=" + memberNo + ", memberEmail=" + memberEmail + ", memberPw=" + memberPw
				+ ", memberNickname=" + memberNickname + ", memberTel=" + memberTel + ", memberAddress=" + memberAddress
				+ ", profileImage=" + profileImage + ", enrollDate=" + enrollDate + ", secessionFlag=" + secessionFlag
				+ "]";
	}
}

 

 

index.jsp 일부만 받아옴.

            <section class="content-1">
            
            	<h3> 회원 정보 조회 ( AJAX )</h3>
            	<p> 이메일을 입력받아 일치하는 회원 정보를 출력</p>
            	
            	이메일 : <input type="text" id="in1">
            	<button id="select1"> 조회 </button>
            	<div id="result1" style="height:150px;">
            	</div>
            </section>

main.js 파일 . 

console.log("main.js loaded.");

// 회원 정보 조회 비동기 통신 (AJAX);

document.getElementById("select1").addEventListener("click",function(){

    const input = document.getElementById("in1");
    const div = document.getElementById("result1");

    // AJAX 코드 작성 (jQuery 방식)
    $.ajax({
        url: "member/selectOne",
        data: {"memberEmail" : input.value},
        type: "POST",
        dataType: "JSON", // dataType : 응답데이터형식을 지정
                    //-> "JSON"으로 지정시 자동으로 JS객체로 변환
        success: function(member){
            console.log(member);
            // 1) div에 작성된 내용 모두 삭제
            div.innerHTML = "";

            if(member != null){ // 회원 정보 존재 O

                // 2) ul 요소 생성
                const ul = document.createElement("ul");

                // 3) li 요소 생성 * 5 + 내용 추가
                const li1 = document.createElement("li");
                li1.innerText = "이메일 : " + member.memberEmail;

                const li2 = document.createElement("li");
                li2.innerText = "닉네임 : " + member.memberNickname;

                const li3 = document.createElement("li");
                li3.innerText = "전화번호 : " + member.memberTel;

                const li4 = document.createElement("li");
                li4.innerText = "주소 : " + member.memberAddress;

                const li5 = document.createElement("li");
                li5.innerText = "가입일 : " + member.enrollDate;

                // 4) ul에 li를 순서대로 추가
                ul.append(li1, li2, li3, li4, li5);

                // 5) div에 ul 추가
                div.append(ul);

            } else { // 회원 정보 존재 X

                // 1) h4 요소 생성
                const h4 = document.createElement("h4");

                // 2) 내용 추가
                h4.innerText = "일치하는 회원이 없습니다";

                // 3) 색 추가
                h4.style.color = "red";

                // 4) div에 추가
                div.append(h4);
            }           
        },
        error: function(request){
            console.log("AJAX 에러 발생");
            console.log("상태코드 : "+request.status); // 404, 500
        }   
      })
});

 

 

 

 

SelectOneServlet.class 

@WebServlet("/member/selectOne")
public class SelectOneServlet extends HttpServlet{

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		//파라미터 얻어오기
		String memberEmail = req.getParameter("memberEmail");
	
		try {
			MemberService service = new MemberService();
			Member member =  service.selectOne(memberEmail);
			
			// JAVA 객체를 Javascript 객체로 변환하여 응답(출력)
			// JAVA 객체 -> javascript형태 JSON -> javascript 객체.
			// GSON 라이브러리를 이용한 JAVA객체 -> JSON 변환
			// new GSON().toJson
			// --> 매개변수에 작성된 객체를 JSON형태로 변환한 후
			//    스트림 통해서 출력
			new Gson().toJson(member, resp.getWriter());
			
			
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
}

 

 

MemberService.class

 

public class MemberService {

	private MemberDAO dao = new MemberDAO();
	
	public Member selectOne(String memberEmail) throws Exception {

		Connection conn = getConnection();
		
		Member member = dao.selectOne(conn , memberEmail);
		
		close(conn);
		
		return member;
	}
}

 

 

member-sql.xml  파일

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<comment>member-sql.xml</comment>

	<entry key="selectOne">
	SELECT MEMBER_EMAIL, MEMBER_NICK, MEMBER_TEL, MEMBER_ADDR,
	TO_CHAR(ENROLL_DT, 'YYYY"년" MM"월" DD"일"') AS ENROLL_DATE
	FROM MEMBER
	WHERE MEMBER_EMAIL = ?
	AND SECESSION_FL = 'N'
	</entry>
	
</properties>

 

MemberDAO . class  

 

public class MemberDAO {
	
	private Statement stmt;
	private PreparedStatement pstmt;
	private ResultSet rs;
	private Properties prop;

	public MemberDAO() {
		try {
			prop = new Properties();
			
			String filePath = MemberDAO.class.getResource("/edu/kh/community/sql/member-sql.xml").getPath();
			
			prop.loadFromXML( new FileInputStream(filePath));
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	public Member selectOne(Connection conn, String memberEmail) throws Exception {
		
		Member member = null;
		try {
			String sql = prop.getProperty("selectOne");
			
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, memberEmail);
			rs = pstmt.executeQuery();
			
			if(rs.next()) {
				member = new Member();
				member.setMemberEmail(rs.getString(1));
				member.setMemberNickname(rs.getString(2));
				member.setMemberTel(rs.getString(3));
				member.setMemberAddress(rs.getString(4));
				member.setEnrollDate(rs.getString(5));
			}
		}finally {
			close(rs);
			close(pstmt);
		}
		return member;
	}
}

 

 

index.jsp 파일

<%@ page language="java" contentType="text/html; cherset=UTF-8"
    pageEncoding ="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>17_웹 문서 구조</title>

    <link rel="stylesheet" href="resources/css/main-style.css">

    <!--  fontawesome 사이트 아이콘 이용   -->
    <script src="https://kit.fontawesome.com/f7459b8054.js" crossorigin="anonymous"></script>
</head>
<body>
	<main>
		<!-- jsp : include 태그 
			다른 jsp 파일의 내용을 해당 위치에 포함시킴
			* 경로 작성시
			  내부 접근경로 ( 최상위 : /webapp )
		-->
		<jsp:include page="/WEB-INF/views/common/header.jsp"/>        <!--  header.jsp 로 include -->


        <section class="content">
            <section class="content-1">
            
            	<h3> 회원 정보 조회 ( AJAX )</h3>
            	<p> 이메일을 입력받아 일치하는 회원 정보를 출력</p>
            	
            	이메일 : <input type="text" id="in1">
            	<button id="select1"> 조회 </button>
            	<div id="result1" style="height:150px;">
            	</div>
            </section>


            <section class="content-2">

                <form action="#" name="login-frm">
        
                    <!-- 아이디, 비밀번호, 로그인 버튼 -->
                    <fieldset id="id-pw-area">
                        <section>
                            <input type="text" name="inputId"
                             placeholder="아이디" autocomplete="off">
                            <!-- autocomplete="off" : 자동완성 사용 X -->
        
                            <input type="password" name="inputPw" placeholder="비밀번호">
                        </section>
        
                        <section>
                            <!-- type="submit"이 기본값 -->
                            <button>로그인</button>
                        </section>
                    </fieldset>
        
        
                    <!-- label 태그 내부에 input태그를 작성하면 자동 연결됨 -->
                    <label>
                        <input type="checkbox" name="saveId"> 아이디 저장
                    </label>
        
        
                    <!-- 회원가입 / ID/PW 찾기 -->
                    <article id="signUp-find-area">
                        <a href="#">회원가입</a>
                        <span>|</span>
                        <a href="#">ID/PW찾기</a>
                    </article>
                </form>
            </section>
        </section>
    </main>
	<jsp:include page="/WEB-INF/views/common/footer.jsp"/>      <!--  footer.jsp 로 include -->
	
    <!-- main.js 연결 -->
    <script src="${contextPath}/resources/js/main.js"></script>
    <!-- jQuery 라이브러리 추가 -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>

</body>
</html>

 

header.jsp

<%@ page language="java" contentType="text/html; cherset=UTF-8"
    pageEncoding ="UTF-8" %>

    <header>
        <section>
       
        <%--
        	<%= request.getContextPath() %>
        	${pageContext.servletContext.contextPath}
        
         --%>     

            <!-- 클릭 시 메인페이지로 이동하는 로고 -->
            <a href="${contextPath}">
                <img src="${contextPath}/resources/images/logo1.jpg" id="home-logo">
            </a>
        </section>

        <!-- 검색창 영역 -->
        <section>

            <article class="search-area">
                <!-- 내부 input 태그의 값을 서버 또는 페이지로 전달(제출) -->
                <form action="#">
                    <fieldset>
                        <input type="text" id="query" name="query" 
                            placeholder="검색어를 입력해주세요.">
                        
                        <!-- 검색 버튼 -->
                        <button type="submit" id="search-btn" class="fa-solid fa-magnifying-glass"></button>
                    </fieldset>
                </form>
            </article>
        </section>

        <section></section>
    </header>

    <nav>
        <ul>
            <li><a href="#">공지사항</a></li>
            <li><a href="#">자유 게시판</a></li>
            <li><a href="#">질문 게시판</a></li>
            <li><a href="#">FAQ</a></li>
            <li><a href="#">1:1문의</a></li>
        </ul>
    </nav>

 

 

 

footer.jsp

<%@ page language="java" contentType="text/html; cherset=UTF-8"
    pageEncoding ="UTF-8" %>


<footer>
    <p>
        Copyright &copy; KH Information Educational Institute A-Class
    </p>

    <article>
        <a href="#">프로젝트 소개</a>
        <span>|</span>
        <a href="#">이용약관</a>
        <span>|</span>
        <a href="#">개인정보처리방침</a>
        <span>|</span>
        <a href="#">고객센터</a>
    </article>
</footer>

 

 

 

 

 

 

 

 

 

Comments