52.Apache Project &.../Struts

기반기술공부 - Struts1 예제 Login

1010 2009. 4. 21. 11:49
반응형
Struts를 이용한 간단한 로그인 예제

이번엔 웹 개발의 전형적인 예로써 사용자의 ID와 Password를 입력 받아 이를 인증 후 결과 페이지로 Forward 시키는 것을 Struts Framework을 이용하여 만들어 보겠습니다.

구성요소들은  다음과 같습니다.

1.        로그인  HTML 페이지
2.        Controller&Model 역할을 하는 LoginAction
3.        ActionForm, 폼빈 역할을 하는 LoginForm
4.        로그인이 성공 이었을 때 분기하는 success.html
5.        로그인이 실패했을 경우 분기하는 fail.html

사용자는 HTML 웹페이지를 이용하여 ID/Password를 입력 후 로그인 버튼을 누릅니다. 이 요청을 Controller 와 Model의 역할을 동시에 수행 하는(이 예제에서…)LoginAction이 이를 받아 폼빈(LoginForm, 사용자가 HTML 폼에서 입력한 정보들이 들어 있다.)을 통해 사용자가 입력 한 정보를 추출 후 인증을 수행 합니다.

폼빈(LoginForm)이 존재 하므로 LoginAction에서는 요청 파라미터를 추출 하는 일은 없습니다. 최근에 발표된 RC2 버전인 경우 매번 폼빈을 생성 할 필요 없이 동적으로 파라미터를 추출 할 수 있도록 했는데 이를 동적 폼빈 이라고 하며 DynaActionForm 클래스를 이용 합니다.

주)이 예제를 이클립스에서 실행 하기 위해서 이전 강좌(Eclipse에서 Struts(HelloWorld))와 같이 struts-test 라는 Tomcat 프로젝트에서 작성을 합니다. 그리고 프로젝트에서 마우스 우측 버튼을 누른 후 속성 - Java Build Path - library - add jars를 하신 후 WEB-INF/lib 아래의 struts를 다운 받아서 푼 jar 파일들을 선택 해 주신 후 아래의 예제를 돌리셔야 합니다.

1.        로그인을 위한 login.jsp를 만듭니다. (struts-test 라는 프로젝트에서 마우스 우측버튼을 누른 후 new , file 한 후 만드세요)

<%@ page language="java" contentType="text/html;charset=euc-kr" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:form action="/login">
        ID : < html:text property="id"/><br>
        Password : <html:password property="pwd"/><br>
        <html:submit value="로긴"/>
</html:form>

2.        로그인이 성공 했을 때 분기할 페이지인 success.html을 만듭니다. (struts-test 라는 프로젝트에서 마우스 우측버튼을 누른 후 new , file 한 후 만드세요)
3.        

<html>
        <head><title>로그인 성공 화면</title></head>
        <body>
                로그인이 성공 되었습니다...
        </body>        
</html>

4.        로그인이 실패 했을 경우 분기 할 페이지인 fail.html을 만듭니다. (struts-test 라는 프로젝트에서 마우스 우측버튼을 누른 후 new , file 한 후 만드세요)

<html>
        <head><title>로그인 실패 화면</title></head>
        <body>
                로그인 실패!!
        </body>        
</html>

5.        사용자가 요청 시 넘기는 값들을 빈으로 저장 해 놓기 위해 Request Parameter와 같은 구조를 가지는 폼빈을 만듭니다. LoginForm.java (이클립스인 경우 WEB-INF/src에서 마우스 우측 버튼을 클릭 후 new, class 하신 후 만드세요)

이 클래스는 Form빈으로서 사용자가 입력 한 값을 적절한 변수(프로퍼티)로 설정 해 주는 역할을 합니다. getXXX, setXXX 메소드등을 이용하여 적절한 변수 값으로 설정 되는 것입니다.


package login;
import org.apache.struts.action.*;

public class LoginForm extends ActionForm {
        protected String id;
        protected String pwd;
       
        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;
        }       
}

6.        이번에는 MVC 모델의 컨트롤러 및 모델의 역할을 동시에 수행하는 LoginAction.java 파일을 만듭니다. 아래 파일에서 AuthUser라는 모듈을 자바빈으로 빼 낸다면 이것이 모델에 해당 하게 될겁니다. 본예제에서는 편의상 컨트롤러와 모델의 기능을 통합 시켰습니다.

