2013년 8월 11일 일요일

Struts DB를 이용한 로그인 예제(Tomcat, DataSource, Filter 사용)

이번 강좌에서는 이전 예제인 “Struts 더 더 간단한 로그인 예제”의 기능을 확장 하여 예제를 만들어 보도록 하자.

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><?xml:namespace prefix = o />

이전 예제와 달라진 기능은 다음과 같다.

 

1.    JCL(Jakarta Commons Logging)을 이용하여 디버깅이 가능하도록 했으며

 

2.    Tomcat Context에 DataSource를 설정하여 JNDI 이름으로 Lookup.

 

3.    사용자의 인증을 처리함에 있어 ILoginDAO.java라는 인터페이스를 만들어 여기에서 authUser라는 메소드를 추상 메소드로 정의 했으며 인터페이스를 구현한 클래스가 LoginDAO.java 이며 이곳에서 실제 인증이 이루어 진다.

 

4.    RequestProcessor를 상속하여 필터를 구현.

 

 

다음의 순서대로 따라 하면 된다.

 

1.  db_login 이라는 Tomcat Project를 하나 만들자.

 

2.  로깅을 위한 파일을 설치하자.

 

자카르타 커먼즈 로깅 패키지 설치

 

http://commons.apache.org/logging/ 에서 commons-logging-1.1.zip다운로드

압축해제후 모든 jar 파일을 /WEB-INF/lib 에 복사

 

로깅 구현체 Log4J 설치

 

http://logging.apache.org/log4j/1.2/download.html에서 apache-log4j-1.2.15.zip 다운로드

압축해제후 log4j-1.2.15.jar 파일을 /WEB-INF/lib에 복사

 

/WEB-INF/src 아래 log4j.properties 파일을 만들자.



log4j.rootLogger=info, consoleAppender

log4j.appender.consoleAppender=org.apache.log4j.ConsoleAppender

log4j.appender.consoleAppender.layout=org.apache.log4j.PatternLayout

log4j.appender.consoleAppender.layout.ConversionPattern=[%C]  %m%n

 

 

3.  DataSource 사용을 위해 Tomcat_Home/conf/catalina/localhost/db_login.xml파일을 다음과 같이 수정한다. (DB SID 및 IP 주소, Port는 적절히 수정한다)

 

<Context path="/db_login" reloadable="true"

docBase="C:\oraclejava\project\db_login"

workDir="C:\oraclejava\project\db_login\work">

<Resource name="jdbc/oraclejava"

auth="Container"

type="javax.sql.DataSource"

username="scott"

password="tiger"

driverClassName="oracle.jdbc.driver.OracleDriver"

url="jdbc:oracle:thin:@192.168.1.104:1521:ORCL"/>

</Context>

 

4.  DB연결을 위한 설치.

 

JDBC Driver 설치

 

사용 하고자 하는 DBMS에 해당하는 JDBC Driver를 인터넷에서 다운 로드한다. Oracle은 Type 4 Driver인 ojdbc.14.jar 또는 classes12.jar을 다운로드 받는다. 해당 JAR 파일은 Tomcat_Home/common/lib/WEB-INF/lib 폴더에 복사한다. (복사 후  Tomcat 재 기동)

 

5.  /WEB-INF/app.tld 파일 작성

 

<?xml version="1.0" encoding="ISO-8859-1" ?>

 

<!DOCTYPE taglib  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"

  "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib>

 

  <tlibversion>1.0</tlibversion>

  <jspversion>1.1</jspversion>

  <shortname>Application Tag Library</shortname>

  <uri>http://jakarta.apache.org/taglibs/struts-example-1.0</uri>

  <info>

    Example Application.

  </info>

  <tag>

 

    <name>IsLogin</name>

 

    <tagclass>login2.IsLogin</tagclass>

 

    <bodycontent>empty</bodycontent>

 

    <info>

 

      Validate that there is a currently logged on user, by checking for

 

      the existence of a session-scope bean under the specified name.

 

      If there is no such bean, forward control to the specified page,

 

      which will typically be a logon form.

 

      name - Name of the session-scope bean to check for [user]

      page - Context-relative path to the logon page [/logon.jsp]

 

    </info>

 

    <attribute>

 

      <name>name</name>

 

      <required>false</required>

 

      <rtexprvalue>true</rtexprvalue>

 

    </attribute>

 

    <attribute>

 

      <name>page</name>

 

      <required>false</required>

 

      <rtexprvalue>true</rtexprvalue>

 

    </attribute>

 

  </tag>

</taglib>

 

 

 

6.  IsLogin.java

 

package login2;

 

 

import javax.servlet.http.HttpSession;

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.tagext.TagSupport;

 

