29
Tutorial - Struts Framework Welington B. Souza [email protected] Introdução O objetivo deste tutorial é dar uma visão geral sobre o funcionamento da Struts Framework. Aqui você irá aprender o necessário para começar a desenvolver uma aplicação web usando a Struts. Embora esta framework implemente o padrão MVC, isso não quer dizer que vamos seguir a risca as explicações de cada camada, mas sim expondo o conteúdo teórico dependendo da necessidade do tutorial, visando a facilidade no entendimento dos conceitos à medida em que eles forem necessários. A Struts Framework é um projeto open source mantido pela Apache Software Foundation. É uma implementação do design pattern MVC (Model-View-Controller) para aplicações java com internet. O objetivo do pattern MVC é separar de maneira clara a camada de apresentação (View) da camada de Negócio (Model). A arquitetura MVC - Model-View-Controller (Modelo-Visualização-Controle) é um padrão que separa de maneira independente o Modelo, que representa os objetos de negócio (Model) da camada de apresentação, que representa a interface com o usuário ou outro sistema (View); e o Controle de fluxo da aplicação (Controller). Figura 1 - O Padrão MVC A Struts Foi escrita por Craig McClanahan em Maio de 2000, e desde então vem sendo melhorado pela comunidade open-source. Foi desenvolvida com o objetivo de fornecer uma framework para facilitar o desenvolvimento de aplicações para web. Motivos utilizar a Struts Framework Se tornou um padrão de mercado; Garantia de que alguém (Apache Group) irá manter a framework (correção de bugs e novos releases); Integração com a maioria das IDEs de mercado Não reinventar a roda, focando os seus esforços em regras de negócio; Separar a camada de negócio da camada de apresentação; Já incorpora diversos design patterns Criação de aplicações padronizadas, facilitando a manutenção; Criação de Aplicações Internacionalizadas; Possibilidade de gerar a saída de acordo com o dispositivo usado (HTML, SHTML, WML, etc); Aumentar a produtividade

Tutorial struts

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Tutorial struts

Tutorial - Struts Framework Welington B. Souza [email protected]

Introdução

O objetivo deste tutorial é dar uma visão geral sobre o funcionamento da Struts Framework. Aqui você iráaprender o necessário para começar a desenvolver uma aplicação web usando a Struts. Embora estaframework implemente o padrão MVC, isso não quer dizer que vamos seguir a risca as explicações de cadacamada, mas sim expondo o conteúdo teórico dependendo da necessidade do tutorial, visando a facilidadeno entendimento dos conceitos à medida em que eles forem necessários. A Struts Framework é um projeto open source mantido pela Apache Software Foundation. É umaimplementação do design pattern MVC (Model-View-Controller) para aplicações java com internet. O objetivodo pattern MVC é separar de maneira clara a camada de apresentação (View) da camada de Negócio(Model). A arquitetura MVC - Model-View-Controller (Modelo-Visualização-Controle) é um padrão que separa demaneira independente o Modelo, que representa os objetos de negócio (Model) da camada de apresentação,que representa a interface com o usuário ou outro sistema (View); e o Controle de fluxo da aplicação(Controller).

Figura 1 - O Padrão MVC A Struts Foi escrita por Craig McClanahan em Maio de 2000, e desde então vem sendo melhorado pelacomunidade open-source. Foi desenvolvida com o objetivo de fornecer uma framework para facilitar odesenvolvimento de aplicações para web.

Motivos utilizar a Struts Framework

• Se tornou um padrão de mercado; • Garantia de que alguém (Apache Group) irá manter a framework (correção de bugs e novos

releases); • Integração com a maioria das IDEs de mercado • Não reinventar a roda, focando os seus esforços em regras de negócio; • Separar a camada de negócio da camada de apresentação; • Já incorpora diversos design patterns • Criação de aplicações padronizadas, facilitando a manutenção; • Criação de Aplicações Internacionalizadas; • Possibilidade de gerar a saída de acordo com o dispositivo usado (HTML, SHTML, WML, etc); • Aumentar a produtividade

Page 2: Tutorial struts

Licença

