Filters
Filters
Grails 컨트롤러(controllers)는 잘 만들어진 인터셉터를 지원한다. 인터셉터는 적은 수의 컨트롤러에는 정말 유용하지만 대형 어플리케이션에서 관리하는 것은 매우 어렵다. 반면에 필터는 컨트롤러, URI 공간(space), 액션들의 그룹에 적용될 수 있다. 필터는 주 컨트롤러 로직과 분리하여 쉽게 끼워넣고plug-in 관리할 수 있고 보안, 로깅, 등에 필요한 크로스커팅(cross cutting)을 지원한다.
Applying Filters
필터를 만드는 방법은 Convention에 따라 grails-app/conf 디렉토리에 Filter로 끝나는 클래스를 만들면된다.
이 클래스 안에 filters 라고 불리는 코드 블럭을 만들고 이 블럭에 필터의 내용을 정의한다.
아래와 같이 net.grails.my.ExampleFilters 를 생성한다.
conf - 우측 마우스 - New - Filters 클릭한다.
Filter 이름을 입력후 Finish 클릭한다
filters 블럭안의 필터들에는 이름과 스콥을 지정할 수 있다.
ExampleFilters 클래스를 보면
all 이라는 메소드가 이름이고, 스콥은 네임드 파라미터인 controller:"*", action:"*" 를 의미한다.
all 이라는 이름의 필터는 모든 클래스와 모든 액션에서 동작한다는 의미이다.
ExampleFilters의 내용을 아래와 같이 변경한다.
package net.grails.my class ExampleFilters { def filters = { all(controller:'*', action:'*') { before = { println "before Controller : " + "아이디는 " + params.id + "입니다. " } } } }
BookController의 내용을 아래와 같이 변경한다.
package net.grails.my class BookController { def index() { } def view = { println "BookController - view 실행" render "Book Controller : view 입니다." } }
확인주소 : http://localhost:8080/mygrails/book/view/?id=kshmeme
실행후 Console 을 확인해보면.
Filter의 내용이 먼저 출력되고 그 다음에 Controller의 내용이 출력되는 것을 확인할 수 있다
all filter는 모든 컨트롤러와 액션에 적용되는 필터이다.
몇개의 필터 예제를 보자
모든 컨트롤러와 액션에 적용되는 필터
all(controller:'*', action:'*') { }
BookController에만 적용되는 필터
justBook(controller:'book', action:'*') { }
URI에 적용되는 필터
someURIs(uri:'/book/**') { }
모든 URI에 적용되는 필터
allURIs(uri:'/**') { }
Filter Types
필터의 바디에 정의할 수 있는 인터셉터의 타입은 다음과 같다
- before - 액션이 실행되기 전에 실행된다. false를 반환하면 뒤따르는 모든 필터와 액션이 실행되지 않음
- after - 액션이 실행된 후에 실행된다. 첫번째 파라미터로 뷰 모델을 넘겨 받음
- afterView - 뷰가 렌더링된 후에 실행
ExampleFilters의 내용을 아래와 같이 변경한다.
package net.grails.my class ExampleFilters { def filters = { loginCheck(controller:'*', action:'*') { before = { if(!session.user && !actionName.equals('login') && !actionName.equals("logined")) { println "login page로 이동합니다." redirect(action:'login') return false } } } } }
BookController의 내용을 아래와 같이 변경한다.
package net.grails.my class BookController { def view = { println "BookController - view 실행" render "Book Controller : view 입니다." } def login = { def html = "id : <input type='text' /><br /> pw : <input type='password' /> " html += "<br /> <input type='button' value='로그인' />" render html } def logined = { session.user = params.id render "사용자는 " + session.user + "입니다." } def logout = { session.user = null render "사용자는 " + session.user + "입니다." } }
확인주소 : http://localhost:8080/mygrails/book/view/?id=kshmeme
http://localhost:8080/mygrails/book/login
http://localhost:8080/mygrails/book/logined?id=kshmeme
http://localhost:8080/mygrails/book/logout
실행 후
http://localhost:8080/mygrails/book/view/?id=kshmeme
접속 해보면
session 에 user 정보가 없으므로 login 페이지로 이동하는 걸 확인할 수 있다.
테스트로 session 에 user정보를 넣는 페이지인
http://localhost:8080/mygrails/book/logined?id=kshmeme
로 이동을 한다.(로그인 프로세스를 실행 했다는 가정하에 session 정보를 저장)
그 이후에
http://localhost:8080/mygrails/book/view/?id=kshmeme 로 다시 접근을 해보면
session에 user 정보가 있기 때문에 아래처럼 정상적으로 페이지가 뜨는 걸 확인할 수 있다.
http://localhost:8080/mygrails/book/logout 에 접속해서 session을 지우고(로그아웃) 다시
http://localhost:8080/mygrails/book/view/?id=kshmeme 에 접속하면
http://localhost:8080/mygrails/book/login 페이지로 이동 하는 걸 확인할 수 있다.
보통의 인증 케이스를 이런식으로 구현 할 수 있다.
filter에서 리턴이 false 이면 액션이 실행되지 않는 다는 점도 기억한다.
Filter Capabilities
필터는 controllers, 태그 라이브러리(tag libraries), 어플리케이션 컨텍스트에서 사용되는 모든 프로퍼티들을 지원한다:
request - HttpServletRequest 객체
response - HttpServletResponse 객체
session - HttpSession 객체
servletContext - ServletContext 객체
flash - flash 객체
params - 요청 파라미터 객체
actionName - 가로챈 액션의 이름
controllerName - 가로챈 컨트롤러의 이름
grailsApplication - 현재 실행중인 Grails 어플리케이션
applicationContext - ApplicationContext 객체
하지만 필터는 컨트롤러나 태그 라이브러리들에서 사용 가능한 모든 메소드들이 아니라 일부분만 지원한다:
redirect - 컨트롤러와 다른 액션으로 리다이렉트시키기 위해 사용
render - 사용자 정의 응답을 렌더링하기 위해 사용한다