Melhor forma de realizar a divisão de tarefas nas actions do Struts

Pessoal, bom dia.

No projeto do qual participo, ficou decidido que seria utilizado DispatchActions, e seria criada uma action por caso de uso. As classes que contém as regras de negócios também foram divididas por caso de uso.

Por exemplo, na parte de manipulação de dados, existe um caso de uso para cadastramento, e outro para manutenção de dados (este ultimo engloba operações do tipo edição, alteração, exclusão etc).

Pois bem, deixa eu dar um exemplo sobre esta implementação de casos de uso, para poder demonstrar uma dúvida que possuo.

Criei uma Action de cadastro, vamos chamar de cadastrarDadosAction. Esta action possui os métodos “inserir”, “inserirSalvo” e “visualizarDadosCadastrados”. Tmb foi criada uma classe que contém as regras de negócios chamada CadastrarDadosBLL. Esta classe contém os métodos “listarUF” e “inserirDados”.

Criei uma outra Action para a manutenção dos dados, vamos chamar de ManterDadosAction. Esta action possui os métodos “iniciar”, “listar”, “excluir”, “alterar”, “alterarSalvo”, “listarDados” e “prepararIniciarPaginaManipulacaoDadosVistoriador”. Também foi criada uma classe que contém as regras de negócios chamada ManterDadosBLL. Esta classe contém os métodos “listarDados”, “obterRegistro”, “alterarRegistro”, “excluirRegistro”, “listarUF”.

Na Action “cadastrarDadosAction”, o método “inserir” faz a carga da página que será utilizada na inseção dos dados, realizando o carregamento de dados para preenchimento de combos, entre outras tarefas.
O método “inserirSalvo” é responsável pela gravação dos dados, mostrando ao final uma página com os dados gravados, para configramação.

Na Action “ManterDadosAction”, o método “iniciar” faz a carga da página.
O método “listar” realiza uma pesquisa com os dados fornecidos pelo usuário, retornando o resultado para a página de manutenção de dados, que irá popular uma grid, que possue ao lado de cada linha os links “excluir” e “alterar”.

O método “excluir” é chamado quando se clica no link “exluir”. Ele realiza a exclusão do registro informado pelo usuário. Como é necessário retornar para a página de manutenção de dados com os dados da grid, e sabendo que este processo tmb será necessário no método “alterarSalvo”, retirei esta função do método listar e a coloquei no método “listarDados”, que é chamado pelos métodos “listar”, “excluir” e “alterarSalvo”, nestes dois ultimos caso não ocorra nenhuma exceção nas regras de negócios.

O método “alterar” deverá carregar os dados numa página para que seja realizada a modificação. Neste caso resolvi utilizar a mesma página usada para o cadastro, só modificando a nela a action e o método que serão chamados no momento da confirmação dos dados, e o título da página. Estas modificações passo para a página via requisição.
Aí já começa algum dos meus problemas.
Esta página eu estou chamando diretamente, tendo em vista que preciso setar algumas modificações. Como esta página de cadastro possui uma combo contendo os estados, devo realizar a carga dos estados antes de prosseguir. Para realizar esta carga, deve existir na minha classe de negócios um método que realize tal tarefa.
Por causa disso necessitei criar o método “listarUF” nas classes de negócios CadastrarDadosBLL e ManterDadosBLL.
Se fosse necessário fazer a carga de 5 campos diferentes, este código seria replicado nas duas actions e nas duas classes de negócios (no caso da classe de negócios o que seria replicado seria mais a chamada, pois o único papel deste método é encapsular o acesso ao médoto da minha classe DAO, que faz o acesso direto aos dados).

Existiria alguma forma melhor de se montar estas actions, de forma a eliminar estas duplicidades?

E quanto a minha decisão de criar um método que concentra um processo comum em várias actions? Está correto? Ou o melhor seria criar um outro método de ação dentro desta action que contenha estes processos, e realizar um forward para ele? Eu tinha feito desta forma inicialmente, mais como estava tendo problemas com a paginação do grid-layout, resolvi mudar. Além que ficou extranho fazer um forward para uma outra ação dentro da minha mesma action, quando poderia acessar diretamente.

[quote]O método “alterar” deverá carregar os dados numa página para que seja realizada a modificação. Neste caso resolvi utilizar a mesma página usada para o cadastro, só modificando a nela a action e o método que serão chamados no momento da confirmação dos dados, e o título da página. Estas modificações passo para a página via requisição.
Aí já começa algum dos meus problemas. [/quote]

Acho melhor separar as telas de cadastro e alteração.
É complicado fazer isso?

:lol: :lol:

[quote=Kleber Santos]Acho melhor separar as telas de cadastro e alteração.
É complicado fazer isso?[/quote]

Porque? Telas de cadastro e alteração tendem a ser bem parecidas, qual o problema em se fazer um reuso? :?

Olá,

