Dúvida com FrontController?

44 respostas
kina

Olá galera…
eu tenho uma pergunta meu boba…
Por acaso se eu criar om FrontController (Servlet) eu poderia redirecionar ela pra outra servlet?
Digamos, estaria saindo da “função” do FrontController?

Valeu

44 Respostas

Rafael_Nunes

Eu acredito que a função de redirecionamento entre recursos de uma aplicação, é função do controller.
Mas não sei até onde é gerar trabalho desnecessário enviar a requisição para um controller pra depois re-enviar para outro front controller, se pode-se enviar de um front controller diretamente para outro.

De qualquer forma, um trecho da especificação do front controller:

kina

Rafael Nunes:
Mas não sei até onde é gerar trabalho desnecessário enviar a requisição para um controller pra depois re-enviar para outro front controller, se pode-se enviar de um front controller diretamente para outro.

Desculpe não consegui entender totalmente o que você quis dizer com isso.
Quanto ao redirecionar a requisição eu entendi.
Você está pensando que a minha intenção seria isso?
FrontController -> FrontController ->Servlet?
[obs]
não que o FrontController não deixe de ser um servlet(neste caso)
[/obs]
outro dia eu estava vendo um código ± assim:
frontController

getActionCollection():
  return actions;

doPost:
Hashtable actions = getActionCollection();
BaseAction action = actions.get("pagina");
if (action==null) synchronized (actions) {
    action = instantiate(mapName("pagina"));
// instantiate
// gera uma nova instancia do  servlet
// mapName pega o caminho completo
    actions.put(actionName,action);
}
action.doPost(req,resp);

Por acaso teria algum problema em fazer isso?
ou seria melhor eu dar um dispatcher nele?

valeu

J

Li alguns autores que recomendam vc ter uma frontcontroler que realiza todas as ações relacionadas.
ex:

Você tem uma tela que tem vários passos:
1-2-3…

O FrontController realizaria todos os passos epoderia redirecionar para diversos views diferentes.
Nunca vi ninguém especificar que um view tenha que ser uma JSP.
Pode ser um HTML, um XML, e porque não uma servlet.
Agora se sua servlet contém lógica de negócios é melhor deixar tudo m um único controler desde de que essa lógica esteja relacionada com a mesma tarefa.

Rafael_Nunes

É, nunca tinha pensado nisso.
Se eu tiver um FrontController, eu vou precisar de um Controller?
Minha idéia era de se usar o FrontController pra executar os processamentos necessários, e um Controller só para receber e direcionar requisições.

Ex:
FontrControlle->Controller->FrontController2->View

[edit]
É, pelo que vi no Core J2EE Patterns, é assim mesmo como eu imaginei, o Controller recebe e dispacha requisições, o FrontController as processa.

J

Na prova isso apesar de ser simples pode confundir um pouco.
MVC e FrontController.

A arquitetura que tem o controller principal é o MVC.
Cada unidade de processamento seria o FrontController neste caso.

EDITADO:

Aqui em cima escrevi errado, queria escrever frontcontroller

Thiago_Senna

Kina… eu costumo utilizar a estratégia front-controller e command!

Então fica assim:

view- --> FrontController --> Command --> negocio --> persistencia

Você pode também criar uma fábrica de commands para facilitar sua vida!
No meu caso, meu frontcontroller recebe a requisição, pega um atributo chamado op (operação), e de acordo com o valor deste atrributo eu sei qual é a operação que ele irá realizar! Então é só vc chamar um command apropriado para executar aquela função. O command por sua vez, executa todo o processamente relacionada a esta operação, e retorna para o frontController o resultado, que no meu caso, é a página que o frontcontroller deverá redirecionar!

O FrontController é um servlet, mas o command é uma classe normal, que não estende servlet. Não sei se é uma boa prática, mas meus commands receber o HttpRequest e o HttpResponse em um método chamado execute!

Tirei este exemplo do livro Core J2ee patterns!

Abraços!
Thiago

Rafael_Nunes

Você tem um FrontController único que recebe o parâmetro ‘op’ e dispacha para o Command apropriado?

Thiago_Senna

Exatamente!!! Eu meu sistema inteiro eu tenho um único Controle!

Rafael_Nunes

Então você não tem um FrontController, você tem um Controller. FrontController seria específico de cada serviço.

[edit]Se bem que na documentação, diz que você pode ter mais de um controller, nãoq ue você deva ter. Sendo assim, não vejo a diferença entre um MVC e um FrontController com um único controller

Thiago_Senna

Rafael!

Esse diagrama que você colocou em cima é uma Herança!

