Métodos CRUD dentro de uma única action no WebWork + validação

18 respostas
Thiago_Senna

Olá a todos!

Primeiramente gostaria de parabenizar aqueles que participaram no CJ. infelizmente não pude ir, mas ano que vem já to lá! :wink:

Hoje, vindo para o serviço, fiquei pensando numa arquitetura para lidar de forma diferente com actions no webwork, de forma similiar ao que ao Ruby on Rails.

Hoje tenho minhas actions mais ou menos assim…

public class IncluiRamoAtividadeAction extends
ActionSupport {
	
	private String nome;
	private String descricao;
	private RamoAtividade ramoAtividade;
	
	private RamoAtividadeDAO ramoAtividadeDAO;
	
	public String execute() throws DAOException {

		if ((nome == null) || (nome.trim().equals(""))) {
			addFieldError("nome", "Por favor, entre com um nome válido!");
			return ERROR;
		}

		if (verificaSeRamoExiste(nome)) {
			addFieldError("nome", "O ramo de atividade fornecido já existe.");
			return ERROR;
		}

		ramoAtividade = new RamoAtividade();
		ramoAtividade.setNome(nome);
		ramoAtividade.setDescricao(descricao);

		ramoAtividadeDAO.create(ramoAtividade);

		return SUCCESS;
	}
	
	private boolean verificaSeRamoExiste(String nome) throws DAOException {			
		RamoAtividade ramo = ramoAtividadeDAO.findByName(nome);
		
		if (ramo != null) 
			return true;
		else
			return false;
	}

	RamoAtividade getRamoAtividade() {
		return ramoAtividade;
	}

	void setDescricao(String descricao) {
		this.descricao = descricao;
	}
	
	void setNome(String nome) {
		this.nome = nome;
	}	

	void setRamoAtividadeDAO(RamoAtividadeDAO ramoAtividadeDAO) {
		this.ramoAtividadeDAO = ramoAtividadeDAO;
	}
}

Em breve farei uns refactoring nas actions referente ao Ramo de Atividade, e ai, o código vai ficar muito simples, mais ou menos assim:

public class IncluiRamoAtividadeAction extends
ActionSupport extends AbstractRamoAtividadeAction {
	
	public String execute() throws DAOException {


		if (verificaSeRamoExiste(ramo.getNome())) {
			addFieldError("nome", "O ramo de atividade fornecido já existe.");
			return ERROR;
		}


		ramoAtividadeDAO.create(ramoAtividade);

		return SUCCESS;
	}
	
	private boolean verificaSeRamoExiste(String nome) throws DAOException {			
		RamoAtividade ramo = ramoAtividadeDAO.findByName(nome);
		
		if (ramo != null) 
			return true;
		else
			return false;
	}
}

Mas estive pensando… Minhas actions ficam muito pequenas. É um desperdício de classe na minha opinião. Eu precisarei de no mínimo 5 actions, e mais 1 AbstractAction para conseguir um refactoring que nem esse. Eu vou poluir meu projeto de actions…

O que estou querendo é colocar tudo isso em uma action só. Isso não parece ser problema, pois posso facilmente configurar o xwrok.xml ou simplemente chamar a action utilizando por exemplo a url http://localhost:8080/minhaApp/RamoAtividadeAction!create.do… usando esta chamada o webwork executaria para mim o método create da minha action, e não o execute, que é o default…

Meu código entaum ficaria assim:

public class RamoAtividadeAction extends AbstractRamoAtividadeAction {	
	
	public String inclui() throws DAOException {

		if (verificaSeRamoExiste(ramoAtividade.getNome())) {
			addFieldError("nome", "O ramo de atividade fornecido já existe.");
			return ERROR;
		}


		ramoAtividadeDAO.create(ramoAtividade);

		return SUCCESS;
	}

	public String altera() throws DAOException {

		// algum código aqui
	}

	public String exclui() throws DAOException {

		// algum código aqui
	}

	public String exibe() throws DAOException {

		// algum código aqui
	}

	public String listaTodos() throws DAOException {

		// algum código aqui
	}

	private boolean verificaSeRamoExiste(String nome) throws DAOException {			
		RamoAtividade ramo = ramoAtividadeDAO.findByName(nome);
		
		if (ramo != null) 
			return true;
		else
			return false;
	}

}