A Struts está disponível sobre a licença "free-to-use-license" da Apache Software Foundation (vejahttp://www.apache.org/LICENSE-1.1).

Detalhes do funcionamento

Figura 2 - Fluxo de Navegação nos componentes da Struts

1. O usuário faz uma solicitação através de uma url no browser. Ex:http://localhost:8080/cadastro/listUsers.do. Note que no final da url tem um .do que será usado parainvocar (na verdade mapear) o servlet controller da struts.

2. Se for a primeira solicitação que o container recebeu para esta aplicação, ele irá invocar o metodoinit() da ActionServlet (controller da Struts) e irá carregar as configurações do arquivo struts-config.xml em estruturas de dados na memória. Vale lembrar que esta passagem só será executadauma única vez, pois nas solicitações subsequentes, a servlet consulta estas estruturas na memóriapara decidir o fluxo a ser seguido.

3. Baseado no fluxo definido no arquivo struts-config.xml, e que neste momento já se encntracarregado em estruturas na memória, o ActionSerlet identificará qual o ActionForm (classe para avalidação dos dados) irá invocar. A classe ActionForm através do método validate irá verificar aintegridade dos dados que foram recebidos na solicitação que vem do browser.

4. O controle da aplicação é retomado pelo ActionServlet, que verifica o resultado da verificação doActionForm.

• Se faltou alguma coisa (campo não preenchido, valor inválido, etc), o usuário recebe umformulário html (geralmente o mesmo que fez a solicitação), informando o motivo do nãoatendimento da solicitação, para que o usuário possa preencher corretamente os dados parafazer uma nova solicitação.

• Se não faltou nenhuma informação, ou seja, todos os dados foram enviados corretamente, ocontroller passa para o proximo passo (Action).

5. O ActionServlet, baseado no fluxo da aplicação (estruturas já carregadas em memória) invoca umaclasse Action. A classe Action passará pelo método execute que irá delegar a requisição para acamada de negócio.

6. A camada de negócio irá executar algum processo (geralmente popular um bean, ou uma coleção).O resultado da execução deste processo (objetos já populados) será usado na camada de

Page 3: Tutorial struts

apresentação para exibir os dados. 7. Quando o controle do fluxo da aplicação votar ao Action que invocou o processo da camada de

negócio, será analisado o resultado, e definido qual o mapa adotado para o fluxo da aplicação. Nesteponto, os objetos que foram populados na camada de negócio serão "atachados" como atributos naseção do usuário.

8. Baseado no mapeamento feito pelo o Action, o Controller faz um forward para o JSP para apresentaros dados.

9. Na camada de apresentação (View), os objetos que foram setados como atributos da sessão dousuário serão consultados para montar o html para o browser.

10.Chega o html da resposta requisitada pelo usuário. O Controller já vem implementado na Struts, embora, caso seja possível estendê-lo a fim de adicionarfuncionalidade. O fluxo da aplicação é programado em um arquivo XML através das ações que serãoexecutadas. As ações são classes base implementadas pela framework seguindo o padrão MVC. Assimdevemos estendê-las a fim de adicionar a funcionalidade desejada. A geração da interface é feita através de custom tags, também já implementadas pela Struts, evitando assimo uso de Scriptlets (códigos java entre <%> e <%>), deixando o código JSP mais limpo e fácil de manter.

Baixando e instalando a documentação

A Struts Framework pode ser baixada em http://jakarta.apache.org/struts. Neste tutorial vamos usar aversão 1.1, pois incorpora uma série de melhorias em relação a versão anterior, e já temos uma versãoestável para produção.Após o download, descompactar o arquivo; dentro do diretório descompactado,possui um diretório chamado webapps contendo as aplicações exemplo. Se você tiver usando o TomCat ououtro WebContainer, copie o arquivo struts-documentation.war, para o diretório <webapps> do seucontainer. Neste ponto a documentação da Struts já se enconrtra instalada na sua máquina.Para acessá-la vá parahttp://localhost:8080/struts-documentation.

Projeto do Tutorial

Para entender melhor o funcionamento, vamos fazer uma aplicação prática. Desenvolveremos um cadastrode Usuários com inclusão, alteração e exclusão. Portanto, um nome sugestivo para a nossa aplicação web é"cadastro" Para criar uma nova aplicação com a Struts Framework, devemos seguir os seguintes passos:

• Vá para a linha de comando do seu sistema operacional; • Vá para o diretório onde a Struts framework foi descompactada, e entre no diretório webapps; • Faça a seguinte sequencia de comandos:

mkdir cadastrocd cadastrojar -xvf ../struts-blank.war

• Agora temos uma aplicação web (em branco) baseada na template da Struts para começar abrincar.

• Mova este diretório para o local que mais lhe convier, uma vez que os fontes da sua aplicaçãoficarão abaixo desta estrutura.

Estrutura de diretórios da aplicação web com Struts: RootDir|+-- META-INF| Contém meta informação. Usado pelo Web Container, utilitários, etc.|+-- WEB-INF | +-- classes | | Este diretório contém as classes java da sua aplicação (camada denegócio). | | | +-- java | | | +-- resources

Page 4: Tutorial struts

| | | +-- application.properties | Contém as mensagens (textos fixos) da aplicação, | inclusive as mensagens de erros. | Este arquivo é responsável pela internacionalizaçãoda aplicação. +--- lib | | | +-- struts.jar | Contém as classes da Struts (Controller, Helper class, | Biblioteca de Tags, etc) | Também no diretório lib contém outras bibliotecas da aplicaçãoweb. | +--*.tld | Contém os XML descriptors da biblioteca de tags da Struts. | +-- struts-config.xml | Arquivo de configuração da Struts. | Mais detalhes sobre este arquivo serão vistos adiante. | +-- web.xml Arquivo de configuração da aplicação web, relativo ao WebContainer. Mais detalhes sobre este arquivo serão vistos adiante.

O arquivo web.xml

O arquivo web.xml deverá ficar algo parecido com: <?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"><web-app> <!-- Standard Action Servlet Configuration (with debugging) --> <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> <init-param> <param-name>debug</param-name> <param-value>2</param-value> </init-param> <init-param> <param-name>detail</param-name> <param-value>2</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <!-- Standard Action Servlet Mapping --> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>

<!-- The Usual Welcome File List --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list>

Page 5: Tutorial struts

<!-- Struts Tag Library Descriptors --> <taglib> <taglib-uri>/tags/struts-bean</taglib-uri> <taglib-location>/WEB-INF/struts-bean.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-html</taglib-uri> <taglib-location>/WEB-INF/struts-html.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-logic</taglib-uri> <taglib-location>/WEB-INF/struts-logic.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-nested</taglib-uri> <taglib-location>/WEB-INF/struts-nested.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-tiles</taglib-uri> <taglib-location>/WEB-INF/struts-tiles.tld</taglib-location> </taglib></web-app>Temos no arquivo web.xml, três importantes seções:

• A definição da Servlet que representa o Controller (ActionServlet) • O URL mapping da servlet, para informar como chamar esta servlet • As definições da biblioteca de tags da Struts

Podemos ver pelo servlet-mapping que a nossa servlet será invocada porhttp://localhost:8080/cadastro/<algumaCoisa>.do, substituindo-se <algumaCoisa> pela ação desejada.

Banco de dados

Por questões de facilidade de obtenção e configuração e Usaremos o MySQL como banco de dados. O MySqlpode ser baixado em http://www.mysql.com Script de criação do banco de dados: CREATE DATABASE strutsdemo;USE strutsdemo;CREATE TABLE usuario( id_usuario INTEGER NOT NULL, nome VARCHAR(50) NULL, login VARCHAR(20) NULL, senha VARCHAR(20) NULL, sexo CHAR NULL, ativo BOOL NULL, faixa_idade INTEGER, PRIMARY KEY(id_usuario));INSERT INTO usuario (id_usuario, nome, login, senha, sexo, ativo, faixa_idade)VALUES (1, 'Marcelo Ferreira Dantas', 'marcelo', 'marcelo', 'M', 1, 1);INSERT INTO usuario (id_usuario, nome, login, senha, sexo, ativo, faixa_idade)VALUES (2, 'Gerson Hernandes Vilela', 'gerson', 'gerson', 'M', 1, 2);INSERT INTO usuario (id_usuario, nome, login, senha, sexo, ativo, faixa_idade)VALUES (3, 'Manuela Rodrigues', 'Manuela', 'manu', 'F', 1, 2);Para acessar os dados no MySQL será necessário adicionar o driver JDBC no lib da nossa aplicação. O driver

Page 6: Tutorial struts

pode ser baixado em http://www.mysql.com/downloads/api-jdbc-stable.html. Após baixá-lo,descompactar e copiar o arquivo mysql-connector-java-3.0.8-stable-bin.jar para diretório lib do seu container(no tomcat é "$CATALINA_HOME/common/lib" já no JBoss vai diretório"$JBOSS_HOME/server/default/deploy").

Definindo as configurações do Connection Pool

A maioria das aplicações para web que usam banco de dados podem ser beneficiadas por um ConnectionPool (coleção de conexões que ficam permanentemente abertas com o SGBD). Estabelecer uma conexão com o banco de dados a cada solicitação que chega no web server paraconsultar/manipular dados é um processo muito dispendioso (conexão e verificação de permissões dousuário do banco). Uma aplicação não usa banco de dados o tempo todo, somente em algums momentos para obter os dados,depois esta conexão não é mais necessária. Nesse sentido, um Connection Pool pode ajudar bastante, eliminando um overread desnecessário de sereconectar a cada solicitação que chega, pois ele fará o gerenciamento da coleção de conexões prontas paraserem usadas, e "marcará" as conexões em uso. Se por acaso você pegar uma conexão e ficar umdeterminado tempo sem fazer nada (timeout), o Connection Pool regata esta conexão para uso, e invalida oobjeto de conexão que você pegou anteriormente. Tamanha é a importância deste tópico, que acabouentrando na especificação JDBC (javax.sql.DataSource). Praticamente todos os Containers possuem ummecanismo que fornecem um Connection Pool. Embora o nosso projeto seja baseado no MySQL, que provavelmente muitos dirão que não há necessidadede se fazer isto com o MySQL, pois o processo de conexão é extremamente rápido, não podemos dizer omesmo de outros bancos. Mesmo assim, é interessante usar um Connection Pool, pois pode parecerimperceptível para uma só solicitação chegando, mas em um ambiente de produção, com a sua aplicaçãosendo macivamente solicitada para manipular e consultar dados, daí sim haverá uma grande diferença. A Struts Framework implementa um Connection Pool usando DataSource. Na versão 1.0, a Conexão eraobtida do ActionServlet. No entanto, nas nos betas e release candidate da versão 1.1 o metodo paraobtenção de conexões ficou deprecated, e passaram esta tarefa para o Action. Por fim no release 1.1 deprodução, as classes que tratam do DataSource foram parar no arquivo struts-legacy.jar, indicandoclaramente a intenção de descontinuar esta funcionalidade em favor de uma solução padrão (JCA), ou seja,implementada pelo container; apesar de ainda continuar funcionando. Assim, vamos usar umaimplementação fornecida pelo container. Para definir as configurações de um DataSource no TomCat, siga os passos abaixo: Altere o arquivo server.xml adicionando o trecho abaixo: <Host name="localhost" debug="0" appBase="webapps" unpackWARs="true"autoDeploy="true"> ... <DefaultContext> <Resource name="jdbc/StrutsDemoDS" auth="Container"type="javax.sql.DataSource" scope="Shareable"/> <ResourceParams name="jdbc/StrutsDemoDS"> <parameter><name>factory</name><value>org.apache.commons.dbcp.BasicDataSourceFactory</value></parameter> <parameter><name>driverClassName</name><value>com.mysql.jdbc.Driver</value></parameter> <parameter><name>url</name><value>jdbc:mysql://localhost/strutsdemo</value></parameter> <parameter><name>username</name><value>root</value></parameter> <parameter><name>password</name><value>root</value></parameter> <parameter><name>maxActive</name><value>20</value></parameter> <parameter><name>maxIdle</name><value>10</value></parameter> <parameter><name>maxWait</name><value>100</value></parameter> </ResourceParams> </DefaultContext> ...</Host>No código Java, quando precisar de uma conexão de banco de dados, você irá solicitar uma conexão aoConnection Pool, o qual irá marcar uma conexão no Pool, como sendo usada, e lhe dará algum tempo parafazer alguma coisa. Tão logo que você use a conexão para consultar ou manipular dados no banco de dados,será necessário devolver a conexão para o pool (se não fizer isto o Connection Pool fecha a conexão paravocê e a resgata para o pool). Para fazer isto, basta executar o método close(), que na verdade não a fecha,

Page 7: Tutorial struts

mas devolve para o Pool (dependendo da implementação do Connection Pool, poderá ter variações damaneira de devolver ao pool, algo do tipo invocar um metodo do tipo releaseConnection, do objetoConnection Pool).

Definindo a Camada de Negócio

Para listar os usuários cadastrados precisaremos definir as classes que farão parte da nossa camada deNegócio. Devemos ter duas classes. Uma classe que representa o registro do usuário "UserData" (valueobject) , e outra que irá gerenciar o cadastro dos usuários "AdminUsers". Segue abaixo o código das duasclasses: package strutsdemo.bean;public class UserData { private int idUsuario; private String nome; private String login; private String senha; private String sexo; private boolean ativo; private int faixaIdade;

public void setIdUsuario(int idUsuario) { this.idUsuario = idUsuario; } public void setLogin(String login) { this.login = login; } public void setNome(String nome) { this.nome = nome; } public void setSenha(String senha) { this.senha = senha; } public void setSexo(String sexo) { this.sexo = sexo; } public void setAtivo(boolean ativo) { this.ativo = ativo; } public void setFaixaIdade(int faixaIdade) { this.faixaIdade = faixaIdade; } public int getIdUsuario() { return idUsuario; } public String getLogin() { return login; } public String getNome() { return nome; } public String getSenha() { return senha; } public String getSexo() { return sexo; } public boolean getAtivo() { return ativo; } public String getDescricaoStatus() { return this.ativo ? "Ativo": "Inativo"; } public int getFaixaIdade() {

Page 8: Tutorial struts

return faixaIdade; }}package strutsdemo.bean;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.LinkedList;import javax.naming.InitialContext;import javax.naming.NamingException;import javax.sql.DataSource;public class AdminUsers {

protected static DataSource dataSource; public AdminUsers() throws Exception { if (dataSource == null) { try { InitialContext ic = new InitialContext(); // se for tomcat dataSource = (DataSource) ic.lookup("java:comp/env/jdbc/StrutsDemoDS"); // no JBoss faça // dataSource = (DataSource) ic.lookup("java:jdbc/StrutsDemoDS"); } catch (NamingException ex) { System.out.println(ex.getMessage()); throw ex; } } } protected Connection getConnection() throws SQLException { Connection conn = null; try { conn = dataSource.getConnection(); } catch (SQLException e) { throw e; } return conn; }

protected void closeConnection( Connection conn, PreparedStatement stmt, ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException e) { } } if (stmt != null) { try { stmt.close(); } catch (SQLException e) { } } if (conn != null) { try {

Page 9: Tutorial struts

conn.close(); } catch (SQLException e) { } } } public LinkedList getUserList() throws SQLException { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; LinkedList users = new LinkedList(); try { conn = getConnection(); stmt = conn.prepareStatement("select * from usuario"); rs = stmt.executeQuery(); while (rs.next()) { UserData user = new UserData(); user.setIdUsuario(rs.getInt("id_usuario")); user.setNome(rs.getString("nome")); user.setLogin(rs.getString("login")); user.setSenha(rs.getString("senha")); user.setSexo(rs.getString("sexo")); user.setAtivo(rs.getBoolean("ativo")); user.setFaixaIdade(rs.getInt("faixa_idade")); users.add(user); } } catch (SQLException e) { throw e; } finally { closeConnection(conn, stmt, rs); } return users; } public void insertUser(UserData user) throws SQLException { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = getConnection(); stmt = conn.prepareStatement( "insert into usuario \n" + "(id_usuario, nome, login, senha, sexo, ativo, faixa_idade) \n"+ "values (?, ?, ?, ?, ?, ?, ?)"); stmt.setInt(1, user.getIdUsuario()); stmt.setString(2, user.getNome()); stmt.setString(3, user.getLogin()); stmt.setString(4, user.getSenha()); stmt.setString(5, user.getSexo()); stmt.setBoolean(6, user.getAtivo()); stmt.setInt(7, user.getFaixaIdade()); stmt.executeUpdate(); } catch (SQLException e) { throw e; } finally { if (rs != null) { rs.close(); } if (stmt != null) { stmt.close(); } } }

Page 10: Tutorial struts

public void updateUser(UserData user) throws SQLException { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = getConnection(); stmt = conn.prepareStatement( "update usuario set \n" + "nome = ?, login = ?, senha = ?, sexo = ?, ativo = ?,faixa_idade = ? \n" + "where id_usuario = ?"); stmt.setString(1, user.getNome()); stmt.setString(2, user.getLogin()); stmt.setString(3, user.getSenha()); stmt.setString(4, user.getSexo()); short ativo = (short) (user.getAtivo()? 1: 0); stmt.setShort(5, ativo); stmt.setInt(6, user.getFaixaIdade()); stmt.setInt(7, user.getIdUsuario()); stmt.executeUpdate(); } catch (SQLException e) { throw e; } finally { if (rs != null) { rs.close(); } if (stmt != null) { stmt.close(); } } } public void deleteUser(int idUsuario) throws SQLException { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = getConnection(); stmt = conn.prepareStatement( "delete from usuario where id_usuario = ?"); stmt.setInt(1, idUsuario); stmt.executeUpdate(); } catch (SQLException e) { throw e; } finally { if (rs != null) { rs.close(); } if (stmt != null) { stmt.close(); } } }}

