일반적인 사용자 외에 직접 주소를 쳐서 접근 하는 사용자를 방지하기 위하여

매번 해당되는 요청시 마다 login검사를 해줘야 하는 경우가 있다.

 

이 경우 login검사를 모든 컨트롤러에서 해주기엔 게시판 하나만 있는 사이트라면 모를까

다수의 기능을 가지고 있는 사이트에서라면 굉장히 애로사항이 꽃을 피울만한 일이다.

 

이런 경우에 login검사 처리를 Spring에서 제공하는 Interceptor를 사용하여 한번에 해결 가능하다

 

InterCeptor에서 제공하는 3가지 메소드는 각각 개입하는 시점이 다르다.

  • preHandle - Controller 실행 요청전
  • postHandle - view(jsp)로 forward되기 전에
  • afterCompletion - 끝난뒤

login 검사를 해야 될 시점은 Dispatcher가 해당 controller로 이어주기 전에 해야 되므로 preHandle메소드를 사용하여 처리하겠다.

HandlerInterceptorAdapter을 상속받은 LoginCheckInterceptor 을 만든다.

 


public class LoginCheckInterceptor extends HandlerInterceptorAdapter {

 

 @Override
 public boolean preHandle(HttpServletRequest request,
   HttpServletResponse response, Object handler) throws Exception {
  // TODO Auto-generated method stub
  

  // session검사
  HttpSession session = request.getSession(false);
  

   if (session == null) {
   // 처리를 끝냄 - 컨트롤로 요청이 가지 않음.
   response.sendRedirect("/login.do");
   return false;
  }
  
  String userId = (String)session.getAttribute("userId");
  if (userId == null) { 
   response.sendRedirect("/login.do");  
   return false;
  }
  return true;
 }
}

preHandle은 리턴값이 boolean형태다. 리턴값이 true가 아닐경우 해당 컨트롤러로 이어주지 않는다.

 

만들어 놓은 login검사를 위한 intercepor인  loginCheckInterceptor를 사용하기 위하여 설정파일에서 bean객체로 설정한다.

 

<!-- Login Check Interceptor -->
<bean id="loginCheckInterceptor" class="test.interceptor.LoginCheckInterceptor" /> 

 

이제 해당 UrlHandlerMapping 사용시 interceptor를 사용하기 위하여 프로퍼티로 추가 한다

 

<bean id="UrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

   <!-- interceptor 추가 -->

  <property name="interceptors">
   <list>
    <ref bean="loginCheckInterceptor" />
   </list>
  </property>

 

  <property name="alwaysUseFullPath" value="true" />
  
  <property name="mappings">
   <props>
  <prop key="/main.do">menuManagementController</prop>
    
   </props>
  </property>
 </bean>

 

이제 main.do라는 요청이 들어오게 되면 해당 컨트롤러인 menuManagementController로 가기 전에

loginCheckInterceptor에서 login검사를 한 후 로그인이 되어 있지 않을 경우 다시 로그인 검사로(login.do)로 보내게 될 것이다.

 

 

[출처] http://blog.naver.com/gigar/60103191032



Posted by linuxism
,


How do I count number of online users?

When you have a web application you might want to know how many users are currently online or connected to your website. If you have visited some of web online forums you can see; usually on the first page; the list of their online users or maybe just the number of currently online users.

How do we know / count how many sessions or users are currently connected to our website. Do you care to know? Let’s see what’s Java Servlet API offers us on this matter.

Servlet API has an interface javax.servlet.http.HttpSessionListener, an implementation of this interface will have the ability to be notified by the servlet engine at anytime when a new session is created or destroyed.

This interface has two methods to be implemented; these methods are sessionCreated(HttpSessionEvent se) andsessionDestroyed(HttpSessionEvent se). These method will be called as a notification that a new session was created and the session was about to be destroyed respectively.

Now let’s create our session listener. The code below is what our class is going to be implemented.

To display information of current online users we need to create a simple JSP page. This JSP file will get the number of online user from HttpSession attribute named counter that we set in our listener above.

The final step to make the listener working is to register it in the web.xml file. Below is the example how to register the listener inweb.xml.



Posted by linuxism
,


@MVC 는 웹 애플리케이션 개발에 필요한 유용한 기능을 대부분 제공한다. 또 다양한 MVC 기능을 전략 패턴을 통해 사용하게 해주므로 스프링이 제공하는 전략 중에서 원하는 것을 선택해 적용할 수 있다. 여기에 더해서 스프링이 제공하는 세부적인 기능을 확장하고 싶다면 스프링이 제공하는 확장 포인트를 이용할 수 있다. 여기서는 애노테이션 방식의 컨트롤러를 만들 때 적용되는 기능을 확장할 수 있도록 준비된 확장 포인트 중에서 몇 유용한 몇 가지를 살펴보자. 그 외에도 기본 동작 방식을 변경하거나 확장할 수 있는 많은 확장포인트가 있으므로 관심이 있다면 각 클래스의 API 문서를 자세히 살펴보기 바란다.