import login2.Constants;

 

 

public final class IsLogin extends TagSupport {

            private String name = login2.Constants.USER_KEY;

            private String page = "/login.jsp";

 

            public String getName() {

 

                          return (this.name);

 

            }

 

            public void setName(String name) {

 

                          this.name = name;

 

            }

 

            public String getPage() {

                          return (this.page);

            }

 

            public void setPage(String page) {

                          this.page = page;

            }

 

            public int doStartTag() throws JspException {

 

                          return (SKIP_BODY);

 

            }

 

            public int doEndTag() throws JspException {

 

                          // Is there a valid user logged on?

                          boolean valid = false;

                          HttpSession session = pageContext.getSession();

                          if ((session != null) && (session.getAttribute(name) != null))

                                        valid = true;

 

                          // Forward control based on the results

                          if (valid)

                                        return (EVAL_PAGE);  //JSP 페이지의 다음을 수행

                          else {

                                        try {

                                                    pageContext.forward(page);

                                        } catch (Exception e) {

                                                    throw new JspException(e.toString());

                                        }

                                        return (SKIP_PAGE);  //JSP 페이지의 다음을 스킵

                          }

 

            }

 

            /**

              * Release any acquired resources.

              */

            public void release() {

 

                          super.release();

                          this.name = Constants.USER_KEY;

                          this.page = "/login.jsp";

 

            }

}

 

 

7.  login.jsp

 

<%@ page pageEncoding="euc-kr" %>

<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>

<html>

<head>

    <title><bean:message key="login.title" /></title>

    <html:base/>

</head>

 

<body>

<!-- 웹서버가 보내는 응답에 오류가 있다면 출력 -->

<html:errors/>

 

<!-- LoginSummit에 대해서는 struts-config.xml에 Mapping을 하게 된다 -->

<!-- focus="id" 라는 문법에 의해 자동으로  자바스크립트를 생성 합니다. -->

<html:form action="/LoginSubmit" focus="id">

        <table>

            <!-- 아래에서 텍스트 출력은 application.properties에서 가져 옵니다... -->

                <tr>                       

                        <th align="right"><bean:message key="prompt.id"/></th>                       

                        <!-- 아래는 input type=text 와 동일한 기능을 합니다 -->

                        <td><html:text property="id" value=""/></td>

                </tr>

                <tr>

                        <th align="right"><bean:message key="prompt.password"/></th>

                       

                        <!-- 만약 로그인을 실패하여 다시 돌아오는 경우 pwd 항목의 값을 비울때는 아래처럼 redisplay="false" 라고 하면 됩니다. HTML의 password 항목과 유사함  -->

                        <td><html:password property="pwd" redisplay="false"/></td>

                </tr>

                <tr>

                        <!-- Submit 버튼과 Reset 버튼을 생성 -->

                        <!-- 버튼의 라벨은 application.properties에서 내용을 가져 옵니다 -->

                        <th></th>

                        <td>

                            <html:submit>

                                <bean:message key="login.login" />

                                  </html:submit>

                       

                            <html:reset>

                                <bean:message key="login.reset" />

                                  </html:reset>

                        </td>

                </tr>                               

        </table>

</html:form>

</body>

</html>

 

 

8.  main.jsp

 

<%@ page language="java" %>

<%@ page contentType="text/html;charset=euc-kr" %>

<!-- 최초 사용자가 접속하게 되는 페이지 입니다. -->

<!-- 아래는 import와 동일한 기능을 하는 태그로 태그 확장을 사용 할 수 있도록 합니다 -->

<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>

<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>

<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic"%>

<%@ taglib uri="/WEB-INF/app.tld" prefix="myTag" %>

 

<!-- 인증이 안된 사용자는 login.jsp로 보내 버립니다. -->

<myTag:IsLogin/>

 

<html>

<head>

    <title><bean:message key="main.title" /></title>

    <html:base/>

</head>       

        <body>               

            <h3>반갑습니다.<bean:write name="user" property="id"/>님!</h3>                                       

                <ul>                       

                        <li>                           

                                <html:link forward="logoff">로그아웃</html:link>

                        </li>                       

                </ul>

        <body>

</html>

 

 

 

9.  MyFilter.java

 

package filter;

 

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

import org.apache.struts.action.RequestProcessor;

 

public class MyFilter extends RequestProcessor {

 

            protected boolean processPreprocess(

                          HttpServletRequest request,

                          HttpServletResponse response) {

                         

                          try {

                                        request.setCharacterEncoding("euc-kr");

                                                                               

                                        return true;

                          } catch (Exception e) {               

                                        return false;                                 

                          }

            }

}

 

10. Constants.java

 