Isso quer dizer que o ServletFront ou o JSPFront herdam características do controle!

Vc pode ou usar JSP como camada de controle(não recomendado) ou uma Servlet!

No meu caso, eu não criei uma interface ou classe abstrata com o nome Controle, mas é uma estratégia interessante também.

Também não há problemas em ter mais de um FrontController. Mas eu pessoalmente prefiro um único controle!!!

Rafael_Nunes

E qual a diferença entre um MVC e um FrontController com um único Controller?

J

Pelo que vi um MVC se caracteriza por ter vários views diferentes para o mesmo seviço.
EDITADO:
Como o Thiago disse não precisa ser um ambiente web.

Eu entendi essa como a principal diferença.

Agora o Thiago colocou uma coisa super importante:

Deixar o controller desacoplado do ambiente web o maior possivel, pois se uma dia precisar mudar para desktop ou outra coisa será bem mais fácil.

Agora JSP como controller fica muito ruim.
Código java no JSP vira uma meleca…

Thiago_Senna

Naum entendi o motivo da pergunta! Mas vamos lá! :smiley:

MVC é uma arquitetura que separa modelo (objetos de negócio), visualização (view) e o controle (operações solicitadas pelo usuário).

Não há igualdade ou diferença dentre FrontController e MVC. O FrontController só é um pattern que você utiliza dentro do MVC para implementar a camada de Controle! Ou seja, FrontController é um pattern, e ele por si só não é MVC.

Imagine também que é possível usar MVC em uma aplicação Swing. Daí eu te pergunto. É possível usasr um servlet como controle em uma aplicação Swing? Bom… talvez até dê… mas é uma verdadeira gambiarra!

Isso só demonstra que existem várias maneiras de você implementar sua camada de controle e ainda atender o padrão MVC.

No livro core j2ee paterns, você perceberá que existe mais de uma estratégia para se implementar a camada de controle. Existe um que o livro aborda com mais profundidade (não sei qual é) e um uma outra estratégia que eles falam bém brevemente, que é o command and controller!

E é exatamente a estratégia Command and Controller que adotei para o sistema que estou desenvolvendo.

Observe que a camada de controle vai além de um FrontController. A camada de controle na verdade é o FrontController junto com todos os commands que realizam as operações solicitadas pelo usuário. Isso tudo junto é a camada de controle! Como eu uso commands, não há motivo de sair criando servlets e outros Fronts controllers, basta receber a requisição do usuário e encaminhá-lo para o command.

Abraços!
Thiago

Thiago_Senna

JProgrammer:
Agora o Thiago colocou uma coisa super importante:
Thiago Senna wrote:

O FrontController é um servlet, mas o command é uma classe normal, que não estende servlet. Não sei se é uma boa prática, mas meus commands receber o HttpRequest e o HttpResponse em um método chamado execute!

Deixar o controller desacoplado do ambiente web o maior possivel, pois se uma dia precisar mudar para desktop ou outra coisa será bem mais fácil.

Concordo JProgrammer. Com esssa colocação que você fez já tira uma dúvida minha. Como meu command recebeo request e o response por parâmetro, então seria difícil reaproveitar estes commands fora da aplicação web. Ou seja, seria interessante bolar uma estratégia na qual o command não precise receber o request e o response, daí sim estariamos mais próximo de reaproveitar os commands em uma aplicação desktop por exemplo!

Abraços!
Thiago

J

Achei bem legal sua ideia.

Thiago_Senna

Bom… não sei se isso vai ajudar muito!
Não é exatamente o que estou fazendo, mas nesta aplicação é um controle para aplicação toda. Acho!

http://java.sun.com/blueprints/code/jps131/src/

Dêem uma cheretada neste link… eu nunca explorei muito este material… mas pode ajudar!

Abraços!

Thiago_Senna

A fonte é esta:

http://java.sun.com/blueprints/corej2eepatterns/Patterns/FrontController.html

Para ter uma idéia, meu código do controle é quase isso aqui..

/** This processRequest method is invoked from both 
  * the servlet doGet and doPost methods **/
protected void processRequest(HttpServletRequest 
  request, HttpServletResponse response)
  throws ServletException, java.io.IOException {

  String resultPage;
  try {
    RequestHelper helper = new RequestHelper(request);

    /** the getCommand() method internally uses a 
     factory to retrieve command objects as follows:
     Command command = CommandFactory.create(
        request.getParameter("op"));
    **/
     Command command =  helper.getCommand();
 
    // delegate request to a command object helper
    resultPage = command.execute(request, response);
  }
  catch (Exception e) {
    LogManager.logMessage("EmployeeController",
      e.getMessage() );
    resultPage = ApplicationResources.getInstance().
                      getErrorPage(e);
  }

  dispatch(request, response, resultPage);
}

