Struts Características Avançadas
Agenda Tags do Struts DispatchAction Multiplos arquivos de configuração Command Pattern DynaActionForm Array s Validation Framework JSP2.0 Expression Language
html html:submit html:cancel html:button html:hidden html:checkbox html:messages html:errors html:file html:form html:javascript html:image/img
html html:link html:messages html:multibox html:selection/option/options/optionscollection html:radio html:reset html:rewrite html:text html:textarea
bean bean:cookie bean:header bean:parameter bean:define bean:include bean:message bean:page bean:resource bean:size
bean bean:struts bean:write
logic logic:empty logic:present logic:iterate logic:{...}
Preparação do Ambiente Crie dois projetos (SistemaDeNoticias e SistemaDeNoticiasWeb) Configure o nome do contexto web para noticia Adicione a lib struts-extras.jar. Utilize, claro, a versão mais recente Crie as páginas Menu.jsp e index.jsp
Menu.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>.: Menu :.</title> <link rel="stylesheet" href="css/estilo.css" type="text/css" /> </head> <body> <table> <tr> <td><html:link page="/paginainicial.do">página Inicial </html:link></td> </tr> </table> </body> </html>
index.jsp <body onload="window.location='paginainicial.do';">
DispatchAction Subtipo de Action que implementa o padrão Command Ao invés de ter várias classes Action, você centraliza todas as ações num único DispatchAction e seleciona a uma ação específica através de um parâmetro (comando) na url Muito prático, economiza várias classes, pois uma mesma Action responde a várias solicitações
NoticiaAction package net.noticias.action; import java.util.*; import javax.servlet.http.*; import net.noticias.form.*; import net.noticias.persistencia.*; import org.apache.struts.action.*; import org.apache.struts.actions.*; public class NoticiaAction extends DispatchAction { public ActionForward listar(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { DAONoticia daonoticia = new DAONoticia(); request.setattribute("noticias", daonoticia.consultanoticias()); return mapping.findforward("mostrarpaginadeconsulta"); } }
Invocando um método do Dispatch Essa é uma subclasse de DispatchAction Todos os métodos devem ter a seguinte lista de parâmetros: ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response O nome do método (no nosso caso listar) será invocado pela url Noticia.do?comando=listar A url completa é http://localhost:8080/noticia/noticia.do?comando=listar
Parâmetros do dispath Noticia.do Chama a ação respectiva no strutsconfig.xml, acionando a classe NoticiaAction O método listar faz carrega uma coleção de notícias na variável noticias e chama o forward MostrarPaginaDeConsulta abrindo a página ConsultarNoticias.jsp comando=listar Parâmetro http utilizado para escolher o método
NoticiaForm package net.noticias.form; import org.apache.struts.action.*; public class NoticiaForm extends ActionForm { private String id; private String texto; private String titulo; private String data; private String tipodenoticia; private String[] noticiasselecionadas; {...} }
Detalhes Crie os métodos getter e setters Temos um atributo do tipo array Array s são utilizados para recuperar valores de componentes como listas de seleção múltipla e checkboxes Essa é uma característica do html, não do Struts
DAONoticia package net.noticias.persistencia; import java.util.*; import net.noticias.form.*; public class DAONoticia { public Collection<NoticiaForm> consultanoticias() { Collection<NoticiaForm> lista = new ArrayList<NoticiaForm>(); NoticiaForm n = new NoticiaForm(); n.setid("1"); n.setdata("01-01-2001"); n.settexto("texto da notícia 1"); n.settitulo("título da notícia 1"); lista.add(n); n = new NoticiaForm(); n.setid("2"); n.setdata("01-01-2002"); n.settexto("texto da notícia 2"); n.settitulo("título da notícia 2"); lista.add(n); n = new NoticiaForm(); n.setid("3"); n.setdata("01-01-2003"); n.settexto("texto da notícia 3"); n.settitulo("título da notícia 3"); lista.add(n); return lista; }
DAONoticia public NoticiaForm consultanoticiapeloid(string id) { NoticiaForm n = new NoticiaForm(); n.setid(id); n.setdata("01-01-2001"); n.settexto("texto da notícia " + id); n.settitulo("título da notícia " + id); n.settipodenoticia("3"); return n; } }
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>sistema de Notícias</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,/WEB-INF/struts-config-form-beans.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>
Múltiplos arquivos de configuração Arquivos de configuração tendem a crescer bastante, dificultando sua visualização Nesse exemplo separamos os form-beans do resto da aplicação Para isso, adicione os arquivos de configuração no parâmetro config separados por vírgula
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> <global-forwards> <forward name="abrirpaginaprincipal" path="/paginainicial.do" /> </global-forwards> <action-mappings> <action path="/paginainicial" forward="/menu.jsp" /> <action path="/noticia" type="net.noticias.action.noticiaaction" name="noticiaform" parameter="comando"> <forward name="mostrarpaginadeedicao" path="/editarnoticia.jsp" /> <forward name="mostrarpaginadeconsulta" path="/consultarnoticias.jsp" /> </action> </action-mappings> <message-resources parameter="messageresources" /> </struts-config>
Command Pattern A ação Noticia deve ter um parâmetro O nome padrão é comando Esse parâmetro será usado para escolher o método a ser executado
Forwards globais São forwards que podem ser utilizados por todos os actions <global-forwards> <forward name="abrirpaginaprincipal" path="/paginainicial.do" /> </global-forwards>
struts-config-form-beans.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="noticiaform" type="net.noticias.form.noticiaform" /> <form-bean name="tipodenoticiaform" type="net.noticias.form.tipodenoticiaform" /> </form-beans> </struts-config>
ConsultarNoticias.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>.: Consulta Notícias :.</title> <link rel="stylesheet" href="css/estilo.css" type="text/css" /> </head> <body> <table width=90% border> <tr> <td colspan=4 align=center> <h2>consulta Notícias</h2> </td> </tr> <tr> <td align=center>data</td> <td>título</td> <td>texto</td> <td>editar</td>
ConsultarNoticias.jsp </tr> <logic:iterate id="noticia" name="noticias"> <tr> <td align=center><bean:write name="noticia" property="data" /></td> <td><bean:write name="noticia" property="titulo" /></td> <td><bean:write name="noticia" property="texto" /></td> <td><html:link page="/noticia.do?comando=editar" paramid="iddanoticia" paramname="noticia" paramproperty="id"> <html:image src="imagens/edit.gif" /> </html:link> </tr> </logic:iterate> <tr> <td colspan=4 align=center><html:button onclick="window.location='paginainicial.do'" property="btnvoltar" value="sair" /></td> </table> </body> </html>
html:link e html:button html:link <html:link page="/noticia.do?comando=editar" paramid="iddanoticia" paramname="noticia" paramproperty="id"> /Noticia.do?comando=editar chama a mesma action (NoticiaAction) executando dessa vez o comando editar paramid nome do parâmetro passado na url paramname nome do bean paramproperty valor da propriedade html:button <html:button onclick="window.location='paginainicial.do'" property="btnvoltar" value="sair" /> Botão com javascript para voltar à página inicial
Novo Menu.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>.: Menu :.</title> <link rel="stylesheet" href="css/estilo.css" type="text/css" /> </head> <body> <table> <tr> <td><html:link page="/paginainicial.do">página Inicial </html:link></td> <td><html:link page="/noticia.do?comando=listar">notícia </html:link></td> </tr> </table> </body> </html>
Tela de Consulta
Comando editar Esse novo comando consulta uma notícia pelo parâmetro iddanoticia Teremos um combobox com os tipos de notícia, para montá-lo precisamos da coleção de tipos Em seguida é só chamar o forward MostrarPaginaDeEdicao
NoticiaAction public ActionForward editar(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { String id = request.getparameter("iddanoticia"); DAONoticia daonoticia = new DAONoticia(); DAOTipoDeNoticia daotipo = new DAOTipoDeNoticia(); Collection<TipoDeNoticiaForm> tipos = daotipo.consultatiposdenoticia(); NoticiaForm n = daonoticia.consultanoticiapeloid(id); request.setattribute("noticia", n); request.setattribute("tipos", tipos); return mapping.findforward("mostrarpaginadeedicao"); }
EditarNoticia.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>.: Editar Notícia :.</title> <link rel="stylesheet" href="css/estilo.css" type="text/css" /> </head> <body> <table width=90% border> <html:form action="/noticia?comando=confirmar"> <tr> <td colspan=3 align=center> <h2>editar Notícia</h2>
EditarNoticia.jsp </td> </tr> <tr> <td align=center>id</td> <td><html:text name="noticia" property="id" /></td> </tr> <tr> <td align=center>data</td> <td><html:text name="noticia" property="data" /></td> </tr> <tr> <td align=center>título</td> <td><html:text name="noticia" property="titulo" /></td> </tr> <tr> <td align=center>texto</td> <td><html:text name="noticia" property="texto" /></td> </tr> <tr> <td colspan=3> <tr>
EditarNoticia.jsp <td align=center>tipo de notícia: <td colspan=2> <html:select name="noticia" property="tipodenoticia"> <html:optionscollection name="tipos" value="id" label="descricao" /> </html:select></td> </tr> <tr> <td colspan=3 align=center> <html:submit value="confirmar" /> <html:button onclick="action='noticia.do?comando=listar';submit()" value="sair" property="btnsair" /></td> </tr> </html:form> </table> </body> </html>
html:form/select <html:form action="/noticia?comando=confirmar"> Os dados dessa página serão enviados para o método confirmar através da NoticiaForm <html:select name="noticia" property="tipodenoticia"> <html:optionscollection name="tipos" value="id" label="descricao" /> </html:select> html:select tag para montar uma combobox, inclusive de seleção múltipla name, property nome/propriedade do bean html:optionscollection valores do combobox name nome da collection value valor de cada option (id de cada tipodenoticia) label valor que será mostrado ao usuário Se o id do bean for igual ao id da combo, essa opção virá selecionada
html:submit <html:submit value="confirmar" /> Submete o form para a ação do form <html:button onclick="action='noticia.do?comando=listar';submit()" value="sair" property="btnsair" /> Muda o valor da ação através de javascript e a submete
Tela de Edição
Confirmando a ação O método confirmar recebe os dados do formulário de edição e faz a persistência dos dados Nossos exemplos não têm bancos de dados, mas um DAO acessando o Hibernate poderia fazer isso facilmente
NoticiaAction public ActionForward confirmar(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { NoticiaForm f = (NoticiaForm) form; System.out.println("Dados informados pelo usuário"); System.out.println("ID: " + f.getid()); System.out.println("Data: " + f.getdata()); System.out.println("Título: " + f.gettitulo()); System.out.println("Texto: " + f.gettexto()); System.out.println("ID do Tipo: " + f.gettipodenoticia()); return mapping.findforward("abrirpaginaprincipal"); }
Camadas de Persistência e Negócio O Struts não fornece nenhuma API para a camada de negócio Seguindo as melhores práticas, a Action deveria acessar um fachada No nosso exemplo temos acessamos um DAO diretamente O próximo passo seria acessar efetivamente o banco relacional
TipoDeNoticiaForm package net.noticias.form; import org.apache.struts.action.*; public class TipoDeNoticiaForm extends ActionForm { private String id; private String descricao; {...} }
Alternativa A classe TipoDeNoticia é bastante simples, tem apenas código e descrição Esse tipo de classe é forte candidata a se transformar em formulário dinâmico, discutido posteriormente
struts-config.xml Acrescente a ação respectiva no arquivo de configuração (siga o padrão da ação Noticia) Já é possível notar a quantidade reduzida de classes Action <action path="/tipodenoticia" name="tipodenoticiaform" type="net.noticias.action.tipodenoticiaaction" parameter="comando"> <forward name="mostrarpaginadeedicao" path="/editartipodenoticia.jsp" /> <forward name="mostrarpaginadeconsulta" path="/consultartipodenoticia.jsp" /> </action>
TipoDeNoticiaAction package net.noticias.action; import java.util.*; import javax.servlet.http.*; import net.noticias.form.*; import net.noticias.persistencia.*; import org.apache.struts.action.*; import org.apache.struts.actions.*; public class TipoDeNoticiaAction extends DispatchAction { public ActionForward editar(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { String id = request.getparameter("iddotipo"); DAOTipoDeNoticia dao = new DAOTipoDeNoticia(); TipoDeNoticiaForm tipo = dao.consultatipodenoticiapeloid(id); request.setattribute("tipo", tipo); return mapping.findforward("mostrarpaginadeedicao"); }
TipoDeNoticiaAction public ActionForward listar(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { DAOTipoDeNoticia d = new DAOTipoDeNoticia(); Collection<TipoDeNoticiaForm> lista = d.consultatiposdenoticia(); request.setattribute("tipos", lista); return mapping.findforward("mostrarpaginadeconsulta"); } public ActionForward confirmar(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { TipoDeNoticiaForm f = (TipoDeNoticiaForm) form; System.out.println("Dados informados pelo usuário"); System.out.println("ID: " + f.getid()); System.out.println("Data: " + f.getdescricao()); return mapping.findforward("abrirpaginaprincipal"); } }
DAOTipoDeNoticia package net.noticias.persistencia; import java.util.*; import net.noticias.form.*; public class DAOTipoDeNoticia { public Collection<TipoDeNoticiaForm> consultatiposdenoticia() { Collection<TipoDeNoticiaForm> lista = new ArrayList<TipoDeNoticiaForm>(); TipoDeNoticiaForm n = new TipoDeNoticiaForm(); n.setid("1"); n.setdescricao("tipo 1"); lista.add(n); n = new TipoDeNoticiaForm(); n.setid("2"); n.setdescricao("tipo 2"); lista.add(n); n = new TipoDeNoticiaForm(); n.setid("3"); n.setdescricao("tipo 3"); lista.add(n); return lista; } public TipoDeNoticiaForm consultatipodenoticiapeloid(string id) { TipoDeNoticiaForm tipo = new TipoDeNoticiaForm(); tipo.setid(id); tipo.setdescricao("tipo " + id); return tipo; } }
TipoDeNoticia Apesar de simples, temos vários elementos utilizados em
ConsultarTipoDeNoticia.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>.: Consulta Tipos de Notícia :.</title> <link rel="stylesheet" href="css/estilo.css" type="text/css" /> </head> <body> <table width=90% border> <tr> <td colspan=4 align=center> <h2>consulta Tipo de Notícia</h2> </td> </tr> <tr> <td align=center>id</td> <td>descrição</td> <td>editar</td> </tr>
ConsultarTipoDeNoticia.jsp <logic:iterate id="tipo" name="tipos"> <tr> <td align=center><bean:write name="tipo" property="id" /></td> <td><bean:write name="tipo" property="descricao" /></td> <td><html:link page="/tipodenoticia.do?comando=editar" paramid="iddotipo" paramname="tipo" paramproperty="id"> <html:img src="imagens/edit.gif" border="0" /> </html:link> </tr> </logic:iterate> <tr> <td colspan=4 align=center><html:button onclick="window.location='paginainicial.do'" property="btnvoltar" value="sair" /></td> </table> </body> </html>
Consultas As consultas seguem o mesmo princípio: a Action salva uma coleção de objetos numa variável (geralmente) de sessão e através do logic:iterate a gente escreve os vários valores na tela
EditarTipoDeNoticia.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:html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>.: Editar Tipo de Notícia :.</title> <link rel="stylesheet" href="css/estilo.css" type="text/css" /> </head> <body> <table width=90% border> <html:form action="/tipodenoticia?comando=confirmar" onsubmit="return validatetipodenoticiaform(this);"> <tr> <td colspan=3 align=center> <h2>edição de Tipo de Notícia</h2> </td> </tr>
EditarTipoDeNoticia.jsp <tr> <td align=center>id</td> <td><html:text name="tipo" property="id" /></td> </tr> <tr> <td align=center>descrição</td> <td><html:text name="tipo" property="descricao" /></td> </tr> <tr> <td colspan=3 align=center><html:submit value="confirmar" /><html:button onclick="action='tipodenoticia.do?comando=listar';submit()" value="sair" property="btnsair" /></td> </tr> </html:form> </table> </body> </html:html>
Edição O id de um dos objetos da lista é enviado pela url para a Action, executando o comando de edição A aplicação deve recuperar o objeto do banco e guardar seus valores em uma variável de sessão A página de edição espera essa variável e escreve seus valores através das tags html
DynaActionForm Formulário dinâmico baseado na interface java.util.map Não é necessário criar uma classe ActionForm Configurado no struts-config como um simples <form-bean> Grande flexibilidade Não utiliza reflexão
struts-config-form-beans.xml Adicione o form-bean para Fonte <form-bean name="fonteform" type="org.apache.struts.action.dynaactionform"> <form-property name="id" type="java.lang.string" /> <form-property name="descricao" type="java.lang.string" /> </form-bean> Os atributos podem usar todas as classes wrapper, collections e arrays Não é necessário criar a classe!
struts-config.xml Acrescente a Action para o novo form-bean Veja a diferença: nenhuma <action path="/fonte" type="net.noticias.action.fonteaction" name="fonteform" parameter="comando"> <forward name="mostrarpaginadeedicao" path="/editarfonte.jsp" /> <forward name="mostrarpaginadeconsulta" path="/consultarfontes.jsp"> </forward> </action>
FonteAction package net.noticias.action; import javax.servlet.http.*; import net.noticias.persistencia.*; import org.apache.struts.action.*; import org.apache.struts.actions.*; public class FonteAction extends DispatchAction { public ActionForward listar(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { DAOFonte dao = new DAOFonte(); request.setattribute("fontes", dao.consultafontes()); return mapping.findforward("mostrarpaginadeconsulta"); } }
Poucas diferenças o método para listar as fontes não difere dos outros A principal diferença fica por conta do DAO, pois os formulários dinâmicos não têm classes concretas Todos são implementados através de mapas
DAOFonte package net.noticias.persistencia; import java.util.*; public class DAOFonte { public Collection<Map<String, String>> consultafontes() { Collection<Map<String, String>> lista = new ArrayList<Map<String, String>>(); Map<String, String> mapa = new HashMap<String, String>(); mapa.put("id", "1"); mapa.put("descricao", "Fonte 1"); lista.add(mapa); mapa = new HashMap<String, String>(); mapa.put("id", "2"); mapa.put("descricao", "Fonte 2"); lista.add(mapa); mapa = new HashMap<String, String>(); mapa.put("id", "3"); mapa.put("descricao", "Fonte 3"); lista.add(mapa); return lista; } public Map<String, String> consultafontepeloid(string id) { Map<String, String> mapa = new HashMap<String, String>(); mapa.put("id", id); mapa.put("descricao", "Tipo " + id); return mapa; } }
Tudo é Map Como não há classe concreta, nosso valores ficam encapsulados em mapas Para fazer a persistência num banco relacional, você deve implementar utilitários que mapeiem os mapas para seus DTO s
ConsultarFontes.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>.: Consulta Notícias :.</title> <link rel="stylesheet" href="css/estilo.css" type="text/css" /> </head> <body> <table width=90% border> <tr> <td colspan=4 align=center> <h2>consulta Fontes</h2> </td> </tr> <tr> <td align=center>id</td> <td>descrição</td> <td>editar</td> </tr>
ConsultarFontes.jsp <logic:iterate id="fonte" name="fontes"> <tr> <td align=center><bean:write name="fonte" property="id" /></td> <td><bean:write name="fonte" property="descricao" /></td> <td><html:link page="/fonte.do?comando=editar" paramid="iddafonte" paramname="fonte" paramproperty="id"> <html:image src="imagens/edit.gif" /> </html:link> </tr> </logic:iterate> <tr> <td colspan=4 align=center><html:button onclick="window.location='paginainicial.do';submit()" property="btnvoltar" value="sair" /></td> </tr> </table> </body> </html>
Consulta com DynaActionForm A página de consulta é idêntica a todas as outras Atenção ao DAO, pois temos que usar apenas Map s
FonteAction public ActionForward editar(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { DAOFonte dao = new DAOFonte(); String id = request.getparameter("iddafonte"); request.setattribute("fonte", dao.consultafontepeloid(id)); return mapping.findforward("mostrarpaginadeedicao"); }
EditarFonte.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>.: Editar Fonte :.</title> <link rel="stylesheet" href="css/estilo.css" type="text/css" /> </head> <body> <table width=90% border> <html:form action="/fonte?comando=confirmar"> <tr> <td colspan=3 align=center> <h2>editar Fonte</h2> </td> </tr>
EditarFonte.jsp <tr> <td align=center>id</td> <td><html:text name="fonte" property="id" /></td> </tr> <tr> <td align=center>descrição</td> <td><html:text name="fonte" property="descricao" /></td> </tr> <tr> <td colspan=3 align=center><html:submit value="confirmar" /> <html:button onclick="action='fonte.do?comando=listar';submit()" value="sair" property="btnsair" /></td> </tr> </html:form> </table> </body> </html>
Edição com DynaActionForm Para preencher a página de edição precisamos fornecer um mapa com os atributos da fonteform public Map<String, String> consultafontepeloid(string id) { Map<String, String> mapa = new HashMap<String, String>(); mapa.put("id", id); mapa.put("descricao", "Tipo " + id); return mapa; }
A utilização de array s Em várias situações precisamos utilizar estruturas complexas, mas quando trabalhamos com ambientes web, temos uma série de limitações Não é interessante, por exemplo, transmitir objetos entre as requisições de usuário. Esse tipo de recurso deve ser evitado ao máximo Os valores transmitidos entre as páginas são sempre do tipo String e quando temos vários componentes em uma requisição com o mesmo nome, o request encapsula seus valores em um array E trabalhar com array sempre foi razoavelmente complicado
struts-config.xml Abaixo está a Action dessa nova funcionalidade O escopo está configurado para request. Depois do primeiro teste, mude para session O parâmetro attribute= noticia cria a variável noticia e a passa para a página seguinte, preenchida com os dados da página atual <action path="/selecaomultipladenoticias" type="net.noticias.action.selecaomultipladenoticiasaction" name="noticiaform" attribute="noticia" scope="request" parameter="comando"> <forward name="mostrarpaginadeconsulta" path="/selecaomultipladenoticias.jsp" /> <forward name="mostrarnoticiasselecionadas" path="/resultadodaselecaomultipladenoticias.jsp" /> </action>
SelecaoMultiplaDeNoticiasAction package net.noticias.action; import javax.servlet.http.*; import net.noticias.persistencia.*; import org.apache.struts.action.*; import org.apache.struts.actions.*; public class SelecaoMultiplaDeNoticiasAction extends DispatchAction { public ActionForward mostrartodasasnoticias(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { DAONoticia d = new DAONoticia(); request.setattribute("noticias", d.consultanoticias()); return mapping.findforward("mostrarpaginadeconsulta"); } public ActionForward mostrarasnoticiasselecionadas(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { return mapping.findforward("mostrarnoticiasselecionadas"); } }
Página de seleção A Action simplesmente envia uma coleção de notícias para a página de seleção que mostra seus valores com uma tag html:selection
SelecaoMultiplaDeNoticias.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>.: Consulta Notícias :.</title> <link rel="stylesheet" href="css/estilo.css" type="text/css" /> </head> <body> <table width=90% border> <html:form action="/selecaomultipladenoticias.do?comando=mostrarasnoticiasselecionadas"> <bean:size id="quantidadedenoticias" name="noticias" /> <tr> <td colspan=2 align=center> <h2><bean:write name="quantidadedenoticias" /> Notícia(s) Cadastrada(s)</h2> </td>
SelecaoMultiplaDeNoticias.jsp </tr> <tr> <td align=center>notícias: <td><html:select name="noticia" property="noticiasselecionadas" multiple="true"> <html:optionscollection name="noticias" value="id" label="titulo" /> </html:select></td> </tr> <tr> <td colspan=2 align=center><html:button onclick="submit()" property="btnselecionar" value="selecionar" /></td> </tr> </html:form> </table> </body> </html>
html:select e bean:size <html:select name="noticia" property="noticiasselecionadas" multiple="true"> <html:optionscollection name="noticias" value="id" label="titulo" /> </html:select> multiple= true Indica que esse select aceitará seleção múltipla Os itens selecionados serão armazenados em um array do formbean <bean:size id="quantidadedenoticias" name="noticias" /> Cria a variável quantidadedenoticias com a quantidade de itens do bean noticias <bean:write name="quantidadedenoticias" /> Escreve o valor da variável quantidadedenoticias
Tela de seleção
ResultadoDaSelecaoMultiplaDeNoticias.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>.: Seleção Múltipla de Notícia :.</title> <link rel="stylesheet" href="css/estilo.css" type="text/css" /> </head> <body> <table width=90% border> <bean:size id="quantidadedenoticiasselecionadas" name="noticia" property="noticiasselecionadas" /> <tr> <td colspan=2 align=center> <h2><bean:write name="quantidadedenoticiasselecionadas" /> Notícia(s) Selecionada(s)</h2> </td>
ResultadoDaSelecaoMultiplaDeNoticias.jsp </tr> <tr> <td align=center>id</td> </tr> <logic:iterate id="iddanoticiaselecionada" property="noticiasselecionadas" name="noticia"> <tr> <td align=center><bean:write name="iddanoticiaselecionada" /></td> </tr> </logic:iterate> <tr> <td colspan=2 align=center><html:button onclick="window.location='selecaomultipladenoticias.do?comando=mostrartodasasnoticias';submit()" property="btnselecionar" value="voltar" /><html:button onclick="window.location='paginainicial.do';submit()" value="sair" property="btnsair" /></td> </tr> </table> </body> </html>
bean:size e logic:iterate <bean:size id="quantidadedenoticiasselecionadas" name="noticia" property="noticiasselecionadas" /> Cria a variável quantidadedenoticiasselecionadas com a quantidade itens da property noticiasselecionadas do bean noticia <bean:write name="quantidadedenoticiasselecionadas" /> Escreve a quantidadedenoticiasselecionadas <logic:iterate id="iddanoticiaselecionada" property="noticiasselecionadas" name="noticia"> Cria a variável iddanoticiaselecionada com o valor de cada item do array <bean:write name="iddanoticiaselecionada" /> Escreve o id na tela
Tela de resultado
Agora é sua vez O Struts entrega os dados, mas o processamento quem faz é você Seguindo as boas práticas, agora é a vez consultar as notícias pelo id, através de uma fachada/dao Nunca coloque regras de negócio em suas Actions
Validation Framework A lógica de validação é escrita em arquivos XML Originado do Validator Framework do Jakarta Incluído no Struts a partir da versão 1.1 Permite validação declarativa para vários campos Valida datas, números, email, cartão de crédito, código postar (USA), tamanhos, range e expressões regulares
Regras de Validação Regras são definidas para campos específicos de um form Já dispõe de vários validadores prontos required, minlength, maxlength, date, integer, mask Extensível: você pode criar seus próprios validadores
Validação do ActionForm Para usar o Validator, torne seus ActionForm s subclasses de ValidatorForm ou ValidatorActionForm Se estiver usando DynaActionForm, passe a extender de DynaValidatorForm ou DynaValidatorActionForm
NoticiaForm package net.noticias.form; import org.apache.struts.validator.*; public class NoticiaForm extends ValidatorActionForm { private String id; private String texto; private String titulo; private String data; private String tipodenoticia; private String[] noticiasselecionadas; {...} }
validation.xml Específico da sua aplicação Configuração das regras aplicadas a cada campo do seu formulário Torna desnecessário o método validate() do ActionForm
validator-rules.xml Fornecido pelo Struts Regras que já fazem parte do Validator Fica dentro da lib struts-core.jar, no pacote org.apache.struts.validator
Plugin Validator Para começar a usar o Validator, acrescente o plugin no struts-config.xml <plug-in classname="org.apache.struts.validator.validatorplugin"> <set-property property="pathnames" value="/org/apache/struts/validator/validator-rules.xml, /WEB-INF/validation.xml" /> </plug-in>
Validação no Cliente O Validator pode fazer a validação no lado do cliente Para tanto, acrescente a tag seguinte logo após o <head> Essa tag irá gerar todo o código javascript para validar seu formulário <head> <html:javascript formname="noticiaform" />
Validação no Cliente É gerado automaticamente um método javascript validatexxx, onde Xxx é o nome do seu formulário Atualize a tag html:form para seus formulários <html:form action="/noticia?comando=confirmar" onsubmit="return validatenoticiaform(this)">
MessageResources # erro.tipodenoticia.id.requerido={0} é requerido erro.tipodenoticia.descricao.requerido={0} é requerida # tipodenoticia.id=id tipodenoticia.descricao=descrição # noticia.id=id noticia.data=data # errors.required={0} is required. errors.minlength={0} can not be less than {1} characters. errors.maxlength={0} can not be greater than {1} characters. errors.invalid={0} is invalid. errors.byte={0} must be a byte. errors.short={0} must be a short. errors.integer={0} must be an integer. errors.long={0} must be a long. errors.float={0} must be a float. errors.double={0} must be a double. errors.date={0} is not a date. errors.range={0} is not in the range {1} through {2}. errors.creditcard={0} is an invalid credit card number. errors.email={0} is an invalid e-mail address.
Mensagens Personalizadas O Validator já tem várias mensagens configuradas (em inglês) Você pode definir suas próprias mensagens
validation.xml <?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.3.0//EN" "http://jakarta.apache.org/commons/dtds/validator_1_3_0.dtd"> <form-validation> <formset> <form name="tipodenoticiaform"> <field property="id" depends="required,integer"> <arg key="tipodenoticia.id" /> </field> <field property="descricao" depends="required"> <msg name="required" key="erro.tipodenoticia.descricao.requerido" /> <arg key="tipodenoticia.descricao" /> </field> </form>
validation.xml <form name="noticiaform"> <field property="id" depends="required,integer"> <arg key="noticia.id" /> </field> <field property="data" depends="required,date"> <arg key="noticia.data" /> <var> <var-name>datepattern</var-name> <var-value>dd/mm/yyyy</var-value> </var> </field> </form> </formset> </form-validation>
Regras de Validação <form name="tipodenoticiaform"> Nome do formulário definido no struts-config.xml <field property="id" depends="required,integer"> Nome da propriedade e suas dependências (definidas no validator-rules.xml) <arg key="tipodenoticia.id" /> Essa é a mensagem que substitui o parâmetro {0} no MessageResources caso o campo não tenha um valor válido <field property="descricao" depends="required"> <msg name="required" key="erro.tipodenoticia.descricao.requerido" /> Essa é a mensagem personalizada para o validador required <var-name>datepattern</var-name> <var-value>dd/mm/yyyy</var-value> Padrão para data. Veja a lista na documentação da SimpleDateFormat
Exemplo de Popup s Ao lado você pode ver alguns exemplos de mensagens No primeiro você pode ver uma mensagem padrão (em inglês) e uma personalizada Para entender o mecanismo de troca de mensagens, veja todos os arquivos envolvidos
Exercícios Crie as regras de validação para o Formulário FonteForm
JSP2.0 EL Linguagem padrão da Sun para a camada de apresentação Acesso conciso, rápido e prático Acessa subpropriedades dos beans Sintaxe incrivelmente simples É da Sun...
Concorrentes jsp:usebean e jsp:getproperty Não pode acessar subpropriedades do bean Complexo e nem um pouco prático bean:write Também não pode acessar subpropriedades do bean Não é a saída mais prática Elementos de script JSP Resulta em um código JSP impossível de manter Destrói o principal propósito do MVC
Instalação da EL Para instalar você só precisa alterar o cabeçalho do web.xml Já faz parte dos containers mais novos, como Tomcat 5 Parte integrante do JSP2.0
web.xml <?xml version="1.0" encoding="iso-8859-1"?> <web-app 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 web-app_2_4.xsd" version="2.4"> {...} </web-app>
Invocando a EL Forma básica ${expressão} ${bean.propriedade} Você pode combiná-la com as demais notações <jsp:include page="${expr1}blah${expr2}" />
Exemplo com Struts <%@ taglib uri="/web-inf/struts-bean.tld" prefix="bean" %> <UL> <LI>First name: <bean:write name="contactformbean" property="firstname"/> <LI>Last name: <bean:write name="contactformbean" property="lastname"/> <LI>Email address: <bean:write name="contactformbean" property="email"/> <LI>Fax number: <bean:write name="contactformbean" property="faxnumber"/> </UL>
Agora com EL <UL> <LI>First name: ${contactformbean.firstname} <LI>Last name: ${contactformbean.lastname} <LI>Email address: ${contactformbean.email} <LI>Fax number: ${contactformbean.faxnumber} </UL>
Exercícios No formulário de consulta notícias, combine as tags Struts com a JSP EL