package login2;

 

public class Constants {

            /**

              * 로그인한 사용자의 LoginForm이 저장될 세션 범위의 Attriute 이름

              */

            public static final String USER_KEY = "user";

           

            /**

              * ActionForward에서 사용되는 값             

              */

            public static final String SUCCESS = "success";

           

            /**

              * ActionForward 로그인 동작을 나타내는 Tocken 

              */

            public static final String LOGIN = "login";

           

            /**

              * ActionForward welcome 동작을 나타내는 Tocken           

              */

            public static final String WELCOME = "welcome";

                                       

}

 

 

 

11. LoginForm.java

 

package login2;

 

import javax.servlet.http.HttpServletRequest;

 

import org.apache.struts.action.ActionErrors;

import org.apache.struts.action.ActionMessage;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionMapping;

import org.apache.struts.action.ActionMessage;

import org.apache.commons.logging.*;

 

public class LoginForm extends ActionForm {

            private static Log log = LogFactory.getLog(LoginForm.class);

           

            private String id=null;

            private String pwd=null;

                         

           

            public String getId() {

                          return id;

            }

           

            public String getPwd() {

                          return pwd;

            }

           

            public void setId(String id) {

                          this.id = id;

            }

           

            public void setPwd(String pwd) {

                          this.pwd = pwd;

            }

           

            public void reset(ActionMapping mapping, HttpServletRequest request) {

                          pwd = "";

                          id = "";

            }

 

           

            /* struts-config.xml 에서 메핑시 validate="true" 라고 설정 되면 아래의

            validate 함수가 호출 되어 입력되는 값에 대한 validation check를 하게 됩니다.

            HTTP 요청으로 부터 해당 폼의 값을 set 한 후 아래 메소드가 호출 됩니다.

            참고로 validate에 위해 반환되는 ActionErrors 객체 역시 Framework에 관련된 클래스 입니다.

            만약 validate에서 null이나 empty가 아닌 ActionError 객체를 리턴하게 되면

            login.jsp에 있는 <html:errors/> 태그는 오류를 출력하고 아니면 넘어가게 됩니다...

            error.id.required, error.pwd.required는 일종의 키값으로  각 Locale마다 고유한 리소스를 가질 수

            있으므로 메시지에 대해 손쉬운 관리를 제공 합니다.

            예를들면 error.id.required = 사용자  ID는 필수 입력 항목 입니다. , 이러한 식으로 설정 합니다.

            */

 

            public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {

                         

                          log.info("validate ... Start ");

                          System.out.println("validate ... Start ");

                         

                          ActionErrors errors = new ActionErrors();

                         

                          if((id == null) || (id.length()<1)) {

                                        errors.add("error.id.required", new ActionMessage("error.id.required"));

                          }

                         

                          if((pwd == null) || (pwd.length()<1)) {

                                        errors.add("error.pwd.required", new ActionMessage("error.pwd.required"));

                          }

                         

                          return errors;                               

            }

           

 

                         

           

}

12. LoginAction.java


package login2;

 

import org.apache.struts.action.Action;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;

import javax.servlet.http.HttpServletResponse;

import login2.LoginForm;

import login2.Constants;

import org.apache.struts.action.ActionErrors;

import org.apache.struts.action.ActionMessage;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionMapping;

import org.apache.struts.action.ActionForward;

import org.apache.commons.logging.*;

 

/**

 * @author 이종철

 */

public class LoginAction extends Action {

                          private static Log log = LogFactory.getLog(LoginAction.class);

 

            public ActionForward execute(ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response) {

                          log.info("Action OK~~...");

                          System.out.println();

                          String id = ((LoginForm)form).getId();

                          String pwd = ((LoginForm)form).getPwd();

                         

                         

                          //Model을 이용하기 이용하여 인증부분의 처리를 합니다.

                          LoginDAO loginDAO = new LoginDAO();

                          log.info("authUser 호출 전....");

                          UserInfoVO userinfo = loginDAO.authUser(id, pwd);

                          log.info("authUser 호출 후....");

                          //에러 내용을 담을 ActionErrors 객체를 생성

                          ActionErrors errors = new ActionErrors();

                         

                          if (userinfo==null) {

                                        //인증 실패                                   

                                        errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionMessage("error.login.invalid"));                                   

                          }

                         

                         

                          //로그인 과정에서 에러가 있을 경우 Action클래스의 saveErrors 메소드를 이용해  에러를 저장하고

                          //이전의 로그인 페이지로 돌려 보내면 login.jsp의 <html:errors/> 태그에 의해 오류가 출력 돔

                          //mapping의 getInputForward()에서 반환하게 되는 정보는 struts-config.xml의 action태그의

