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>&nbsp;
<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
Download

private - Marco Reis