이 클래스는 사용자가 입력 한 파라미터(id, pwd)를 LoginForm(폼빈)으로부터 받아 이
값을 이용하여 인증을 한 후 적절한 View를 선택 하여 포워딩을 하는 것입니다.

예제의 간결함을 위해 본 예제에서는 AuthUser 메소드는 무조건 인증이 성공됨을 알
리는 true를 리턴 합니다. 이 부분을 Oracle과 같은 DB와 JDBC등을 이용한 적절한
인증을 구현 하시는 것은 여러분들의 몫으로 넘기겠습니다.


package login;

import org.apache.struts.action.*;
import javax.servlet.http.*;
import java.io.*;

public class LoginAction extends Action {
        public ActionForward execute(ActionMapping mapping, ActionForm form,
                                              HttpServletRequest req, HttpServletResponse res) {
                String id = ((LoginForm)form).getId();
                String pwd = ((LoginForm)form).getPwd();
               
                boolean isOK = authUser(id, pwd);
               
                if (isOK) {
                        return (mapping.findForward("success"));
                }
                else {
                        return (mapping.findForward("fail"));
                }               
        }
       
        public boolean authUser(String id, String pwd) {
                //이곳에서 디비에 접속해서 ID와 Password가 맞는지 확인 한다.
                //본 예제에서는 무조건 인증이 된것으로 true를 리턴 합니다
                return true;
        }
}


7.        이번에는 web.xml을 만듭니다. (WEB-INF에서 마우스 우측 버튼을 누른 후 new, file 하신 후 만드세요)

web.xml 파일에서 추가 한 내용은 URL창에 확장자가 .do인 요청이 들어 오면 ora.apache.struts.action.ActionServlet으로 요청을 보내도록 설정을 했습니다. 그런다음 스트럿츠의 설정 파일인 struts-config.xml의 위치를 알려주고 있습니다.

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <display-name>Welcome to Tomcat</display-name>
  <description>
     Welcome to Tomcat
  </description>
        <!-- Struts Tag Library Descriptors -->
        <taglib>
            <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
            <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
        </taglib>
        <taglib>
            <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
            <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
        </taglib>
        <taglib>
            <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
            <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
        </taglib>    
       
        <!-- ActionServlet Congif =====================================-->
        <servlet>
                <servlet-name>action</servlet-name>
                <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
                <init-param>
                        <param-name>config</param-name>
                        <param-value>/WEB-INF/struts-config.xml</param-value>
                </init-param>
                <load-on-startup>1</load-on-startup>                
        </servlet>
       
       
        <!-- ActionServlet Mapping ====================================-->
        <servlet-mapping>
                <servlet-name>action</servlet-name>
                <url-pattern>*.do</url-pattern>
        </servlet-mapping>


</web-app>


8.        이번에는 struts 설정을 위한 struts-config.xml을 만듭니다. . (WEB-INF에서 마우스 우측 버튼을 누른 후 new, file 하신 후 만드세요)