                          //input 속성에  정의된 페이지로 이동하게 됩니다.

                          if (!errors.isEmpty()) {

                        saveErrors(request, errors);

                    return (mapping.getInputForward());

                          }           

                                       

                          //인증 성공한 경우 세션에 LoginInfoVO(로그인한 사용자 정보를 담은 객체)저장

                          HttpSession session = request.getSession();

                          session.setAttribute(Constants.USER_KEY, userinfo);

 

                         

                          //로그를 남기자.

                          StringBuffer buf = new StringBuffer("LoginAction : User --> ");

                          buf.append(id + "logged in session");

                          servlet.log(buf.toString());

                                                   

                          return (mapping.findForward(Constants.SUCCESS));                                       

                         

            }

 

           

}

 

 

13. LogoffAction.java

 

package login2;

 

import org.apache.struts.action.Action;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;

import org.apache.struts.action.ActionMapping;

import org.apache.commons.logging.*;

 

import login2.Constants;

 

public class LogoffAction extends Action {           

            private static Log log = LogFactory.getLog(LogoffAction.class);

 

            public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) {

                         

                          //필요한 어트리뷰트를 뽑아 냅니다.

                          //LoginAction에서 사용자의 로그온개체를 Consants.USER_KEY라는 이름으로 세션에 저장했음

                          HttpSession session = request.getSession();

                          UserInfoVO userinfo = (UserInfoVO)session.getAttribute(Constants.USER_KEY);

                         

                                        log.info("User Logout : " + userinfo.getId());

                         

                          //사용자의 로그인을 삭제, session.invaidate() 의 경우 션의 모든 것을 무효화 시킴.

                          session.removeAttribute(Constants.USER_KEY);

                          //session.invalidate();

                         

                          //성공적으로 처리 되었음을 알림

                          return (mapping.findForward(Constants.SUCCESS));

                         

            }

 

           

}

 

 

14. ILoginDAO.java

 

 

DAO 클래스가 구현해야 하는 메소드를 정의 했습니다.

 

package login2;

 

import login2.UserInfoVO;

 

/**

 * 데이터를 Access 하는 것들에 대한 인터페이스를 정의

 */

public interface ILoginDAO {

            public UserInfoVO authUser(String id, String pwd);  //abstract method

}

 

 

15. LoginDBFactory.java

 

 

package login2;

 

import java.sql.*;

import java.util.*;

import javax.naming.*;

import javax.sql.*;

import org.apache.commons.logging.*;

 

public class LoginDBFactory {

          private static Log log = LogFactory.getLog(LoginDBFactory.class);

          private static DataSource dataSource;

 

          public static Connection getConnection() throws Exception {

                    if (dataSource == null) {

                                try {

                                          Context context = new InitialContext();

                                          dataSource = (DataSource) context

                                                                .lookup("java:comp/env/jdbc/oraclejava");

                                } catch (Exception e) {

                                          log.equals("Connection Error");

                                }

                    }

                    return dataSource.getConnection();

          }

}

 

16. LoginDAO.java

 

 

package login2;

 

import java.sql.SQLException;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.DriverManager;

import org.apache.commons.logging.*;

 

public class LoginDAO implements ILoginDAO {

            private static Log log = LogFactory.getLog(LoginDAO.class);

           

            public UserInfoVO authUser(String id, String pwd) {

                          /**

                          * 이부분은 실제 DB에서 ID와 PASWORD로 인증을 해야 하는 부분 입니다.

                          */

                                                   

                          Connection con=null;

                         

                          try {                   

                            con = LoginDBFactory.getConnection();

                                                     

                            String sql = "select pwd from userinfo where id = ?";

                                       

                            PreparedStatement pstmt = con.prepareStatement(sql);

                            pstmt.setString(1, id);

 

                            ResultSet rs = pstmt.executeQuery();

 

                            if (rs.next()) {             

                                        if (rs.getString("pwd").toString().equals(pwd)) {

                                                    log.info("인증 OK >>>>>> ID :" + id);

                                                    return new UserInfoVO(id,(String)rs.getString("pwd"));

                                        }           

                                        else {

                                                    log.info("인증 Fail >>>>>> ID :" + id);

                                                    return null;

                                        }                                   

                              }

                            else {

                                        return null;

                            }                                                             

                          }

                          catch (SQLException sqle) {

                                        log.info(sqle.toString());

                                        return null;

                          }

                          catch (Exception e) {

                                        log.info(e.toString());

                                        return null;

                          }

                          finally {

                                            try{

                                              if (con != null) {

                                                  con.close();

                                              }

                                            }

                                            catch (SQLException e) {     

                  & 

댓글 없음:

댓글 쓰기