VRaptor

Aceitando URLs com ou sem barra no final

por Tomaz Lavieri, adaptado para VRaptor 4

Para quem teve dificuldade em conseguir determinar urls como:

@Path("produto/{produto.id}")
public void visualiza(Produto produto) {...}

quando digitava a URI /produto/1/ e o link não funcionava, segue abaixo duas maneiras de corrigir o problema.

Nota: Isso não é necessariamente um problema, pois a URL /abc é diferente da /abc/. Portanto o comportamento de dar 404 é o esperado.

A primeira maneira é colocar os dois tipos de URL (com e sem barra) na anotação @Path, assim:

@Path(value = {"produto/{produto.id}", "produto/{produto.id}/"})
public void visualiza(Produto produto) {...}

Note que esta modificação só irá funcionar para o método que possui a anotação @Path. Os outros métodos não serão afetados por esta mudança.

A outra maneira é escrever a classe abaixo. Desta forma, diferentemente da primeira, fará com que as duas URLs (com ou sem barra) sejam equivalentes.

import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.Event;
import javax.enterprise.inject.Specializes;
import javax.inject.Inject;
import javax.servlet.FilterChain;

import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.events.ControllerNotFound;
import br.com.caelum.vraptor.http.MutableRequest;
import br.com.caelum.vraptor.http.MutableResponse;
import br.com.caelum.vraptor.http.route.ControllerNotFoundException;
import br.com.caelum.vraptor.http.route.Router;
import br.com.caelum.vraptor.view.Results;

@RequestScoped
@Specializes
public class Error404 extends DefaultControllerNotFoundHandler {

    private final Router router;
    private final Result result;
    
    /**
     * @deprecated CDI eyes only
     */
    protected Error404() {
        this(null, null, null);
    }

    @Inject
    public Error404(Router router, Result result, Event<ControllerNotFound> event) {
        super(event);
        this.router = router;
        this.result = result;
    }
    
    @Override
    public void couldntFind(FilterChain chain, 
            MutableRequest request, MutableResponse response) {
        try {
            String uri = request.getRequestedUri();
            if (uri.endsWith("/")) {
                tryMovePermanentlyTo(request, uri.substring(0, uri.length()-1));
            } else {
                tryMovePermanentlyTo(request, uri + "/");
            }
        } catch (ControllerNotFoundException ex) {
            super.couldntFind(chain, request, response);
        }
    }
    
    private void tryMovePermanentlyTo(MutableRequest request, String newUri) {
        router.parse(newUri, HttpMethod.of(request), request);
        result.use(Results.status()).movedPermanentlyTo(newUri);
    }
}