Struts2 도 해보자 시작1

2013. 6. 30. 20:34Java

Struts2 요것이 무엇인가를 집중적으로 분석해보고 이걸을 토대로 게시판 하나 만들어 볼랍니다.




참고 url : 01. 스트럿츠2(Struts2)란 무엇인가? 

1.    Struct2 의 배경
Apache Struts
2000년에 등장하여 많은 자바 기반의 웹 어플리케이션들을 개발하는데 도움을 주며 성장을 해왔고, 2005 JavaONE 에서 Struts 프로젝트의 개발자와 비하이브의 개발자가 미팅을 통해 Struts Ti 제안 초안을 구성 , 그리고 여러 웹 프레임워크의 좋은 아이디어들을 하나로 통합하는 것에 흥미를 가진 개발자들 간의 모임이 만들어지면서, 본격적으로 Struts2 의 개발이 시작. Struts1 의 보완과 웹워크 의 장점을 결합한 형태이다.

2.    Struts2 의 의미
용어의 뜻으로는 지주, 버팀목, 받침대라는 뜻을 갖고 있고, MVC 아키텍쳐를 채용하고 있는 자바 기반의 프레임 워크 이다.

3.    Struts2 의 특징
-
완전히 새로운 프레임워크(Struts1 때와는 다른 웹워크 2 MVC 아키텍쳐 채용)
-
직관적인 개발 (POJO 기반 액션
)
-
신속한 리로딩 ( 변경된 환경 설정 파일의 내용을 컨테이너 재시작 없이 리로드
)
-
손쉬운 Ajax 구현 (Dojo 프레임워크 포함, Ajax 테마 지원 태그
)
-
다양한 표현식 언어 EL(Expression Language) 지원
(JSTL , OGNL)
-
다양한 리절트 타입의 지원 및 프로파일링

4.    Struts2 환경 구축
- JDK ..
기설치
- Tomcat
기설치
- Eclipse
기설치
- Struts 2
Jar 파일 필요
  Apache Struts 2.3.15 GA :  http://struts.apache.org/

5.         Apache Struts 2.3.15 GA 압축 파일내의 구성
이중 아래의 5가지 Jar 파일을 WEB-INF/lib 폴더에 넣으면 끝?
- struts2-core-x.x.x.jar : Struts 2
Core library.
- xwork-core-x.x.x.jar :
웹 워크와 통합

- ognl-x.x.x.jar : OGNL , Struts2
를 위한 EL 이다.
- commons-logging-x.x.x.jar : log4j
와 같은 로깅을 위한 라이브러리
.
- freemarker-x.x.x.jar : UI
태크 템플릿을 위한 것
.

Struts
애플리케이션에 필요한 요소를 설정한다
.


  - web.xml : URL
확장자에 따라 FilterDispatcher에 의해서 액션을 실행하기 위한 환경 구축

요 말은.. 다시 말해 모든 사용자의 요청은 FilterDispatcher Class 를 거쳐간다라는 설정을 볼수 있다.
(WEB-INF
폴더 내에 web.xml 파일이 존재 한다
.)

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>Struts Blank</display-name>
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>



- struts.xml :
실행 후 결과를 처리할 Result 와 매핑을 설정

(WEB-INF/src/java/
폴더 내에 struts.xml 파일이 존재한다.)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
 "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="true" />

    <package name="default" namespace="/" extends="struts-default">

        <default-action-ref name="index" />

        <global-results>
            <result name="error">/error.jsp</result>
        </global-results>

        <global-exception-mappings>
            <exception-mapping exception="java.lang.Exception" result="error"/>
        </global-exception-mappings>

        <action name="index">
            <result type="redirectAction">
                <param name="actionName">HelloWorld</param>
                <param name="namespace">/example</param>
            </result>
        </action>
    </package>

    <include file="example.xml"/>

    <!-- Add packages here -->

</struts> 