Você está colocando responsabilidades demais na camada de apresentação.

Divida tarefas entre camadas, crie uma camada de negócios e chame-a através das suas Actions, não processe dados de negócio nas Actions.

Shoes

Você tá indo no caminho certo, se a coisa é só ir “pra lá e pra cá” com as informações do banco de dados e não tem nenhum código de banco de dados dentro dos Action, tá tudo certo.

É bom definir um action pra cuidar de uma, e apenas uma, entidade. Se você tem uma entidade usuário, crie um UsuarioAction, que faça tudo do usuário, criar, editar, excluir e listar, mas esse action não deve fazer mais nada com nenhuma outra entidade. Quando eu fiz, criei uma classe abstrata CrudAction, que fazia todo o trabalho repetido, e as outras actions implementavam o que havia pra ser implementado, que eram só os métodos de preencher as classes do modelo.

Eu, pessoalmente, não gosto de DispatchActions, porque eles dificultam o uso de ActionForms pra cada método, eu prefiro usar MappingDispatchActions, que me deixam definir um ActionForm pra cada método a ser chamado dentro daquele Action.

E sobre fazer o forward, não faça mesmo não, eu tive um problemão aqui por causa disso no Tomcat, usando um filtro pra fechas as conexões com o banco, quando eu dava o forward, o filtro simplesmente não terminava de executar, evite forwards o máximo possível.

blz, se são “parecidas” crie uma camada de negócios pra isso…

gangrel-br, no que eu entendi ele esta se perdendo numa coisa que eu acho básica e esta acontecendo varios erros, se for utilizar o reuso, isso tem q ser pensado em ultimo caso, pq isso pode afetar as camadas de negócio…

bele

[quote=Kleber Santos]
Acho melhor separar as telas de cadastro e alteração.
É complicado fazer isso?

:lol: :lol: [/quote]

Kleber, neste caso até que a tela é simples, mais existem outros casos de usos em que as telas são bem mais complexas. Acredito que separar as telas só aumentaria na duplicação de código. O código que inseri dentro da tela para informar qual action chamar e mudar o título, ficou bem pequeno (acho que são 2 ou 3 linhas).

Não acredito que isto vai ajudar. O que eu estou na dúvida é a melhor forma de separar as actions, para evitar justamente duplicação de código. :roll:

[quote=caiosiqueira]
Não acredito que isto vai ajudar. O que eu estou na dúvida é a melhor forma de separar as actions, para evitar justamente duplicação de código. :roll: [/quote]

Se cada Action só faz os serviços de uma entidade, como é que você está encontrando duplicação de código?

[quote=pcalcado]Olá,

Você está colocando responsabilidades demais na camada de apresentação.

Divida tarefas entre camadas, crie uma camada de negócios e chame-a através das suas Actions, não processe dados de negócio nas Actions.

Shoes[/quote]

Olá pcalcado,

acho que você não me entendeu. Eu estou utilizando divisões de camadas. A minha action está chamando um método existente numa classe de negócios. Não processo regras de negócios na action.

O problema é que no modelo que estou usando, foi decidido que deveria ser dividido as actions e classes de negócios por caso de uso.

Como o caso de uso Cadastrar Dados e Manter Dados acabam utilizando uma tela em comum, que é a tela de manipulação de dados, e esta tela possui uma combo que deverá ser preenchida com valores oriundos da base de dados, preciso replicar a chamada a minha classe de persistência nas classes de negócios referentes aos casos de uso Cadastrar Dados e Manter Dados.

Gostaria de saber se seria melhor unificar estas duas classes de negócios e actions em uma única, que representaria a entidade, como o Maurício sugeriu. Eu acredito que seria melhor, mais quero ter certeza para poder conversar com o analista do projeto sobre isso.

Por casa do modelo empregado, aonde existe uma action e uma classe de negócios para cada caso de uso.

Neste caso específico, por existirem dois casos de uso que se referenciam há uma mesma entidade, acaba gerando esta duplicação. Se bem que esta duplicação até agora se resumiu a criação de um mesmo método nestas duas classes de negócios que se referenciam a um mesmo método de uma mesma classe de persistência. Só levantei esta bola que achei que este mapeamento ficou extranho.

Concordo com o Marcelo Linhares…

pq?

Acho que o problema é que alguém está misturando casos de uso com o modelo de negócios.

Pra mim, casos de uso servem pra ajudar a modelar o sistema e dizer o que ele deve ou não fazer, não como ele deve ser feito. Se você for criar um Action pra cada caso de uso, imagine quando você for fazer as implementações dos casos de uso que tenham como pre-requisito o login no sistema, como é que você vai fazer isso?

Divida as responsabilidades das coisas por entidades, fica muito mais fácil de você lidar, porque mudar uma entidade não vai mudar os milhares de actions que tem casos de uso relacionados a ela, vai mudar só o action dela.

