Struts Aplicação de exemplo [email protected] Aplicação de exemplo • Vamos criar uma aplicação para ver os principais componentes do Struts • Não faremos acesso ao banco de dados, mas veremos as entradas onde ele pode ser usado • Veremos algumas das melhores técnicas para gerenciar o emaranhado de classes, arquivos de configuração e lib’s de todo projeto java Primeiros passos • • • • • • • • Crie a estrutura de diretórios para o projeto Escreva o web.xml Escreva o struts-config.xml Escreva as classes ActionForm Escreva as classes Action Crie o arquivo de mensagens Escreva as páginas JSP Instale e teste sua aplicação AloMundo • Vamos criar um projeto chamado AloMundo • Crie uma pasta chamada lib e copie nela todas as nossas bibliotecas • registre-as: botão direito -> Build Path -> Add to Build Path • No fim de tudo, teremos algo parecido com a imagem ao lado AloMundo • Contém as classes de formulário, actions e as lib’s do Struts • Nesse projeto teremos o processamento das requisições, forwards e arquivos de mensagens* • Representa o Model e o Controller do MVC • Não é interessante ter regras de negócio aqui, mas esse é um assunto para outro curso Propriedades • Botão direito no projeto -> Properties • Guia Libraries • Botão Add Variable Nova variável • Clique no botão Extend... Lib do Tomcat • Vamos adicionar algumas lib’s do Tomcat • As classes do Struts precisam dessas bibliotecas • Precisamos adicionar o commons-el, jsp-api e servlet-api Agora, a parte web • Vamos criar mais um projeto, dessa vez será o AloMundoWeb • Aqui teremos as páginas web, folhas de estilo, arquivos de configuração e taglib’s • Representa a parte View do MVC • Copie as taglib’s para o diretório informado na imagem ao lado • A imagem ao lado é do projeto no seu final web.xml • Arquivo de configuração da aplicação web • Esse arquivo segue a especificação da Sun • Não é um arquivo de configuração do Struts propriamente dito • Declara o servlet de controle do Struts, bem com suas taglib’s web.xml <?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN“ "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <display-name>Alo Mundo - Struts</display-name> <servlet> <servlet-name>action</servlet-name> <servlet-class> org.apache.struts.action.ActionServlet </servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> web.xml <!-- Standard Action Servlet Mapping --> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <taglib> <taglib-uri>/tags/struts-bean</taglib-uri> <taglib-location>/WEB-INF/lib/struts-bean.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-html</taglib-uri> <taglib-location>/WEB-INF/lib/struts-html.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-logic</taglib-uri> <taglib-location>/WEB-INF/lib/struts-logic.tld</taglib-location> </taglib> </web-app> struts-config.xml • Principal arquivo de configuração do Struts • Essa é sua primeira versão, onde iremos apenas mostrar a página de boas-vindas da aplicação struts-config.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd"> <struts-config> <action-mappings> <action path="/BemVindo" forward="/BemVindo.jsp" /> </action-mappings> </struts-config> struts-config.xml • A parte importante aqui é essa: – <action path="/BemVindo“ forward="/BemVindo.jsp" /> • O path é o caminho referenciado pelo browser, com o sufixo “.do” • O Struts irá abrir a página BemVindo.jsp index.jsp <body onLoad="window.location='BemVindo.do';"> Cont. • Artifício de programação HTML para redirecionar a aplicação para a página inicial BemVindo.jsp <%@ page language="java" contentType="text/html; charset=UTF-8"%> <%@ taglib uri="/tags/struts-html" prefix="html"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>.: Bem-Vindo :.</title> <link rel="stylesheet" href="css/Estilo.css" type="text/css" /> </head> <body> <table width=90% height=90%> <tr> <td align=center> <table border> <tr> <td align=center>Esta é sua primeira aplicação Struts! <p><html:link href="TelaDeLogin.do">Tela de login</html:link> <p><html:image src="imagens/ar_design.gif" /> </tr> </table> </td> </tr> </table> </html> Tags • struts-html: importa as taglibs com controles html • Exemplos: – html:link – tag para montar um link – html:image – tag para mostrar uma imagem Para acessar a aplicação • http://localhost:8080/alomundo • A url acima irá acessar a página index.jsp que irá redirecionar a aplicação para BemVindo.do • A partir desse momento o controller do Struts estará controlando a aplicação Atenção • A imagem está no link http://marcoreis.net/imagens/ar_design.gif • A folha de estilo também: http://marcoreis.net/css/Estilo.css • Todos os demais arquivos seguem o mesmo princípio Próxima fase • Agora, vamos aumentar a complexidade da nossa aplicação, adicionando mais alguns mapeamentos e arquivos MessageResources.properties # login.nome=Nome: login.senha=Senha: # errors.header=<table><tr><td>Erros no formulário</td></tr> errors.login.nome=<tr><td>Nome é obrigatório</td></tr> errors.login.senha=<tr><td>Senha incorreta</td></tr> errors.footer=</table> Mensagens • Podemos associar uma chave com uma palavra/frase • errors.header e errors.footer fazem parte de um padrão, representam o cabeçalho e rodapé da área de erros UsuarioForm package com.alomundo; import org.apache.struts.action.*; public class UsuarioForm extends ActionForm { private String nome; private String senha; public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public String getSenha() { return senha; } public void setSenha(String senha) { this.senha = senha; } } UsuarioForm • O formulário de login propriamente dito • Deve ter um atributo para campo da tela • Os valores serão preenchidos automaticamente pelo Controller • Cada tela terá seu próprio formulário struts-config.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd"> <struts-config> <form-beans> <form-bean name="usuarioForm" type="com.alomundo.UsuarioForm"></form-bean> </form-beans> <action-mappings> <action path="/BemVindo" forward="/BemVindo.jsp" /> <action path="/TelaDeLogin" forward="/TelaDeLogin.jsp" /> <action path="/EfetuarLogin" name="usuarioForm“ type="com.alomundo.LoginAction" attribute="usuario"> <forward name="Sucesso" path="/PaginaPrincipal.jsp" /> </action> </action-mappings> <message-resources parameter="MessageResources" /> </struts-config> Variáveis de sessão • <form-beans> – Todos os formulários da sua aplicação devem estar registrados – Dessa maneira o framework pode mapear o conteúdo dos campos de sua página para os atributos de sua classe Nova versão do EfetuarLogin • Esse bloco de código representa uma ação típica de uma aplicação Struts • O Struts cria uma variável de sessão do tipo UsuarioForm chamada usuario e mapeia nela os campos da página • Os nomes dos campos da página e do bean devem ser iguais <action path="/EfetuarLogin" name="usuarioForm" type="com.alomundo.LoginAction" attribute="usuario"> TelaDeLogin.jsp <%@ page language="java" contentType="text/html; charset=UTF-8"%> <%@ taglib uri="/tags/struts-html" prefix="html"%> <%@ taglib uri="/tags/struts-bean" prefix="bean"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>.: Login :.</title> <link rel="stylesheet" href="css/Estilo.css" type="text/css" /> </head> <body> <table width=90% height=90%> <tr> <td align=center> <table width=50% border> <tr> <td> <table width=100%> <html:form action="/EfetuarLogin"> <tr> <td colspan=2><html:errors /> TelaDeLogin.jsp <tr> <td><bean:message key="login.nome" /></td> <td><html:text property="nome" name="usuario" /></td> </tr> <tr> <td><bean:message key="login.senha" /></td> <td><html:password property="senha" name="usuario" /></td> </tr> <tr> <td colspan=2 align=center><html:submit value="Entrar" /></td> </tr> <tr> <td colspan=2 align=center><html:image src="imagens/cup.gif" /></td> </tr> </html:form> </table> </td> </tr> </table> </td> </tr> </table> </body> </html> TelaDeLogin.jsp • struts-bean: taglibs para manipulação de beans • html:errors – mostra as mensagens de erro que se aplicam para essa página • html:text/password – faz a ligação entre uma caixa de texto e uma propriedade do bean (no caso, usuario) • bean:message – recupera uma mensagem do arquivo de mensagens PaginaPrincipal.jsp <%@ taglib uri="/tags/struts-bean" prefix="bean"%> <%@ taglib uri="/tags/struts-html" prefix="html"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>.: Alô Mundo - Struts :.</title> <link rel="stylesheet" href="css/Estilo.css" type="text/css" /> </head> <body> <table width=90% height=90%> <tr> <td align=center> <table border> <tr> <td align=center>Bem-Vindo ao sistema, <bean:write name="usuario" property="nome" /> <p><html:link href="BemVindo.do">Página Inicial</html:link> <p><html:image src="imagens/T4.gif" /></p> </td> </tr> </table> </td> </tr> </table> </html> Acesso a beans • Lembra que temos a variável de sessão usuario preenchida com os valores informados na página? • Esse é o momento de acessá-la • No trecho seguinte estamos escrevendo na tela a propriedade nome do bean usuario <bean:write name="usuario" property="nome" /> LoginAction package com.alomundo; import javax.servlet.http.*; import org.apache.struts.action.*; public class LoginAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { UsuarioForm f = (UsuarioForm) form; System.out.println("Dados fornecidos pelo usuário:"); System.out.println("Nome:" + f.getNome()); System.out.println("Senha: " + f.getSenha()); return mapping.findForward("Sucesso"); } } LoginAction • O Controller executa o método execute • A variável f (UsuarioForm) já foi preenchida com os valores da tela • A classe irá direcionar a aplicação para o mapeamento Sucesso (veja no strutsconfig) • Poderíamos direcionar para outro lugar se o usuário não fosse validado Versão final • Nossa aplicação conhecerá agora alguns novos recursos • Atenção para os conceitos • Não é o momento de entender todos os detalhes do Struts DAOUsuario package com.alomundo; public class DAOUsuario { public boolean validaUsuario(String nome, String senha) { if (senha.equals("senha")) { return true; } return false; } } DAOUsuario • Classe responsável pelo acesso a dados • Nessa nossa implementação não faz quase nada, apenas valida o usuário com uma senha já definida • Uma versão completa será discutida posteriormente LoginAction public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { UsuarioForm f = (UsuarioForm) form; DAOUsuario dao = new DAOUsuario(); if (dao.validaUsuario(f.getNome(), f.getSenha())) { return mapping.findForward("Sucesso"); } else { ActionErrors e = new ActionErrors(); e.add("senha", new ActionMessage("errors.login.senha")); saveErrors(request, e); return new ActionForward(mapping.getInput()); } } LoginAction • Atualize o método execute • Se não conseguir validar o usuário, preenche a variável errors com uma mensagem padrão do arquivo MessageResources • Para voltar à mesma página mostrando a mensagem de erro utilizamos o bloco de código return new ActionForward(mapping.getInput()); UsuarioForm public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = new ActionErrors(); if (nome.equals("")) { errors.add("nome", new ActionMessage("errors.login.nome")); } return errors; } UsuarioForm • Adicione esse método • Implementação padrão para validação • Se o usuário não informar o nome adicionamos uma mensagem de erro do arquivo ResourceMessages struts-config.xml <action path="/EfetuarLogin" name="usuarioForm" type="com.alomundo.LoginAction" attribute="usuario" validate="true" input="/TelaDeLogin.jsp"> <forward name="Sucesso" path="/PaginaPrincipal.jsp" /> </action> struts-config.xml • Atualize a ação EfetuarLogin • validate=“true” diz que esse formulário (UsuarioForm) deve passar pelo método validate() para essa ação • O input indica a página que será aberta no caso do formulário não ser validado Versão final • Vamos acrescentar a rotina de logout e uma mensagem para verificar se o usuário já está autorizado LoginAction } else { ActionErrors e = new ActionErrors(); e.add("senha", new ActionMessage("errors.login.senha")); saveErrors(request, e); request.getSession().removeAttribute("usuario"); return new ActionForward(mapping.getInput()); } LoginAction • Em caso de erro, precisamos remover a variável usuario da sessão LogoutAction package com.alomundo; import javax.servlet.http.*; import org.apache.struts.action.*; public class LogoutAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { request.getSession().removeAttribute("usuario"); return mapping.findForward("Sucesso"); } } LogoutAction • Quando o usuário clicar no link Sair do sistema também removemos o bean da sessão UsuarioForm if (nome.equals("")) { errors.add("nome", new ActionMessage("errors.login.nome")); request.getSession().removeAttribute("usuario"); } UsuarioForm • Mais uma vez, se houver algum erro na validação, removemos a variável da sessão struts-config.xml <action path="/EfetuarLogout“ type="com.alomundo.LogoutAction" validate="false"> <forward name="Sucesso" path="/BemVindo.jsp" /> </action> struts-config.xml • Quando o usuário estiver saindo do sistema não é necessário validar o formulário • O default é true, por isso precisamos mudálo para false TelaDeLogin.jsp <%@ page language="java" contentType="text/html; charset=UTF-8"%> <%@ taglib uri="/tags/struts-html" prefix="html"%> <%@ taglib uri="/tags/struts-bean" prefix="bean"%> <%@ taglib uri="/tags/struts-logic" prefix="logic"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>.: Login :.</title> <link rel="stylesheet" href="css/Estilo.css" type="text/css" /> </head> <body> <table width=90% height=90%> <tr> <td align=center> <table width=50% border> <tr> <td colspan=2><html:errors /> <tr> <td> <table width=100%> TelaDeLogin.jsp <logic:present name="usuario"> <tr> <td>Você já está autorizado, <bean:write name="usuario" property="nome" /></td> </tr> <tr> <td><html:link action="/EfetuarLogout">Sair do Sistema</html:link></td> </tr> <tr> <td><html:link action="/EfetuarLogin">Entrar no Sistema</html:link></td> </tr> </logic:present> TelaDeLogin.jsp <logic:notPresent name="usuario"> <html:form action="/EfetuarLogin"> <tr> <td><bean:message key="login.nome" /></td> <td><html:text property="nome" name="usuario" /></td> </tr> <tr> <td><bean:message key="login.senha" /></td> <td><html:password property="senha" name="usuario" /></td> </tr> <tr> <td colspan=2 align=center><html:submit value="Entrar" /></td> </tr> <tr> <td colspan=2 align=center><html:image src="imagens/cup.gif" /></td> </tr> </html:form> </logic:notPresent> TelaDeLogin.jsp </table> </td> </tr> </table> </td> </tr> </table> </body> </html> Tags lógicas • logic:present – verifica se o bean usuario está carregado na sessão • O bloco dentro dessa tag só aparecerá se o bean for diferente de null • Ou seja, se o usuário já tiver acessado o sistema, mostramos apenas uma mensagem para ele e dando a opção de ir para a página inicial ou sair Tags lógicas • logic:notPresent – esse bloco será mostrado se o bean não estiver carregado • Nesse caso, mostramos a tela de login Exercício • Vamos criar um cadastro de pessoas • Os atributos do ActionForm são nome, endereço, telefone e cpf, todos do tipo String • Na página principal, vamos acrescentar um link para esse cadastro PessoaForm package com.alomundo; import org.apache.struts.action.*; public class PessoaForm extends ActionForm { private String nome; private String endereco; private String telefone; private String cpf; public String getCpf() { return cpf; } public void setCpf(String cpf) { this.cpf = cpf; } PessoaForm } public String getEndereco() { return endereco; } public void setEndereco(String endereco) { this.endereco = endereco; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public String getTelefone() { return telefone; } public void setTelefone(String telefone) { this.telefone = telefone; } Formulário • Nenhuma novidade nesse formulário, não é? MessageResources # pessoa.nome=Nome: pessoa.endereco=Endereço: pessoa.telefone=Telefone: pessoa.cpf=CPF: Mais mensagens • Vamos acrescentar mais essas mensagens ao nosso arquivo ResourceMessages CadastroDePessoa.jsp <%@ page language="java" contentType="text/html; charset=UTF-8"%> <%@ taglib uri="/tags/struts-html" prefix="html"%> <%@ taglib uri="/tags/struts-bean" prefix="bean"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>.: Login :.</title> <link rel="stylesheet" href="css/Estilo.css" type="text/css" /> </head> <body> <table width=90% height=90%> <tr> <td align=center> <table width=50% border> <tr> <td colspan=2><html:errors /> <tr> <td> <table width=100%> CadastroDePessoa.jsp <html:form action="/CadastrarPessoa"> <tr> <td><bean:message key="pessoa.nome" /></td> <td><html:text property="nome" name="pessoa" /></td> </tr> <tr> <td><bean:message key="pessoa.endereco" /></td> <td><html:text property="endereco" name="pessoa" /></td> </tr> <tr> <td><bean:message key="pessoa.telefone" /></td> <td><html:text property="telefone" name="pessoa" /></td> </tr> <tr> <td><bean:message key="pessoa.cpf" /></td> <td><html:text property="cpf" name="pessoa" /></td> CadastroDePessoa.jsp </tr> <tr> <td colspan=2 align=center><html:submit value="Gravar" /></td> </tr> <tr> <td colspan=2 align=center><html:image src="imagens/cup.gif" /></td> </tr> </html:form> </table> </td> </tr> </table> </td> </tr> </table> </body> </html> Nova página de cadastro • Nossas páginas são formadas por mensagens e componentes HTML • Não se esqueça: esses componentes são ligados (bind) aos atributos do formulário em questão PaginaPrincipal.jsp <p><html:link href="BemVindo.do">Página Inicial</html:link> <p><html:link href="CadastroDePessoa.do">Cadastro de Pessoa</html:link> <p><html:image src="imagens/T4.gif" /></p> Menu da página principal • Vamos acrescentar a chamada ao nosso novo cadastro • Quando o usuário clicar no link CadastroDePessoa o Struts irá direcionar a aplicação para a página CadastroDePessoa.jsp struts-config.xml <form-beans> <form-bean name="usuarioForm" type="com.alomundo.UsuarioForm" /> <form-bean name="pessoaForm" type="com.alomundo.PessoaForm" /> </form-beans> Lista de formulários • Todos os formulários criados devem ser registrados nessa tag struts-config.xml <action path="/CadastroDePessoa" forward="/CadastroDePessoa.jsp" /> <action path="/CadastrarPessoa" name="pessoaForm" type="com.alomundo.PessoaAction" attribute="pessoa" scope="request"> <forward name="Sucesso" path="/PaginaPrincipal.jsp" /> </action> Ações do novo cadastro • Os dados da variável usuario ficam gravados na sessão e podem ser usados a qualquer instante • Os dados desse formulário não precisam viver mais que o próprio request, não precisa ficar guardado para depois PessoaAction package com.alomundo; import javax.servlet.http.*; import org.apache.struts.action.*; public class PessoaAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { PessoaForm f = (PessoaForm) form; System.out.println("Dados recuperados da tela"); System.out.println("Nome: " + f.getNome()); System.out.println("Endereço: " + f.getEndereco()); System.out.println("Telefone: " + f.getTelefone()); System.out.println("CPF:" + f.getCpf()); return mapping.findForward("Sucesso"); } } PessoaAction • Quando o usuário clicar no botão Gravar o Struts chama o método execute Agora é sua vez • Seguindo os exemplos que vimos, crie um cadastro de notícias • Sua notícia terá titulo, texto e data, todos do tipo String