(<struts> 요소는 루트요소 이다. Package name 은 사용자 임의설정이지만, 여기서 중요한 것은 extends 속성인데, struts-default 는 사용자가 변경하면 안 되는 중요한 속성 값이다
.
이 속성값은 .xml이 생략되어 있는데, struts-default.xml 파일이 struts-core-x.x.xx.jar 파일안에 존재한다. <package></package> 안에 다양한 action result 들이 들어간다
.)
또한 여기서 include file 이라고 되어 있는 example.xml 을 보도록 하자
.
액션과 리절트의 매팅을 위한 struts.xml 설정 하는데, 따로 include 형태로 빼서 관리를 하는구나
.
(WEB-INF/src/java/
폴더 내에 struts.xml 파일이 존재하는 곳과 동일
.)


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

    <package name="example" namespace="/example" extends="default">

        <action name="HelloWorld" class="example.HelloWorld">
            <result>/example/HelloWorld.jsp</result>
        </action>

        <action name="Login_*" method="{1}" class="example.Login">
            <result name="input">/example/Login.jsp</result>
            <result type="redirectAction">Menu</result>
        </action>

        <action name="*" class="example.ExampleSupport">
            <result>/example/{1}.jsp</result>
        </action>

        <!-- Add actions here -->
    </package>
</struts>

 





사실 이전에 위에서 사용하는 Java Action Class 를 생성해야 한다.
다시 보면 package name example 이고, action name HelloWorld 라는 Class를 만드는 것이지, 또한 태그 상에서도 class 에 대한 패키지 경로 함께 해당 클래스의 이름을 다시 기재를 해준다
.
<result>
name 속성은 success 는 액션클래스의 execute() 메소드 안의 return 값과 일치하여야 한다
.
/example/HelloWorld.jsp
는 웹 브라우저에 보여질 jsp파일 경로 이다
.

 

package example;

/**
 * <code>Set welcome message.</code>
 */
public class HelloWorld extends ExampleSupport {

    public String execute() throws Exception {
        setMessage(getText(MESSAGE));
        return SUCCESS;
    }

    /**
     * Provide default valuie for Message property.
     */
    public static final String MESSAGE = "HelloWorld.message";

    /**
     * Field for Message property.
     */
    private String message;

    /**
     * Return Message property.
     *
     * @return Message property
     */
    public String getMessage() {
        return message;
    }

    /**
     * Set Message property.
     *
     * @param message Text to display on HelloWorld page.
     */
    public void setMessage(String message) {
        this.message = message;
    }
}


 



상속 되어진 아버지 클래스도 함께 가져왔다
.


package example;

import com.opensymphony.xwork2.ActionSupport;

/**
 * Base Action class for the Tutorial package.
 */
public class ExampleSupport extends ActionSupport {
}

 




.. 그러면 마지막으로 결과를 보기 위한 해당 jsp 파일을 불러 보자
.

 <%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title><s:text name="HelloWorld.message"/></title>
</head>

<body>
<h2><s:property value="message"/></h2>

<h3>Languages</h3>
<ul>
    <li>
        <s:url id="url" action="HelloWorld">
            <s:param name="request_locale">en</s:param>
        </s:url>
        <s:a href="%{url}">English</s:a>
    </li>
    <li>
        <s:url id="url" action="HelloWorld">
            <s:param name="request_locale">es</s:param>
        </s:url>
        <s:a href="%{url}">Espanol</s:a>
    </li>
</ul>

</body>
</html>



참 쉽다라고 보이는 가
?
여기서 처음 접하는 부분이 있다. 바로 taglib 부분과 더불어 html 이 아닌 부분들이 보인다
.
${message}
OGNL EL 표현 방법으로 출력한것이다. 여기서는 없네요
.
<s:property>
는 스트럿츠2 태그라이브러리로 출력한것이다
.
<%=request.getAttribute(“message”)%>
는 일반 jsp로 출력한 것이다
.
message
는 자바빈즈의 원리에 의해 액션 클래스에 작성하였던 getMessage() 메소드를 호출한 것이다
.

