Seam - 사용자 IPAddress 확인

Seam은 애플리케이션 UI 프레임웍으로 JSF를 사용합니다. JSF는 컴포넌트 기반 프레임웍이고 Seam과 결합하여 완전한 컴포넌트 기반 프레임웍의 모습을 갖추고 있습니다.

Seam 애플리케이션을 개발하다 보면 HttpServletRequest와 HttpSession 객체를 전혀 접근하지 않고 등록된 컴포넌트를 참조하여 사용하게 됩니다. 사용자 등록 폼 정보는 컴포넌트 맵핑 정보를 이용하여 사용하면 되지만 간혹 사용자가 입력하지 않는 별도의 정보를 사용해야 할 수도 있습니다.

가령 어떤 어떤 IP/Host에서 접근하는지 로깅을 남겨야 하거나 게시판에서 게시글의 IP Adress를 저장해야 한다면 어떻게 해야 할까요?

막상 이런 문제가 발생하면 약간은 막막해 지는 것이 사실입니다. 이 문제를 해결하는 방법은 크게 두 가지가 있습니다.

Seam Framework은 사용할 컴포넌트를 클래스 상단에 @Name을 추가하여 등록하던지 @Factory 어노테이션을 메서드에 설정하여 컴포넌트로 등록하고 사용합니다.

  • 클라이언트의 IP Address, Host 명, 사용 Port를 출력

지금은 클라이언트 정보를 HttpServeletRequest로 부터 가져와야 합니다. 이 정보를 가져오기 위해서는 Seam 컴포넌트를 등록하는 방법과 API로 가져오는 방법 두가지가 있습니다. Seam 프레임웍은 기본적으로 자바 클래스에 어노테이션을 추가하거나 /WEB-INF/components.xml에 컴포넌트를 설정하는 두 가지 방식으로 컴포넌트를 등록하여 사용합니다.

기본적으로는 어노테이션 사용법을 권장하며 어노테이션을 사용할 수 없는 부득이한 상황에서는 components.xml에 설정하는 방식을 사용합니다.

Client 정보 추출 방법

현재 요청의 클라이언트 정보는 HttpServletRequest에서 추출할 수 있습니다. 관련 메서는 다음과 같습니다.

  • 클라이언트 IP Address: public java.lang.String getRemoteAddr()
  • 클라이언트 호스트 명: public java.lang.String getRemoteHost()
  • 클라이언트 포트: public int getRemotePort()

위 와 같은 3개의 메서드를 이용하여 정보를 추출할 수 있습니다. 이 정보를 Seam 컴포넌트로 등록하는 방법은 다음과 두 가지 방법이 존재 합니다.

components.xml 파일에 컴포넌트 등록

위 3개의 메서드를 이용하여 추출한 정보를 컴포넌트로 사용하기 위해서는components.xml에 등록하는 방법이 있습니다. 이 방법을 사용하는 이유는 이 API를 사용하는 어노테이션을 마땅히 설정할 클래스가 없기 때문입니다. components.xml에 다음과 같이 등록하여 사용할 수 있습니다.

  • 설정 대상 파일: {SEAM_GEN_PROJECT}/resoueces/WEB-INF/components.xml
<factory name="clientAddr" value="#{request.remoteAddr}" scope="EVENT"/>
<factory name="clientHost" value="#{request.remoteHost}" scope="EVENT"/>
<factory name="clientPort" value="#{request.remotePort}" scope="EVENT"/>
  • Seam 페이지 컴포넌트 사용 코드: {SEAM_GEN_PROJECT}/view/layout/menu.xhtml
<rich:toolBarGroup>
    <h:outputText value="#{projectName}:"/>
    <s:link id="menuHomeId" view="/home.xhtml" value="Home" propagation="none"/>
    Client Info: IP: #{clientAddr}, Host: #{clientHost}, Port: #{clientPort}
</rich:toolBarGroup>
  • facesContext Injection 하는 컴포넌트 만들기

JSF는 UI 디바이스 독립적인 프레임웍입니다. 따라서 프로토콜을 추상화하는 형태로 디자인 되어 있습니다. 웹 상에서 모든 요청은 HttpServletRequest로 유입이 되고 JSF는 이것은 FacesContext라는 객체 형태로 변형하여 프레임웍에서 사용합니다. 또한 FacesContext로 부터 HttpServletRequest를 접근할 수 있습니다.

Seam 프레임웍은 FacesContext 객체를 Seam 컴포넌트에 Injection하는 것을 지원합니다.

따라서 Seam 프레임웍이 Injection 해준 FacesContext를 이용하여 클라이언트 정보를 추출하는 @Factory 메서드를 작성할 수 있습니다.

이렇게 만들어진 컴포넌트는 다음과 같습니다.

import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;

@Name("clientInfo")
public class ClientInfo {
  @In private FacesContext facesContext;   

  @Factory(value="clientAddr", scope=ScopeType.EVENT)
  public String getClientIpAddress(){
    HttpServletRequest request =
      (HttpServletRequest)facesContext.getExternalContext().getRequest();
    return request.getRemoteAddr();
  }
  @Factory(value="clientHost", scope=ScopeType.EVENT)
  public String getClientHost(){
    HttpServletRequest request =
      (HttpServletRequest)facesContext.getExternalContext().getRequest();
    return request.getRemoteHost();
  }
  @Factory(value="clientPort", scope=ScopeType.EVENT)
    public int getClientPort(){
      HttpServletRequest request =
        (HttpServletRequest)facesContext.getExternalContext().getRequest();
      return request.getRemotePort();
  }
}

이 컴포넌트는 앞에서 설정한 components.xml의 설정과 동일한 기능을 제공합니다.

지금까지 Seam 프레임웍에서 HttpServletRequest 자원을 컴포넌트화 하는 두 가지 방법을 살펴 보았습니다. 이렇게 Seam 프레임웍은 XML 설정과 Seam 컴포넌트 Bijection 기능을 이용하여 컴포넌트를 만들고 사용하는 방법을 제공합니다.

작성자: 김태완
김태완 avatar
작성자: 김태완
1999년 부터 Java, Framework, Middleware, SOA, DB Replication, Cache, CEP, NoSQL, Big Data, Cloud를 키워드로 살아왔습니다. 현재는 빅데이터와 Machine Learning을 중점에 두고 있습니다.
E-mail: taewanme@gmail.com