Entaum… a minha dúvida cruel sobre essa arquitetura é quanto a validação. Eu precisava que dependendo do método que fosse executado, fosse usado uma configuração diferente de validação.

Até onde estudei, o webwork tem 3 tipos de validações, e a que mais parece se enquadrar para minha situação é um que vc cria um arquivo com mais ou menos este nome…

NomeDaClasseDaAction-NomeDaAction-validate.xml

Por acaso é esse o tipo de validaçção específica para cada ação da minha action, ou seja, eu teria que criar os seguintes arquivos de validação:

RamoAtividadeAction-inclui-validate.xml
RamoAtividadeAction-altera-validate.xml
RamoAtividadeAction-exclui-validate.xml
(e outros…)

Será que alguém poderia me dar uma luz? Estou querendo fazer isso, mas tenho dúvidas se realmente vale a pena colocar tudo isso na prática!

Abraços!
Thiago Senna

18 Respostas

Mauricio_Linhares

Aqui no meu eu faço assim (é Spring MVC):

package br.edu.cefetpb.spring.action;

imports.....;

public class GenericInsertUpdateAction extends SimpleFormController {
    
    private GenericDao crudDao;

	public GenericDao getDao() {
		return crudDao;
	}

	public void setDao(GenericDao crudDao) {
		this.crudDao = crudDao;
	}
    
	protected Object formBackingObject(HttpServletRequest request)
			throws Exception {

        int id = RequestUtils.getIntParameter(request, "id", 0);
        Object objeto = null;
        
        if (id != 0 ) {
         objeto = this.getDao().getById(new Integer(id), this.getCommandClass() );
         return objeto;
        }              
		return super.formBackingObject(request);
	}
    
	protected ModelAndView onSubmit(HttpServletRequest request,
			HttpServletResponse response, Object command, BindException errors)
			throws Exception {
        
        this.getDao().save(command);
        
		return new ModelAndView( this.getSuccessView() );
	}
    
}

Esse Action tem acesso a classe que ele deve tratar, a um validador pra essa classe e a um DAO genérico que faz CRUD. Quando ele é chamado pela primeira vez (via GET) ele olha se tem um parâmetro chamado "id" (esse deveria ser configurável, mas não é :lol: ), se tiver, ele vai no DAO genérico e manda carregar o objeto com o "id" definido lá, se não tiver, ele instância o objeto.

Nessa hora ele vai e mostra o formulário vazio (ou com os dados do objeto que foi carregado do banco) e quando o usuário dá o submit ele valida o formulario (e retorna se houverem erros) e chama o "save" no DAO genérico. Nesse save, é verificado se o objeto tem um "id" (na verdade, quem verifica é o Hibernate...), se não tiver, é "save" mesmo, se não tiver vira "update".

Mauricio_Linhares

Ah, sobre listar e deletar eu tenho dois Actions que fazem isso, também são configurados via IoC com as informações da classe que eles tem que tratar.

Thiago_Senna

Hehe… o spring mvc parece ser mais flexível para se adaptar com a nossa imaginação! :lol:

Mais pra frente vou ver se aprende Spring MVC, e vou ver de perto como ele funciona.

Infelizmente, o trabalho que estou fazendo, tenho que entregar em outubro. Por isso estou naquela correria (foi por causa desta merda que naum fui no CJ :twisted: ). Felizmente já sei alguma coisa de webowrk, e só pelo fato de eu saber que é possível implementar tranquilamente aquela gambi q eu postei lá em cima, já fico muito feliz.

No entanto, se eu ficar com a validação acoplada ao meu código não vai valer a pena eu usar estar arquitetura. É melhor eu ficar com o método tradicionar, ou seja, uma classe action para cada possível ação do usuário.

IMHO, essa arquitetura que to querendo implementar só vai ter valor caso os métodos CRUD se mantiverem simples super simples!

Valeu pelo apoio! :smiley:

Jair_Rillo_Junior

pelo que eu entendi Thiago, vc quer ter 1 tipo de validação para 1 mesma action, mas esse tipo de validação deve ser diferente dependendo do “parametro” que essa action receber, certo?

Eu particularmente nao sei fazer isso, nem se é possivel, mas seria muito interssante saber se existe alguma maneira.

Thiago_Senna

ManchesteR:
pelo que eu entendi Thiago, vc quer ter 1 tipo de validação para 1 mesma action, mas esse tipo de validação deve ser diferente dependendo do “parametro” que essa action receber, certo?