ùnica observação que tenho para fazer é que tenho um interface que armazena para mim todas as operações possiíveis.. tipo assim

interface Operacoes {

public static int INCLUI_EMPRESA = 01;
public static int EXCLUI_EMPRESA = 02;

}

E POR AI VAI!!!

Outra opçção interessante é que você pode ao invés de adotar uma classe ou interface contendo todas as operações, vc pode criar uma classe, um método ou alguma coisa que recebe a a url, e dependendo do nome da url ele identifica qual operação deve ser executada.

tipo assim:
http://localhost:8080/MinhaApp/IncluiEmpresa.do

Configure o método ou objeto para pegar apenas o dado "IncluiEmpresa.do" (é possível configurar no web.xml para que todos as chamadas que terminem com .do sejam encaminhados para o FrontController). Já que na URL está a String IncluiEmpresa.do, é só chamar o Command:

IncluiEmpresaCommand

Desta forma vc não precisa ficar passando as operações na requisição.
Vai de vocês escolherem qual é a melhor opção!

Abraços!
Thiago

J

Obs:
Mas o esquema seria não passar para o command nem request, nem response para que o mesmo fique desacoploado do ambiente web e possa ser reaproveitado mais facilmente.

class Command 
{
   public void execute(Map parameters)
   {
       int valor = ((Integer) parameters.get("valor")).intValue();
       // faz o que tem que fazer
   }
}
Thiago_Senna
jprogrammer:
Obs: Mas o esquema seria não passar para o command nem request, nem response para que o mesmo fique desacoploado do ambiente web e possa ser reaproveitado mais facilmente.
class Command 
{
   public void execute(Map parameters)
   {
       int valor = ((Integer) parameters.get("valor")).intValue();
       // faz o que tem que fazer
   }
}

Boa!!
Isso para mim era um enigma! :D

Valeu!

J

Como assim enigma ?

Thiago_Senna

Eu não sabia como resolver este problema…

Daí com a dica que você deu, onde o command recebe um mapa, ai ficou claro!!!

Já to vendo que vou ter que fazer um Refactoring no Projeto!:smiley:

Abraços!
Thiago

Thiago_Senna

Uns tutoriais interessante!

http://www.argonavis.com.br/cursos/java/j550/j550_13.pdf
http://www.argonavis.com.br/cursos/java/j931/J931_02.pdf

Abraços!
Thiago

J

Um dos melhores tutoriais que eu vi.
Muito bem feito.
Simples e bem feito

Rafael_Steil

Rafael Nunes:
Então você não tem um FrontController, você tem um Controller. FrontController seria específico de cada serviço.

Nao, eh o contrario :wink:

FrontController eh um ponto unico de acesso. Em ambiente web, se voce tem um controller para cada servico / pagina, tem o que chamam de PageController

Rafael

Rafael_Steil
jprogrammer:
Obs: Mas o esquema seria não passar para o command nem request, nem response para que o mesmo fique desacoploado do ambiente web e possa ser reaproveitado mais facilmente.
class Command 
{
   public void execute(Map parameters)
   {
       int valor = ((Integer) parameters.get("valor")).intValue();
       // faz o que tem que fazer
   }
}

Eh um motivo nobre, mas passar um Map nao eh uma solucao muito adequada. O ideal seria encapsular os dados em uma classe propria, como "RequestData", que voce popula com os parametros / dados que quiser.

Rafael

Rafael_Nunes

Mas na especificação diz que você pode ter mais de um Controller, no FrontController. :roll:

While the Front Controller pattern suggests centralizing the handling of all requests, it does not limit the number of handlers in the system, as does a Singleton. An application may use multiple controllers in a system, each mapping to a set of distinct services.

Rafael_Steil

Tudo bem, mas o ponto inicial de entrada eh o teu unico FrontController. Ele, por sua vez, delega para os casos especificos. Ou seja, a requisicao chega nos controllers “inferiores” atraves do FrontController, e nao diretamente.

Rafael

Rafael_Nunes

Então o FrontController seria uma Interface, e os Controllers os Servlets que implementam esta interface, como no diagrama?

Rafael_Steil

Aquele diagrama sugere que voce tera um controllador extra-generico que pode delegar servicos para uma camada web, swing, texto e etc… Nao eh muito comum voce encontrar implementacoes assim… o xwork, creio, faz algo parecido com isso.