[quote=Maurício Linhares]
Divida as responsabilidades das coisas por entidades, fica muito mais fácil de você lidar, porque mudar uma entidade não vai mudar os milhares de actions que tem casos de uso relacionados a ela, vai mudar só o action dela.[/quote]

Beleza cara. Vou conversar com o Analista sobre isso para mudar esta politica de criação de Actions. Também acho que por entidade ficará mais simples.

Aproveitando, deixa lhe perguntar outra coisa. Pretendo usar validação automática. Neste caso acabei criando um único formBean, que serve tanto a tela de manutenção de dados como a que contém o cadastro. Fiz isso para transportar os dados que foram selecionados na tela de manutenção de dados para a tela de cadastro.
Eu conseguiria definir, por exemplo, que determinados campos deste form devem ter seu preenchimento obrigatório na tela de cadastro, e na tela de manutenção não devem ser validados? Como você trataria este caso? Você usa um único formBean, ou o melhor seria criar mais de um, utilizando uma action que extende MappingDispatchActions?

Acho legal fazer um ActionClass por form.
Isso seria uma boa ideia ? :roll:

Olá Caio,

Quanto a validação, pelo fato de estar utilizando DispatchActions e não estar utilizando Validator, acho que poderia fazer o seguinte, codificar dentro dos seus métodos da Action e chamar a validação na mão, pois me lembro de ter enfrentado certo problema ao utilizar DispatchActions com “validate=true”, portanto mantenha validade=false, implemente o método validate() no ActionForm, e chame manualmente conforme o exemplo abaixo:

    public ActionForward save(ActionMapping mapping, ActionForm form, 
HttpServletRequest request, HttpServletResponse response) throws Exception {
        //Criando objetos ActionMessages        
        ActionMessages errors = new ActionMessages();
                
        //Capturando erros de validação por form
        errors = form.validate(mapping, request);
        
        //Verificando se houve erro de validação de form
        if ( errors != null && !errors.isEmpty() ) {
            //Salva o erros encontrados em form.validate() no request
            saveErrors(request, errors);
            
            //Carregando recursos necessários para o form
            setUp(request);
            
            //Redireciona para o próprio form
            return (mapping.findForward(UIConstants.TO_FORM));
        }

Espero que possa ser útil.

Abraço.

[quote=caiosiqueira]
Aproveitando, deixa lhe perguntar outra coisa. Pretendo usar validação automática. Neste caso acabei criando um único formBean, que serve tanto a tela de manutenção de dados como a que contém o cadastro. Fiz isso para transportar os dados que foram selecionados na tela de manutenção de dados para a tela de cadastro.

Eu conseguiria definir, por exemplo, que determinados campos deste form devem ter seu preenchimento obrigatório na tela de cadastro, e na tela de manutenção não devem ser validados? Como você trataria este caso? Você usa um único formBean, ou o melhor seria criar mais de um, utilizando uma action que extende MappingDispatchActions?[/quote]

Se você usar o DispatchAction vai ser mais complicado, mas seria possível, usando o MappingDispatchAction é muito mais fácil, porque você poderia definir um ActionForm pra cada método dentro do MappingDispatchAction.

Sobre a validação automática, é possível fazer desse jeito, você pode reutilizar a mesma classe para dois ActionForms diferentes, só que você vai ter que dar um nome diferente pra cada “encarnação” do ActionForm e vai ter que definir as validações específicas de cada um deles lá nas configurações do Validator.

[quote=oandrade]Olá Caio,

Quanto a validação, pelo fato de estar utilizando DispatchActions e não estar utilizando Validator, acho que poderia fazer o seguinte, codificar dentro dos seus métodos da Action e chamar a validação na mão, pois me lembro de ter enfrentado certo problema ao utilizar DispatchActions com “validate=true”, portanto mantenha validade=false, implemente o método validate() no ActionForm, e chame manualmente conforme o exemplo abaixo:
[/quote]

Olá Andrade.

Quanto a validação, eu gostaria de fazer usando o validade automático, por já implementar a validação no cliente e no servidor, e possuir algums validações interessantes, como a máscara usada pelo campo.

Pessoal, vocês aconselham utilizar o validador automático, ou é melhor fazer na mão?

Pergunto isso pois já comecei a implementar o validadorAutomático aqui. Até que estou conseguindo, mais fiquei decepcionado com um erro que ocorre no javaScript que ele gera. Logo um dos diferenciais dele, que é gerar também o código JavaScript, está com erro. O erro ocorre no seguinte código: var formName = form.getAttributeNode(“name”);

E aí, ainda assim vale a pena utilizar validador automático, ou o melhor é implementar na mão, tanto no cliente como no servidor?

Eu nunca vi nenhum erro no Validator…

Que erro é esse que ele está encontrando? Acontece o que com o form?

Eu só escrevo validação quando o validator não tem nenhuma opção, o que é raríssimo.