CRUD
O caso de uso mais comum em aplicações empresariais é o CRUD. O NEO disponibiliza um controller e algumas tags justamente para relizar esse tipo de operação. Para fazer um CRUD precisamos dos seguintes componentes: A entidade, o dao e o service já foram explicados em capítulos anteriores. O Controller é um CrudController que extende o MultiActionController e já possui alguns métodos implementados. Os JSPs de listagem e entrada são JSPs comuns.

Vejamos um CRUD de Uf. O Uf possuirá os campos id, nome e sigla.
package org.neoframework.exemplo.bean;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import br.com.linkcom.neo.validation.annotation.MaxLength;
import br.com.linkcom.neo.validation.annotation.Required;

@Entity
@SequenceGenerator(name = "sq_uf", sequenceName = "sq_uf")
public class Uf {

    Integer id;
    String nome;
    String sigla;
    
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO, generator="sq_uf")
    public Integer getId() {
        return id;
    }
	public String getNome() {
		return nome;
	}
	public String getSigla() {
		return sigla;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	public void setSigla(String sigla) {
		this.sigla = sigla;
	}
}

POJO que representa a tabela. Registrado no Hibernate.
package org.neoframework.exemplo.dao;

import org.neoframework.exemplo.bean.Uf;

import br.com.linkcom.neo.persistence.GenericDAO;

public class UfDAO extends GenericDAO<Uf> {

}
DAO para Uf
package org.neoframework.exemplo.service;

import org.neoframework.exemplo.bean.Uf;

import br.com.linkcom.neo.service.GenericService;

public class UfService extends GenericService<Uf> {

}

Service para Uf
Como foi visto anteriormente a classe Uf será registrada no Hibernate por possuir a anotação @Entity. As classes DAO e Service serão registradas no Spring porque extendem GenericDAO e GenericService (não sendo necessário utilizar a anotação @Bean).
Já existem métodos no DAO e Service para o controle de Crud. Esses métodos já vem implementados, mas podem ser sobrescritos caso deseje modificar alguma funcionalidade.
O Controller deve ser um CrudController e também deve ser configurado com as entidades em questão.
package org.neoframework.exemplo.controller;

import org.neoframework.exemplo.bean.Uf;

import br.com.linkcom.neo.controller.Controller;
import br.com.linkcom.neo.controller.crud.CrudController;
import br.com.linkcom.neo.controller.crud.FiltroListagem;

@Controller(path="/modulo/crud/Uf")
public class UfCrud extends CrudController<FiltroListagem, Uf, Uf> {

}
Controller para o CRUD de Uf
O CrudController recebe três argumentos genéricos. O primeiro é a classe que será utilizada na listagem, essa classe deve extender FiltroListagem. Como não temos nenhum filtro, utilizamos o próprio FiltroListagem.
O segundo argumento é a classe que será utilizada na tela de entrada de dados, geralmente é a mesma classe do bean.
E o terceiro argumento é a classe do bean (entidade do hibernate) que está sendo manipulado.

Crie um arquivo JSP no caminho "/WebRoot/WEB-INF/jsp/modulo/crud/ufListagem.jsp" e adicione o seguinte conteúdo:
[JSP]
<%@ taglib prefix="n" uri="neo"%>
<%@ taglib prefix="t" uri="template"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<t:listagem>
	<t:janelaResultados>
		<t:tabelaResultados>
			<t:property name="id"/>
			<t:property name="nome"/>
			<t:property name="sigla"/>
		</t:tabelaResultados>
	</t:janelaResultados>
</t:listagem>
JSP de listagem
Agora crie um novo arquivo JSP no caminho "/WebRoot/WEB-INF/jsp/modulo/crud/ufEntrada.jsp" e adicione o seguinte conteúdo:
[JSP]
<%@ taglib prefix="n" uri="neo"%>
<%@ taglib prefix="t" uri="template"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<t:entrada>
	<t:janelaEntrada>
		<t:tabelaEntrada>
			<t:property name="id"/>
			<t:property name="nome"/>
			<t:property name="sigla"/>
		</t:tabelaEntrada>
	</t:janelaEntrada>
</t:entrada>
JSP de entrada
O NEO possui tags exclusivas para as telas de listagem e entrada de dados. É possível alterar o layout ou até mesmo algum funcionamento dessas tags alterando seus templates.
O CrudController coloca no escopo informações para essas tags utilizarem. Por isso não é necessário informar onde estam as listas ou se o modo é input ou output.