자 그렇다면

http://localhost:8080/struts2-blank/example/HelloWorld.action 상으로 테스트를 해보았다. 이게 끝이다

.


6.          지금까지의 동작 원리







사용자가
http://localhost:8080/struts2-blank/example/HelloWorld.action를 요청한다
.
요청은 즉시 web-inf/web.xml 에 있는 filterFilterDispatcher 를 거친다
.

<filter
>
        <filter-name>struts2</filter-name
>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class
>
    </filter
>

무조건 거친 후 HelloWorld.action(액션명) struts.xml 에서 찾는다
.
<action name=”HelloWorld”>
를 찾아 class 속성으로 기재되어 있는 해당 클래스에 접근한다. (여기에서는
example.HelloWorld)

       
<action name="HelloWorld" class="example.HelloWorld">
            <result>/example/HelloWorld.jsp</result
>
        </action>


클래스에 접근했다면 자동적으로 실행되는 메소드 execute() 메소드를 실행한다.

public String execute() throws
Exception {
        setMessage(getText(
MESSAGE
));
       
return
SUCCESS;
}

비즈니스 로직을 처리후 return “success”처리.
리턴값이 “success” 라는 문자열을 struts.xml 에서 <result name=”success”>와 일치하여 /stoneWorld.jsp 처리 결과 페이지로 매핑한다
.


아래와 같이 다양한 방법으로 액션 클래스의 멤버변수들을 접근하여 데이터를 핸들링 한다
.
<<JSP
파일 참조
>>

7.         Struts2 흐름.

1.
http://localhost.....action
다시말해 client로부터 request 가 들어오면 struts 의 생명주기 시작.

2. Struts2
상의 web.xml struts.xml 에서
FilterDispatcher 통과후 URL 필터링.
 ( Servlet container
는 이 request를 표준 filter chain 으로 전달하는데, FilterDispatch 라는 Filter 가 호출 됨
.)

3.
Filter ActionMapper 를 참조해서 Action를 호출할지 안 할지 결정
.

4.
만약 ActionMapper가 호출해야 할 Action을 찾으면 FilterDispatcher ActionProxy에게 통제권을 넘겨줌
.

5. ActionProxy
Struts.xml 과 같은 설정(Configuration) file을 읽어서 ActionInvocation class를 생성한 후에 통제권을 넘겨줌
.

6. ActionInvocation
은 필요할 경우 interceptor를 하나씩 호출한 후, 처음에 호출하기로 결정한 Action을 호출 합니다. 해당 class 파일로 이동해서 execute 실행후 return 값 돌려줌.(Interceptor Logging, Validation, File upload, double-submit guard struts 에서 제공하는 특정 역할을 수행한다
.)

7.
Action 의 결과값이 반환되면 ActionInvocation struts.xml 에 정의된 결과 Page를 찾는다.( Page는 결국 Response가 된다
.)

8. Action
호출전에 호출되었던 interceptor를 역순으로 하나씩 호출한 후, response Filter(대부분 FilterDispatcher)에게 넘겨준다
.

9.
이후 결과가 servlet Container에 넘겨지고  return 값에 따른 jsp(VIEW)Client에게 보여줌
.


8.         Struts Interceptor
Interceptor
는 액션이 실행 되기 전,후 에 실행되는 인터셉터는 Struts의 꽃이랍니다. 우선 Interceptor 요소를 살펴보시길.

A.     <Interceptors /> 요소
<interceptors /> 요소는 인터셉터를 설정하기 위한 용도, <package>의 하위요소.
<interceptors>
요소는 하위 요소에는 <interceptor> <interceptor-stack>를 하위요소로 갖는다
.
<interceptor-ref>
요소는 액션의 실행 전 후로 실행될 인터셉터를 지정할 때 사용
.

