Computer/Java, Kotlin

JSP + Oracle DB를 통한 로그인 시스템 만들기

kentakang 2018. 6. 17. 02:53
반응형

JSP + Oracle DB를 통한 로그인 시스템 만들기


안녕하세요, kentakang 입니다.

오늘은 전공 과목 수행평가를 준비할 겸 JSP + Oracle DB를 통한 로그인 시스템 제작을 해보려고 합니다.

우선 제 개발 환경은 이렇습니다.


개발 환경


Oracle Express Edition Express Edition 11g Release 2

Java 10 + Java EE 8

Apache Tomcat 9.0.7


데이터베이스 만들기


우선 로그인 시스템에 사용할 데이터베이스를 만들도록 하겠습니다.

우선 테이블을 생성하겠습니다.

제 로그인 시스템에 들어갈 정보는 아이디, 비밀번호, 이름, 전화번호, 성별 입니다.

CREATE TABLE MEMBER(name varchar2(20), id varchar2(20), pw varchar2(100), phone varchar2(20), gender varchar2(20));

이름, 아이디, 비밀번호, 전화번호, 성별 데이터가 들어가는 MEMBER 테이블을 생성했습니다.

그 다음 commit 명령어를 통해 해당 데이터를 반영합니다.


프로그램 설계


프로그램에서 어떤 동작이 필요한지, 어떤 JSP 페이지를 만들고 서블릿을 만들지 설계하도록 하겠습니다.

저는 이런식으로 만들도록 하겠습니다.


JSP 페이지 제작


이제 위 설계표를 토대로 JSP 페이지를 먼저 만들어 보겠습니다.

개발 순서는 어떻게 하시더라도 상관 없습니다.

우선 로그인 폼을 제작하도록 하겠습니다.


* 톰캣 실행 전 주의 사항

오라클 DB는 8080 포트를 사용합니다.

Build Configuration에서 Tomcat의 포트를 변경해주세요.


저는 이렇게 제작했습니다.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Login</title>
    <meta charset="utf-8">
</head>
<body>
    <h1>Login</h1>
    <form action="login" method="POST">
        <dl>
            <dd>
                <label for="id">아이디 : </label>
                <input type="text" name="id" id="id" size="10">
            </dd>
            <dd>
                <label for="pw">비밀번호 : </label>
                <input type="password" name="pw" id="pw" size="10">
            </dd>
            <dd>
                <input type="submit" value="로그인">
            </dd>
            <dd>
                <a href="/signup">회원가입</a>
            </dd>
        </dl>
    </form>
</body>
</html>

실행해보니 제대로 표시되네요.

로그인 폼의 정보는 Login 서블릿으로 보내 처리할거고, 

회원가입의 링크가 signup인 이유는 회원가입 서블릿을 제작할 때 다시 설명 드리겠습니다.

이제 회원 가입 폼을 만들어보도록 하겠습니다.

저는 이렇게 작성했습니다.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Signup</title>
    <meta charset="utf-8">
</head>
<body>
    <h1>Signup</h1>
    <form action="signup" method="POST">
        <dd>
            <label for="id">아이디 : </label>
            <input type="text" name="id" id="id" size="10">
        </dd>
        <dd>
            <label for="pw">비밀번호 : </label>
            <input type="password" name="pw" id="pw" size="10">
        </dd>
        <dd>
            <label for="name">이름 : </label>
            <input type="text" name="name" id="name" size="10">
        </dd>
        <dd>
            <label for="phone1">전화번호 : </label>
            <select name="phone1" id="phone1">
                <option value="010">010</option>
                <option value="011">011</option>
                <option value="012">012</option>
                <option value="013">013</option>
                <option value="014">014</option>
                <option value="015">015</option>
                <option value="016">016</option>
                <option value="017">017</option>
                <option value="018">018</option>
                <option value="019">019</option>
            </select> -
            <input type="text" name="phone2" size="5"> -
            <input type="text" name="phone3" size="5">
        </dd>
        <dd>
            <label for="gender">성별 : </label>
            <input type="radio" name="gender" id="gender" value="male"> 남성
            <input type="radio" name="gender" value="female"> 여성
        </dd>
        <dd>
            <input type="submit" value="회원가입">
            <input type="reset" value="초기화">
        </dd>
    </form>
</body>
</html>

전화번호 입력란과 성별 입력란이 살짝 복잡해진 걸 제외하면 전 코드와 거의 동일합니다.