AnnotationMethodHandlerAdapter

확장 포인트가 가장 많은 전략은 다양한 관례와 규칙을 이용해 컨트롤러 메소드를 호출해 주는 AnnotationMethodHandlerAdapter 다. 이미 WebBindingInitializer 와 HttpMessageConverter 를 활용하는 방법은 설명했다. 그 외에도 다음과 같은 인터페이스를 구현한 확장 기능을 적용할 수 있다.

SessionAttributeStore

@SessionAttribute 에 의해 지정된 모델은 자동으로 HTTP 세션에 저장됐다가 다음 요청에서 사용할 수 있다. 정확히 말하자면 SesionAttributeStore 인터페이스의 구현 클래스에 의해 저장됐다가 다시 참조할 수 있는 것이다. 디폴트로 등록된 SessionAttributeStore 의 구현 클래스가 HTTP 세션을 이용하는 DefaultSessionAttributeStore 이기 때문에 기본적으로 HTTP 세션에 저장된다. HTTP 세션은 잘 다루지 않으면 웹 애플리케이션 메모리 누수의 원인이 될 수 있다. 적절하게 SessionStatus 의 setComplete() 을 호출해주지 않으면, 필요 없는 모델 오브젝트가 메모리에 계속 남게 된다. 세션 타임아웃에 결려서 해당 사용자의 모든 세션 정보가 제거되기 전까지 계속 메모리를 잠식하게 된다. 문제는 아무리 코드를 잘 작성했다고 하더라도 사용자가 폼을 완료하기 전에 다른 페이지로 이동하는 작업이 반복되면 HTTP 세션에는 모델 오브젝트가 쌓일 수 있다는 점이다. 또 다른 문제는 클러스터링을 통해 한 대 이상의 서버를 동시에 적용한 경우다. 서버다운 등으로 사용자가 다른 서버로 연결돼도 HTTP 세션 정보를 유지하기 위해 HTTP 세션 정보를 서버 사이에 복제하는 작업이 필요하다. WAS에 따라 다양한 기법이 있지만, 어쨌든 서버의 개수가 많아지면 HTTP 세션 정보 복제 작업이 상한한 부담이 될 수 있다. 

따라서 고성능을 요구하면서 대규모의 사용자를 처리해야 하는 서버라면 아예 @SessionAttribute 를 적용하지 않아서 HTTP 세션의 사용을 피하는 방법을 선택할 수밖에 없다. 또는 다른 더 효율적이고 빠른 방식으로 세션 정보를 저장하도록 만들어야 한다. 예를 들면 대규모 클러스터 내에서 효과적으로 정보를 공유하는 데이터 그리드에 세션 정보를 저장하거나, 메모리에 부담을 주지 않도록 별도의 위치에 세션 정보를 저장하는 방법을 사용할 수 있다.

이런 경우 SessionAttributeStore 인터페이스를 구현해서 세션정보를 저장하는 방법을 바꿀 수 있다.

또는 HTTP 세션에 저장하지만 세션 타임아웃이 되기 전에라도 일정 시간 이상 저장된 모델 오브젝트를 자동으로 삭제하게 할 수도 있다. 

구현한 SessionAttributeStore 클래스는 빈으로 등록하고 AnnotationMethodHandlerAdapter 의 sessionAttributeStore 프로퍼티로 등록해주면 디폴트 구현을 대체할 수 있다.

WebArgumentResolver

컨트롤러 메소드의 파라미터로 사용할 수 있는 타입과 애노테이션의 종류는 20여 가지나 된다. 웬만한 HTTP 요청정보는 메소드 파라미터 선언을 통해 원하는 형태로 전달받을 수 있다.  하지만 필요하다면 이를 더 확장할 수도 있다. 이때 사용하는 것이 바로 WebArgumentResolver 다. 이 인터페이스를 구현하면 애플리케이션에 특화된 컨트롤러 파라미터 타입을 추가할 수 있다.

