: : www.mundoj.com.br : :
Rógel Garcia de Oliveira
([email protected]): formado em Ciência da
Computação pela Universidade FUMEC, trabalha com Java
desde 2003. Desde 2005 é especialista em frameworks.
Trabalha atualmente com consultoria de soluções,
desenvolvimento de sistemas e lecionando cursos Java.
Certificado SCJP.
Next Framework
Produtividade com Java EE
Qual é o objetivo de um framework? Dar produtividade
ao desenvolvimento. Essa resposta deve estar na
"ponta da língua" de muitos profissionais envolvidos
com desenvolvimento de sistemas. Mas será que o
desenvolvimento hoje segue esse princípio? Temos muitas
opções de frameworks, mas ainda vemos arquiteturas
complexas e burocráticas. Isso acontece porque nem sempre
um framework é adequado para determinada situação.
Existe uma ideia de que um bom framework é aquele
que possui uma série de camadas, vários design patterns
aplicados, várias configurações disponíveis. Essa é uma
ideia incorreta, pois apenas adiciona complexidade ao
desenvolvimento. Esse tipo de arquitetura aumenta a curva
de aprendizado, dificulta a implementação dos requisitos
da aplicação, e o desenvolvedor tem que implementar
soluções para satisfazer o framework e não o aplicativo
desenvolvido. É fácil identificar esse tipo de solução, basta
verificar quanto tempo e aprendizado são necessários para
48
fazer coisas simples. Quanto tempo é necessário para
identificar e corrigir determinado problema. Ou então, se é
mais fácil implementar determinada solução se não usar o
framework. Um framework eficiente é aquele que resolve o
problema da aplicação facilitando o desenvolvimento.
Este artigo propõe a utilização do framework Next para
desenvolver um sistema de forma produtiva, mas mantendo
o nível de profissionalismo necessário. O Next parte do
princípio da simplicidade. Quanto mais simples for o
desenvolvimento, melhor. Qualquer desenvolvedor que
conheça o desenvolvimento JEE, conseguirá desenvolver
aplicações com o Next com poucas horas de estudo
e de maneira eficiente. A facilidade de se trabalhar
com o framework oferece vantagens como baixa curva
de aprendizado, menor tempo de desenvolvimento e
principalmente de manutenção. Desenvolver aplicações
JEE pode ser simples, se mantermos o foco em soluções
simples.
m framework é um software que visa facilitar a criação
de determinada funcionalidade ou utilização de determinada tecnologia. Com a evolução dos frameworks,
e maior oferta destes, era esperado que o desenvolvimento de
aplicações ficasse mais fácil. Mas desenvolver para a plataforma
JEE requer cada vez mais estudo e experiência. Essa dificuldade
acontece porque os sistemas estão sendo criados com superarquiteturas que requerem muito tempo de aprendizado e com uma
série de situações novas que muitas vezes o programador desconhece. Além do básico de JEE, como servlets e http, também é
necessário aprender uma série de fluxos, anotações, interfaces e
situações específicas da ferramenta de trabalho. No Next o conteúdo a ser aprendido é bem menor do que em outros frameworks
equivalentes.
Além de todo o tempo gasto no aprendizado, a utilização desses
artefatos acaba fazendo com que o programador ao invés de satisfazer os requisitos da aplicação, tenha que satisfazer os requisitos
do framework. Como o Next possui uma filosofia na qual a simplicidade é o foco principal, o framework ao invés de impor novos
requisitos ajuda o desenvolvedor com soluções que eliminam trabalho do programador. Quanto tempo você gasta hoje para iniciar
um projeto web? Quantas páginas de documentação devem ser
lidas antes de se começar a trabalhar com determinada tecnologia? Quantas horas já foram perdidas tentando resolver problemas
simples, mas que por causa do framework usado o problema se
tornou bem mais complicado? A necessidade por soluções simples
existe, pois mesmo com uma série de limitações, as ferramentas
como Ruby on Rails ou Grails vêm ganhando espaço. Novas propostas aparecem tentando dar produtividade ao desenvolvimento,
mesmo que se perca uma série de vantagens que uma linguagem
como Java e suas ferramentas possam oferecer.
É necessário utilizar frameworks no desenvolvimento, pois elevando o nível de abstração podemos reduzir realmente o tempo
de desenvolvimento. A utilização de um framework simples e
direto, onde não são adicionados novos problemas é o ideal para
conseguir a diminuição do tempo de desenvolvimento. Ao invés
de criar uma arquitetura complexa na qual se gasta muito tempo
no aprendizado e depois no desenvolvimento de aplicações com
a mesma, o framework Next auxilia o programador com soluções
para os problemas encontrados no desenvolvimento de sistemas
JEE. O resultado disso é uma baixa curva de aprendizado, maior
produtividade, menor tempo de desenvolvimento e custos mais
baixos de manutenção. A intenção do Next não é reinventar uma
forma de trabalho ou ferramenta. Por isso ele utiliza como base o
Spring e o Hibernate e propõe uma solução conjunta com esses
dois frameworks, inclusive facilitando a sua utilização.
Neste artigo será demonstrado como o Next pode ajudar no
desenvolvimento através de uma aplicação do tipo blog, onde é
possível cadastrar vários tópicos e os usuários fazem comentários
sobre eles. A aplicação construída possuirá diversos tipos de funcionalidades. como cadastro de dados (crud), upload de arquivos,
mestre / detalhe, ajax. Tudo isso será feito com poucas páginas
neste artigo. E, no final, teremos uma aplicação completa e você
já possuirá conhecimento suficiente para desenvolver sistemas
profissionais.
Criando um projeto Next
A aplicação que criaremos nesse tutorial será um blog onde poderão ser cadastrados tópicos que irão receber comentários. A
aplicação será dividida em dois módulos, um que será a parte
onde os tópicos e comentários são visualizados, e o outro módulo
será a parte administrativa, na qual será feita a manutenção desses
registros. Os tópicos terão autores que deverão ser previamente
cadastrados. Cada tópico terá também uma categoria.
Não será utilizado nenhum plug-in ou ferramenta geradora de código. Por isso, iremos explicar no início como fazer a configuração
manual do projeto. Apesar de essa parte ser um pouco tediosa, ela
é bem simples, e rapidamente já desenvolveremos a aplicação. Basicamente iremos copiar alguns arquivos do framework e colocar
nos lugares corretos. Uma vez configurado o projeto, é possível
programar sem maiores burocracias.
Baixando os arquivos necessários
Para este tutorial utilizaremos o Next 3.5.1. O Next pode ser
baixado no site http://www.nextframework.org na seção de downloads. No mesmo site, podem ser encontrados documentação,
fórum de discussão, tutoriais e vídeos sobre o framework.
Você poderá baixar o código-fonte completo da aplicação no site
da revista. É interessante que você utilize uma IDE (como o eclipse) com suporte a aplicações Web para facilitar o trabalho. Também será necessário um banco de dados para fazer a persistência
dos dados. É recomendado a utilização do servidor Tomcat 6.
É interessante que você saiba como publicar e configurar um projeto JEE. Também é interessante ter noções de frameworks ORM
(Object Relational Mapping, como o Hibernate).
Configurando o projeto
Crie na sua ferramenta de desenvolvimento um projeto Web, dê o
nome de blog para esse projeto.
Agora, copie para a pasta /WEB-INF/lib da aplicação os seguintes
arquivos JAR da distribuição do Next:
t OFYUKBSRVFFTUÈOBSBJ[EBEJTUSJCVJÎÍP
t UPEPTPTBSRVJWPT+"3RVFFTUÍPOBQBTUBMJC
t TFVUJMJ[BSPTFSWJEPS5PNDBUDPQJFPTBSRVJWPT+"3EBQBTUB
lib/optional.
Agora que já temos todas as bibliotecas disponibilizadas na aplicação, iremos configurar o web.xml. O Next já possui na pasta /
sample um arquivo web.xml padrão, copie esse arquivo para a
pasta /WEB-INF/ da sua aplicação.
Banco de dados e hibernate Banco de dados
e hibernate
Iremos utilizar dois arquivos para configurar o banco de dados
e o hibernate. Esses arquivos devem ficar na raiz dos fontes (geralmente na pasta src). Crie um arquivo connection.properties
seguindo o modelo da Listagem 1.
49
: : www.mundoj.com.br : :
Listagem 1. Modelo do arquivo connection.properties.
driver=org.postgresql.Driver
url=jdbc:postgresql://localhost/blog
username=postgres
password=123456
Troque os valores de driver, url, username e password para os
parâmetros JDBC do banco de dados que irá utilizar. Copie o
driver JDBC do seu banco de dados para a pasta /WEB-INF/lib
da aplicação.
Driver do banco de dados
O Next não vem com nenhum driver JDBC, ele deve ser
baixado da internet de acordo com seu banco de dados. Não
esqueça de colocar o driver JDBC do seu banco de dados na
pasta /WEB-INF/lib.
O segundo arquivo é o hibernate.properties. Nele iremos colocar
uma configuração para criar automaticamente a estrutura do banco
de dados, o conteúdo do arquivo deve estar como na Listagem 2.
Listagem 2. Modelo do arquivo hibernate.properties.
hibernate.hbm2ddl.auto=update
É interessante fazer uma publicação e ligar o servidor, verifique se a
aplicação é inicializada sem erros. Você pode pedir no seu navegador
a URL http://localhost:8080/blog/next, se for exibida uma mensagem
de congratulações, a aplicação estará funcionando perfeitamente.
Distribuindo a aplicação em módulos
No Next, você pode distribuir a sua aplicação em módulos. Essa
distribuição facilita a escolha do design, esquema de permissões
e organização de cada módulo. Vamos utilizar dois módulos predefinidos no Next. Um é o módulo public, que utilizaremos para
fazer a parte onde serão apresentados os tópicos e os comentários.
O outro módulo é o admin, que utilizaremos para manter os dados administrativos do site. A única diferença entre os módulos
nesse momento é o nome, eles estão cadastrados no arquivo web.
xml que você copiou para sua aplicação. A Listagem 3 mostra um
exemplo de configuração de um módulo.
Cada módulo pode ter um arquivo base.jsp que serve como um
container das páginas do módulo (inclui o cabeçalho, javascripts,
css e rodapé das páginas). Na distribuição do Next, na pasta /samples, existe um arquivo base.jsp de exemplo. Copie esse arquivo
para a pasta /WEB-INF/jsp/public e para a pasta /WEB-INF/jsp/
admin. Mais informações podem ser encontradas em documentação no próprio base.jsp.
Personalizando o estilo
O arquivo base.jsp copiado anteriormente possui uma tag
<n:head> que é responsável por incluir arquivos CSS e JS da sua
aplicação de forma automática. Essa tag já inclui um arquivo
default.css para toda a aplicação. Esse é um estilo interessante
para a parte administrativa do sistema, mas para a parte pública
iremos utilizar um diferente. Para isso, crie uma pasta /css/public
e coloque um arquivo default.css com o conteúdo conforme a Listagem 4. O Next irá detectar que esse módulo possui um arquivo
default.css configurado e não irá incluir o padrão.
Listagem 4. Conteúdo do arquivo /css/public/default.css.
/* Esse import irá buscar outro estilo disponível no Next. Utilizaremos as
classes definidas nesse CSS para personalizar o estilo da parte pública do
sistema. */
@IMPORT url(“../../resource/css/layout/simpleposts/default.css”);
Vamos fazer os últimos ajustes na parte visual do sistema. No
arquivo /WEB-INF/jsp/public/base.jsp, troque a linha com ${application} por <a href="${application}">Meu BLOG!</a> para dar
um título mais elegante ao site.
No arquivo /WEB-INF/jsp/admin/base.jsp “descomente” o código
onde começa com <div class="menubar">, conforme mostrado na
Listagem 5. Esse código adiciona um menu à aplicação. Repare
que a tag <n:menu> indica como path o caminho /WEB-INF/
menu.xml. Copie o arquivo menu.xml da pasta /samples da distribuição do Next para a pasta /WEB-INF/ da sua aplicação.
Listagem 5. Conteúdo do arquivo /css/public/default.css.
<div class=”menubar”>
Listagem 3. Exemplo de configuração do módulo admin no
web.xml
<div class=”menubar-before”></div>
<servlet>
<div class=”menubar-in”>
<servlet-name>admin</servlet-name>
<servlet-class>org.nextframework.controller.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>admin</servlet-name>
<url-pattern>/admin/*</url-pattern>
</servlet-mapping>
50
Os arquivos JSP de cada módulo devem ficar na pasta /WEB-INF/
jsp/[modulo]. Crie as pastas /WEB-INF/jsp/public e /WEB-INF/
jsp/admin na sua aplicação para armazenar os arquivos JSP.
<div class=”menubar-after”></div>
<n:menu menupath=”/WEB-INF/menu.xml”/>
</div>
</div>
Você deve ter uma estrutura de projeto semelhante à estrutura
da figura 1 (os arquivos JAR dentro da pasta lib não estão sendo
mostrados para facilitar a visualização).
Listagem 6. Classe Categoria.
package blog.entity;
//os imports são sempre do pacote javax.persistence
import javax.persistence.*;
@Entity
public class Categoria {
Long id;
String nome;
@Id
Figura 1. Estrutura da aplicação.
@GeneratedValue
Agora a aplicação já está configurada para começarmos a codificação do sistema.
public Long getId() {
return id;
}
Full-stack
public String getNome() {
O Next é um framework full-stack, ou seja, possui recursos desde
a camada de visão até a camada de persistência. A persistência
no Next é feita utilizando-se o Hibernate. O Next também propõe DAOs para fazer o acesso ao banco de dados, e uma camada
de serviço (service) para as regras de negócio. Por fim, temos os
controllers que fazem a interação com as requisições do cliente e
JSPs para a camada de visão. Os controllers, services e daos serão
configurados pelo Spring. Esta é uma estrutura básica de um projeto Next, esquematizado na figura 2.
return nome;
}
public void setId(Long id) {
this.id = id;
}
public void setNome(String nome) {
this.nome = nome;
}
}
Não será necessário criar a tabela no banco de dados, pois na etapa de configuração da aplicação já informamos ao Hibernate para
gerá-las automaticamente. Também não será necessário registrar
entidade Categoria no Hibernate, o Next se encarrega de procurar
todas as entidades da aplicação e fazer esse registro.
Figura 2. Esquema básico de organização de uma aplicação Next.
Não é necessário ser um “expert” em Hibernate ou Spring para
trabalhar com o Next. O importante é entender que o Hibernate
fará o mapeamento entre as classes da aplicação que são entidades
e o banco de dados. E o Spring fará a configuração das classes que
possuírem alguma lógica do sistema, como services, controllers e
daos. É interessante estar familiarizado com o desenvolvimento
de aplicações JEE.
Primeiro cadastro
Vamos começar nosso sistema pela parte administrativa, assim poderemos cadastrar dados que serão exibidos pelo blog. Faremos inicialmente um CRUD de Categoria. CRUD é uma sigla que significa
create, read, update, delete (criar, ler, atualizar e excluir) que são as
quatro operações básicas. Para fazer um CRUD no Next, primeiro
devemos definir a entidade que representará a tabela do banco de
dados. Crie uma classe Categoria conforme a Listagem 6.
Hibernate Annotations
As entidades do Hibernate são configuradas através de anotações Java. Essas anotações fazem parte do Hibernate Annotations. Quando for criar uma entidade, lembre-se de alguns
detalhes. Primeiro é que a anotação @Entity deve ser a do
pacote javax.persistence. Deve existir pelo menos um campo
com a anotação @Id que indicará o campo primary key no
banco de dados. Utilizamos a anotação @GeneratedValue para
indicar que o valor do campo deve ser gerado pelo hibernate.
Caso esteja utilizando um banco de dados que use sequences,
como o PostgreSQL ou o Oracle, você pode marcar a estratégia de geração de código como SEQUENCE. Exemplo: @
GeneratedValue(strategy = GenerationType.SEQUENCE).
Consulte a documentação do Hibernate Annotations para
mais informações no site http://www.hibernate.org.
51
: : www.mundoj.com.br : :
Precisamos agora de componentes nos quais possamos escrever a lógica de persistência, de negócios e também a parte de controle. Para
a camada de persistência e serviços, o Next já fornece duas classes
genéricas com diversas funcionalidades já implementadas. As classes
são a GenericDAO e a GenericService, respectivamente. Faça um DAO
e um Service para a entidade Categoria conforme as Listagens 7 e 8.
Listagem 7. DAO para a entidade Categoria.
package blog.dao;
import org.nextframework.persistence.GenericDAO;
import blog.entity.Categoria;
public class CategoriaDAO extends GenericDAO<Categoria>{
}
Listagem 8. Classe de serviços para a entidade Categoria.
package blog.service;
import org.nextframework.service.GenericService;
import blog.entity.Categoria;
public class CategoriaService extends GenericService<Categoria>{
}
As classes estão prontas para a utilização. Não é necessário implementar nenhum código para o que iremos fazer, todo o código necessário já está implementado nas classes que herdamos. Utilizamos
o recurso de Generics do java para indicar sobre qual entidade o
service ou dao deve ser configurado. É interessante que para cada
entidade da aplicação exista um GenericService e um GenericDAO.
No service é onde devem estar as regras de negócio e no dao é onde
colocamos as queries e funções para interagir com o banco de dados.
A última classe que precisamos criar para fazer a funcionalidade de
um CRUD para a entidade Categoria é o controller. Um controller é o
responsável por receber as requisições do usuário e chamar as funcionalidades do sistema. Todos os controllers no Next devem estender
da classe MultiActionController, que é um controller genérico. Esse
controller permite que vários métodos sejam criados para receber
diferentes requisições. No caso do CRUD teríamos os métodos para
listar, criar, editar, salvar e excluir, por exemplo. O Next já provê um
controller que estende de MultiActionController e implementa essas
funcionalidades. Esse controller especifico para casos onde se deseja
fazer um CRUD é o CrudController. Implemente uma classe chamada CategoriaCrud conforme a Listagem 9.
Listagem 9. Controlador do tipo CRUD para Categoria.
Cada controller deve ter uma anotação @Controller com um atributo
path que indica em qual URL esse controller deve responder. No
caso, configuramos a URL para /admin/crud/categoria. A primeira
parte do path sempre deve ser um módulo configurado. Como essa
funcionalidade deve estar no módulo admin, a path começa com /
admin. Depois do módulo, pode ser utilizado qualquer caminho que
desejar. O CrudController recebe três argumentos genéricos, o primeiro é o filtro da lista que iremos mostrar, se não tiver nenhum filtro
especial podemos usar a classe FiltroListagem que já possui paginação e ordenação. O segundo indica qual é a classe que iremos utilizar
como formulário para entrada de dados, e o terceiro qual é a classe
do objeto que iremos persistir. Normalmente utilizaremos a mesma
classe para o formulário e a persistência. O CrudController demanda
dois JSPs. Um JSP é utilizado para listar os dados. O segundo JSP
é utilizado como formulário de entrada de dados. Os JSPs de um
controller devem sempre ficar no diretório /WEB-INF/jsp/[modulo],
o controller pode opcionalmente especificar subdiretórios. No caso
do CrudController, é especificado o subdiretório crud.
No cadastro que estamos construindo, os JSPs devem ficar em /WEBINF/jsp/admin/crud. Um JSP deve se chamar categoriaListagem.jsp e
o outro categoriaEntrada.jsp. O código desses dois arquivos pode ser
visto nas Listagens 10 e 11.
Listagem 10. JSP de listagem de dados de categoria.
<%@ taglib prefix=”t” uri=”template”%>
<t:listagem>
<t:janelaResultados>
<t:tabelaResultados>
<t:property name=”id”/>
<t:property name=”nome”/>
</t:tabelaResultados>
</t:janelaResultados>
</t:listagem>
Listagem 11. JSP de entrada de dados de categoria.
<%@ taglib prefix=”t” uri=”template”%>
<t:entrada>
<t:janelaEntrada>
<t:tabelaEntrada>
<t:property name=”id”/>
<t:property name=”nome”/>
</t:tabelaEntrada>
</t:janelaEntrada>
</t:entrada>
package blog.controller.admin;
import org.nextframework.controller.Controller;
import org.nextframework.controller.crud.*;
import blog.entity.Categoria;
@Controller(path=”/admin/crud/categoria”)
public class CategoriaCrud extends CrudController<FiltroListagem, Categoria,
Categoria>{
}
52
Agora, edite o arquivo menu.xml para adicionar um link ao seu
novo controller conforme Listagem 12. O cadastro de categoria está
pronto. Publique a aplicação no seu servidor e acesse através da URL
http://localhost:8080/blog/admin/crud/categoria. Sua aplicação deve
estar como na figura 3.
Já começamos a ter alguma funcionalidade na aplicação. Cadastre
algumas categorias para termos dados que possam ser utilizados nos
próximos cadastros.
Listagem 12. Menu do sistema.
<?xml version=”1.0” encoding=”ISO-8859-1”?>
<!DOCTYPE menugroup PUBLIC “//Next//Next Menu 1.0//EN” “http://www.
nextframework.org/dtd/menu.dtd”>
<menugroup>
<menu title=”Blog”>
<menu title=”Index” url=”/index.jsp” />
</menu>
<menu title=”Cadastro”>
<menu title=”Categoria” url=”/admin/crud/categoria” />
</menu>
</menugroup>
cessário implementar uma interface chamada File. Essa interface
apenas define getters e setters de propriedades que devem existir
na classe que a implementa. A classe que implementar a interface
File deve ser uma entidade normal do hibernate como mostrado
na Listagem 13 (os getters e setters que não têm peculiaridades
serão omitidos de agora em diante, para maior clareza do código).
Agora, na entidade Autor, basta criar uma propriedade do tipo
Arquivo, como mostrado na Listagem 14. Essa propriedade do
tipo Arquivo deve ser anotada com @ManyToOne, para indicar o
relacionamento entre as entidades.
Listagem 14. Classe Autor, com um relacionamento manyto-one para Arquivo.
package blog.entity;
import javax.persistence.*;
@Entity
public class Autor {
Long id;
String nome;
Arquivo foto;
@Id
@GeneratedValue
public Long getId() {
return id;
}
Figura 3. Tela de listagem de dados de Categoria.
Upload de arquivos
@ManyToOne
public Arquivo getFoto() {
return foto;
}
// getters e setters ...
Listagem 13. Classe Arquivo para permitir o upload de
arquivos na aplicação.
package blog.entity;
import javax.persistence.*;
import org.nextframework.types.File; //utilize a interface File do Next
@Entity
public class Arquivo implements File {
Long cdfile; //o atributo cdfile deve ser o primary key da entidade
byte[] content; //guarda os bytes do arquivo
String contenttype; //tipo do arquivo
String name; //nome do arquivo
Long size; //tamanho do arquivo
@Id
@GeneratedValue
public Long getCdfile() {
return cdfile;
}
// getters e setters
}
Para concluir o cadastro de Autor, basta criar o AutorDAO, AutorService e AutorCrud, exatamente como foi feito com a Categoria, apenas
mudando o tipo genérico de Categoria para Autor. O código dessas
classes poderá ser baixado no site da revista. Mude também o path
da anotação @Controller da classe AutorCrud para /admin/crud/autor. Crie também os JSPs /WEB-INF/jsp/admin/crud/autorListagem.
jsp e /WEB-INF/jsp/admin/crud/autorEntrada.jsp. Troque as tags
<t:property> para refletir as propriedades de Autor (id, nome e foto).
Não será necessário informar na tag <t:property> que se deseja um
componente de upload, o Next irá detectar o tipo da propriedade e fará
toda a configuração necessária. Se acessar a URL http://localhost:8080/
blog/admin/crud/autor, terá uma tela como mostrado na figura 4. Adicione uma entrada para a tela de autor ao menu da aplicação.
}
O cadastro de categoria foi um cadastro bem simples. Agora vamos
criar a entidade autor e um CRUD para ela. A entidade-autor irá
representar quem escreveu determinado tópico. O autor possuirá
uma foto e criaremos um sistema de upload de arquivos para satisfazer esse requisito. Para o upload de arquivos no Next, será ne-
Figura 4. Cadastro de autor, com componente de upload escolhido automaticamente.
53
: : www.mundoj.com.br : :
Com apenas a implementação de uma interface criamos um
upload de arquivos. Nenhum código ou tratamento especial foi
necessário, tudo é controlado pelo Next.
Listagem 16. Classe Comentario, com referência many-toone para a classe Topico.
package blog.entity;
Mapeamentos entre entidades
Já criamos as entidades Arquivo, que são utilizadas para uploads,
Autor e Categoria. Está faltando agora apenas duas entidades para
completarmos o nosso modelo: Topico e Comentario. A entidade
Topico possui um relacionamento “muitos-para-um” (many-toone) com Categoria e com Autor. Da mesma forma, a entidade
Comentario tem um relacionamento “muitos-para-um” (manyto-one) com Topico. No caso do relacionamento entre Topico e
Comentario, é interessante também mapearmos o lado oposto do
relacionamento, isto é, um Topico possui vários objetos Comentario, isso é um relacionamento “um-para-muitos” (one-to-many).
As entidades Topico e Comentario ficariam conforme Listagens 15
e 16, respectivamente.
import javax.persistence.*;
import java.util.Date;
@Entity
public class Comentario {
Long id;
String conteudo;
String autor;
Topico topico;
Date data = new Date();
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
public Long getId() {
return id;
}
@ManyToOne
public Topico getTopico() {
return topico;
}
Listagem 15. Classe Topico, com relacionamentos manyto-one e one-to-many.
package blog.entity;
}
import javax.persistence.*;
import java.util.*;
@Entity
public class Topico {
Long id;
String titulo;
Date data = new Date();
String conteudo;
Autor autor;
Categoria categoria;
List<Comentario> comentarios;
@Id
@GeneratedValue
public Long getId() {
return id;
}
@ManyToOne
public Categoria getCategoria() {
return categoria;
}
@ManyToOne
public Autor getAutor() {
return autor;
}
// como estamos mapeando a parte inversa do relacionamento
// utilizamos o atributo mappedBy
@OneToMany(mappedBy=”topico”)
public List<Comentario> getComentarios() {
return comentarios;
}
//outros getters e setters
}
54
As entidades estão completas, crie um DAO, um Service e um
CrudController para as novas entidades. Crie também o JSP de
listagem e entrada. Esses arquivos estão disponíveis no site da revista. Lembre-se de trocar os tipos genéricos e as tags <t:property>
para refletir as propriedades da entidade. Troque também as URLs
nos controllers. Nos JSPs de tópico não mapeie a propriedade
Comentarios, iremos fazer isso posteriormente. Se desejar, modifique também o arquivo de menu, para adicionar um link de
cadastro para cada tela.
Ajustando as descrições
Você deve ter percebido que o Next ajusta o input de acordo
com a necessidade. Por exemplo, em um campo do tipo Date, foi
colocado um input com formatação para datas. Em um campo
que era referência para outra entidade, foi colocado um combobox. Bem interessante não? Só que os combos não ficaram com
uma boa descrição, isso porque o Next fez um toString no objeto
resultando em algo como Topico@84BAf3. Para informar ao Next
qual propriedade deve ser mostrada nos combos, basta anotar o
getter da propriedade mais descritiva da entidade. Por exemplo,
a entidade Topico, seria interessante que fosse mostrado o Titulo.
Para isso, anote o getter da propriedade Titulo com a anotação @
DescriptionProperty, conforme mostrado na Listagem 17.
Listagem 17. Exemplo de utilização da anotação @DescriptionProperty.
@DescriptionProperty //marca essa propriedade como a que descreve o
objeto
public String getTitulo() {
return titulo;
}
Essa anotação informa ao Next que, sempre que desejar mostrar
algum tópico, use a propriedade Titulo. É sempre interessante ter
alguma propriedade na entidade com a anotação @DescriptionProperty. Nas entidades Autor e Categoria, coloque um @DescriptionProperty no método getNome. Agora o sistema irá mostrar mensagens mais descritivas para as entidades. Você também pode utilizar
a anotação @DisplayName para dar descrições as propriedades e
classes. Essa anotação também deve ser colocada no getter. No caso
da propriedade Titulo seria @DisplayName("Título"). Com isso, os
labels do sistema seriam atualizados com o nome correto.
qualquer propriedade dos beans apenas navegando na sua árvore
de propriedades. Agora, que já temos os dois combos, informamos ao Next que queremos filtrar os resultados de acordo com o
valor do combo pai utilizando a tag <n:comboReloadGroup>. O
resultado final ficará como na Listagem 19. Adicione também a
taglib next na primeira linha do JSP.
Listagem 19. Utilização de combos aninhados com AJAX.
<%@ taglib prefix=”n” uri=”next”%>
Validação
Para fazer a validação dos dados, são utilizadas algumas anotações.
Nesse tutorial mostraremos apenas a validação de campos obrigatórios. Na documentação da ferramenta, pode ser encontrada a
referência completa de validação.
Para colocar uma validação de campo obrigatório, utilizamos a anotação @Required do pacote org.nextframework.validation.annotation no getter da propriedade. Coloque uma anotação @Required
no getTitulo da classe Topico, conforme o exemplo da Listagem 18.
Listagem 18. Validação do campo título, como obrigatório.
@DescriptionProperty //marca essa propriedade como a que descreve o
objeto
@Required //valida essa propriedade como sendo obrigatória
public String getTitulo() {
return titulo;
}
O campo título agora é obrigatório, se tentar salvar um tópico sem
informar um título será feita uma validação Javascript conforme
a figura 5 e também uma validação no servidor, caso o Javascript
esteja desabilitado no cliente.
<n:comboReloadGroup>
<t:property name=”topico.categoria”/>
<t:property name=”topico”/>
</n:comboReloadGroup>
O Next irá verificar a dependência entre categoria e tópico e filtrar
os resultados automaticamente, utilizando AJAX. É possível colocar quantos combos aninhados desejar.
Mestre/detalhe
Nas entidades que definimos, temos um relacionamento de
agregação, em que um tópico possui vários comentários. Quando temos esse tipo de relacionamento, é interessante podermos
editar o tópico e seus comentários ao mesmo tempo. Esse tipo de
funcionalidade é chamada mestre/detalhe. No caso, o tópico será
o mestre e os comentários serão os detalhes. Podemos utilizar o
próprio CRUD de tópico e apenas adicionar a funcionalidade do
detalhe. Para adicionar o detalhe, basta que quando carregarmos
os tópicos carregarmos também os comentários. Ao salvar o tópico, salvamos também os comentários. Essa funcionalidade lida
com persistência, então colocamos no TopicoDAO. Adicione dois
métodos ao TopicoDAO como mostra a Listagem 20 (adicione
também os imports necessários).
Listagem 20. Métodos sobrescritos na classe TopicoDAO
para adicionar funcionalidades ao salvar e carregar tópicos.
public void updateEntradaQuery(QueryBuilder<Topico> query) {
// puxamos a coleção de comentários
Figura 5. Validação de campos no cliente.
query.fetchCollection(“comentarios”);
}
Campos como datas ou números ganham validação automática
para o tipo de dados. Não será possível inserir a data 32/02/2010,
por exemplo.
public void updateSaveOrUpdate(SaveOrUpdateStrategy save) {
Combos aninhados
}
É bastante comum no desenvolvimento de aplicações a utilização
de combos aninhados, em que o valor de um combo pai, filtra os
itens do combo filho. O Next possui uma tag especial que facilita
bastante a utilização desse tipo de funcionalidade.
Na tela de comentários (comentarioEntrada.jsp), podemos filtrar
os tópicos de acordo com a categoria. Você deve ter criado uma tag
<t:property name="topico"/> para colocar um combo de tópicos.
Antes dessa tag, coloque outra <t:property name="topico.categoria"/>, isso irá criar um combo de categoria. É possível mapear
//salvamos a coleção de comentários
save.saveOrUpdateManaged(“comentarios”);
O GenericDAO já possui alguns métodos para alterar a funcionalidade ao carregar e salvar itens. Iremos utilizar o updateEntradaQuery e o updateSaveOrUpdate. O updateEntradaQuery recebe
um objeto do tipo QueryBuilder, que já vem pré-configurado com
a query padrão para entrada de dados, então, basta adicionarmos
o código para "puxar" os detalhes. O updateSaveOrUpdate recebe
um SaveOrUpdateStrategy, que é um objeto onde são colocadas
várias operações de persistência. Essas operações são executadas
em conjunto dentro de uma transação. No SaveOrUpdateStrategy
iremos indicar que também queremos persistir os comentários.
55
: : www.mundoj.com.br : :
Para completar a funcionalidade de mestre detalhe, colocamos
uma tabela na tela de entrada de dados para adicionar, editar
ou remover os comentários. Existe uma tag <t:detalhe> que
cria uma tabela com as funcionalidades desejadas. Adicione ao
topicoEntrada.jsp imediatamente antes do fechamento da tag
</t:janelaEntrada> o código da Listagem 21.
Listagem 21. Código do topicoEntrada.jsp para mostrar o
detalhe de comentários para o tópico.
Agora que já possuímos o filtro, vamos atualizar o TopicoCrud
para usar o filtro criado. Modifique a declaração da classe TopicoCrud para ficar conforme a Listagem 23.
Listagem 23. Atualização da classe TopicoCrud para usar
o filtro TopicoFiltro.
public class TopicoCrud extends CrudController<TopicoFiltro, Topico, Topico>{}
<t:detalhe name=”comentarios”>
<t:property name=”id”/>
<t:property name=”data”/>
Listagem 24. Atualização da classe TopicoDAO para adicionar parâmetros à query de listagem de tópicos.
<t:property name=”autor”/>
<t:property name=”conteudo” cols=”30” rows=”2”/>
public void updateListagemQuery(QueryBuilder<Topico> query, FiltroListagem filtro) {
</t:detalhe>
TopicoFiltro topicoFiltro = (TopicoFiltro) filtro;
Agora podemos editar os comentários na tela de tópicos, conforme mostrado na figura 6.
query.where(“topico.categoria = ?”, topicoFiltro.getCategoria())
.whereLikeIgnoreAll(“topico.titulo”, topicoFiltro.getTitulo());
}
Assim como no updateEntradaQuery, basta atualizar o QueryBuilder
com as cláusulas desejadas. Para finalizar, devemos mostrar os campos
a serem filtrados na tela de listagem de dados de tópico. Atualize o
código do JSP topicoListagem.jsp, colocando o código mostrado na
Listagem 25 logo abaixo da abertura da tag <t:listagem>. Com isso, a
tela de tópicos possuirá campos para filtrar o resultado e um botão
de pesquisa.
Listagem 25. Código do filtro de tópicos.
Figura 6. Detalhe de comentários em tópico.
O CrudController é bastante genérico, e permite que independetemente da complexidade ou dos dados mostrados na tela, o seu
funcionamento continue o mesmo. Vimos isso no caso do upload, e
agora utilizando uma funcionalidade mestre/detalhe. Isso facilita para o
programador que não precisa escolher entre diversas implementações
diferentes. É possível ter quantos detalhes desejar na tela, basta carregar
e salvar os itens, e adicionar o código para montar a tabela de detalhes.
Filtrando os dados
Para finalizar o trabalho com o CRUD, vamos adicionar um filtro para
personalizar a consulta de tópicos. O filtro terá os campos categoria
e titulo. Um filtro para um CRUD deve estender de FiltroListagem.
Crie uma classe conforme a Listagem 22 para servir de filtro.
Listagem 22. Classe que será usada como filtro na listagem
de tópicos.
package blog.controller.admin.filtro;
import org.nextframework.controller.crud.FiltroListagem;
import blog.entity.Categoria;
public class TopicoFiltro extends FiltroListagem {
Categoria categoria;
String titulo;
//getters e setters
}
56
<t:janelaFiltro>
<t:tabelaFiltro>
<t:property name=”categoria”/>
<t:property name=”titulo”/>
</t:tabelaFiltro>
</t:janelaFiltro>
Caso de uso fora do padrão
A parte administrativa do blog está completa, vamos criar agora
a parte pública. Utilizaremos o módulo public configurado no
início do tutorial para fazer essa parte do sistema. Vamos criar um
controller que permitirá visualizar os tópicos e adicionar comentários. Precisaremos de um JSP para exibir essas informações. Crie
um controller chamado BlogController conforme a Listagem 26.
Listagem 26. Controller de propósito geral BlogController,
que irá receber as requisições da parte pública do blog.
package blog.controller.pub;
import org.nextframework.controller.Controller;
import org.nextframework.controller.MultiActionController;
@Controller(path=”/public/blog”)
public class BlogController extends MultiActionController {
}
O MultiActionController é um controller de propósito geral utilizado quando o caso de uso não encaixa em algum controller
como o CrudController. Para esse controller, configuramos o path
/public/blog.
Injeção de dependência
Para mostrar as informações dos tópicos e comentários, o BlogController precisará acessar as informações do banco de dados.
Nós já temos DAOs para a classe Topico e Comentario, portanto
vamos apenas injetar esses DAOs na classe BlogController. Para
realizar a injeção dessa dependência, basta criar um atributo do
tipo desejado e um setter para esse atributo. Crie atributos e setters para o TopicoDAO e ComentarioDAO, conforme a Listagem
27 na classe BlogController.
Listagem 27. Injeção de dependência de TopicoDAO e
ComentarioDAO.
TopicoDAO topicoDAO;
ComentarioDAO comentarioDAO;
Esse método irá colocar no escopo de requisição um atributo com
a lista de tópicos, e retornar para o JSP /WEB-INF/jsp/public/
blogPage.jsp. A anotação @DefaultAction indica que se nenhuma
ação for explicitamente requerida, o método index() deverá responder à requisição.
Exibindo informações na camada de visão
Crie um JSP na pasta /WEB-INF/jsp/public/ com o nome blogPage.
jsp. Nesse JSP, iremos mostrar as informações da lista de tópicos
configurada no controller. Adicione o conteúdo da Listagem 29
ao JSP.
Listagem 29. JSP blogPage.jsp que mostrará as informações
dos tópicos.
<%@ taglib prefix=”n” uri=”next”%>
<%@ taglib prefix=”t” uri=”template”%>
<n:dataGrid itens=”${listaTopicos}” itemType=”blog.entity.Topico” >
<n:column>
<n:link action=”verTopico” parameters=”id=${row.id}” class=”title”>
<t:property name=”titulo”/>
public void setComentarioDAO(ComentarioDAO comentarioDAO) {
this.comentarioDAO = comentarioDAO;
}
public void setTopicoDAO(TopicoDAO topicoDAO) {
this.topicoDAO = topicoDAO;
}
</n:link>
Postado em <t:property name=”data”/> por <t:property name=”autor”/>
<t:property name=”conteudo” class=”contents”/>
</n:column>
</n:dataGrid>
<n:link url=”/admin/crud/topico”>Administração do Blog</n:link>
Quando a aplicação for inicializada, o BlogController ganhará
uma instancia de TopicoDAO e ComentarioDAO configurados
para serem utilizados nos seus métodos.
Nesse momento, a URL http://localhost:8080/blog/public/blog
deve trazer uma página semelhante à página mostrada na figura 7.
Ações personalizadas
O MultiActionController, como o próprio nome diz, permite que
sejam criadas várias ações para esse controller. Uma ação nada
mais é do que um método que pode ser chamado pelo cliente.
A primeira ação que iremos criar irá buscar as informações dos
tópicos para listarmos na tela. Crie um método na classe BlogController conforme a Listagem 28.
Figura 7. Tela do blog com alguns tópicos cadastrados.
Listagem 28. Ação principal para o controller BlogController.
@DefaultAction
public String index(){
setAttribute(“listaTopicos”, topicoDAO.findAll());
return “blogPage”;
}
Redirecionamento para JSPs
Apesar de o método index da Listagem 26 retornar apenas
"blogPage", essa String será modificada para refletir qual JSP
será chamado. Como esse controller está no módulo public,
todos os seus JSPs devem ficar na pasta /WEB-INF/jsp/public.
O framework Next irá concatenar esse caminho + o nome do
jsp + .jsp e formar /WEB-INF/jsp/public/blogPage.jsp que é o
caminho completo da página a ser chamada.
Listagem 30. Ação verTopico para visualizar informações
específicas de determinado tópico.
public String verTopico(Topico topico){
setAttribute(“listaTopicos”, Arrays.asList(topicoDAO.loadForEntrada(topico)));
setAttribute(“mostrarComentarios”, true);
Comentario comentario = new Comentario();
comentario.setTopico(topico);
setAttribute(“comentario”, comentario);
return “blogPage”;
}
Nesse JSP utilizamos a tag <n:dataGrid> que define uma tabela
e a tag <n:column> para definir uma coluna. Os itens da tag
<n:dataGrid> estão no atributo listaTopicos, configurado anteriormente no controller. Dentro da coluna usamos a tag <n:link> que
57
: : www.mundoj.com.br : :
montará um link para o tópico. Mostramos também a data, autor e
conteúdo do tópico. Repare que na tag <n:link> existe um atributo action, esse atributo indica qual ação no controller desejamos
chamar ao clicar nesse link. Nesse link também estamos passando um parâmetro id, que é o id do tópico sendo interagido no
momento. Vamos criar um método verTopico no BlogController,
esse método receberá um Topico. O parâmetro id será mapeado a
propriedade id desse objeto Topico. Adicione o código conforme
a Listagem 30 na classe BlogController.
Listagem 31. Atualização do arquivo blogPage.jsp para
adicionar informações de comentários.
<n:panel rendered=”${mostrarComentarios}”>
<n:dataGrid property=”comentarios”>
<n:column>
<t:property name=”conteudo” mode=”output”/>
<p class=”author”>por <t:property name=”autor” mode=”output”/>
</p>
</n:column>
</n:dataGrid>
<n:form forBean=”comentario”>
<t:property name=”topico” type=”hidden” />
<n:panelGrid propertyRenderAsDouble=”true”>
<t:property name=”autor”/>
<t:property name=”conteudo” rows=”5” cols=”80” label=”Comentário”/>
<n:submit action=”comentar”>Enviar comentário</n:submit>
</n:panelGrid>
</n:form>
</n:panel>
A primeira linha do método verTopico coloca a listaTopicos no
escopo de requisição para ser utilizado no JSP (será uma lista com
apenas um item). O parâmetro Topico do método vem apenas
com o campo id configurado. Precisamos então carregar as outras
informações, que é feito pelo método loadForEntrada. Foi utilizado o loadForEntrada porque no DAO de tópicos esse método busca também os comentários do tópico. A segunda linha coloca um
flag indicando que devemos mostrar os comentários do tópico. As
linhas seguintes criam um comentário configurado com o tópico
em questão, esse comentário será utilizado num formulário. E
por fim redirecionamos para o blogPage.jsp que criamos anteriormente. Reaproveitamos o JSP, mas agora precisamos colocar
58
as informações relativas aos comentários dos tópicos, adicione o
código da Listagem 31 no arquivo blogPage.jsp logo após a tag
<t:property name="conteudo" class="contents"/>.
Utilizamos uma tag <n:dataGrid> para mostrar as informações
dos comentários do tópico. Logo abaixo um <n:form> criará um
formulário para o objeto comentario que está no escopo de requisição. Colocamos as propriedades que devem ser mostradas e um
<n:submit> que enviará o formulário para o controller na ação
comentar. Vamos adicionar a ação comentar ao BlogController
conforme a Listagem 32.
Listagem 32. Ação para o BlogController para adicionar
um comentário ao sistema.
public String comentar(Comentario comentario) {
comentarioDAO.saveOrUpdate(comentario);
Long idTopico = comentario.getTopico().getId();
return redirectToActionWithParams(“verTopico”, “id=”+idTopico);
}
Figura 8. Tela de comentários de tópico.
O método comentar recebe um comentário como parâmetro, salva
o comentário e depois redireciona para a ação verTopico passando
como parâmetro o id do tópico. Esse redirecionamento evitará que
seja duplicado o comentário em caso de o usuário pedir um reload
da página. Agora já será possível escrever comentários sobre os
tópicos como mostrado na figura 8.
A aplicação está completa. Vimos grande parte das funcionalidades requeridas para uma aplicação empresarial, como cadastros,
validação, AJAX etc. No site do framework você poderá buscar
mais informações. Experimente criar outro sistema com a ferramenta e os recursos que ela provê. Boa diversão!
Considerações finais
Como visto no tutorial, trabalhar com o Next é bastante simples.
Desenvolvemos uma aplicação completa com diversos recursos em
pouco tempo e sem burocracia. O Next é um framework construído
para facilitar o trabalho do programador. Seu projeto começou em
2005 e sua primeira versão open-source foi disponibilizada em 2007
com o nome de Neo. Em 2009 o framework teve uma reformulação
e passou a se chamar Next. Diversos sistemas já foram desenvolvidos com a ferramenta, e a maturidade e estabilidade do framework
possibilitam a sua utilização já em produção. O framework conta
com vantagens como baixa curva de aprendizado, menor custo de
desenvolvimento e principalmente de manutenção. Isso permite que
o tempo de treinamento na ferramenta seja reduzido, e sistemas produzidos com qualidade profissional em menos tempo. O Next conta
ainda com vários outros recursos que não couberam nesse tutorial.
Possui integração com a maioria das ferramentas existentes através do
Spring. Conta com tipos de dados como Money para trabalhar com
dados monetários, além dos tipos brasileiros CEP, CPF, CNPJ, todos
com máscara e formatação – não escreva frases sem verbos. Possui
um suporte bem simples para download de arquivos e controller especial para trabalhar com relatórios e integração com JasperReports.
Sistema de templates que permitem aplicações com "caras" e funcionalidades totalmente diferentes, mas a mesma forma de trabalho.
Toda essa facilidade e recursos disponíveis fazem com que o Next seja
VNBGPSUFGFSSBNFOUBEFUSBCBMIPt
Eu uso
Túlio Lucas da Silva e Cruz
([email protected]): Bacharel em Ciência da Computação,
tem 5 anos de experiência em desenvolvimento de sistemas em Java/
JavaEE, possui certificado SCJP 5.0 e especialização em Segurança
da Informação.
sem perder a essência de todo o processo de desenvolvimento.
Indico para todos os desenvolvedores independentemente do
nível, pois desde um usuário em nível iniciante até nível avançado podem usufruir de suas funcionalidades, em diferentes
contextos, de simples CRUDs a processos complexos. Acredito
que os pontos fortes do framework Next estão ligados à facilidade de configuração de uma aplicação e a produção de
fontes mais limpos e menos verbosos, já que são utilizadas as
anotações para as configurações, tanto nos beans de entidade,
como configurações dos controladores. O controle e a injeção
de dependência (obtidos através do Spring) também norteiam
e gerenciam o desenvolvedor. A facilidade em desenvolver
front-end, com a utilização de templates, fácil integração com
tecnologias relacionadas às interfaces ricas e tags customizadas
completam o framework.
Glauco Gonçalves Cardoso
([email protected]): Pós-graduado em Gerenciamento
Estratégico de Projetos. Bacharel em Ciências da Computação – SCJP
5. Atualmente trabalha como arquiteto de Sistemas para o Governo
do Estado de Minas Gerais na PRODEMGE.
Trabalho há mais de cinco anos com programação JEE e já
experimentei diversos frameworks que prometem “mundos
e fundos” para melhorar a vida do programador, contudo até
hoje não conheci nenhum outro que supere o Next no quesito
facilidade, simplicidade e rapidez. Sem geradores de código
é possível com poucas linhas construir CRUDS, relatórios,
chamadas AJAX, entre outros. Em minutos, consigo fazer um
upload de arquivos que em outros frameworks "top de linha"
gasto horas.
Utilizei o Next em um projeto grande da Universidade FUMEC e o seu uso garantiu que pudéssemos diminuir consideravelmente o tempo de entrega do sistema. Era comum nessa
empresa que trabalhei, os desenvolvedores não quererem
trabalhar com projetos que não usavam o Next. Em minha
opinião, o Next facilita tanto a vida do programador que nos
sentimos mais motivados ao trabalhar com a ferramenta.
Trabalho com o framework Next em vários projetos sob a
plataforma J2EE, sempre obtendo uma boa produtividade e
59
Download

Next Framework – Produtividade com Java EE