Para executar este exemplo é necessário criar as seguintes tabelas (estes scripts foram gerados para o Postgres, caso esteja testando em outro banco de dados talvez seja necessário alterar o script):
CREATE SEQUENCE sq_uf;

CREATE TABLE uf
(
  id integer NOT NULL,
  nome character varying(100) NOT NULL,
  sigla character varying(2) NOT NULL,
  CONSTRAINT uf_pkey PRIMARY KEY (id)
);
Alterando o comportamento padrão
O CrudController e o GenericDAO possibilitam a alteração do comportamento padrão para isso alguns métodos são disponibilizados. A tabela abaixo mostra os principais métodos e a funcionalidade implementada por eles. Veja a API dessas classes para maiores informações.
ClasseMétodoFuncionalidade
CrudControllerlistagemMétodo que deve ser sobrescrito para adicionar novas funcionalidades para a listagem. Esse método é chamado antes de ir para a tela de listagem de dados
CrudControllergetListagemModelAndViewRetorna o ModelAndView que representa o JSP de listagem
CrudControllerentradaMétodo que deve ser sobrescrito para adicionar novas funcionalidades para a entrada. Esse método é chamado antes de ir para a tela de entrada de dados
CrudControllergetEntradaModelAndViewRetorna o ModelAndView que representa o JSP de entrada
CrudControllercarregarCarrega o banco de dados um determinado bean. Esse método recebe um bean apenas com o id configurado, e deve retornar um bean completo.
CrudControllercriarCria um novo bean
CrudControllersalvarSalva determinado bean no banco de dados
CrudControllerexcluirExclui determinado bean
GenericDAOupdateListagemQueryAtualiza a query de listagem, recebe um objeto da mesma classe do filtro do CRUD
GenericDAOupdateEntradaQueryAtualiza a query de entrada de dados
GenericDAOupdateSaveOrUpdateAtualiza o SaveOrUpdateStrategy para salvar o bean
Adicionando um filtro à listagem
Para utilizar um filtro na listagem, os seguintes passos são necessários:
Criar uma classe de filtro como no exemplo:
package org.neoframework.exemplo.controller;

import br.com.linkcom.neo.controller.crud.FiltroListagem;

public class UfFiltro extends FiltroListagem {

	String nome;

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}
}
Informar ao controller a classe de filtro que estamos utilizando:
package org.neoframework.exemplo.controller;

import org.neoframework.exemplo.bean.Uf;

import br.com.linkcom.neo.controller.Controller;
import br.com.linkcom.neo.controller.crud.CrudController;
import br.com.linkcom.neo.controller.crud.FiltroListagem;

@Controller(path="/modulo/crud/Uf")
public class UfCrud extends CrudController<UfFiltro, Uf, Uf> {

}
Alterar o JSP para adicionar o campo na tela.
[JSP]
<%@ taglib prefix="n" uri="neo"%>
<%@ taglib prefix="t" uri="template"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<t:listagem>
	<t:janelaFiltro>
		<t:tabelaFiltro>
			<t:property name="nome"/>
		</t:tabelaFiltro>
	</t:janelaFiltro>
	<t:janelaResultados>
		<t:tabelaResultados>
			<t:property name="id"/>
			<t:property name="nome"/>
			<t:property name="sigla"/>
		</t:tabelaResultados>
	</t:janelaResultados>
</t:listagem>
Alterar o comportamento da query para utilizar o filtro:
package org.neoframework.exemplo.dao;

import org.neoframework.exemplo.bean.Uf;
import org.neoframework.exemplo.controller.UfFiltro;

import br.com.linkcom.neo.controller.crud.FiltroListagem;
import br.com.linkcom.neo.persistence.GenericDAO;
import br.com.linkcom.neo.persistence.QueryBuilder;

public class UfDAO extends GenericDAO<Uf> {

	@Override
	public void updateListagemQuery(QueryBuilder<Uf> query, FiltroListagem _filtro) {
		UfFiltro filtro = (UfFiltro) _filtro;
		query.whereLike("uf.nome", filtro.getNome());
	}
	
}

A query recebida como parâmetro já possui a cláusula FROM configurada. Por isso foi apenas necessário criar a clásula where.