O FrontController nao eh uma interface, mas sim uma implementacao concreta que tem um minimo de conhecimento sobre o ambiente e a capacidade de delegar a requisicao para alguem mais especializado, que, nesse caso entao, seria interessante ter uma interface padrao, como se fosse um Command (considerando que nao seja um command), evitando assim um monte de if-else no teu codigo.

Rafael

caiofilipini

Também poderia ser interessante fazer um esquema para injetar os parâmetros, não?

[]'s

J

Bem melhor. Essa é a evolução de ideias.
Isso é o bom do GUJ.
Poderia ser assim

class RequestData
{
   private HttpServletRequest req;
   public RequestData(HttpServletRequest req)
  {
      thisreq = req; 
   }
   public int getInt(String key) {
      return Integer.parseInt(req.getParameter)(key) 
   }

  // asim vai... 
}

class Command
{
    public void execute(RequestData requestData)
   {
        int valor = requestData.getInt("valor");
   }
}

// no controller
command.execute(new RequestData(request));

Aviso o Thiago antes que ele afça o refactory

EDITADO
Obs:
Um dos motivos por eu não gostar do struts é esse. Ele deixa a Action com forte acoplamento.

Rafael_Steil

Entao, oRequestData nao deveria nem receber um HttpServletRequest… assim voce ainda esta acoplando as coisas. Voce poderia ter algo assim:

public interface RequestData {
    public String getValue(String key);
    // outros metodos que possam ser uteis
}

public class HttpRequestData implements RequestData {
    private HttpServletRequest request;

    public HttpRequestData(HttpServletRequest request) {
        this.request = request;
    }

    public String getValue(String key) {
        return this.request.getParameter(key);
    }
}

public class MapRequestData implements RequestData {
    private Map dados;

    public MapRequestData(Map dados) {
        this.dados = dados;
    }

    public String getValue(String key) {
        return (String)this.dados.get(key);
    }
}

e ai vc passa a implementacao concreta especifica para o ambiente que voce esta.

Rafael

kina

Outra pergunta…
Seria válido eu dizer que o meu FrontController é um Filter?
Não teria alguma problema com isso?

J

Legal !
Mas voltando a discussão eu acredito que o FrontController é caracterizado por um objeto que atenda as requisições relacionadas a um determinado serviço como o Rafael Nunes falou.
Ou Não ?

Thiago_Senna

Valeu!
Mas ainda assim estou acompanhando o tópico!
Estou distribuindo estrelas pra galera toda, pois estas informações estão sendo muito úteis para mim!

Quero aproveitar e fazer uma colocação!

O ideal seria que esta conversão do Request para um RequestData acontecesse dentro de uma classe RequestHelper…

Ou eu estou viajando? Pelo que li, foi isso que eu entendi!

Outro ponto interessante é que é no RequestHelper que ficaria a tabela contendo quais são as operações de cada command, como por exemplo,
a operação x = IncluiEmpresa, y = excluiEmpresa, e por ai vai!

É isso mesmo?

Abraços!
thiago

J

Poderia sim.
Não estou falando de acordo com a documentação, mas pelo que acho.
Poderia, pois o código de conversão ficarei dentro de um lugar só e você poderia usar o RequestHelper em diversos Controllers e os mesmos só teriam o papel de “despachar” requisições.
O que acham ?

Thiago_Senna

Pessoal… olhem este outro tutorialzinho!

http://www.inf.ufrgs.br/procpar/direto/trabalhos/apresentacao_tc_romulo_rosinha.pdf

Dá um salvar destino como… eu só consegui visualizar assim!

Pelo que está neste tutorial, o objetivo do Request Helper é:

:arrow: Descobrir o comando que será executado!

Sem Mais! :wink:

Thiago

Rafael_Steil

kina:
Outra pergunta…
Seria válido eu dizer que o meu FrontController é um Filter?
Não teria alguma problema com isso?

Nao, nao da para chamar de Filter. Embora ambos tenham algumas propriedades parecidas - o que, alias, aconcente com muitos patterns -, eles ainda sao para propositos bem distintos

Rafael

kina

Rafael Steil:
kina:
Outra pergunta…
Seria válido eu dizer que o meu FrontController é um Filter?
Não teria alguma problema com isso?

Nao, nao da para chamar de Filter. Embora ambos tenham algumas propriedades parecidas - o que, alias, aconcente com muitos patterns -, eles ainda sao para propositos bem distintos

Rafael


E usar a classe Filter como FrontController?
Há algum problema?

Thiago_Senna

kina:
Rafael Steil:
kina:
Outra pergunta…
Seria válido eu dizer que o meu FrontController é um Filter?
Não teria alguma problema com isso?