B.     <interceptor /> 요소
name 속성 과 class 속성으로 이뤄짐.
ex) <interceptor name=”testInterceptor” class=”test.StoneInterceptor” />

C.     <interceptor-ref /> <interceptor-stack /> 요소
<interceptor-ref /> 요소는 액션의 실행 전 후로 실행될 인터셉터를 지정할 때 사용.
<interceptor-stack />
요소는 <interceptor-ref /> 요소를 이용하여 이미 정의된 인터셉터들을 여러 개씩 묶어서 하나의 이름으로 참조할 수 있도록 하는 인터셉터 스택을 정의하는 요소

ex)
<interceptor-stack name=”StoneStack”>
  <interceptor-ref name=”Stack01” />
  <interceptor-ref name=”Stack02” />
  <interceptor-ref name=”Stack03” />
</interceptor-stack>

Struts2
는 이미 struts_default.xml 에서 다양한 인터셉터를 미리 만들어 두었다.
하지만 개발자가 직접 인터셉터를 만들어 사용할 수 있는데 인터셉터를 상속하여 개발자가 원하는 대로 확장하는 것을 커스텀 인터셉터라 한다
.

그럼 인터셉터 자바 파일을 생성해 보자
.
public class OneInterceptor extends AbstractInterceptor{
  @Override
  public String intercept(ActionInvocation invocation) throws Exception{
    //
액션 수행하기 전에 처리할 일
.
    String result = invocation.invoke();
    //
액션 수행 후 처리할 일

    return result;
  }
}
public class TwoInterceptor extends AbstractInterceptor{
  @Override
  public String intercept(ActionInvocation invocation) throws Exception{
    //
액션 수행하기 전에 처리할 일.
    String result = invocation.invoke();
    //
액션 수행 후 처리할 일

    return result;
  }
}

이 만들어진 인터셉터 자바파일은 struts.xml 파일에 설정
<struts>
  <package name=”struts2” extends=”struts_default”>
    <interceptors>
      <interceptor name=”oneInterceptor” class=”interceptor.OneInterceptor” />
      <interceptor name=”oneInterceptor” class=”interceptor.OneInterceptor” />
    </interceptors>

    <action name=”StoneWorld” class=”action.StoneWorld”>
      <interceptor-ref name=”oneInterceptor” />
      <interceptor-ref name=”oneInterceptor” />
      <result name=”success”>/stoneWorld.jsp</result>
    </action>
  </package>
</struts>

이렇게 만들어 놓으면, oneInterceptor -> twoInterceptor -> Action -> TwoInterceptor -> OneInterceptor  이런식으로 실행된다.

이걸로 할수 있는 기능은 무엇일까
?
회원들의 권한관리, 메뉴별 권한, 파라미터 값 체크, 로그인 체크, 로그 분석 등 다양하다
.
로그인 체크로 예를 들면, 액션이 실행되기 전에 로그인을 체크하는 인터셉터로 액션 접근을 막을수 있다
.


9.    Struts RESULT
 struts framework
에서 액션이 실행된 이후에 사용자에게 어떠한 결과를 보여주어야 하는지를 결정한다. 예를 들어 성공적으로 실행이 완료되었다면, 사용자 응답을 생성해야 하고, 에러가 발생하였다면 사용자 입력 화면으로 되돌아가도록 하는 등의 설정을 Result 에서 한다.
<result type />
에 따라 사용자 페이지 화면이 결정되어 진다
.
개발자가 어떠한 Result type을 주었느냐에 따라 사용자에게 보여질 화면을 컨트롤 할 수 있다
.
Result <action />의 하위 요소 이며, 다양한 리절트의 종류가 있다
.

A.     기본 속성
- name (
선택) : 액션 메소드에서 리턴한 문자열을 지정, 기본값은 “success”이다. 사용자 임의의 문자열로 사용 가능.
- type(
선택) : struts-default 패키지에 선언되어 있는 result-type 을 사용하여 result type을 지정한다. 기본값은 dispatcher 이다
.

