---
title: Interceptadores
---
#Quando interceptar?
O uso de interceptadores é feito para executar alguma tarefa antes e/ou depois de uma lógica de negócios, sendo os usos mais comuns a validação de dados, controle de conexão e transação do banco, log e criptografia/compactação de dados.
##Como interceptar?
No VRaptor utilizamos uma abordagem onde o interceptador define quem será interceptado, muito mais próxima a abordagens de interceptação que aparecem em sistemas baseados em AOP (Programação Orientada a Aspectos).
Portanto, para interceptar uma requisição, basta anotar a classe com a anotação `@Intercepts`. Assim como qualquer outro componente, com o uso das anotações de escopo você pode dizer em que escopo o interceptador será armazenado.
##Exemplo simples
A classe a seguir mostra um exemplo de como interceptar todas as requisições em um escopo de requisição e simplesmente mostrar na saída do console o que está sendo invocado. Lembre-se de que o interceptador é um componente como qualquer outro e pode receber quaisquer dependências por meio de Injeção de Dependências.
~~~
#!java
@Intercepts
@RequestScoped
public class Log {
@Inject
private final HttpServletRequest request;
@AroundCall
public void intercept(SimpleInterceptorStack stack) {
System.out.println("Interceptando " + request.getRequestURI());
// código a ser executado antes da lógica
stack.next(); // continua a execução
}
}
~~~
Para executar um código apenas antes ou depois da execução do controller, podemos usar as anotações `@BeforeCall` e `@AfterCall`:
~~~
#!java
@Intercepts
@RequestScoped
public class Log {
@BeforeCall
public void before() {
// código a ser executado antes da lógica
}
@AfterCall
public void after() {
// código a ser executado depois da lógica
}
}
~~~
Repare que não é mais obrigatório implementar a interface `Interceptor`, basta criar a classe e usar as anotações acima.
##Definindo quando interceptar
No exemplo acima todas as requisições são interceptadas. Podemos então definir que iremos interceptar apenas os métodos que possuem uma anotação chamada `@Audit`. Para isso basta implementar um método que retorne um `boolean`com a condição necessária e anotá-lo com `@Accepts`.
~~~
#!java
@Accepts
public boolean accepts(ControllerMethod method) {
return method.containsAnnotation(Audit.class);
}
~~~
No VRaptor4 também temos outra maneira de definir a condição de aceitação. O exemplo acima é um caso bem comum e acabamos tendo de repetir esse código muitas vezes. Para essas situações você pode usar a annotation `@AcceptsWithAnnotations`.
~~~
#!java
@AcceptsWithAnnotations(Audit.class)
public class AuditInterceptor {
@AroundCall
public void around(SimpleInterceptorStack stack){
stack.next();
}
}
~~~
##Criando o seu Accepts customizado
Logo acima usamos o exemplo do Accepts customizado. Este é um que já vem pronto VRaptor. Mas nada impede de você criar o seu para as suas necessidades. O fluxo é bem parecido com o de criação de uma validação customizada para a BeanValidation. Primeiro você deve criar sua Annotation.
~~~
#!java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@AcceptsConstraint(WithAnnotationAcceptor.class)
@Inherited
public @interface AcceptsWithAnnotations {
public Class extends Annotation>[] value();
}
~~~
Perceba que usamos a Annotation `@AcceptsConstraint` para indicar qual a classe responsável por fazer a verificação. Agora precisamos implementar essa classe.
~~~
#!java
public class WithAnnotationAcceptor implements AcceptsValidator {
@Override
public boolean validate(ControllerMethod controllerMethod,
ControllerInstance instance) {
//aqui entra sua logica de validação do método ou instancia do controller.
return true;
}
@Override
public void initialize(AcceptsWithAnnotations annotation) {
//aqui você pode acessar as informações contidas na annotation customizada.
this.allowedTypes = Arrays.asList(annotation.value());
}
}
~~~
Esta classe só precisa implemetar a interface `AcceptsValidator` onde T é o tipo da sua Annotation customizada. Dessa maneira você pode criar as suas condições customizadas e disponibilizá-las para todos os projetos que você precisa.
##Como garantir ordem: after e before
Se é preciso garantir a ordem de execução de um conjunto de interceptors, você pode usar os atributos `after` e `before` da anotação `@Intercepts`. Suponha que o `PrimeiroInterceptor` tenha que rodar antes do `SegundoInterceptor`, então você pode configurar isso tanto com:
~~~
#!java
@Intercepts(before=SegundoInterceptor.class)
public class PrimeiroInterceptor {
...
}
~~~
quanto com:
~~~
#!java
@Intercepts(after=PrimeiroInterceptor.class)
public class SegundoInterceptor {
...
}
~~~
Você pode especificar mais de um Interceptor:
~~~
#!java
@Intercepts(after={PrimeiroInterceptor.class, SegundoInterceptor.class},
before={QuartoInterceptor.class, QuintoInterceptor.class})
public class TerceiroInterceptor {
...
}
~~~
O VRaptor lançará uma exception se existir um ciclo na ordem dos interceptors, então tenha cuidado.
##Interagindo com os interceptors do VRaptor
O VRaptor possui sua própria sequência de interceptor, e você pode definir a ordem dos seus interceptors baseados na do VRaptor.
Aqui estão os principais interceptors do VRaptor e o que eles produzem:
* `ExceptionHandlerInterceptor` - intercepta todas as requisições para tratar as exceções não capturadas
* `FlashInterceptor` - mantém por mais uma request os parâmetros da request
* `ForwardToDefaultViewInterceptor` - redireciona (forward) para a jsp padrão se nenhuma outra view foi usada.
Se você precisa executar um interceptor antes ou depois de algum interceptor do VRaptor, basta utilizar os atributos `after` e `before` passando a classe do interceptor como valor. Algo como:
~~~
#!java
@Intercepts(
after=ExceptionHandlerInterceptor.class,
before=ForwardToDefaultViewInterceptor.class)
~~~