: : 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