B.     Result 타입의 종류.

                i.         chain.
 -
먼저 실행한 액션의 프로퍼티(멤버변수의 값들)를 현재 실행 중인 액션에 셋팅할 수 있게 된다는 장점이 있다.
예를 들어 회원가입 후 다음페이지에서 회원 가입이 완료되었습니다. OOO님 정보가 성공적으로 등록되었습니다.” 이런 문자열을 띄운다고 하였을 때 OOO의 아이디 정보를 가져와야 한다
.
회원 가입 과 동시에 insert 가 실행 될테고, 회원 가입 완료 페이지로 왔을 때 회원 아이디를 select 할 필요없이 그대로 가져올수 있다는 말이다.

               ii.         dispatcher
 -
이 타입은 <result />요소의 기본 값이기도 하다.
  <action name=”Stone” class=”stone.Stone”>
   <result name=”success”>/stone.jsp</result>
  </action>
 
위와 같이 선언되었을 경우 Stone.action 으로 접근시 request 객체가 유지 된다
.
 
요청 처리를 다른 웹 리소스로 위임하는 것이다
.
 
따라서 웹 브라우저에 요청 URL이 바뀌지 않는다
.
 
예전의 서블릿 코딩시

  RequestDispatcher dispatcher = request.getRequestsDispatcher(“/stone.jsp");
  dispatcher.forward(request.response);
 
이거와 같은 의미이다.

              iii.         Redirect
  -
페이지가 이동할 URL을 응답으로 웹 브라우저에 보낸다.
   URL
로 새롭게 서버와 연결이 되므로 request가 새롭게 생성되는 것을 의미한다
.
  
웹 브라우저에 나타나는 URL도 바뀐다. 예전의 Servlet 코딩시

   Response.sendRedirect(“/stone.jsp");
와 같다.

              iv.         RedirectAction
  - Dispatcher
와 유사하다. 하지만 dispatcher는 리다이렉트 할 URL을 지정하였지만 redirectAction actionName(액션명)을 리다이렉트 대상이 될 액션 이름으로 지정한다.
  <action name=”Stone” class=”stone.Stone”>
   <result name=”success” type=”redirectAction”>
     <param name=”actionName”>StoneGo</param>
     <param name=”message”>${message}</param>
   </result>
  </action>
<param />
요소에 이동될 액션명과 message 라는 멤버변수의 값을 get 방식으로 가져간다
.
redirectAction이 사용되는 경우는 예를 들어 게시판의 글을 수정 후 다시 상세보기로 돌아올 때 사용하기도 한다.(상세보기를 돌아올 때 게시판의 일련번호를 가져와야 할 때 message가 아닌 게시판 일련 번호 멤버변수가 됨
.)

               v.         Freemaker ,httpheader, stream, velocity , xslt , plaintext.
 
파일 다운로드시에 stream를 쓰고 나머지는 거의 쓸일이 없다고 한다.
 






* 용어 설명
 - Framework :
동일한 형태의 개발을 위해 이미 만들어진 어플리케이션 모델과 개발에 도움이 되는 API 의 집합
 - Architecture :
시스템 전체의 설계 방식 , 시스템 구성
 - POJO (Plain Old Java Object) :
순수 자바 클래스, 프레임워크 및 컨테이너 (톰캣 등) 종속되지 안는 평범한 클래스
 -
컨테이너 : 자바기반의 웹 애플리케이션을 돌리기 위한 프로그램, 톰캣, 제우스, 웹로직, 웹스피어스..
- Ajax :
자바스크립트 기술, 비동기 통신
.
- Dojo :
자바스크립트의 라이브러리(프레임워크
)
- JSTL : Jsp
태그 라이브러리

- OGNL : j
네 태그 사용을 더 쉽게 표현한 언어