A Primeira Aplicação
Esse capítulo é apenas uma introdução ao desenvolvimento com o Neo.
Nele iremos construir uma aplicação simples, mostrando algumas funcionalidades
para você se sentir familiarizado. Uma explicação mais detalhada será feita nos
próximos capítulos. A documentação será voltada
à aplicações J2EE, uma vez que este é o foco principal do framework.
Apesar desta especialidade, também é possível utilizar o Neo em aplicações desktop.
Hello World!
A aplicação que iremos construir será um cadastro de mensagens.
Será utilizado envio de formulários, navegação e alguns componentes visuais do Neo.
Essa aplicação será dividida em 3 etapas:
- Criação de um controller e um JSP com a mensagem 'Hello World'
- Criação de novas ações para o controler, entradas de dados no JSP e
utilização de um modelo de dados
- Injeção de dependencias
Estrutura da aplicação
Antes de iniciar o desenvolvimento, faça o download do Neo
no site
http://www.neoframework.org/downloads.
Crie uma aplicação J2EE e adicione os jars no lib da aplicação conforme a estrutura abaixo:
Imagem 1 - Estrutura inicial de arquivos e diretórios
Essa é a configuração mínima necessária para rodar os exemplos do capítulo 2. Para uma aplicação
completa copie todos os arquivos JAR do NEO para a aplicação.
Configuração do web.xml
Configure o web.xml da seguinte forma:
[JSP]
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
[ATTR]http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<listener>
<listener-class>br.com.linkcom.neo.core.web.init.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>modulo</servlet-name>
<servlet-class>br.com.linkcom.neo.controller.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>modulo</servlet-name>
<url-pattern>/modulo/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>resourceServlet</servlet-name>
<servlet-class>br.com.linkcom.neo.view.ResourceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>resourceServlet</servlet-name>
<url-pattern>/resource/*</url-pattern>
</servlet-mapping>
</web-app>
-
ContextLoaderListener
(linhas 8 - 10)
Listener que configura o contexto do Neo fazendo as iniciaizações necessárias.
-
DispatcherServlet
(linhas 12 - 19)
Servlet responsável pelo controle das requisiões e registro dos controllers da aplicação.
-
ResourceServlet
(linhas 21 - 28)
Fornece alguns recursos para a aplicação. Como arquivos de estilo e javascript.
A única configuração de arquivo XML para a utilização do NEO é do web.xml. Uma vez configurado não será
mais necessário a sua modificação. Depois de configurar o web.xml e com os arquivos JAR dentro do lib, a aplicação já está funcionando.
Ela ainda não possui nenhuma funcionalidade, mas, através do log do servidor, já é possível verificar que o NEO está ativo.
Criação do Controller
Para adicionar alguma funcionalidade a aplicação precisaremos criar uma classe que chamamos de controller.
Um controller é o responsável por receber as requisições do cliente e executar alguma funcionalidade.
Crie uma classe conforme o exemplo:
package controller;
import org.springframework.web.servlet.ModelAndView;
import br.com.linkcom.neo.controller.Controller;
import br.com.linkcom.neo.controller.DefaultAction;
import br.com.linkcom.neo.controller.MultiActionController;
import br.com.linkcom.neo.core.web.WebRequestContext;
@Controller(path="/modulo/exemplo")
public class MensagemController extends MultiActionController {
@DefaultAction
public ModelAndView executar(WebRequestContext request){
return new ModelAndView("pagina");
}
}
-
@Controller(path="/modulo/exemplo")
(linha 10)
Registra essa classe como um Controller que responderá pela url /modulo/exemplo .
-
@DefaultAction
(linha 13)
Registra um determinado método como o padrão para receber as requisições.
-
public ModelAndView executar(WebRequestContext context)
(linha 14)
Para responder à uma requisição, um método deve possuir um
parâmetro do tipo WebRequestContext e ter o tipo de retorno ModelAndView ou void.
-
new ModelAndView("pagina")
(linha 15)
Representa o JSP para onde o controller enviará a requisição.
O caminho completo do JSP será /WEB-INF/jsp/modulo/pagina.jsp
A URL declarada no path do @Controller deve iniciar com o módulo onde essa
classe deve ser registrada, nesse caso /modulo (o mesmo configurado no web.xml).
Esse controller possui o método executar que será o método padrão para responder as requisições.
Voce verá mais adiante que um mesmo controller pode ter vários métodos para responder as requisições.
Isso possibilida que códigos que fazem parte do mesmo conceito fiquem dentro da mesma classe.
Não é necessário declarar nenhuma configuração em arquivos XML. O NEO detecta as classes e faz
a configuração automaticamente.
Criação do JSP
Crie um JSP com o nome pagina.jsp no diretório /WEB-INF/jsp/modulo/.
[JSP]
<html>
<body>
Hello World!!
</body>
</html>
Resumo
Agora já é possível verificar alguma funcionalidade. Publique a aplicação e ligue o servidor. Ao pedir no browser
http://localhost:8080/Capitulo2/modulo/exemplo
(troque http://localhost:8080/Capitulo2 pela configuração do seu servidor e aplicação),
uma requisição chegará ao controller que criamos. O controller, por sua vez, encaminhará a requisição para o JSP
exibindo no browser a mensagem Hello World!
Imagem 2 - Amarração entre os nomes definidos
Fluxo
Agora que já temos um controller, vamos adicionar alguma navegação e um modelo de dados. Nessa etapa, o usuário irá
digitar uma mensagem e enviar para o servidor. No servidor, o controller vai receberá a mensagem e mostrará através do JSP.
Modelo de dados
O primeiro passo para o aperfeiçoamento da nossa aplicação é criar uma classe para representar os dados.
Essa classe servirá para guardar uma mensagem e a data de envio. Crie uma classe na aplicação conforme o exemplo:
package bean;
import java.util.Date;
public class Mensagem {
private String texto;
private Date data;
public Date getData() {
return data;
}
public void setData(Date data) {
this.data = data;
}
public String getTexto() {
return texto;
}
public void setTexto(String texto) {
this.texto = texto;
}
}
Adicionando ações a controllers existentes
O controller criado na seção 2.1 apenas redireciona para o JSP. Precisamos de uma nova ação
para receber a mensagem do cliente. Não será necessário criar outro controller para isso.
Devemos apenas alterar o controller já existente:
package controller;
import org.springframework.web.servlet.ModelAndView;
import bean.Mensagem;
import br.com.linkcom.neo.controller.Controller;
import br.com.linkcom.neo.controller.DefaultAction;
import br.com.linkcom.neo.controller.MultiActionController;
import br.com.linkcom.neo.core.web.WebRequestContext;
@Controller(path="/modulo/exemplo")
public class MensagemController extends MultiActionController {
@DefaultAction
public ModelAndView executar(WebRequestContext request){
return new ModelAndView("pagina");
}
public ModelAndView receberMensagem(WebRequestContext request, Mensagem mensagem){
return new ModelAndView("pagina", "mensagem", mensagem.getTexto());
}
}
Adicionamos ao código as linhas 19, 20 e 21.
O método que criamos recebe um parâmetro mensagem. O atributo texto de mensagem irá conter o texto que o usuário digitar.
O NEO mapeia os parâmetros da requisição a esse bean. Ou seja, se chegar um parâmetro na requisição com o nome 'texto', o valor desse atributo será
configurado no bean mensagem e será possivel verificar esse valor através do método getTexto().
Utilizamos um outro construtor de ModelAndView que recebe 3 parâmetros. Esse construtor recebe no primeiro parâmetro
a página para onde deve ser encaminhada a requisição. O segundo parâmetro é o nome, no escopo de requisição, que
desejamos que o modelo seja salvo. O terceiro parâmetro é o modelo. Poderiamos ter substituido esse construtor pelo
código abaixo que o resultado seria o mesmo.
request.setAttribute("mensagem", mensagem.getTexto());
return new ModelAndView("pagina");
Alterando o JSP
O controller já está pronto para receber as mensagens que o usuário digitar, precisamos agora, alterar o JSP.
Modifique o arquivo pagina.jsp que está em /WEB-INF/jsp/modulo/ para ficar como o exemplo:
[JSP]
<%@taglib uri="neo" prefix="n"%>
<html>
<body>
Hello World!!
<n:form>
<n:input type="text" name="texto"/>
<n:submit action="receberMensagem">Adicionar</n:submit>
<BR>
Mensagem recebida: ${mensagem}
</n:form>
</body>
</html>
-
<%@taglib uri="neo" prefix="n"%>
(linha 1)
Importa a taglib do NEO
-
<n:form> ... </n:form>
(linha 6 e 11)
Cria um formulário HTML.
-
<n:input type="text" name="texto"/>
(linha 7)
Cria um input HTML com o nome 'texto'. O valor desse input
será mapeado no atributo texto no bean do controller.
-
<n:submit action="receberMensagem"> Adicionar </n:submit>
(linha 8)
Cria um botão submit que irá enviar para a ação 'receberMensagem'.
A ação 'receberMensagem' é o método receberMensagem que criamos no controller.
-
Mensagem recebida: ${mensagem}
(linha 10)
Imprime a última mensagem recebida pelo controller.
Organizando o layout
O Neo possui algumas tags que facilitam a organização dos componentes em uma página JSP. Veja o exemplo:
[JSP]
<%@taglib uri="neo" prefix="n"%>
<html>
<body>
<n:form>
<n:panelGrid columns="2" width="400px" align="center">
<n:panel style="font-weight:bold" colspan="2">Hello World!!</n:panel>
<n:input type="text" name="texto" style="width:350px"/>
<n:submit action="receberMensagem">Adicionar</n:submit>
<n:panel colspan="2">Mensagem recebida: ${mensagem}</n:panel>
</n:panelGrid>
</n:form>
</body>
</html>
A tag panelGrid cria uma tabela com 400 pixels, 2 colunas e alinhada ao centro.
Não é necessário criar as tags TR. O panelGrid
automaticamente detecta o final da linha, e faz a quebra de acordo com as colunas.
Os componentes são colocados cada um dentro de um TD.
Resumo
A aplicação agora já é capaz de interagir com o usuário. Foram mostradas algumas tags do Neo e um controller
com várias ações.
Integrando recursos
Uma aplicação real possui várias partes que integram entre si. O NEO utiliza dependency injection para
integrar essas partes. É criado um contexto onde os objetos são criados e depois as dependencias
são satisfeitas. Todos os controllers já são incluidos nesse contexto.
Nessa etapa, criaremos uma classe para gerenciar as mensagens que o usuário enviar. O controller que recebe as mensagens
irá utilizar esse gerenciador para controlar as mensagens.
Beans gerenciados
No NEO existem dois tipos de beans: beans gerenciados e não gerênciados. Os não gerenciados não tem nenhum
comportamento especial. Os gerenciados são construidos e destruidos pelo NEO. Para um bean ser gerenciado
pelo NEO a sua classe deve ser anotada com @Bean. Algumas classes eliminam a necessidade dessa anotação. É
o caso dos controllers. O NEO detecta a dependência entre essas classes e faz a configuração.
Uma explicação mais detalhada será feita nos capitulos futuros.
Para nossa aplicação iremos criar uma classe para gerenciar as mensagens do usuário. Crie uma classe conforme o exemplo:
package gerencia;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import bean.Mensagem;
import br.com.linkcom.neo.bean.annotation.Bean;
@Bean
public class GerenciadorMensagem {
List<Mensagem> mensagens = new ArrayList<Mensagem>();
public List<Mensagem> getMensagens() {
return mensagens;
}
public boolean adicionarMensagem(Mensagem mensagem) {
mensagem.setData(new Date());
return mensagens.add(mensagem);
}
}
Essa classe possui uma lista que irá conter as mensagens que o usuário enviar.
O método getMensagens() retorna essa lista. E
o método adicionarMensagem(...) adiciona uma nova mensagem na lista com a data de inserção. Como
essa classe possui a anotação @Bean, será gerenciada pelo NEO.
Injeção de dependencia
Precisamos agora alterar o nosso controller para utilizar o gerenciador de mensagens.
package controller;
import gerencia.GerenciadorMensagem;
import org.springframework.web.servlet.ModelAndView;
import bean.Mensagem;
import br.com.linkcom.neo.controller.Controller;
import br.com.linkcom.neo.controller.DefaultAction;
import br.com.linkcom.neo.controller.MultiActionController;
import br.com.linkcom.neo.core.web.WebRequestContext;
@Controller(path="/modulo/exemplo")
public class MensagemController extends MultiActionController {
private GerenciadorMensagem gerenciadorMensagem;
public void setGerenciadorMensagem(GerenciadorMensagem gerenciadorMensagem) {
this.gerenciadorMensagem = gerenciadorMensagem;
}
@DefaultAction
public ModelAndView executar(WebRequestContext request){
return new ModelAndView("pagina", "lista", gerenciadorMensagem.getMensagens());
}
public ModelAndView receberMensagem(WebRequestContext request, Mensagem mensagem){
gerenciadorMensagem.adicionarMensagem(mensagem);
return executar(request);
}
}
O controller agora possui um gerenciadorMensagem. O NEO detecta que o
gerenciadorMensagem é um bean gerenciado, ele então cria um objeto da
classe GerenciadorMensagem e chama o método
setGerenciadorMensagem(...) no controller.
Dentro dos métodos do controller, é possível, utilizar o atributo gerenciadorMensagem.
Toda vez que um bean gerenciado tiver um setter para um outro bean gerenciado o NEO irá satisfazer
a dependencia automaticamente. Cada bean é criado apenas uma vez por aplicação.
Alteramos o método receberMensagem(...) para utilizar o gerenciadorMensagem
e depois repassar para o método executar(...). O método executar(...)
colocará no escopo a lista de mensagens do gerenciadorMensagem. E então
a requisição será enviada para o JSP.
Alterando o JSP
Atualmente o JSP mostra apenas a útlima mensagem enviada. Como agora precisamos mostrar várias mensagens, o
JSP deve ser novamente alterado.
[JSP]
<%@taglib uri="neo" prefix="n"%>
<%@taglib uri="template" prefix="t"%>
<html>
<body>
<n:form>
<n:panelGrid columns="2" width="400px" align="center">
<n:panel style="font-weight:bold" colspan="2">Hello World!!</n:panel>
<n:input type="text" name="texto" style="width:350px"/>
<n:submit action="receberMensagem">Adicionar</n:submit>
<n:dataGrid itens="${lista}" itemType="bean.Mensagem" panelcolspan="2" style="border: 1px solid gray">
<t:property name="texto"/>
<t:property name="data" headerStyle="width:80px"/>
</n:dataGrid>
</n:panelGrid>
</n:form>
</body>
</html>
-
<%@taglib uri="template" prefix="t"%>
(linha 2)
Importa a taglib do NEO
-
<n:dataGrid...> ... </n:dataGrid>
(linha 13 e 16)
A tag dataGrid monta uma tabela para exibir dados
-
<t:property.../>
(linha 14 e 15)
A tag property é uma tag dinamica que renderiza o HTML dependendo
do contexto onde ela está inserida. Como ela está dentro de uma tag dataGrid cada proprerty
representará uma coluna.
A aplicação agora já controla várias mensagens. Os componentes estão organizados na tela, mas não possuem
um estilo. O NEO vem com um estilo padrão, que depois pode ser alterado pelo usuário. Para utilizar o estilo
padrão adicione uma tag head no JSP conforme o exemplo:
[JSP]
<%@taglib uri="neo" prefix="n"%>
<%@taglib uri="template" prefix="t"%>
<html>
<head>
<n:head/>
</head>
<body>
<n:form>
<n:panelGrid columns="2" width="400px" align="center">
<n:panel style="font-weight:bold" colspan="2">Hello World!!</n:panel>
<n:input type="text" name="texto" style="width: 350px"/>
<n:submit action="receberMensagem">Adicionar</n:submit>
<n:dataGrid itens="${lista}" itemType="bean.Mensagem" panelcolspan="2" style="border: 1px solid gray">
<t:property name="texto"/>
<t:property name="data" headerStyle="width: 80px"/>
</n:dataGrid>
</n:panelGrid>
</n:form>
</body>
</html>
A tag n:head adiciona vários imports (css, javascript) necessários do NEO.
Resumo
Chegamos ao fim da primeira aplicação. Nesse capítulo foi possível ver como o NEO utiliza anotações,
ao invés de XML, para fazer a configuração da aplicação. Vimos também que um controller pode ter
várias ações, o que permite que códigos relacionados fiquem na mesma classe. Algumas das tags e a
aplicação de um estilo para o site foram utilizados.
Uma das formas que o NEO facilita o desenvolvimento de aplicações é a diminuição de arquivos necessários.
Não utilizamos XML e precisamos de apenas um controller para implementar funcionalidades relacionadas. O NEO
mapeia automaticamente os parâmetros da requisição para um objeto que for argumento de uma ação do
controller.