reset 이라는 새로운 type이 나왔는데, 이 버튼의 경우 폼에 있는 모든 값을 초기화 시켜주는 역할입니다.

한번 실행시켜 볼까요?

제대로 출력되네요.

이제 회원 수정 폼을 만들어 보겠습니다.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Modify</title>
    <meta charset="utf-8">
</head>
<body>
    <h1>Modify</h1>
    <form action="modify" method="POST">
        <dd>
            <label for="id">아이디 : </label>
            <input type="text" name="id" id="id" size="10">
        </dd>
        <dd>
            <label for="pw">비밀번호 : </label>
            <input type="password" name="pw" id="pw" size="10">
        </dd>
        <dd>
            <label for="name">이름 : </label>
            <input type="text" name="name" id="name" size="10">
        </dd>
        <dd>
            <label for="phone1">전화번호 : </label>
            <select name="phone1" id="phone1">
                <option value="010">010</option>
                <option value="011">011</option>
                <option value="012">012</option>
                <option value="013">013</option>
                <option value="014">014</option>
                <option value="015">015</option>
                <option value="016">016</option>
                <option value="017">017</option>
                <option value="018">018</option>
                <option value="019">019</option>
            </select> -
            <input type="text" name="phone2" size="5"> -
            <input type="text" name="phone3" size="5">
        </dd>
        <dd>
            <label for="gender">성별 : </label>
            <input type="radio" name="gender" id="gender" value="male"> 남성
            <input type="radio" name="gender" value="female"> 여성
        </dd>
        <dd>
            <input type="submit" value="회원정보 수정">
            <input type="reset" value="초기화">
        </dd>
    </form>
</body>
</html>

기본적인 폼의 구조는 회원가입 폼과 동일합니다.

저는 해당 파일을 복사해 Form 태그의 action을 modify로 수정하고

회원 가입등의 텍스트를 회원정보 수정으로 변경해줬습니다.

이제 서블릿을 만들어보도록 하겠습니다.


서블릿 제작


이제 위 설계표를 토대로 서블릿을 만들어 보겠습니다.

우선 회원가입 서블릿부터 만들겠습니다.

package com.kentakang.jsplogin;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/signup")
public class ServletSignup extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

기본적인 서블릿의 구조입니다.

최상단 패키지의 경우 저와 다르거나 없어도 상관 없습니다.

우선 IDE를 통해 서블릿을 만드시고, @WebServlet 부분을 위 코드와 같이 수정해주세요.

해당 주소를 통해 서블릿에 접근한다는 의미입니다.

그 밑에 있는 doGet 메소드와 doPost는 각각 접근 방식에 따른 코드를 작성할건데요,

POST 메소드는 우리가 회원가입 폼의 정보를 전송할 때 사용하고, GET 메소드는 주소를 통해 브라우저로 접근했을 때 사용하도록 하겠습니다.

우선 doGet 메소드를 작성하겠습니다.

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.sendRedirect("/signup.jsp");
}

doGet 메소드는 request, response 클래스를 매개변수로 받습니다.

request 클래스는 요청을 받고 response는 응답을 해주는 기능을 합니다.

위 코드는 response의 sendRedirect 메소드를 통해 /signup을 링크 또는 브라우저로 직접 접속했을 때는 signup.jsp로 이동시키는 기능을 합니다.

이제 회원가입을 처리하는 doPost 메소드를 작성해 보겠습니다.

회원가입 서블릿을 만들기 전, 먼저 Oracle JDBC 드라이버가 필요합니다.

제가 사용 중인 IntelliJ IDEA 기준으로 드라이버 설치 법을 알려드리겠습니다.

우선 File -> Project Structure -> Libraries에 들어가주세요.

오라클 JDBC 드라이버는 저와 같은 환경을 사용하신다면,

C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib\ 폴더에 있습니다.

거기서 ojdbc6.jar을 라이브러리로 추가해주시면 드라이버 설치가 끝납니다.

이제 드라이버도 추가했으니 doPost 메소드를 작성하기 전에, 이 프로젝트에서는 DB를 사용할 때가 많습니다.

따라서 데이터베이스 연결을 위한 클래스를 하나 작성하겠습니다. 저는 DBConnection 이라는 이름의 클래스를 작성하겠습니다.

package com.kentakang.jsplogin;

import java.sql.Connection;
import java.sql.DriverManager;