예를 들어보자. 로그인한 사용자에 대한 정보가 암호화돼서 쿠기에 encodedUserInfo 라는 이름으로 저장되어 있다고 해보자. 로그인한 사용자를 가져오려면 일단 쿠키에서 이 값을 꺼내서 사용자 정보로 다시 변환해주는 라이브러리를 호출해야 한다. 쿠키 값은 @CookieValue 애노테이션을 이용해 가져올 수 있으니 다음과 같이 메소드를 선언하고 인증정보 암호화 오브젝트를 DI 받아서 이 쿠키 값으로부터 사용자 정보를 돌려주는 메소드를 호출해야 할 것이다.

1
2
3
4
5
6
@Autowired
private UserService userService;
 
public void add(@CookieValue String encodedUserInfo) {
    User currentUser = userService.decodeUserInfo(encodedUserInfo);
}

매번 코드를 통해 사용자 정보를 가져오는 작업이 번거롭게 느껴진다면, WebArgumentResolver 를 이용해 쿠키 값으로부터 사용자 정보를 가져와 메소드 파라미터로 전달받도록 만들 수 있다. WebArgumentResolver 는 다음과 같은 매우 단순한 메소드 하나만 구현하면 된다.

1
2
3
4
5
6
7
8
9
10
package org.springframework.web.bind.support;
 
import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;
 
public interface WebArgumentResolver {
 
    Object UNRESOLVED = new Object();
    Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) throws Exception;
}

메소드 파라미터 정보와 웹 요청 정보를 받아서 파라미터 타입과 애노테이션을 참고해 오브젝트를 생성할 수 있으면 이를 리턴하고, 아니라면 UNRESOLVED 를 돌려주면 된다. 이를 이용하면 간단히 다음과 같은 메소드 파라미터를 사용할 수 있다.

public void add(@Current User user) { ... }

WebArgumentResolver 에서 파라미터 타입이 User 이고 @CurrentUser 라는 애노테이션이 붙어 있다면 쿠키에 저장한 값을 꺼내서 이를 User 로 변환해주도록 만들면 된다.10줄 미만의 코드를 작성함으로써 애플리케이션의 로그인 사용자 정보를 가져오는 방법을 깔끔하게 만들 수 있다. 메소드도 간결해졌을 뿐 아니라, 이후에 현재 로그인된 사용자 정보를 가져오는 방법이 바뀌더라도 컨트롤러는 전혀 수정할 필요가 없게 된다.

이렇게 만든 WebArgumentResolver 구현 클래스는 빈으로 등록하고 AnnotationMethodHandlerAdapter 의 customArgumentResolver 또는 customArgumentResolvers 프로퍼티에 설정해주면 된다.

WebArgumentResolver 느 스프링 @MVC 의 가장 매력적인 확장 포인트다. 이를 잘 활용하면 매우 간결한 컨트롤러 메소드를 만들 수 있다. 스프링 MVC 는 자신만의 MVC 프레임워크를 만들게 해주는 기반 프레임워크라는 사실을 잘 느끼게 해주는 멋진 기능이다.

ModelAndViewResolver

ModelAndViewResolver 는 컨트롤러 메소드의 리턴 타입과 메소드 정보, 애노테이션 정보 등을 참고해서 ModelAndView 를 생성해주는 기능을 만들 수 있다. 스프링은 7가지 정도의 리턴 방식을 지원한다. 여기에 더해서 특별한 타입의 리턴 값 또는 메소드 레벨의 애노테이션 등을 이용해  ModelAndView 를 생성하는 방법을 추가할 수 있다. 다음과 같이 ModelAndViewResolver 인터페이스를 구현하면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package org.springframework.web.servlet.mvc.annotation;
 
import java.lang.reflect.Method;
 
import org.springframework.ui.ExtendedModelMap;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.servlet.ModelAndView;
 
public interface ModelAndViewResolver {
 
    ModelAndView UNRESOLVED = new ModelAndView();
 
    ModelAndView resolveModelAndView(Method handlerMethod,
            Class handlerType,
            Object returnValue,
            ExtendedModelMap implicitModel,
            NativeWebRequest webRequest);
}

메소드 파라미터 중에서 implicitModel 은 @ModelAttribute 파라미터처럼 스프링이 자동으로 추가해둔 모델 오브젝트가 담겨 있는 맵이다. ModelAndViewResolver 를 구현한 클래스는 빈으로 등록하고 AnnotationMethodHandlerAdapter 의 customModelAndViewResolver 나 customModelAndViewResolvers 프로퍼티에 설정해주면 적용된다. ModelAndViewResolver 는 WebArgumentResolver 보다 상대적으로 활용도가 적긴 하지만 컨트롤러의 리턴정보에서 일정한 패턴을 발견할 수 있다면 유용하게 쓸 수 있다.



출처 - http://springsource.tistory.com/91




Posted by linuxism
,