Eu particularmente nao sei fazer isso, nem se é possivel, mas seria muito interssante saber se existe alguma maneira.

sim… vamos supor o seguinte…

Se o usuário quiser criar um novo ramo de atividade, para mim só será interssante validar se o nome do ramo de atividade não está em branco ou nulo!

Se o usuário quiser fazer um findByIdPK(Long id), minha validação deve garantir que o id sendo passado naum é nulo e que realmente é um número.

Por isso, dependendo da ação do usuario, a validação deveria ser diferente! O exemplo que dei é escroto, e é perfeitamente possível contornar bolando uma boa interface com o usuário, mas haverão situações (com certeza haverão) em que isso não será possível! :cry:

Thiago

Mauricio_Linhares

A jogada não é ser Spring MVC, é IoC companheiro. O WW tem um também né?

Então, faz um Dao genérico e um action genérico (tipo o que eu postei), vai dar um pouco mais de trabalho (que na verdade vai ser quase nada mesmo…) mas pelo menos você fica livre e vai fazer muito menos CTRL+C CTRL+V.

O WebWork faz transformação automática de valores e passa eles pro command sozinho também né? O resto é só felicidade :mrgreen:

Mas, gaste o seu tempinho pra estudar o Spring mesmo, você não imagina o quanto ele ajuda :thumbup:

Mauricio_Linhares

Thiago Senna:
Se o usuário quiser fazer um findByIdPK(Long id), minha validação deve garantir que o id sendo passado naum é nulo e que realmente é um número.

Assim, esse tipo de coisa é dilema, se a busca no banco só pode ser feita pelo pk que está sendo passado e essa chamada vem de um link que você mesmo criou na sua interface, a única chance dela vir errada é o cara mexer no link “pra ver o que acontece” e se ele fizer isso, um maravilhoso stack trace de number format exception é mais do que merecido :lol:

Ou então mostra uma página de erro, (como as configuradas no web.xml) dizendo que as informações enviadas são incorretas.

Thiago_Senna

Tem sim Maurício! Inclusive estou usando ele para setar o DAO. Mas infelizmente naum entendi bém sua colocação. Por acaso vc estaria dizendo sugerindo de eu usar IoC para a validação dos dados?

Bom, o meu problema em adotar radicalmente esta sua solução, apesar de muito estigante, é que estou usando Desenvolvimento guiado por testes. Não vai valer a pena pra mim agora mudar todos estes testes, sem contar que o padrão de action que o webwork traz é mais simples de usar se comparado com o spring (eu acho). Para testar um método qualquer da minha action, o único mock que eu precisaria criar era um MockDAO no máximo!:wink:

Outra vantagem que não estou afim de abrir mão é a simplicidade, e a forma direta como o assunto está sendo tratado. Se o método é incluir, quer dizer incluir Ramo de Atividade e acabou. Não é necessário de um principiante no projeto ficar interpretando o que o código tá fazendo para saber se ele vai excluir, alterar e etc… Seu eu fizer essa alteração, meu grupo de trabalho terá mais dificuldades de acompanhar! :wink:

Essa passagem automática de parâmetro seria pegar os parâmetros vindo do request e setá-los dentro de modelo? Se for isso, sim, o webwork faz! :wink:

Mas a grande questão é que o webwork já possui um mecanismo bastante maduro para validação utilizando interceptor e arquivos de configuração com xml, deixando assim minha action bém desacoplada da validação. Isso é algo que eu gostaria de reaproveitar deste framework.

Maruício:

Mas, gaste o seu tempinho pra estudar o Spring mesmo, você não imagina o quanto ele ajuda :thumbup:

Com certeza! Não vejo a hora de começar a estudar! hehe

Thiago

Thiago_Senna

Se eu conseguir descobrir algo, colocarei aqui neste tópico a solução que eu adotei! :wink:

Thiago_Senna

Pessoal… acho que encontrei a solução!

Só encontrei a fonte para estudar e colocar validações diferentes para uma mesma action! O link é este:

http://wiki.opensymphony.com/display/WW/Validation+Examples

Daí dêem uma olhada em Visitor Validation Example.

Felizmente, é possível fazer com que o webwork consiga usar diferentes validações para uma mesma action!

Obrigado a todos pela ajuda!
Abraços!