public class DBConnection {
    public static Connection connect() {
        Connection conn = null;

        try {
            String user = "user";
            String password = "password";
            String url = "jdbc:oracle:thin:@localhost:1521:xe";

            Class.forName("oracle.jdbc.driver.OracleDriver");
            conn = DriverManager.getConnection(url, user, password);
        } catch (Exception e) {
            System.out.println(e);
        }

        return conn;
    }
}

저는 이렇게 작성해줬습니다.

클래스에서 반복해서 사용해야 하는 코드는, 이런식으로 따로 클래스를 작성해주시면 나중에 사용할 때 편리하게 사용하실 수 있습니다.

참고로 이렇게 데이터베이스가 들어간 코드를 GitHub등 저장소에 업로드 하실 때는 사용자 정보 데이터를 삭제해주세요.

이제 doPost 메소드를 작성하겠습니다.

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        Connection conn = null;
        PreparedStatement pst = null;
        String query = "INSERT INTO MEMBER(id, pw, name, phone, gender) VALUES (?, ?, ?, ?, ?)";

        String id = request.getParameter("id");
        String pw = request.getParameter("pw");
        String name = request.getParameter("name");
        String phone = request.getParameter("phone1") + request.getParameter("phone2") + request.getParameter("phone3");
        String gender = request.getParameter("gender");
        boolean isSuccess = true;

        try {
            conn = DBConnection.connect();
            pst = conn.prepareStatement(query);

            pst.setString(1, id);
            pst.setString(2, pw);
            pst.setString(3, name);
            pst.setString(4, phone);
            pst.setString(5, gender);

            pst.execute();

        } catch (Exception e) {
            System.out.println(e);
            isSuccess = false;
        } finally {
            try {
                if (pst != null)
                    pst.close();

                if (conn != null)
                    conn.close();
            } catch (Exception e) {
                System.out.println(e);
            }
        }

        if (isSuccess) {
            request.setCharacterEncoding("UTF-8");
            response.setContentType("text/html; charset=UTF-8");
            PrintWriter writer = response.getWriter();

            writer.println("회원가입에 성공했습니다.<br>");
            writer.println("<a href="\"./index.jsp\"">로그인</a>");
        }
    }

제가 작성한 doPost 메소드 입니다.

우선 Connection과 PreparedStatement를 비어있는 상태로 선언했습니다.

그 다음 회원가입에 사용 될 쿼리를 작성했습니다.

INSERT INTO MEMBER(id, pw, name, phone, gender) VALUES (?, ?, ?, ?, ?) 이라는 쿼리는 

MEMBER 테이블의 id, pw, name, phone, gender 칼럼에 VALUES에 있는 내용을 추가한다는 쿼리인데,

PreparedStatement는 VALUES에 들어갈 내용을 처음 쿼리 작성시에는 비워놓고 나중에 setString 등의 메소드를 통해 내용을 넣어줄 수 있습니다.

코드 작성 상 더 깔끔해 보이고 SQL 인젝션 공격을 방지해주기 때문에 사용했습니다.

그 다음 앞에서 작성해 둔 DBConnection Class의 connect 메소드를 통해 DB에 연결합니다.

DB 연결이 성공하면 prepareStatement에 값들을 집어 넣은 뒤 쿼리를 실행합니다.

그 다음 회원가입에 성공했다면 회원가입에 성공했습니다. 라는 메세지를 띄웁니다.

회원가입 기능은 완성이 되었네요, 이제 로그인 기능을 만들어 보겠습니다.

package com.kentakang.jsplogin;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

우선 LoginServlet의 기본적인 구조입니다.

이 서블릿에 로그인 기능을 구현할 예정입니다.

우선 doGet 메소드부터 작성하겠습니다.

저는 이 서블릿에 직접 접근한다면 로그인 폼으로 다시 보내주려 합니다.

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.sendRedirect("/index.jsp");
}