Nao, nao da para chamar de Filter. Embora ambos tenham algumas propriedades parecidas - o que, alias, aconcente com muitos patterns -, eles ainda sao para propositos bem distintos

Rafael


E usar a classe Filter como FrontController?
Há algum problema?

Kina, acredito que não!
Me corrijam se eu estiver errado!

Até onde sei de filtros, quando um servlet receber uma requisição, o filtro seria executado antes do servlet ser executado, e quando o servlet terminasse de ser executado, daí o filtro executaria novamente um pós processamento…

Resumindo:
:arrow: Filtro faz um pré-processamento
:arrow: Servlet entra em ação!
:arrow: Filtro faz um pós processamento

Seria interessante vc usar filtro para verificar se o usuário que está acessando é um usuário válido, criar log… Ou usará filtro sempre que quiser adicionar um pré e pós processamento em um Servlet!

Abraços!
Thiago

Rafael_Steil

kina:

E usar a classe Filter como FrontController?
Há algum problema?

Bom, nao eh responsabilidade do Filter esse tipo de decisao. Ele serve mais para coisas como as que o Thiago citou.

Rafael

C

Boa tarde pessoal.

Esta discução foi muito produtiva. Com ela consegui esclarecer várias dúvidas deste pattern, e aproveitei para incluir ele numa aplicação de testes que desenvolvi, para me aprofundar em alguns conceitos de Java para Web.

Modifiquei toda a minha aplicação, mais fiquei com uma dúvida. Irei explicar abaixo qual o objetivo da aplicação e como realizei a divisão, para que vocês consigam enchergar melhor o meu problema.

A aplicação de testes que estou desenvolvendo se baseia num pequeno caso de usos referente a clínicas médicas, aonde pode se realizar as seguintes operações:
Pesquisar Clínicas
Inserir telefones da clínica
Remover Telefones da clínica
Localizar município aonde a clínica está instalada
Atualizar dados da clínica

Pois bem, baseando-me na discução realizada neste forum, criei uma arquitetura no meu projeto, aonde existe a classe ClinicaControler, que é uma Servlet e é o Front Controller da aplicação. Este Front Controller instancia a classe RequestHelper, que realiza duas funções em seu contrutor: Encapsular o request na classe HttpRequestData (que implementa a interface RequestData), e executa o método create da classe CommandFactory (passando os atributos URI de requisição da página e o objeto HttpRequestData).
Este atributo irá me retornar o command referente a solicitação realizada. Nesta classe eu capturo na requisição o mapeamento, que coloquei terminando com “.do” para facilitar a declaração no web.xml, e verifico em um if qual classe devo instanciar (Não sei se esta seria a melhor forma de implementar esta Factory. Caso exista um jeito melhor, por favor me avisem).

Beleza. Então já tenho o meu command instanciado. Agora executo o método execute, que irá processar a tarefe que o Command instanciado implementa. É neste ponto que tenho um problema.

Vou dar um exemplo:

Os comandos “Adicionar Telefone” e “Remover Telefone”, como o nome sugere, adicionam ou removem os telefones. Estes telefones se encontram numa collections da VO Telefone, que se encontra na sessão (o restante dos dados da clínica se encotnram no escopo da requisição. O caso dos telefones é a única excessão). Pois bem, depois de ter adicionado ou removido um telefone da lista, devo chamar retornar a minha página. O problema é que a página precisa receber um objeto VO da classe Clínica, populado, para preencher novamente a página. Por causa disso preciso preencher esta classe tanto no command AdicionarTelefone quanto no RemoverTelefone. Isto gera uma duplicação de código.

Gostaria de saber como poderia fazer para resolver esta incoveniência no meu modelo.

Espero que tenham entendido o meu problema. :slight_smile:

maniacs

Eu sei que a discução aqui é velha, mas tenho uma duvida relacionada ao RequestData que é mencionado aqui
eu devo passar o request e response e ficar acoplado a web ou abstrair para um RequestData como mencionado ai ?
dei uma olhada por cima, se for usar HttpSession existe um problema para encapsular e controlar os dados…

Dennys

Thiago Senna:
Uns tutoriais interessante!

http://www.argonavis.com.br/cursos/java/j550/j550_13.pdf
http://www.argonavis.com.br/cursos/java/j931/J931_02.pdf

Abraços!
Thiago

Link quebrado =(

Queria ver as apresentações… :frowning:

Criado 6 de maio de 2005
Ultima resposta 10 de jan. de 2008
Respostas 44
Participantes 9