ricardolecheta

Thiago,

é como vc escreveu antes:

neste caso tem um action declarada no xwork.xml para cada alias, ex:
<action name=“altera” class="…" method=“altera”
<action name=“inclui” class="…" method=“inclui”

lembrando que vc pode usar o metodo validate() da action tb…

e o esquema do DAO genérico e IoC é show de bola mesmo :slight_smile:

Thiago_Senna

Valeu Ricardo…

Pelo que eu li da doc do webwork, vi que dava para fazer o que eu estava querendo, mas tava muito difícil de enteder… e isso pq ia ser do jeito mais difícil.

Agora que vc falou que dá pra fazer assim tranquilamente, demoro… é esse mesmo que eu vou fazer!

Só mais uma pergunta…

E quando eu chamar a minha action através de uma urnl, e eu colocar o nome RamoAtivadadeAction!Inclui, o webwork também executará o RamoAtividadeAction-inclui-validate.xml ?

Abraços!
Thiago

Mauricio_Linhares

Assim, só pra matar a curiosidade, se pra inserir tem uma validação, que tem que ser obedecida pra poder enviar os dados pro banco, porque a de editar é diferente?

ricardolecheta

boa pergunta :slight_smile: não sei…

acho que não pq este !bang é um atalho que vc usa para indicar o método que vai executar, e não o alias… precisa testar para ver :slight_smile:

ricardolecheta

concordo com vc Maurício, o legal é fazer um método salvar genérico que ou salva ou altera um registro… desta forma pode-se utilizar a mesma validação :wink:

Thiago_Senna

Olá!

Bom, no caso (edit: era saco) do update e edit não tem muita diferença. É praticamente a mesma validação. Mas para mim, a coisa se complicaria por exemplo quando fosse inclui e exclui.

Para incluir, precisarei validar o nome do ramo apenas. Para excluir eu não preciso que o nome do ramo esteja preenchido.

Ou seja, se eu ficar com o mesmo arquivo de validação tanto para incluir como para excluir, quando tentar excluir a validação não vai passar, já que este está validando o nome do ramo, pois ele estará em branco na hora da exclusão!

Ricardo:
boa pergunta não sei…

acho que não pq este !bang é um atalho que vc usa para indicar o método que vai executar, e não o alias… precisa testar para ver


blz… este fim de semana farei o teste! :wink: Daí eu dou um retorno!

Obrigado pela ajuda!
Thiago

Mauricio_Linhares

Assim, mais uma vantagem de se usar o Hibernate :lol:

Pra excluir eu tenho também um Action só, ele pega o ID do objeto e o nome da classe (na verdade, no caso aqui ele só pega o último nome, o pacote é comum), aí é só “delete()” e feito. Tudo simples e em um único lugar :mrgreen:

Quem precisa de ferramentas RAD ainda? 8)

Thiago_Senna

hehe…

Acredita que também andei pensando nisso.

Essa arquitetura que eu vou fazer no meu projeto, apesar de ainda não ser das melhores, já é mais que suficiente para questionar se realmente precisamos de uma ferramenta RAD.

No meu projeto só gastamos tempo fazendo o modelo, e tá dando um pouquinho mais de trabalho para implementar os DAO’s, e a camada de controle fica super simples, e a view também!

Se eu usar hibernate, pronto, a camada de persistência fica moleza! A única parte mais difícil seria mesmo as views.

Dependendo do projeto, é só usar Ruby on Rails, ou mesmo, caso o projeto tenha que ser em java, o Ruby on Rails ainda seria uma ótima opção para se desenvolver um protótipo para então consultar o cliente sobre o andamento do projeto.

Outra coisa que tenho sentido uma grande diferença na agilidade no processo de desenvolvimento é sem dúvida alguma os Refactorings!

Já fiz uma renca de refactoring com o intuito de agilizar o desenvolvimento e facilitar o TDD (Test Driven Development). Como não deixo acumular muito refactoring, e sempre que ele vem na cabeça eu vo lá e faço, estamos conseguindo desenvolver o projeto em uma velocidade bastante agradável!

Desculpa ai pessoal, acabei me empolgando… não consegui me conter! :mrgreen:

Abraços!
Thiago Senna

Criado 22 de agosto de 2005
Ultima resposta 24 de ago. de 2005
Respostas 18
Participantes 4