이제 doPost 메소드를 작성해서, 로그인 기능을 구현하도록 하겠습니다.

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String id = request.getParameter("id");
        String pw = request.getParameter("pw");
        String query = "SELECT * FROM MEMBER WHERE ID=? AND PW=?";
        Connection conn = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        HttpSession session = request.getSession();

        try {
            conn = DBConnection.connect();
            pst = conn.prepareStatement(query);
            pst.setString(1, id);
            pst.setString(2, pw);
            rs = pst.executeQuery();

            if (rs.next()) {
                String name = rs.getString("name");
                String phone = rs.getString("phone");
                String gender = rs.getString("gender");

                session.setAttribute("id", id);
                session.setAttribute("name", name);
                session.setAttribute("phone", phone);
                session.setAttribute("gender", gender);

                response.sendRedirect("/index.jsp");
            } else {
                response.sendRedirect("/index.jsp");
            }

        } catch (Exception e) {
            System.out.println(e);
        } finally {
            try {
                if (rs != null)
                    rs.close();

                if (pst != null)
                    pst.close();

                if (conn != null)
                    conn.close();
            } catch (Exception e) {
                System.out.println(e);
            }
        }
    }

제가 작성한 doPost 메소드입니다.

많은 부분들이 회원가입 서블릿과 비슷한데, 우선 쿼리부터 설명해드리겠습니다.

SELECT * FROM MEMBER 쿼리를 통해 MEMBER 테이블의 모든 데이터를 가져왔던거 기억나시죠?

이번에는 그 쿼리 뒤에 WHERE을 붙여 조건을 만족하는 데이터만 가져오는 쿼리입니다.

id와 pw가 입력받은 값과 동일한 데이터만 가져오는 쿼리입니다.

ResultSet에는 그렇게 들어온 데이터가 담겨 있게 되구요, 만약 조건에 맞는 쿼리가 없다면 로그인 폼으로 돌려 보냅니다.

그 다음 세션에 아이디, 이름, 전화번호, 성별 값을 담아 로그인 폼으로 보냅니다.

여기서 로그인 폼을 약간 수정했는데요,

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Login</title>
    <meta charset="utf-8">
</head>
<body>
    <%
        if (session.getAttribute("id") != null) {
            String name = (String) session.getAttribute("name");
    %>
        <h1><%=name%>님 환영합니다!</h1>
        <a href="/modify.jsp">내 정보 수정하기</a>
    <%
        } else {
    %>
    <h1>Login</h1>
    <form action="login" method="POST">
        <dl>
            <dd>
                <label for="id">아이디 : </label>
                <input type="text" name="id" id="id" size="10">
            </dd>
            <dd>
                <label for="pw">비밀번호 : </label>
                <input type="password" name="pw" id="pw" size="10">
            </dd>
            <dd>
                <input type="submit" value="로그인">
            </dd>
            <dd>
                <a href="/signup">회원가입</a>
            </dd>
        </dl>
    </form>
    <%
        }
    %>
</body>
</html>

이렇게 수정했습니다.

세션의 id 속성을 가져와 비어있지 않다면 (로그인이 되었다면) 이름님 환영합니다! 와 내 정보 수정하기 링크를 띄우고,

로그인이 안되어 있다면 로그인 폼을 띄우는 코드입니다.

이제 테스트 해볼까요?

우선 회원가입을 하겠습니다.

회원가입에 성공했네요, 이제 가입한 아이디로 로그인 해보겠습니다.

제대로 로그인 되는 걸 볼 수 있습니다.

이제 내 정보 수정하기 기능을 만들어 보겠습니다.

위에 있는 설계표에서는 modify.jsp가 회원 정보 수정 폼이였죠?

보통 회원 정보 수정 폼의 경우에는 기존 정보를 표시해주기 때문에, 해당 기능을 하는 코드를 jsp에 추가하겠습니다.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Modify</title>
    <meta charset="utf-8">