이 파일에서는 프로그램에서 사용 할 폼빈을 LoginForm으로 설정 하고 프로그램에서 사용 할 포워딩 이름을 설정 하는데(물론 이 부분은 action 설정에서 할 수도 있지만 전역적으로 설정 하기 위해 global-forwards 로 설정을 했습니다.

그리고 실제 요청을 처리 할 action 부분을 설정 하는데 예제 에서는 URL에 “/login”이 포함되어 있는 경우에 처리하라고 지정 했는데 LoginAction이 그 일을 하는거죠… 또한 폼빈으로 LoginForm을 설정 했습니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
     
    <!-- ========== Form Bean Definitions ================================== -->
    <form-beans>
        <form-bean name="LoginForm" type="login.LoginForm">          
        </form-bean>        
    </form-beans>
   
  
    <!-- ========== Global Forward Definitions =============================== -->
    <global-forwards>
        <forward name="success" path="/success.html" />
        <forward name="fail" path="/fail.html" />
    </global-forwards>
   
    <!-- ========== Action Mapping Definitions =============================== -->
    <action-mappings>
        <action          
                path="/login"
                type="login.LoginAction"
            name="LoginForm"                        
            validate="false"
        >
        </action>        
    </action-mappings>  
</struts-config>

위에서 주석 만드실 때 주의하세요… <!—다음에 줄 두개짜립니다. “====” 만약 다음과 같이 하시면 Tomcat 시작시 오류 뜹니다.<!--------------  

그리고 이클립스에서 만드시면 별도로 LoginForm.java나 LoginAction.java를 별도로 컴파일 하실 필요는 없습니다. 브라우저에서 다음과 같이 입력 하신면 로그인 화면이 나타나며 적절한 ID/PWD를 입력하시면 인증이 성공 했다는 success.html이 실행 될겁니다.

실행 후 화면을 보시면 주소창에 /login.do 라고 나타나 있을 것입니다. 이 같이 함으로써 사용자의 입장에서는 마지막 결과가 어느 페이지에서 나오는지를 알 수가 없습니다.(멋지죠^^) 당연히 직접 그 페이지로 접근 한다는 것은 불가능 합니다.

그러므로 success.jsp와 같은 결과 페이지를 만드는 사람과 Action등을 만드는 사람의 업무가 분리가 가능 하다는 이야기 입니다. 결국 이러한 장점이 MVC 모델의 장점이 되는거구요…

다음 강좌부터는 이 로그인 예제를 하나씩 기능을 추가해 가도록 하죠^^

먼저 HTML을 이용해서  Form양식을 만들어야만 한다.

Form 양식은 id와 pwd를 입력받는 일반 Web상의 login소스를 생각하면 된다.


<%@ page language="java" pageEncoding="EUC-KR"%>

<%@ taglib uri="/WEB-INF/tld/struts-html.tld" prefix="html" %>

<html:html>

<html:form action="/login">

<table width="200" height="138" border="0" cellpadding="0" cellspacing="0">
  <tr>
    <td height="8" colspan="3"><img src="images/login_title.gif" width="200" height="40"></td>
  </tr>
  <tr>
    <td width="79" align="left" class="style36 style16"><img src="images/id.gif" width="70" height="20"></td>
    <td width="89" height="20">
   
     <html:text property="uid" value="" size="12" style="width:75px;height:17px; border: #4882B2 1px solid"/>
      
    </td>
    <td width="38" rowspan="2">
    <html:img src="images/icon/btn_left_login.gif" width="35" height="46"
     onclick="loginCheck()" onmouseover="this.style.cursor='hand'"/>

    </td>
  </tr>
  <tr>
    <td height="20" align="left" class="style37"><img src="images/pwd.gif" width="70" height="20"></td>
    <td>
      <p>
     
      <html:password property="password" value="" size="12" style="width:75px;height:17px; border: #4882B2 1px solid"/>
     
    </p></td>
  </tr>
  <tr align="left" valign="middle">
    <td height="16" colspan="3">&nbsp;&nbsp;<a href="#" class="style16 style25" onMouseOver="MM_swapImage('Image17','','images/icon_left02.gif',1)" onMouseOut="MM_swapImgRestore()"><strong><img src="images/icon/icon1.gif" width="11" height="11">&nbsp;
    <html:link action="registerAgree">
     회원가입
    </html:link>
    </strong></a></td>
  </tr>
  <tr align="left">
    <td height="8" colspan="3">&nbsp;&nbsp;<a href="#" class="style26" onMouseOver="MM_swapImage('Image18','','images/icon_left02.gif',1)" onMouseOut="MM_swapImgRestore()"><strong><img src="images/icon/icon1.gif" width="11" height="11">&nbsp;
    아이디/ 비밀번호 찾기
    </strong></a></td>
  </tr>
 
</table>

</html:form>


</html:html>



위와 같은 양식을 이용해서 Struts-config.xml파일에선 2개의 property를 생성후

parameter를 받을수 있도록 설정을 해준다.


<form-bean name="loginForm" type="com.chestnut.logins.LoginForm">
           <form-property name="uid"  type="java.lang.String" />
            <form-property name="password"  type="java.lang.String" />
</form-bean>


위의 설정이 끝났으면 Action을 설정해준다.

<action
         attribute="loginForm"
         path="/login"
         name="loginForm"
            input="/sources/user/guest/Pindex.jsp"
            type="com.chestnut.logins.LoginAction"
            validate="false"
            scope="request">
            <forward name="success" path="/home.do"/>
            <forward name="fail" path="/sources/user/guest/PregisterAgree.jsp"/>
        </action>


로그인이 완료 됬을경우 home으로 실패 할경우 회원 가입 페이지로 forward를 시켜주는 부분이다.


Form을 통한 Action처리이기 때문에 크게 3개의 클래스가 필요하다.

Form클래스 Action처리 클래스 회원 정보를 저장해서 가지고 있을 DTO명칭 대신 단순하게UserInfo라는 클래스.


Class들을 만들자.

먼저 Login Form처리 클래스이다.

/*
 * Created on 2005. 7. 23
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package com.chestnut.logins;

/**
 * @author 한진석
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
import javax.servlet.http.HttpServletRequest;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;

public class LoginForm extends ActionForm {
 
 private String password;
 private String uid;
 
  public void reset( ActionMapping mapping, HttpServletRequest request ) {
   this.password= "";
    this.uid= "";
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

public String getUid(){
  try{
   return new String( this.uid.getBytes("ISO8859_1"), "EUC_KR" );
  }catch( Exception e){
   return new String("");
  }
 }
 public String getPassword(){
  try{
   return new String( this.password.getBytes("ISO8859_1"), "EUC_KR" );
  }catch( Exception e){
   return new String("");
  }
 }
}

getter와 setter 함수 작성시 잘 모르는 사람들은 고생을 많이 한다.

Getter와 setter작성시 항상 주의를 해야만 한다. Form에서 넘겨주는 name값이 반드시 getter와

setter에 들어가야만 한다.

위에서 보면 uid와 password로 넘겨 주고 ActionForm을 상속받은 클래스에선 getPassword(...

getUid라는 이름으로 작성을 하였다.

틀릴경우 Log파일을 보면 Error내용이 나온다. getter 또는 setter를 찾을수 없다는 내용의 ..


마지막으로 Action클래스를 작성.

/*
 * Created on 2005. 7. 23
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package com.chestnut.logins;

import java.sql.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.chestnut.logins.LoginForm;

/**
 * @author 한진석
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class LoginAction extends Action {
 
   public ActionForward execute(
     ActionMapping mapping,
     ActionForm form,
     HttpServletRequest request,
     HttpServletResponse response)
     throws Exception {

    String forwards = "";

    String uid         = "";
    String pwd       = "";
    
    LoginForm loginform = (LoginForm)form;
    
    uid  = loginform.getUid().trim();
    pwd  = loginform.getPassword().trim();
  
    javax.sql.DataSource src = getDataSource( request, "ora");
    Connection dbcon = null;
    PreparedStatement pstmt = null;
    
    ResultSet rs = null;
    ResultSet rs1 = null;
    
    UserInfo ui = null;
    
    try{
     dbcon = src.getConnection();
     String query ="SELECT * FROM USERS WHERE " +
     " USERID='"  + uid +"'"+
   " AND PWD='" + pwd +"'";
     pstmt = dbcon.prepareStatement(query);
     rs = pstmt.executeQuery();    
     String userId ="";
    
       if( rs.next() ){
        userId = rs.getString("USERID");
        HttpSession session = request.getSession();
       
        ui =
         new UserInfo(
           userId,
       rs.getString("NAME"),
       0,
       rs.getInt("USERTYPE"),
       rs.getString("UPYUN"),
       rs.getString("ADDRESS"),
       rs.getString("PHONE"),
       rs.getString("CPHONE")
     );
                       
        String query2 ="UPDATE USERS SET LASTLOGIN=SYSDATE" +
          " WHERE USERID='"+userId+"'";

        pstmt.executeUpdate( query2 );
               
        String query3 = "select * from mileage " +
          " where userid='"+userId+"'";
              
        pstmt = dbcon.prepareStatement(query3);
        rs1 = pstmt.executeQuery();
       
        if(rs1.next()){
         ui.setMileage(rs1.getInt("MILEAGE"));
        }
        rs1.close();
       
        dbcon.commit();
       
        session.setAttribute("user", ui );
        forwards = "success";
       
       }else{
        request.setAttribute("notuser",new String("1"));
        forwards= "fail";
       }
       
  }catch( Exception e){

   System.out.println("(SQL Error( Login ERROR ): "+ e );
   
  }finally{

   if(pstmt != null){pstmt.close();}
   if(dbcon != null){ dbcon.close();}
   if(rs != null){rs.close();}


    }
 
    return mapping.findForward( forwards );
   }

 }