Definindo o Controller

O Controller é responsável por receber as requisições do browser e invocar os objetos de negócio do Modelpara executar algum processo retornando um resultado que servirá de base para que o Controller possadirecionar para o JSP que deverá gerar a interface com o usuário. O ActionServlet lê as configurações do arquivo struts-config.xml. Ao receber as solicitações do usuário,chama o ActionBean correspondente à requisição, e de acordo com o resultado do ActionBean, executa umJSP.

Page 11: Tutorial struts

Para incluir, alterar ou excluir um usuário, precisamos exibir todos os usuários cadastrados para saber o quefazer. Assim, a nossa primeira implementação será exibir os usuários já cadastrados.

Siga os procedimentos abaixo:

• Criar uma package strutsdemo, e uma classe chamada ListUsersAction dentro desta package. A classedeve estender de org.apache.struts.action.Action (vamos entrar em mais detalhes sobre esta classe naseção "Definindo o Action Bean").

package strutsdemo;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.struts.action.Action;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;public class ListUsersAction extends Action { /* Metódo que invoca a camada de negócios.*/ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { return null; // somente para compilar, implementação futura ... }}• Adicionar configuração no arquivo strutus-config.xml do Action Mapping e seus possíveis forwards de

saída. </struts-config> <action-mappings> <action path="/listUsers" type="strutsdemo.ListUsersAction"> <forward name="success" path="/listUsers.jsp" /> </action> </action-mappings></struts-config>Neste caso, quando for solicitado pelo browser /listUsers.do" o Controller chamará o ListUsersAction atravésdo método process, e se este objeto retornar um ActionForward com o valor "sucess", O controllerencaminhará a solicitação para o arquivo "/pages/listUsers.jsp". Se retornar "failure", será encaminhado parao arquivo "/pages/error.jsp".

Definindo o Action Bean

Como foi visto anteriormente, o Controller irá invocar o Action que foi definido no struts-config.xml. Há umacerta discussão sobre que parte pertence o Action e o ActionForm no padrão MVC (vamos entrar em maioresdetalhes mais adiante em ActionForm, por hora ainda não é necessário). Na realidade tanto o Action, quantoo ActionForm são Helper Classes. A grosso modo podemos entender como classes auxiliadores paraexecução no padrão MVC. Basicamente, os ActionBeans realizam as seguintes ações: • Obtem os valores necessários do ActionForm, JavaBean, request, session ou de outro local; • Chama os objetos de negócio do modelo; • Analisa o resultado da chamada da camada de negócio, e baseado nisso, retorna o ActionForward

(indicando qual JSP irá apresentar os dados) correspondente O Código da nossa Action ficará assim: package strutsdemo.action;import java.sql.SQLException;import java.util.LinkedList;

Page 12: Tutorial struts

import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.apache.struts.action.Action;import org.apache.struts.action.ActionError;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;import strutsdemo.bean.AdminUsers;public class ListUsersAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { LinkedList users = null; ActionErrors errors = new ActionErrors(); try { AdminUsers adminUsers = new AdminUsers(); users = adminUsers.getUserList(); HttpSession session = request.getSession(); session.setAttribute("userListBean", users); } catch (SQLException e) { errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error.user.list")); getServlet().log("Erro carregando a lista de usuários", e); } if (!errors.isEmpty()) { saveErrors(request, errors); return (mapping.findForward("failure")); } else { return (mapping.findForward("success")); } }}

Definindo a camada de apresentação

A Camada de apresentação representa o view (visualização) no padrão MVC. É em sua grande maioriabaseada em JSPs e alguns servlets envolvidos na geração da interface com o usuário ou com outrossistemas. A Struts framework fornece suporte para construir aplicações multi-idiomas, interação comformulários e outras utilidades através de tags personalizadas (Custom Tags).

Internacionalização

No nosso projeto (baseado no template struts-blank ), possui um arquivo de chamado application.propertiesno diretório cadastro/WEB-INF/classes/java/resources. Este arquivo deve conter as chaves e os valores noformato: chave.subchave=texto que pertence ao idioma padrão da aplicação. Vamos adicionar algumaschaves que serão usadas em nosso projeto. Obs: Este arquivo pode ter qualquer nome, desde que terminecom .properties. No entanto existe um certo padrão, geralmente é chamado deApplicationResources.properties. A única ressalva, é que se você mudar o nome deste arquivo, tambémdeverá ser mudado no arquivo struts-config.xml. welcome.title=Bem Vindo ao Projeto Tutorial Strutswelcome.heading=Bem vindo!welcome.message=Projeto Tutorial Struts

Page 13: Tutorial struts

application.title= Struts Demo - Cadastroindex.header=Bem vindo ao Demo da Strutus Framework - Cadastrousers.title=Cadastro de UsuárioseditUser.title=Alteração de UsuárioinsertUser.title=Inclusão de Usuárioprompt.idUsuario=Códigoprompt.nome=Nomeprompt.login=Loginprompt.senha=Senhaprompt.confirmacaoSenha=Confirmação da Senhaprompt.sexo=Sexoprompt.ativo=Ativoprompt.status=Statusprompt.faixaIdade=Faixa Etáriaprompt.excluir=Excluirprompt.incluir=Incluirprompt.voltar=Voltarprompt.Masculino=Masculinoprompt.Feminino=Femininoprompt.ate20=Até 20 anosprompt.de21a30=De 21 a 30 anosprompt.de31a40=De 31 a 40 anosprompt.de41a50=De 41 a 50 anosprompt.de51a60=De 51 a 60 anosprompt.acima60=Acima de 60 anosprompt.senhaAntiga=Senha Antigaprompt.novaSenha=Nova Senhaprompt.confirmacaoNovaSenha=Confirmação da Senhabutton.send=Enviarbutton.reset=Cancelarerror.title=Erro Inesperadoerror.user.list=Erro obtendo a lista de usuárioserror.idUsuario.required=O identificador do usuário é um campo obrigatórioerror.login.required=O login do usuário é um campo obrigatórioerror.nome.required=O nome do usuário é um campo obrigatórioerror.get.user=Erro ao carregar o usuárioerror.senhaAntiga.required=A senha antiga é um campo obrigatórioerror.novaSenha.required=A nova senha é um campo obrigatórioerror.confirmacaoNovaSenha.required=A confirmação da nova senha é um campoobrigatórioerror.ConfirmacaoSenha=Erro na confirmação da nova senhaerror.user.notFound=Usuário não encontradoerror.senhaAntiga=A senha Antiga não confereerror.update.user=Erro alterando o usuárioerror.update.user=Erro incluindo o usuárioerror.delete.user=Erro excluindo o usuárioerror.idUsuario.duplicateKey=Este código de usuário já existePara cada idioma alternativo, devemos adicionar um novo arquivo (no mesmo diretório do arquivo ondetemos o arquivo do idioma padrão) no formato "application_xx.properties", onde xx é o código ISO doidioma. Ex: (application_en.properties). No arquivo struts-config.xml devemos definir a localização do arquivo com o idioma padrão.Coloque neste: <message-resources parameter="resources.application"/>Obs: Na Struts 1.0 este arquivo era definido no arquivo web.xml

Nos JSPs que utilizaremos a internacionalização deveremos incluir: ...<%@ taglib uri="/tags/struts-bean" prefix="bean" %>...Para declarar que utilizaremos a TagLibrary struts-bean com o prefixo bean e definida no arquivo /WEB-INF/struts-bean.tld, configurados no arquivo web.xml. E finalmente, utilizaremos a tag (no JSP)<bean:message key="chave.subchave"/> onde a chave e a subchave correspondem ao texto que seráinserido de acordo com o idioma do usuário. Exemplo: ...

Page 14: Tutorial struts

<h3><bean:message key="application.title"/></h3>...Por default, a Struts acessa o idioma principal da aplicação. Devemos utilizar a tag <html:htmllocale="true"> substituindo a tag <html>, assim, deveremos substituir também a tag </html> por</html:html> Deste modo, será usado preferencialmente o idioma principal que se encontra no header"Accept-Language" enviado pelo navegador.

Quando o usuário fizer uma solicitação escolher um novo idioma, baseado em uma lista de idiomassuportados, informados previamente, adicionaremos o trecho abaixo: session.setAttribute(Action.LOCALE_KEY,new Java.util.Locale(country, language));Onde country e language será a string do país e que será feita a tradução. Para mais informações a respeitodo assunto, veja a documentação oficial da Sun disponível emhttp://java.sun.com/j2se/1.4.2/docs/guide/intl. Por questões de organização vamos colocar todos os nossos JSPs no diretório cadastro/pages/. Assim, já podemos escrever o nosso primeiro JSP para listar os usuários: <%@ taglib uri="/tags/struts-logic" prefix="logic" %><%@ taglib uri="/tags/struts-html" prefix="html" %><%@ taglib uri="/tags/struts-bean" prefix="bean" %><logic:notPresent name="userListBean" scope="session"> <logic:redirect forward="error"/></logic:notPresent><html:html locale="true"><head> <title><bean:message key="users.title"/></title></head><body> <center> <font face="Comic Sans MS" size="3"> <blockquote> <center> <h3><font color="blue"><bean:messagekey="users.title"/></font></h3> <table width="80%" border="1"> <tr> <th width="10%"><bean:messagekey="prompt.idUsuario"/></th> <th width="50%"><bean:message key="prompt.nome"/></th> <th width="20%"><bean:message key="prompt.login"/></th> <th width="10%"><bean:message key="prompt.ativo"/></th> <th width="10%"></th> </tr> <%-- loop que percorre a Collection de usuarios --%> <logic:iterate name="userListBean" id="user" > <tr> <td align="center"> <bean:write name="user" property="idUsuario"/> </td> <td> <html:link page="/editUser.do"paramId="idUsuario" paramName="user" paramProperty="idUsuario"> <bean:write name="user" property="nome"/> </html:link> </td> <td><bean:write name="user" property="login"/></td> <td><bean:write name="user"property="descricaoStatus"/></td> <td> <html:link page="/deleteUser.do"paramId="idUsuario" paramName="user" paramProperty="idUsuario"> <bean:message key="prompt.excluir"/> </html:link> </td> </tr>

Page 15: Tutorial struts

</logic:iterate> </table> <br/> <html:link page="/insertUser.do">incluir</html:link> <html:link page="/Welcome.do">Página Inicial</html:link> </center> </lockquote> </body></html:html>Neste ponto, já temos uma aplicação funcionando parcialmente (listando os usuários). No entanto se clicarem algum link, irá ocorrer um erro, pois ainda não temos os ActionBeanss necessários para invocar acamada de negócio. Neste momento para facilitar o entendimento, vamos implementar apenas os Beansnecessários para Alterar o usuário. Devemos criar um ActionBean que deverá invocar a camada de negócio epopular um bean com os dados do usuário a ser alterado, e enviar para a camada de apresentação para queos dados possam ser alterados. Segue abaixo o código do ActionBean. package strutsdemo.action;import java.util.Iterator;import java.util.LinkedList;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.apache.struts.action.Action;import org.apache.struts.action.ActionError;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;import strutsdemo.bean.AdminUsers;import strutsdemo.bean.UserData;public class EditUserAction extends Action { public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionErrors errors = new ActionErrors(); try { HttpSession session = request.getSession(); AdminUsers adminUsers = new AdminUsers(); String idUsuario = request.getParameter("idUsuario"); session.removeAttribute("editUserBean"); LinkedList userList = (LinkedList)session.getAttribute("userListBean"); Iterator iter = userList.iterator(); while (iter.hasNext()) { UserData user = (UserData)iter.next(); if (user.getIdUsuario() == Integer.parseInt(idUsuario)) { session.setAttribute("editUserBean", user); break; } } UserData user = (UserData)session.getAttribute("editUserBean"); if (user == null) { errors.add( ActionErrors.GLOBAL_ERROR, new ActionError("error.user.notFound")); } } catch (Exception e) { errors.add( ActionErrors.GLOBAL_ERROR,

Page 16: Tutorial struts

new ActionError("error.get.user")); getServlet().log("Erro carregando o Usuário", e); }

if (!errors.isEmpty()) { saveErrors(request, errors); return (mapping.findForward("failure")); } else { return (mapping.findForward("success")); } }}Agora devemos alterar o arquivo struts-config.xml, ou seja acrescentar um action-mapping. Para isto bastaadicionar o trecho de código abaixo na seção <action-mappings> <action path="/editUser" scope="session" type="strutsdemo.action.EditUserAction" unknown="false" validate="false"> <forward name="success" path="/pages/editUser.jsp" redirect="false" contextRelative="false" /></action>Por fim vamos ver como fica o código JSP para alterar o usuário(editUser.jsp). Vale lembrar que o códigoJSP abaixo ainda não pode ser executado, pois depende de um Action que ainda não foi implementado. <%@ taglib uri="/tags/struts-logic" prefix="logic" %><%@ taglib uri="/tags/struts-bean" prefix="bean"%><%@ taglib uri="/tags/struts-html" prefix="html"%><html:html locale="true"> <head> <title><bean:message key="editUser.title"/></title> </head> <body> <font face="Comic Sans MS" size="3"> <center> <h3><font color="blue"><bean:messagekey="editUser.title"/></font></h3> <html:form action="/saveEditUser.do" method="post"focus="login"> <html:hidden property="idUsuario" name="editUserBean"/> <table width="80%" border="0"> <tr> <td width="30%"></td> <td width="70%"> <%-- exibe os erros de validação --%> <logic:messagesPresent> <ul> <html:messages id="error"> <li><bean:write name="error"/></li> </html:messages> </ul> </logic:messagesPresent> </td> <tr> <tr> <td align="right"><bean:messagekey="prompt.idUsuario"/>: </td> <td align="left"><b><bean:write property="idUsuario"name="editUserBean"/></b></td> </tr> <tr> <td align="right"><bean:message

Page 17: Tutorial struts

key="prompt.login"/>: </td> <td align="left"><html:text property="login"name="editUserBean" size="20"/></td> </tr> <tr> <td align="right"><bean:messagekey="prompt.nome"/></td> <td align="left"><html:text property="nome"name="editUserBean" size="60"/></td> </tr> <tr> <td align="right"><bean:messagekey="prompt.senhaAntiga"/>: </td> <td align="left"><html:passwordproperty="senhaAntiga" size="16" maxlength="20" redisplay="false"value="zzzzz"/></td> </tr> <tr> <td align="right"><bean:messagekey="prompt.novaSenha"/>: </td> <td align="left"><html:password property="novaSenha"size="16" maxlength="20" redisplay="false"value="zzzzz"/></td> </tr> <tr> <td align="right"><bean:messagekey="prompt.confirmacaoNovaSenha"/>: </td> <td align="left"><html:passwordproperty="confirmacaoNovaSenha" size="16" maxlength="20" redisplay="false"value="zzzzz"/></td> </tr> <tr> <td align="right"><bean:messagekey="prompt.faixaIdade"/>: </td> <td align="left"> <html:select property="faixaIdade"name="editUserBean"> <html:option value="1"><bean:messagekey="prompt.ate20"/></html:option></html:option> <html:option value="2"><bean:messagekey="prompt.de21a30"/></html:option></html:option> <html:option value="3"><bean:messagekey="prompt.de31a40"/></html:option></html:option> <html:option value="4"><bean:messagekey="prompt.de41a50"/></html:option></html:option> <html:option value="5"><bean:messagekey="prompt.de51a60"/></html:option></html:option> <html:option value="6"><bean:messagekey="prompt.acima60"/></html:option></html:option> </html:select> </td> </tr> <tr> <td align="right"><bean:message key="prompt.sexo"/>:</td> <td align="left"> <html:radio property="sexo" value="M"name="editUserBean"> <bean:message key="prompt.Masculino"/> </html:radio> <html:radio property="sexo" value="F"name="editUserBean"> <bean:message key="prompt.Feminino"/> </html:radio> </td>

Page 18: Tutorial struts

</tr> <tr> <td align="right"><bean:messagekey="prompt.ativo"/>: </td> <td align="left"> <html:checkbox property="ativo"name="editUserBean" titleKey="prompt.ativo"/> </td> </tr> <tr> <td colspan="2" align="center"> <html:submit><bean:messagekey="button.send"/></html:submit> <html:reset><bean:messagekey="button.reset"/></html:reset> </td> </tr> </table> </html:form> <br/> <html:link page="/listUsers.do">voltar</html:link> </center> </font> </body></html:html>

Forms

Uma das tarefas mais trabalhosas no desenvolvimento de uma aplicação é a interação com formulários, parase alterar e obter nova informação. As validações, o tratamento de erros, a apresentação, e o mesmo aentrada de dados do form pelo usuário e mensagens de erros, são contempladas pela Struts, o que torna avida um pouco mais fácil. Todo trabalho de validação e geração de mensagens de erros serãoimplementados nos ActionForm e todo o trabalho de geração de interface no JSP. Basicamente o ActionForm será um espelho dos inputs que vem do html do browser, ou seja, deverá contertodos os campos (variaveis privadas com os devidos metodos gets e sets), coincidindo com o nome dosinputs do formulário html. Toda validação de dados pela Struts passa por um FormBean. O FormBean é a primeira classe (quandodefinida no action-mapping) a ser chamada através do método validate (Detalhes na Figura 2). No entanto,nem toda solicitação que vem da web necessita de validação de dados. Assim só será necessário usar umFormBean quando necessitarmos de validação dos dados. No nosso caso, quando precisarmos salvar os dados que foram alterados pelo usuário. No entanto, antes dedevemos fazer uma validação para que não vá besteira para o banco de dados. Um ActionForm possui doismétodos importantes. São eles reset e validate. Veja abaixo a implementação do nosso ActionForm que faz as validações mínimas necessárias. package strutsdemo.form;import javax.servlet.http.HttpServletRequest;import org.apache.struts.action.ActionError;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionMapping;public class SaveEditUserForm extends ActionForm { private String idUsuario; private String login; private String nome; private String ativo; private String faixaIdade; private String sexo; private String senhaAntiga; private String novaSenha; private String confirmacaoNovaSenha;

Page 19: Tutorial struts

public void reset(ActionMapping mapping, HttpServletRequest request) { idUsuario = "-1"; login = ""; nome = ""; ativo = "false"; faixaIdade = "1"; sexo = "M"; senhaAntiga = ""; novaSenha = ""; confirmacaoNovaSenha = ""; } public ActionErrors validate( ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = new ActionErrors(); if ((idUsuario == null) || (idUsuario.length() < 1)) { errors.add("idUsuario", new ActionError("error.idUsuario.required")); } if ((login == null) || (login.length() < 1)) { errors.add("login", new ActionError("error.login.required")); } if ((nome == null) || (nome.length() < 1)) { errors.add("nome", new ActionError("error.nome.required")); } if ((novaSenha == null) || (novaSenha.length() < 1)) { errors.add("nome", new ActionError("error.novaSenha.required")); } if ((confirmacaoNovaSenha == null) || (confirmacaoNovaSenha.length() <1)) { errors.add("confirmacaoNovaSenha", new ActionError("error.confirmacaoNovaSenha.required")); } if ((senhaAntiga == null) || (senhaAntiga.length() < 1)) { errors.add("senhaAntiga", new ActionError("error.senhaAntiga.required")); } if (errors.isEmpty()) { if (!novaSenha.equals(confirmacaoNovaSenha)) { errors.add("senhaAntiga", new ActionError("error.ConfirmacaoSenha")); } } return errors; } public String getNovaSenha() { return novaSenha; } public void setNovaSenha(String novaSenha) { this.novaSenha = novaSenha; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public String getAtivo() { return ativo; } public void setAtivo(String ativo) { this.ativo = ativo; } public String getLogin() { return login;

Page 20: Tutorial struts

} public void setLogin(String login) { this.login = login; } public String getSenhaAntiga() { return senhaAntiga; } public void setSenhaAntiga(String senhaAntiga) { this.senhaAntiga = senhaAntiga; } public String getSexo() { return sexo; } public void setSexo(String sexo) { this.sexo = sexo; } public String getConfirmacaoNovaSenha() { return confirmacaoNovaSenha; } public void setConfirmacaoNovaSenha(String confirmacaoNovaSenha) { this.confirmacaoNovaSenha = confirmacaoNovaSenha; } public String getFaixaIdade() { return faixaIdade; } public void setFaixaIdade(String faixaIdade) { this.faixaIdade = faixaIdade; } public String getIdUsuario() { return idUsuario; } public void setIdUsuario(String idUsuario) { this.idUsuario = idUsuario; }}Quando terminar a execução do método validate, se ocorrer algum erro, será adicionado em um Collectionde erros. Se este collection tiver algum erro, o FormBean devolve para o jsp que entrou com os dados, comos campos devidamente preenchidos, e com as mensagens dos erros ocorridos. Caso contrário, ou seja, senão ocorrer nenhum erro, então o fluxo segue para um ActionBean para invocar a camada de negócio paragravar estes dados no banco de dados. Logo, precisamos criar este bean. Segue abaixo o código do nossoActionBean. package strutsdemo.action;import java.sql.SQLException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import javax.sql.DataSource;import org.apache.commons.beanutils.BeanUtils;import org.apache.struts.action.Action;import org.apache.struts.action.ActionError;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;import strutsdemo.bean.AdminUsers;import strutsdemo.bean.UserData;import strutsdemo.form.SaveEditUserForm;public class SaveEditUserAction extends Action { public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request,

Page 21: Tutorial struts

HttpServletResponse response) throws Exception { ActionErrors errors = new ActionErrors(); try { HttpSession session = request.getSession(); SaveEditUserForm editUserForm = (SaveEditUserForm)form; UserData user = (UserData)session.getAttribute("editUserBean"); if (!editUserForm.getSenhaAntiga().equals("zzzzz")) { if (!user.getSenha().equals(editUserForm.getSenhaAntiga())) { errors.add( ActionErrors.GLOBAL_ERROR, new ActionError("error.senhaAntiga")); } else { user.setSenha(editUserForm.getNovaSenha()); } } if (errors.isEmpty()) { BeanUtils.copyProperties(user, editUserForm); DataSource dataSource = getDataSource(request); AdminUsers adminUsers = new AdminUsers(); adminUsers.updateUser(user); } } catch (SQLException e) { errors.add( ActionErrors.GLOBAL_ERROR, new ActionError("error.update.user")); getServlet().log("Erro alterando o Usuário", e); }

if (!errors.isEmpty()) { saveErrors(request, errors); return (mapping.findForward("failure")); } else { return (mapping.findForward("success")); } }}Agora, que fizemos o FormBean e o ActionBean, devemos fazer o action-mapping associando estes beans.Segue abaixo as alterações necessárias no struts-config.xml. <form-beans><form-bean dynamic="false" name="saveEditUserForm" type="strutsdemo.form.SaveEditUserForm"></form-beans>...<action-mappings>... <action attribute="saveEditUserForm" input="/pages/editUser.jsp" name="saveEditUserForm" path="/saveEditUser" scope="session" type="strutsdemo.action.SaveEditUserAction" unknown="false" validate="true"> <forward name="success" path="/pages/listUsers.jsp" redirect="false" contextRelative="false" /> </action>

Page 22: Tutorial struts

...</action-mappings>Obs: Até a versão 1.0 da Struts, a única maneira de validar os dados era herdando do ActionForm, ecolocando as regras de validação no método validate. No entanto com a Struts 1.1 é possível fazer avalidação através de um Form Dinâmico, mais adiante veremos como definir um Form dinâmico. Outra novidade na Struts 1.1 é o suporte para validação do lado client através de uma biblioteca dejavascript definidos no arquivo validator.xml. Assim, podemos evitar o overread gerado pelas solicitaçõesdesnecessárias no servidor, pois quando a solicitação chega ao web server, estaremos tratando com osdados previamente tratados pelo javascript do lado client. Só pra constar como lembrete para os novatos em internet. Pode parecer tentador, mas nunca deixe devalidar os dados no lado servidor se tiver tudo tratado no lado client, pois o usuário pode desabilitar ojavascript do browser e causar erros imprevisíveis na sua aplicação. Conclusão: Use javascript para validar sepuder, e sempre use validação do lado servidor.

Validando dados via javascript

Para fazer a validação com a struts no client via javascript devemos acrescentar os criterios no arquivo noarquivo validation.xml. Adicionar o trecho de código abaixo na seção <formset>. <formset> <form name="saveEditUserForm"> <field property="idUsuario" depends="required"> <arg0 key="prompt.idUsuario"/> </field> <field property="login" depends="required"> <arg0 key="prompt.login"/> </field> <field property="nome" depends="required"> <arg0 key="prompt.nome"/> </field> <field property="novaSenha" depends="required,mask"> <arg0 key="prompt.novaSenha"/> <var> <var-name>mask</var-name> <var-value>^[0-9a-zA-Z]*$</var-value> </var> </field> <field property="senhaAntiga" depends="required,mask"> <arg0 key="prompt.senhaAntiga"/> <var> <var-name>mask</var-name> <var-value>^[0-9a-zA-Z]*$</var-value> </var> </field> <field property="confirmacaoNovaSenha" depends="required,mask"> <arg0 key="prompt.confirmacaoNovaSenha"/> <var> <var-name>mask</var-name> <var-value>^[0-9a-zA-Z]*$</var-value> </var> </field> </form> </formset>Também precisaremos "traduzir" algumas mensagens que já vieram no arquivo application.properties datemplate struts-blank.war, pois serão usados no javascript. # Mensagens de erro padrão para as validaçõeserrors.required={0} é um campo obrigatório.errors.minlength={0} Não pode ser menor que {1} caracteres.errors.maxlength={0} Não pode ser maior que {2} caracteres.errors.invalid={0} está inválido.errors.byte={0} deve ser um byte.errors.short={0} deve ser um inteiro curto.errors.integer={0} deve ser um inteiro.errors.long={0} deve ser um inteiro longo.errors.float={0} deve ser um ponto flutuante de precisão simples.errors.double={0} deve ser um ponto flutuante de precisão dupla.

Page 23: Tutorial struts

errors.date={0} não é uma data.errors.range={0} não está na faixa entre {1} e {2}.errors.creditcard={0} não é um número de cartão de crédito válido.errors.email={0} não é um e-mail válido.Neste ponto temos a aplicação Listando e alterando o cadastro de usuários. No entanto, precisamos aindafazer a Inclusão e a Exclusão de Usuários. Então vamos lá ...

Forms Dinâmicos

Uma das grandes melhorias do Struts 1.1 em relação à 1.0 (pode haver controvérsias, mas ...) foi aintrodução dos DynamicForms. Assim você não é mais "obrigado" a criar um Form para validar as entradasde cada formulário HTML. O Dynamic Form é configurado apenas no struts-config.xml e a Struts já tem umaclasse "prontinha para fazer as validações para você. Veja o trecho abaixo do codigo para um Form Dinâmico: <form-bean dynamic="true" name="saveInsertUserForm"type="org.apache.struts.validator.DynaValidatorForm"> <form-property name="idUsuario" type="java.lang.String" /> <form-property name="login" type="java.lang.String" /> <form-property name="nome" type="java.lang.String" /> <form-property name="faixaIdade" type="java.lang.String" /> <form-property name="sexo" type="java.lang.String" /> <form-property name="ativo" type="java.lang.String" /> <form-property name="senha" type="java.lang.String" /> <form-property name="confirmacaoSenha" type="java.lang.String" /></form-bean>

Terminando o projeto

Neste ponto o nosso projeto está praticamente finalizado. A partir de agora vamos repetir alguns passos quejá foram feitos antes. ou seja, se você chegou até aqui, só falta um pouco de pratica para você se tornar umexpert nesta framework. Segue abaixo os codigos que ainda faltam: • cadastro/pages/Welcome.jsp <%@ taglib uri="/tags/struts-bean" prefix="bean" %><%@ taglib uri="/tags/struts-html" prefix="html" %><%@ taglib uri="/tags/struts-logic" prefix="logic" %><html:html locale="true"><head><title><bean:message key="welcome.title"/></title><html:base/></head> <body bgcolor="white"> <font face="Comic Sans MS" size="3"> <center> <h1><font color="blue"><bean:messagekey="welcome.title"/></font></h1> <logic:notPresent name="org.apache.struts.action.MESSAGE"scope="application"> <font color="red"> ERROR: Application resources not loaded -- checkservlet container logs for error messages. </font> </logic:notPresent> <h3><bean:message key="welcome.heading"/></h3> <p><bean:message key="welcome.message"/></p> <html:link page="/listUsers.do">Cadastro de Usuários</html:link> </center> <p><font color="darkblue"> Autor: <html:link href="mailto:[email protected]">WelingtonB.Souza</html:link> <br>01/07/2003 </font></p> </p> </font>

Page 24: Tutorial struts

</body></html:html>• cadastro/pages/error.jsp <%@ taglib uri="/tags/struts-bean" prefix="bean" %><%@ taglib uri="/tags/struts-html" prefix="html" %><%@ taglib uri="/tags/struts-logic" prefix="logic" %><html:html locale="true"><head><title><bean:message key="error.title"/></title><html:base/></head><body bgcolor="white"> <font face="Comic Sans MS" size="3"> <center> <blockquote> <h1><font color=red><bean:message key="error.title"/></font></h1> <logic:messagesPresent> <ul> <html:messages id="error"> <li><bean:write name="error"/></li> </html:messages> </ul> </logic:messagesPresent> </blockquote> <br/> <html:link page="/Welcome.do">Página Inicial</html:link> </center></body></html:html>package strutsdemo.action;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.apache.struts.action.Action;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;import strutsdemo.bean.UserData;public class InsertUserAction extends Action { public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { HttpSession session = request.getSession(); UserData user = new UserData(); session.setAttribute("insertUserBean", user); return (mapping.findForward("success")); }}• cadastro/pages/insertUser.jsp <%@ taglib uri="/tags/struts-logic" prefix="logic" %><%@ taglib uri="/tags/struts-bean" prefix="bean"%><%@ taglib uri="/tags/struts-html" prefix="html"%><html:html locale="true"> <head> <title><bean:message key="insertUser.title"/></title> </head> <body> <font face="Comic Sans MS" size="3">

Page 25: Tutorial struts

<center> <h3><font color="blue"><bean:messagekey="insertUser.title"/></font></h3> <html:form action="/saveInsertUser.do" method="post"onsubmit="return validateSaveInsertUserForm(this);" focus="idUsuario"> <table width="80%" border="0"> <tr> <td width="30%"></td> <td width="70%"> <%-- exibe os erros de validação --%> <logic:messagesPresent> <ul> <html:messages id="error"> <li><bean:write name="error"/></li> </html:messages> </ul> </logic:messagesPresent> </td> <tr> <tr> <td align="right"><bean:messagekey="prompt.idUsuario" name="insertUserBean"/>: </td> <logic:equal name="insertUserBean"property="idUsuario" value="0"> <td align="left"><html:text property="idUsuario"size="5" value=""/></td> </logic:equal> <logic:notEqual name="insertUserBean"property="idUsuario" value="0"> <td align="left"><html:text property="idUsuario"size="5" name="insertUserBean"/></td> </logic:notEqual> </tr> <tr> <td align="right"><bean:messagekey="prompt.login"/>: </td> <td align="left"><html:text property="login"size="20" name="insertUserBean"/></td> </tr> <tr> <td align="right"><bean:messagekey="prompt.nome"/></td> <td align="left"><html:text property="nome"size="60" name="insertUserBean"/></td> </tr> <tr> <td align="right"><bean:messagekey="prompt.senha"/>: </td> <td align="left"> <html:password property="senha" size="16"maxlength="20" redisplay="false"/> </td> </tr> <tr> <td align="right"><bean:messagekey="prompt.confirmacaoSenha"/>: </td> <td align="left"> <html:password property="confirmacaoSenha"size="16" maxlength="20" redisplay="false"/> </td> </tr> <tr> <td align="right"><bean:messagekey="prompt.faixaIdade"/>: </td> <td align="left"> <html:select property="faixaIdade"name="insertUserBean"> <html:option value="1"><bean:message

Page 26: Tutorial struts

key="prompt.ate20"/></html:option></html:option> <html:option value="2"><bean:messagekey="prompt.de21a30"/></html:option></html:option> <html:option value="3"><bean:messagekey="prompt.de31a40"/></html:option></html:option> <html:option value="4"><bean:messagekey="prompt.de41a50"/></html:option></html:option> <html:option value="5"><bean:messagekey="prompt.de51a60"/></html:option></html:option> <html:option value="6"><bean:messagekey="prompt.acima60"/></html:option></html:option> </html:select> </td> </tr> <tr> <td align="right"><bean:message key="prompt.sexo"/>:</td> <td align="left"> <html:radio property="sexo" value="M"name="insertUserBean"> <bean:message key="prompt.Masculino"/> </html:radio> <html:radio property="sexo" value="F"name="insertUserBean"> <bean:message key="prompt.Feminino"/> </html:radio> </td> </tr> <tr> <td align="right"><bean:messagekey="prompt.ativo"/>: </td> <td align="left"> <html:checkbox property="ativo"titleKey="prompt.ativo" name="insertUserBean" /> </td> </tr> <tr> <td colspan="2" align="center"> <html:submit><bean:messagekey="button.send"/></html:submit> <html:reset><bean:messagekey="button.reset"/></html:reset> </td> </tr> </table> </html:form> <br/> <html:link page="/listUsers.do">voltar</html:link> </center> </font> </body> <html:javascript formName="saveInsertUserForm"/></html:html>package strutsdemo.action;import java.sql.SQLException;import java.util.LinkedList;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;

import org.apache.struts.action.Action;import org.apache.struts.action.ActionError;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;

Page 27: Tutorial struts

import org.apache.struts.validator.DynaValidatorForm;import strutsdemo.bean.AdminUsers;import strutsdemo.bean.UserData;public class SaveInsertUserAction extends Action { public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { DynaValidatorForm dynaForm = (DynaValidatorForm) form; ActionErrors errors = new ActionErrors(); String senha1 = (String)dynaForm.get("senha"); String senha2 = (String)dynaForm.get("confirmacaoSenha"); // como utilizamos um DynamicForm, precisamos terminar a validação aqui. if (senha1.equals(senha2)) { try { HttpSession session = request.getSession(); // popula o bean do usuario com os dados que vieram do Form UserData user = (UserData) session.getAttribute("insertUserBean"); user.setIdUsuario(Integer.parseInt((String)dynaForm.get("idUsuario"))); user.setLogin((String)dynaForm.get("login")); user.setNome((String)dynaForm.get("nome")); user.setFaixaIdade(Integer.parseInt((String)dynaForm.get("faixaIdade"))); user.setSexo((String)dynaForm.get("sexo")); user.setNome((String)dynaForm.get("nome")); user.setSenha(senha1); boolean ativo = ((String)dynaForm.get("ativo")).equals("on"); user.setAtivo(ativo); AdminUsers adminUsers = new AdminUsers(); adminUsers.insertUser(user); LinkedList userList = (LinkedList) session.getAttribute("userListBean"); userList.add(user); session.removeAttribute("insertUserBean"); } catch (SQLException e) { if (e.getErrorCode() == 1062) { errors.add( ActionErrors.GLOBAL_ERROR, new ActionError("error.idUsuario.duplicateKey")); } else { errors.add( ActionErrors.GLOBAL_ERROR, new ActionError("error.insert.user")); } } } else { errors.add( ActionErrors.GLOBAL_ERROR, new ActionError("error.ConfirmacaoSenha")); }

if (!errors.isEmpty()) {

Page 28: Tutorial struts

saveErrors(request, errors); return (mapping.findForward("error")); } else { return (mapping.findForward("success")); } }}

package strutsdemo.action;import java.util.Iterator;import java.util.LinkedList;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.apache.struts.action.Action;import org.apache.struts.action.ActionError;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;import strutsdemo.bean.AdminUsers;import strutsdemo.bean.UserData;public class DeleteUserAction extends Action { public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { HttpSession session = request.getSession(); String idUsuario = request.getParameter("idUsuario"); ActionErrors errors = new ActionErrors(); try { LinkedList userList = (LinkedList)session.getAttribute("userListBean"); Iterator iter = userList.iterator(); while (iter.hasNext()) { UserData user = (UserData)iter.next(); if (user.getIdUsuario() == Integer.parseInt(idUsuario)) { AdminUsers adminUsers = new AdminUsers(); adminUsers.deleteUser(Integer.parseInt(idUsuario)); userList.remove(user); break; } } } catch (Exception e) { errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error.delete.user")); getServlet().log("Erro carregando a lista de usuários", e); } if (!errors.isEmpty()) { saveErrors(request, errors); return (mapping.findForward("failure")); } else { return (mapping.findForward("success")); }

Page 29: Tutorial struts

}}

Outras fontes de pesquisa

• Struttin' With Struts - Lessons • Stepping through Jakarta Struts • About Struts • i18n with Struts • Introduction to Jakarta Struts Framework • Learn Struts' Form-Related Tags • TheServerSide.com J2EE Community • Project Refinery, Inc • Create Better Web Apps with Struts • Struts Tutorial Overview

Ferramentas para a Struts

Atualmente existem diversas ferramentas para configuração da Struts de forma visual com diversas opçõesentre produtos pagos e open source (EasyStruts, Struts Console). No entanto, é recomendável familiarizar-seprimeiro com a configuração manual antes de utilizar estas ferramentas, pois caso ocorra algum problemaimprevisto, possa ser corrigido manualmente. Você pode encontrar mais detalhes em buscas noSourceForge.net, tem um monte de coisas legais lá.

Integração com outras bibliotecas

Assim como existe a Struts, existem também outras bibliotecas para algumas funcionalidades específicas(custom tags, templates, etc). Assim é possível fazer uma série de combinações no sentido de conseguir oefeito desejado na sua aplicação web. Veja algumas bibliotecas que podem ser integradas à Struts.

• Struts-Layout • Struts Menu • Velocity • JavaServer Faces • Novamente faça buscas no site SourceForge.net

Boa sorte nos seus projetos com a Struts Framework ! Clique aqui e baixe os fontes deste tutorial.