</head>
<body>
    <%
        if (session.getAttribute("id") != null) {
            String phone = (String) session.getAttribute("phone");
            String phone1 = phone.substring(0, 3);
            String phone2 = phone.substring(3, 7);
            String phone3 = phone.substring(7, 11);
            String gender = (String) session.getAttribute("gender");
    %>
    <h1>Modify</h1>
    <form action="modify" method="POST">
        <dd>
            <label>아이디 : </label>
            <%=session.getAttribute("id")%>
        </dd>
        <dd>
            <label for="pw">기존 비밀번호 : </label>
            <input type="password" name="pw" id="pw" size="10">
        </dd>
        <dd>
            <label for="pwmodify">변경할 비밀번호 : </label>
            <input type="password" name="pwmodify" id="pwmodify" size="10">
        </dd>
        <dd>
            <label for="name">이름 : </label>
            <input type="text" name="name" id="name" size="10" value="<%=session.getAttribute("name")%>">
        </dd>
        <dd>
            <label for="phone1">전화번호 : </label>
            <select name="phone1" id="phone1">
                <%
                    for (int i = 10; i <= 19; i++) {
                        if (phone1.equals("0" + i)) {
                %>
                <option value="0<%=i%>" checked>0<%=i%></option>
                <%
                        } else {
                %>
                <option value="0<%=i%>">0<%=i%></option>
                <%
                        }
                    }
                %>
            </select> -
            <input type="text" name="phone2" size="5" value="<%=phone2%>"> -
            <input type="text" name="phone3" size="5" value="<%=phone3%>">
        </dd>
        <dd>
            <label for="gender">성별 : </label>
            <%
                if (gender.equals("male")) {
            %>
            <input type="radio" name="gender" id="gender" value="male" checked> 남성
            <input type="radio" name="gender" value="female"> 여성
            <%
                } else {
            %>
            <input type="radio" name="gender" id="gender" value="male"> 남성
            <input type="radio" name="gender" value="female" checked> 여성
            <%
                }
            %>
        </dd>
        <dd>
            <input type="submit" value="회원정보 수정">
            <input type="reset" value="초기화">
        </dd>
    </form>
    <%
        } else {

    %>
    <h1>세션이 만료되었거나 잘못된 접근입니다.</h1>
    <%
        }
    %>
</body>
</html>

제가 수정한 modify.jsp 코드입니다.

우선 세션에서 id 값을 받아와 로그인이 되어 있는지 확인하고, 그 다음 아이디, 이름, 전화번호, 성별 칸에 기존에 입력되어 있던 값을 넣어줍니다.

휴대폰 번호 부분은 약간 복잡할 수 있는데, for 문을 돌려 기존 선택되어 있던 국번을 선택하고, 나머지는 하나로 통합되어 있던 phone 스트링을

잘라서 값으로 집어 넣습니다.

회원 정보 수정은 기존 비밀번호가 맞아야 수정되게 하겠습니다.

이제 Modify 서블릿을 만들어 보겠습니다.

package com.kentakang.jsplogin;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/modify")
public class ModifyServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

Modify 서블릿의 기본 구조입니다.

서블릿의 특성상 doGet 메소드는 만들지 않겠습니다.

이제 doPost 메소드를 작성해볼까요?

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        String id = (String) session.getAttribute("id");
        String pw = request.getParameter("pw");
        Connection conn = null;
        PreparedStatement pst = null;
        String query = null;
        String phone = request.getParameter("phone1") + request.getParameter("phone2") + request.getParameter("phone3");

        if (request.getParameter("pwmodify") != null) {
            query = "UPDATE MEMBER SET NAME=?, PW=?, PHONE=?, GENDER=? WHERE ID=? AND PW=?";
        } else {
            query = "UPDATE MEMBER SET NAME=?, PHONE=?, GENDER=? WHERE ID=? AND PW=?";
        }

        try {
            conn = DBConnection.connect();
            pst = conn.prepareStatement(query);
            if (request.getParameter("pwmodify") != null) {
                pst.setString(1, request.getParameter("name"));
                pst.setString(2, request.getParameter("pwmodify"));
                pst.setString(3, phone);
                pst.setString(4, request.getParameter("gender"));
                pst.setString(5, id);
                pst.setString(6, pw);
            } else {
                pst.setString(1, request.getParameter("name"));
                pst.setString(2, phone);
                pst.setString(3, request.getParameter("gender"));
                pst.setString(4, id);
                pst.setString(5, pw);
            }
            pst.executeUpdate();
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            try {
                if (pst != null)
                    pst.close();

                if (conn != null)
                    conn.close();

                session.invalidate();
            } catch (Exception e) {
                System.out.println(e);
            }
        }

        response.sendRedirect("/index.jsp");
    }

제가 작성한 doPost 메소드입니다.

이제 이런 코드를 많이 봐오셔서 보시면 어느정도 이해가 가시죠?

session.invalidate()는 세션을 초기화 하는 메소드입니다.

이제 테스트 해보겠습니다.

비밀번호를 test에서 test1로 이름도 test에서 test1로 변경하겠습니다.

제대로 변경이 되네요!

이렇게 설계표에 작성한 기능들을 모두 구현하여 로그인 시스템을 완성했습니다.

이론만 살펴보다가 이런식으로 직접 구현해보니 상당히 재미있네요.

앞으로도 이런 예제 구현식의 학습을 많이 진행해 봐야겠습니다.

반응형