SlideShare uma empresa Scribd logo
1 de 29
Baixar para ler offline
Tutorial - Struts Framework
Welington B. Souza wbsouza@yahoo.com.br


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
Licença
A Struts está disponível sobre a licença "free-to-use-license" da Apache Software Foundation (veja
http://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 para
        invocar (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 metodo
        init() 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á executada
        uma única vez, pois nas solicitações subsequentes, a servlet consulta estas estruturas na memória
        para decidir o fluxo a ser seguido.
     3. Baseado no fluxo definido no arquivo struts-config.xml, e que neste momento já se encntra
        carregado em estruturas na memória, o ActionSerlet identificará qual o ActionForm (classe para a
        validação dos dados) irá invocar. A classe ActionForm através do método validate irá verificar a
        integridade 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 do
        ActionForm.
              • Se faltou alguma coisa (campo não preenchido, valor inválido, etc), o usuário recebe um
                 formulário html (geralmente o mesmo que fez a solicitação), informando o motivo do não
                 atendimento da solicitação, para que o usuário possa preencher corretamente os dados para
                 fazer uma nova solicitação.
              • Se não faltou nenhuma informação, ou seja, todos os dados foram enviados corretamente, o
                 controller passa para o proximo passo (Action).
     5. O ActionServlet, baseado no fluxo da aplicação (estruturas já carregadas em memória) invoca uma
        classe Action. A classe Action passará pelo método execute que irá delegar a requisição para a
        camada 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
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. Neste
        ponto, os objetos que foram populados na camada de negócio serão "atachados" como atributos na
        seção do usuário.
     8. Baseado no mapeamento feito pelo o Action, o Controller faz um forward para o JSP para apresentar
        os dados.
     9. Na camada de apresentação (View), os objetos que foram setados como atributos da sessão do
        usuá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 adicionar
funcionalidade. O fluxo da aplicação é programado em um arquivo XML através das ações que serão
executadas. As ações são classes base implementadas pela framework seguindo o padrão MVC. Assim
devemos 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 assim
o 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 a
versão 1.1, pois incorpora uma série de melhorias em relação a versão anterior, e já temos uma versão
está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 ou
outro WebContainer, copie o arquivo struts-documentation.war, para o diretório <webapps> do seu
container.
Neste ponto a documentação da Struts já se enconrtra instalada na sua máquina.Para acessá-la vá para
http://localhost:8080/struts-documentation.

Projeto do Tutorial
Para entender melhor o funcionamento, vamos fazer uma aplicação prática. Desenvolveremos um cadastro
de 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 cadastro
        cd cadastro
        jar -xvf ../struts-blank.war

    •   Agora temos uma aplicação web (em branco) baseada na template da Struts para começar a
        brincar.
     • Mova este diretório para o local que mais lhe convier, uma vez que os fontes da sua aplicação
        ficarã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 de
negócio).
       |       |
       |       +-- java
       |              |
       |              +-- resources
|               |
     |               +-- application.properties
     |                     Contém as mensagens (textos fixos) da aplicação,
     |                     inclusive as mensagens de erros.
     |                     Este arquivo é responsável pela internacionalização
da 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ção
web.
     |
     +--*.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 Web
Container.
              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>
<!-- 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 por
http://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 MySql
pode 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
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 Connection
Pool (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 para
consultar/manipular dados é um processo muito dispendioso (conexão e verificação de permissões do
usuá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 se
reconectar a cada solicitação que chega, pois ele fará o gerenciamento da coleção de conexões prontas para
serem usadas, e "marcará" as conexões em uso. Se por acaso você pegar uma conexão e ficar um
determinado tempo sem fazer nada (timeout), o Connection Pool regata esta conexão para uso, e invalida o
objeto de conexão que você pegou anteriormente. Tamanha é a importância deste tópico, que acabou
entrando na especificação JDBC (javax.sql.DataSource). Praticamente todos os Containers possuem um
mecanismo que fornecem um Connection Pool.
Embora o nosso projeto seja baseado no MySQL, que provavelmente muitos dirão que não há necessidade
de se fazer isto com o MySQL, pois o processo de conexão é extremamente rápido, não podemos dizer o
mesmo de outros bancos. Mesmo assim, é interessante usar um Connection Pool, pois pode parecer
imperceptível para uma só solicitação chegando, mas em um ambiente de produção, com a sua aplicação
sendo 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 era
obtida do ActionServlet. No entanto, nas nos betas e release candidate da versão 1.1 o metodo para
obtenção de conexões ficou deprecated, e passaram esta tarefa para o Action. Por fim no release 1.1 de
produção, as classes que tratam do DataSource foram parar no arquivo struts-legacy.jar, indicando
claramente 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 uma
implementaçã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.BasicData
SourceFactory</value></parameter>
             <parameter><name>driverClassName</name><value>com.mysql.jdbc.Driver</va
lue></parameter>
             <parameter><name>url</name><value>jdbc:mysql://localhost/strutsdemo</va
lue></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 ao
Connection Pool, o qual irá marcar uma conexão no Pool, como sendo usada, e lhe dará algum tempo para
fazer 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 para
você e a resgata para o pool). Para fazer isto, basta executar o método close(), que na verdade não a fecha,
mas devolve para o Pool (dependendo da implementação do Connection Pool, poderá ter variações da
maneira de devolver ao pool, algo do tipo invocar um metodo do tipo releaseConnection, do objeto
Connection Pool).

Definindo a Camada de Negócio
Para listar os usuários cadastrados precisaremos definir as classes que farão parte da nossa camada de
Negócio. Devemos ter duas classes. Uma classe que representa o registro do usuário "UserData" (value
object) , e outra que irá gerenciar o cadastro dos usuários "AdminUsers". Segue abaixo o código das duas
classes:
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() {
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 {
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();
            }
        }
    }
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 Model
para executar algum processo retornando um resultado que servirá de base para que o Controller possa
direcionar 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 um
JSP.
Para incluir, alterar ou excluir um usuário, precisamos exibir todos os usuários cadastrados para saber o que
fazer. 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 classe
  deve estender de org.apache.struts.action.Action (vamos entrar em mais detalhes sobre esta classe na
  seçã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és
do método process, e se este objeto retornar um ActionForward com o valor "sucess", O controller
encaminhará a solicitação para o arquivo "/pages/listUsers.jsp". Se retornar "failure", será encaminhado para
o 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á uma
certa discussão sobre que parte pertence o Action e o ActionForm no padrão MVC (vamos entrar em maiores
detalhes mais adiante em ActionForm, por hora ainda não é necessário). Na realidade tanto o Action, quanto
o ActionForm são Helper Classes. A grosso modo podemos entender como classes auxiliadores para
execuçã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;
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 maioria
baseada em JSPs e alguns servlets envolvidos na geração da interface com o usuário ou com outros
sistemas. A Struts framework fornece suporte para construir aplicações multi-idiomas, interação com
formulá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.properties
no diretório cadastro/WEB-INF/classes/java/resources. Este arquivo deve conter as chaves e os valores no
formato: chave.subchave=texto que pertence ao idioma padrão da aplicação. Vamos adicionar algumas
chaves que serão usadas em nosso projeto. Obs: Este arquivo pode ter qualquer nome, desde que termine
com .properties. No entanto existe um certo padrão, geralmente é chamado de
ApplicationResources.properties. A única ressalva, é que se você mudar o nome deste arquivo, também
deverá ser mudado no arquivo struts-config.xml.
welcome.title=Bem Vindo ao Projeto Tutorial Struts
welcome.heading=Bem vindo!
welcome.message=Projeto Tutorial Struts
application.title= Struts Demo - Cadastro
index.header=Bem vindo ao Demo da Strutus Framework - Cadastro
users.title=Cadastro de Usuários
editUser.title=Alteração de Usuário
insertUser.title=Inclusão de Usuário
prompt.idUsuario=Código
prompt.nome=Nome
prompt.login=Login
prompt.senha=Senha
prompt.confirmacaoSenha=Confirmação da Senha
prompt.sexo=Sexo
prompt.ativo=Ativo
prompt.status=Status
prompt.faixaIdade=Faixa Etária
prompt.excluir=Excluir
prompt.incluir=Incluir
prompt.voltar=Voltar
prompt.Masculino=Masculino
prompt.Feminino=Feminino

prompt.ate20=Até 20 anos
prompt.de21a30=De 21 a 30 anos
prompt.de31a40=De 31 a 40 anos
prompt.de41a50=De 41 a 50 anos
prompt.de51a60=De 51 a 60 anos
prompt.acima60=Acima de 60 anos

prompt.senhaAntiga=Senha Antiga
prompt.novaSenha=Nova Senha
prompt.confirmacaoNovaSenha=Confirmação da Senha
button.send=Enviar
button.reset=Cancelar

error.title=Erro Inesperado
error.user.list=Erro obtendo a lista de usuários
error.idUsuario.required=O identificador do usuário é um campo obrigatório
error.login.required=O login do usuário é um campo obrigatório
error.nome.required=O nome do usuário é um campo obrigatório
error.get.user=Erro ao carregar o usuário
error.senhaAntiga.required=A senha antiga é um campo obrigatório
error.novaSenha.required=A nova senha é um campo obrigatório
error.confirmacaoNovaSenha.required=A confirmação da nova senha é um campo
obrigatório
error.ConfirmacaoSenha=Erro na confirmação da nova senha
error.user.notFound=Usuário não encontrado
error.senhaAntiga=A senha Antiga não confere
error.update.user=Erro alterando o usuário
error.update.user=Erro incluindo o usuário
error.delete.user=Erro excluindo o usuário
error.idUsuario.duplicateKey=Este código de usuário já existe
Para cada idioma alternativo, devemos adicionar um novo arquivo (no mesmo diretório do arquivo onde
temos o arquivo do idioma padrão) no formato "application_xx.properties", onde xx é o código ISO do
idioma. 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:
...
<h3><bean:message key="application.title"/></h3>
...
Por default, a Struts acessa o idioma principal da aplicação. Devemos utilizar a tag <html:html
locale="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 idiomas
suportados, 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 respeito
do assunto, veja a documentação oficial da Sun disponível em
http://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:message
key="users.title"/></font></h3>
                 <table width="80%" border="1">
                      <tr>
                           <th width="10%"><bean:message
key="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>
</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 clicar
em algum link, irá ocorrer um erro, pois ainda não temos os ActionBeanss necessários para invocar a
camada de negócio. Neste momento para facilitar o entendimento, vamos implementar apenas os Beans
necessários para Alterar o usuário. Devemos criar um ActionBean que deverá invocar a camada de negócio e
popular um bean com os dados do usuário a ser alterado, e enviar para a camada de apresentação para que
os 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,
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 basta
adicionar 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ódigo
JSP 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:message
key="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:message
key="prompt.idUsuario"/>: </td>
                                     <td align="left"><b><bean:write property="idUsuario"
name="editUserBean"/></b></td>
                                </tr>

                               <tr>
                                    <td align="right"><bean:message
key="prompt.login"/>: </td>
                              <td align="left"><html:text property="login"
name="editUserBean" size="20"/></td>
                         </tr>
                         <tr>
                              <td align="right"><bean:message
key="prompt.nome"/></td>
                              <td align="left"><html:text property="nome"
name="editUserBean" size="60"/></td>
                         </tr>

                        <tr>
                             <td align="right"><bean:message
key="prompt.senhaAntiga"/>: </td>
                             <td align="left"><html:password
property="senhaAntiga" size="16"
                                 maxlength="20" redisplay="false"
value="zzzzz"/></td>
                        </tr>
                        <tr>
                             <td align="right"><bean:message
key="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:message
key="prompt.confirmacaoNovaSenha"/>: </td>
                             <td align="left"><html:password
property="confirmacaoNovaSenha" size="16"
                                 maxlength="20" redisplay="false"
value="zzzzz"/></td>
                        </tr>
                        <tr>
                             <td align="right"><bean:message
key="prompt.faixaIdade"/>: </td>
                             <td align="left">
                                 <html:select property="faixaIdade"
name="editUserBean">
                                     <html:option value="1"><bean:message
key="prompt.ate20"/></html:option></html:option>
                                     <html:option value="2"><bean:message
key="prompt.de21a30"/></html:option></html:option>
                                     <html:option value="3"><bean:message
key="prompt.de31a40"/></html:option></html:option>
                                     <html:option value="4"><bean:message
key="prompt.de41a50"/></html:option></html:option>
                                     <html:option value="5"><bean:message
key="prompt.de51a60"/></html:option></html:option>
                                     <html:option value="6"><bean:message
key="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>
</tr>
                         <tr>
                              <td align="right"><bean:message
key="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:message
key="button.send"/></html:submit>
                                  <html:reset><bean:message
key="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, para
se alterar e obter nova informação. As validações, o tratamento de erros, a apresentação, e o mesmo a
entrada de dados do form pelo usuário e mensagens de erros, são contempladas pela Struts, o que torna a
vida um pouco mais fácil. Todo trabalho de validação e geração de mensagens de erros serão
implementados 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á conter
todos os campos (variaveis privadas com os devidos metodos gets e sets), coincidindo com o nome dos
inputs do formulário html.
Toda validação de dados pela Struts passa por um FormBean. O FormBean é a primeira classe (quando
definida 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 um
FormBean quando necessitarmos de validação dos dados.
No nosso caso, quando precisarmos salvar os dados que foram alterados pelo usuário. No entanto, antes de
devemos fazer uma validação para que não vá besteira para o banco de dados. Um ActionForm possui dois
mé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;
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;
}
     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 Collection
de erros. Se este collection tiver algum erro, o FormBean devolve para o jsp que entrou com os dados, com
os campos devidamente preenchidos, e com as mensagens dos erros ocorridos. Caso contrário, ou seja, se
não ocorrer nenhum erro, então o fluxo segue para um ActionBean para invocar a camada de negócio para
gravar estes dados no banco de dados. Logo, precisamos criar este bean. Segue abaixo o código do nosso
ActionBean.
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,
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>
...
</action-mappings>
Obs: Até a versão 1.0 da Struts, a única maneira de validar os dados era herdando do ActionForm, e
colocando as regras de validação no método validate. No entanto com a Struts 1.1 é possível fazer a
validaçã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 de
javascript definidos no arquivo validator.xml. Assim, podemos evitar o overread gerado pelas solicitações
desnecessárias no servidor, pois quando a solicitação chega ao web server, estaremos tratando com os
dados previamente tratados pelo javascript do lado client.
Só pra constar como lembrete para os novatos em internet. Pode parecer tentador, mas nunca deixe de
validar os dados no lado servidor se tiver tudo tratado no lado client, pois o usuário pode desabilitar o
javascript do browser e causar erros imprevisíveis na sua aplicação. Conclusão: Use javascript para validar se
puder, 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 no
arquivo 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 da
template struts-blank.war, pois serão usados no javascript.
# Mensagens de erro padrão para as validações
errors.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.
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 ainda
fazer 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 a
introdução dos DynamicForms. Assim você não é mais "obrigado" a criar um Form para validar as entradas
de cada formulário HTML. O Dynamic Form é configurado apenas no struts-config.xml e a Struts já tem uma
classe "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 que
já foram feitos antes. ou seja, se você chegou até aqui, só falta um pouco de pratica para você se tornar um
expert 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:message
key="welcome.title"/></font></h1>
                  <logic:notPresent name="org.apache.struts.action.MESSAGE"
scope="application">
                      <font color="red">
                          ERROR: Application resources not loaded -- check
servlet 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:wbsouza@yahoo.com.br">Welington
B.Souza</html:link>
                <br>01/07/2003
             </font></p>
             </p>
        </font>
</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">
<center>
                <h3><font color="blue"><bean:message
key="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:message
key="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:message
key="prompt.login"/>: </td>
                              <td align="left"><html:text property="login"
size="20" name="insertUserBean"/></td>
                         </tr>
                         <tr>
                              <td align="right"><bean:message
key="prompt.nome"/></td>
                              <td align="left"><html:text property="nome"
size="60" name="insertUserBean"/></td>
                         </tr>
                         <tr>
                              <td align="right"><bean:message
key="prompt.senha"/>: </td>
                              <td align="left">
                                  <html:password property="senha" size="16"
maxlength="20" redisplay="false"/>
                              </td>
                         </tr>
                         <tr>
                              <td align="right"><bean:message
key="prompt.confirmacaoSenha"/>: </td>
                              <td align="left">
                                  <html:password property="confirmacaoSenha"
size="16" maxlength="20" redisplay="false"/>
                              </td>
                         </tr>
                         <tr>
                              <td align="right"><bean:message
key="prompt.faixaIdade"/>: </td>
                              <td align="left">
                                  <html:select property="faixaIdade"
name="insertUserBean">
                                      <html:option value="1"><bean:message
key="prompt.ate20"/></html:option></html:option>
                                      <html:option value="2"><bean:message
key="prompt.de21a30"/></html:option></html:option>
                                      <html:option value="3"><bean:message
key="prompt.de31a40"/></html:option></html:option>
                                      <html:option value="4"><bean:message
key="prompt.de41a50"/></html:option></html:option>
                                      <html:option value="5"><bean:message
key="prompt.de51a60"/></html:option></html:option>
                                      <html:option value="6"><bean:message
key="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:message
key="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:message
key="button.send"/></html:submit>
                                  <html:reset><bean:message
key="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;
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()) {
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"));
        }
}
}

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ções
entre produtos pagos e open source (EasyStruts, Struts Console). No entanto, é recomendável familiarizar-se
primeiro com a configuração manual antes de utilizar estas ferramentas, pois caso ocorra algum problema
imprevisto, possa ser corrigido manualmente. Você pode encontrar mais detalhes em buscas no
SourceForge.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 o
efeito 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.



•
•

Mais conteúdo relacionado

Mais procurados

Node.js - #1 - Introdução - Rodrigo Branas
Node.js - #1 - Introdução - Rodrigo BranasNode.js - #1 - Introdução - Rodrigo Branas
Node.js - #1 - Introdução - Rodrigo BranasRodrigo Branas
 
General introduction to intellij idea
General introduction to intellij ideaGeneral introduction to intellij idea
General introduction to intellij ideaYusup
 
Apache ActiveMQ and Apache Camel
Apache ActiveMQ and Apache CamelApache ActiveMQ and Apache Camel
Apache ActiveMQ and Apache CamelOmi Om
 
Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)
Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)
Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)Helder da Rocha
 
Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans Hitesh-Java
 
Spring Framework
Spring FrameworkSpring Framework
Spring FrameworkNaLUG
 
Spring framework IOC and Dependency Injection
Spring framework  IOC and Dependency InjectionSpring framework  IOC and Dependency Injection
Spring framework IOC and Dependency InjectionAnuj Singh Rajput
 
Java Spring framework, Dependency Injection, DI, IoC, Inversion of Control
Java Spring framework, Dependency Injection, DI, IoC, Inversion of ControlJava Spring framework, Dependency Injection, DI, IoC, Inversion of Control
Java Spring framework, Dependency Injection, DI, IoC, Inversion of ControlArjun Thakur
 
Microservices com Spring Boot e Spring Cloud Netflix
Microservices com Spring Boot e Spring Cloud NetflixMicroservices com Spring Boot e Spring Cloud Netflix
Microservices com Spring Boot e Spring Cloud NetflixNatanael Fonseca
 
Websphere Application Server V8.5
Websphere Application Server V8.5Websphere Application Server V8.5
Websphere Application Server V8.5IBM WebSphereIndia
 
Spring boot Introduction
Spring boot IntroductionSpring boot Introduction
Spring boot IntroductionJeevesh Pandey
 
Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introductionRasheed Waraich
 
Sistemas Distribuídos baseados na Web
Sistemas Distribuídos baseados na WebSistemas Distribuídos baseados na Web
Sistemas Distribuídos baseados na WebRafael Chagas
 
Glassfish An Introduction
Glassfish An IntroductionGlassfish An Introduction
Glassfish An IntroductionJumping Bean
 
Introduction to Spring Framework
Introduction to Spring FrameworkIntroduction to Spring Framework
Introduction to Spring FrameworkASG
 
Spring Boot & Actuators
Spring Boot & ActuatorsSpring Boot & Actuators
Spring Boot & ActuatorsVMware Tanzu
 

Mais procurados (20)

Node.js - #1 - Introdução - Rodrigo Branas
Node.js - #1 - Introdução - Rodrigo BranasNode.js - #1 - Introdução - Rodrigo Branas
Node.js - #1 - Introdução - Rodrigo Branas
 
General introduction to intellij idea
General introduction to intellij ideaGeneral introduction to intellij idea
General introduction to intellij idea
 
Apache ActiveMQ and Apache Camel
Apache ActiveMQ and Apache CamelApache ActiveMQ and Apache Camel
Apache ActiveMQ and Apache Camel
 
Introduction to Spring Boot
Introduction to Spring BootIntroduction to Spring Boot
Introduction to Spring Boot
 
Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)
Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)
Curso de RESTful WebServices em Java com JAX-RS (Java EE 7)
 
Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans Spring - Part 1 - IoC, Di and Beans
Spring - Part 1 - IoC, Di and Beans
 
Spring Framework
Spring FrameworkSpring Framework
Spring Framework
 
Struts Basics
Struts BasicsStruts Basics
Struts Basics
 
Spring framework IOC and Dependency Injection
Spring framework  IOC and Dependency InjectionSpring framework  IOC and Dependency Injection
Spring framework IOC and Dependency Injection
 
Java Spring framework, Dependency Injection, DI, IoC, Inversion of Control
Java Spring framework, Dependency Injection, DI, IoC, Inversion of ControlJava Spring framework, Dependency Injection, DI, IoC, Inversion of Control
Java Spring framework, Dependency Injection, DI, IoC, Inversion of Control
 
Spring Core
Spring CoreSpring Core
Spring Core
 
Microservices com Spring Boot e Spring Cloud Netflix
Microservices com Spring Boot e Spring Cloud NetflixMicroservices com Spring Boot e Spring Cloud Netflix
Microservices com Spring Boot e Spring Cloud Netflix
 
Introduction to Maven
Introduction to MavenIntroduction to Maven
Introduction to Maven
 
Websphere Application Server V8.5
Websphere Application Server V8.5Websphere Application Server V8.5
Websphere Application Server V8.5
 
Spring boot Introduction
Spring boot IntroductionSpring boot Introduction
Spring boot Introduction
 
Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introduction
 
Sistemas Distribuídos baseados na Web
Sistemas Distribuídos baseados na WebSistemas Distribuídos baseados na Web
Sistemas Distribuídos baseados na Web
 
Glassfish An Introduction
Glassfish An IntroductionGlassfish An Introduction
Glassfish An Introduction
 
Introduction to Spring Framework
Introduction to Spring FrameworkIntroduction to Spring Framework
Introduction to Spring Framework
 
Spring Boot & Actuators
Spring Boot & ActuatorsSpring Boot & Actuators
Spring Boot & Actuators
 

Semelhante a Tutorial struts

Desenvolvimento de Apps e Games para Android - Parte 5
Desenvolvimento de Apps e Games para Android - Parte 5Desenvolvimento de Apps e Games para Android - Parte 5
Desenvolvimento de Apps e Games para Android - Parte 5Erisvaldo Junior
 
Spring & Struts
Spring & StrutsSpring & Struts
Spring & Strutseduan
 
2005 0 X Stn Ti Jaime Correia (Amostra)
2005 0 X   Stn   Ti   Jaime Correia (Amostra)2005 0 X   Stn   Ti   Jaime Correia (Amostra)
2005 0 X Stn Ti Jaime Correia (Amostra)Walter Cunha
 
ASP.NET MVC - Alexandre Tarifa
ASP.NET MVC - Alexandre TarifaASP.NET MVC - Alexandre Tarifa
ASP.NET MVC - Alexandre Tarifaguestea329c
 
Desenvolvendo aplicações com Angular e Laravel no Back-end
Desenvolvendo aplicações com Angular e Laravel no Back-endDesenvolvendo aplicações com Angular e Laravel no Back-end
Desenvolvendo aplicações com Angular e Laravel no Back-endGiovanny Valente
 
Técnicas e recursos para desenvolvimento Web em cenários de grande escala
Técnicas e recursos para desenvolvimento Web em cenários de grande escalaTécnicas e recursos para desenvolvimento Web em cenários de grande escala
Técnicas e recursos para desenvolvimento Web em cenários de grande escalaAlexandre Tarifa
 
hibernate annotation
hibernate annotationhibernate annotation
hibernate annotationeduardo dias
 
Java Web Dev Introdução
Java Web Dev IntroduçãoJava Web Dev Introdução
Java Web Dev IntroduçãoMarcio Marinho
 
Curso de WebServlets (Java EE 7)
Curso de WebServlets (Java EE 7)Curso de WebServlets (Java EE 7)
Curso de WebServlets (Java EE 7)Helder da Rocha
 

Semelhante a Tutorial struts (20)

Apache Struts
Apache StrutsApache Struts
Apache Struts
 
Framework struts2v2.5
Framework struts2v2.5Framework struts2v2.5
Framework struts2v2.5
 
Desenvolvimento de Apps e Games para Android - Parte 5
Desenvolvimento de Apps e Games para Android - Parte 5Desenvolvimento de Apps e Games para Android - Parte 5
Desenvolvimento de Apps e Games para Android - Parte 5
 
Spring & Struts
Spring & StrutsSpring & Struts
Spring & Struts
 
2005 0 X Stn Ti Jaime Correia (Amostra)
2005 0 X   Stn   Ti   Jaime Correia (Amostra)2005 0 X   Stn   Ti   Jaime Correia (Amostra)
2005 0 X Stn Ti Jaime Correia (Amostra)
 
Asp net mvc
Asp net mvcAsp net mvc
Asp net mvc
 
ASP.NET MVC - Alexandre Tarifa
ASP.NET MVC - Alexandre TarifaASP.NET MVC - Alexandre Tarifa
ASP.NET MVC - Alexandre Tarifa
 
ASP.NET MVC
ASP.NET MVCASP.NET MVC
ASP.NET MVC
 
Desenvolvendo aplicações com Angular e Laravel no Back-end
Desenvolvendo aplicações com Angular e Laravel no Back-endDesenvolvendo aplicações com Angular e Laravel no Back-end
Desenvolvendo aplicações com Angular e Laravel no Back-end
 
Técnicas e recursos para desenvolvimento Web em cenários de grande escala
Técnicas e recursos para desenvolvimento Web em cenários de grande escalaTécnicas e recursos para desenvolvimento Web em cenários de grande escala
Técnicas e recursos para desenvolvimento Web em cenários de grande escala
 
hibernate annotation
hibernate annotationhibernate annotation
hibernate annotation
 
Java Web Dev Introdução
Java Web Dev IntroduçãoJava Web Dev Introdução
Java Web Dev Introdução
 
ApresentaçãO Mvc
ApresentaçãO MvcApresentaçãO Mvc
ApresentaçãO Mvc
 
Apresentação M V C
Apresentação M V CApresentação M V C
Apresentação M V C
 
1409243945064
14092439450641409243945064
1409243945064
 
Oficina cake php
Oficina cake phpOficina cake php
Oficina cake php
 
Curso de WebServlets (Java EE 7)
Curso de WebServlets (Java EE 7)Curso de WebServlets (Java EE 7)
Curso de WebServlets (Java EE 7)
 
Palestra
PalestraPalestra
Palestra
 
Aplicações web parte 2
Aplicações web parte 2Aplicações web parte 2
Aplicações web parte 2
 
Tutorial JSF 2.0 (2012)
Tutorial JSF 2.0 (2012)Tutorial JSF 2.0 (2012)
Tutorial JSF 2.0 (2012)
 

Mais de Fernando Palma

CRM Gerenciamento Do Relacionamento Com Clientes | Prof. Francisco Alves | C...
CRM Gerenciamento Do Relacionamento Com Clientes | Prof. Francisco Alves |  C...CRM Gerenciamento Do Relacionamento Com Clientes | Prof. Francisco Alves |  C...
CRM Gerenciamento Do Relacionamento Com Clientes | Prof. Francisco Alves | C...Fernando Palma
 
Formação em ciência de dados
Formação em ciência de dadosFormação em ciência de dados
Formação em ciência de dadosFernando Palma
 
Apostila de Introdução ao Arduino
Apostila de Introdução ao ArduinoApostila de Introdução ao Arduino
Apostila de Introdução ao ArduinoFernando Palma
 
Apostila Arduino Basico
Apostila Arduino BasicoApostila Arduino Basico
Apostila Arduino BasicoFernando Palma
 
Cartilha Segurança na Internet - CERT.br
Cartilha Segurança na Internet - CERT.brCartilha Segurança na Internet - CERT.br
Cartilha Segurança na Internet - CERT.brFernando Palma
 
Ebook Apache Server: Guia Introdutório
Ebook Apache Server: Guia IntrodutórioEbook Apache Server: Guia Introdutório
Ebook Apache Server: Guia IntrodutórioFernando Palma
 
Apostila Zend Framework
Apostila Zend FrameworkApostila Zend Framework
Apostila Zend FrameworkFernando Palma
 
Ebook Governança de TI na Prática
Ebook Governança de TI na PráticaEbook Governança de TI na Prática
Ebook Governança de TI na PráticaFernando Palma
 
Simulado ITIL Foundation - Questões Comentadas
Simulado ITIL Foundation - Questões ComentadasSimulado ITIL Foundation - Questões Comentadas
Simulado ITIL Foundation - Questões ComentadasFernando Palma
 
Introdução à Aprendizagem de Máquina
Introdução à Aprendizagem de MáquinaIntrodução à Aprendizagem de Máquina
Introdução à Aprendizagem de MáquinaFernando Palma
 
PDTI - Plano Diretor de Tecnologia da Informação (modelo)
PDTI - Plano Diretor de Tecnologia da Informação (modelo)PDTI - Plano Diretor de Tecnologia da Informação (modelo)
PDTI - Plano Diretor de Tecnologia da Informação (modelo)Fernando Palma
 
Guia Salarial 2017 Robert Half Brasil
Guia Salarial 2017 Robert Half BrasilGuia Salarial 2017 Robert Half Brasil
Guia Salarial 2017 Robert Half BrasilFernando Palma
 
Gerenciamento na nuvem e System Center
Gerenciamento na nuvem e System CenterGerenciamento na nuvem e System Center
Gerenciamento na nuvem e System CenterFernando Palma
 
SAN: Storage Area Network
SAN: Storage Area NetworkSAN: Storage Area Network
SAN: Storage Area NetworkFernando Palma
 
Ebook ITIL Na Prática
Ebook ITIL Na PráticaEbook ITIL Na Prática
Ebook ITIL Na PráticaFernando Palma
 
Exemplo de Plano Estratégico de TI - MEC
Exemplo de Plano Estratégico de TI - MECExemplo de Plano Estratégico de TI - MEC
Exemplo de Plano Estratégico de TI - MECFernando Palma
 
Apostila Tutorial CakePHP
Apostila Tutorial CakePHPApostila Tutorial CakePHP
Apostila Tutorial CakePHPFernando Palma
 

Mais de Fernando Palma (20)

CRM Gerenciamento Do Relacionamento Com Clientes | Prof. Francisco Alves | C...
CRM Gerenciamento Do Relacionamento Com Clientes | Prof. Francisco Alves |  C...CRM Gerenciamento Do Relacionamento Com Clientes | Prof. Francisco Alves |  C...
CRM Gerenciamento Do Relacionamento Com Clientes | Prof. Francisco Alves | C...
 
Formação em ciência de dados
Formação em ciência de dadosFormação em ciência de dados
Formação em ciência de dados
 
Apostila de Introdução ao Arduino
Apostila de Introdução ao ArduinoApostila de Introdução ao Arduino
Apostila de Introdução ao Arduino
 
Apostila Arduino Basico
Apostila Arduino BasicoApostila Arduino Basico
Apostila Arduino Basico
 
Cartilha Segurança na Internet - CERT.br
Cartilha Segurança na Internet - CERT.brCartilha Segurança na Internet - CERT.br
Cartilha Segurança na Internet - CERT.br
 
Ebook Apache Server: Guia Introdutório
Ebook Apache Server: Guia IntrodutórioEbook Apache Server: Guia Introdutório
Ebook Apache Server: Guia Introdutório
 
Apostila Zend Framework
Apostila Zend FrameworkApostila Zend Framework
Apostila Zend Framework
 
Hacker Ético
Hacker ÉticoHacker Ético
Hacker Ético
 
Ebook Governança de TI na Prática
Ebook Governança de TI na PráticaEbook Governança de TI na Prática
Ebook Governança de TI na Prática
 
Simulado ITIL Foundation - Questões Comentadas
Simulado ITIL Foundation - Questões ComentadasSimulado ITIL Foundation - Questões Comentadas
Simulado ITIL Foundation - Questões Comentadas
 
Introdução à Aprendizagem de Máquina
Introdução à Aprendizagem de MáquinaIntrodução à Aprendizagem de Máquina
Introdução à Aprendizagem de Máquina
 
PDTI - Plano Diretor de Tecnologia da Informação (modelo)
PDTI - Plano Diretor de Tecnologia da Informação (modelo)PDTI - Plano Diretor de Tecnologia da Informação (modelo)
PDTI - Plano Diretor de Tecnologia da Informação (modelo)
 
Guia Salarial 2017 Robert Half Brasil
Guia Salarial 2017 Robert Half BrasilGuia Salarial 2017 Robert Half Brasil
Guia Salarial 2017 Robert Half Brasil
 
Tutorial memcached
Tutorial memcachedTutorial memcached
Tutorial memcached
 
Gerenciamento na nuvem e System Center
Gerenciamento na nuvem e System CenterGerenciamento na nuvem e System Center
Gerenciamento na nuvem e System Center
 
SAN: Storage Area Network
SAN: Storage Area NetworkSAN: Storage Area Network
SAN: Storage Area Network
 
Linguagem ABAP
Linguagem ABAPLinguagem ABAP
Linguagem ABAP
 
Ebook ITIL Na Prática
Ebook ITIL Na PráticaEbook ITIL Na Prática
Ebook ITIL Na Prática
 
Exemplo de Plano Estratégico de TI - MEC
Exemplo de Plano Estratégico de TI - MECExemplo de Plano Estratégico de TI - MEC
Exemplo de Plano Estratégico de TI - MEC
 
Apostila Tutorial CakePHP
Apostila Tutorial CakePHPApostila Tutorial CakePHP
Apostila Tutorial CakePHP
 

Tutorial struts

  • 1. Tutorial - Struts Framework Welington B. Souza wbsouza@yahoo.com.br 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
  • 2. Licença A Struts está disponível sobre a licença "free-to-use-license" da Apache Software Foundation (veja http://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 para invocar (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 metodo init() 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á executada uma única vez, pois nas solicitações subsequentes, a servlet consulta estas estruturas na memória para decidir o fluxo a ser seguido. 3. Baseado no fluxo definido no arquivo struts-config.xml, e que neste momento já se encntra carregado em estruturas na memória, o ActionSerlet identificará qual o ActionForm (classe para a validação dos dados) irá invocar. A classe ActionForm através do método validate irá verificar a integridade 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 do ActionForm. • Se faltou alguma coisa (campo não preenchido, valor inválido, etc), o usuário recebe um formulário html (geralmente o mesmo que fez a solicitação), informando o motivo do não atendimento da solicitação, para que o usuário possa preencher corretamente os dados para fazer uma nova solicitação. • Se não faltou nenhuma informação, ou seja, todos os dados foram enviados corretamente, o controller passa para o proximo passo (Action). 5. O ActionServlet, baseado no fluxo da aplicação (estruturas já carregadas em memória) invoca uma classe Action. A classe Action passará pelo método execute que irá delegar a requisição para a camada 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
  • 3. 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. Neste ponto, os objetos que foram populados na camada de negócio serão "atachados" como atributos na seção do usuário. 8. Baseado no mapeamento feito pelo o Action, o Controller faz um forward para o JSP para apresentar os dados. 9. Na camada de apresentação (View), os objetos que foram setados como atributos da sessão do usuá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 adicionar funcionalidade. O fluxo da aplicação é programado em um arquivo XML através das ações que serão executadas. As ações são classes base implementadas pela framework seguindo o padrão MVC. Assim devemos 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 assim o 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 a versão 1.1, pois incorpora uma série de melhorias em relação a versão anterior, e já temos uma versão está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 ou outro WebContainer, copie o arquivo struts-documentation.war, para o diretório <webapps> do seu container. Neste ponto a documentação da Struts já se enconrtra instalada na sua máquina.Para acessá-la vá para http://localhost:8080/struts-documentation. Projeto do Tutorial Para entender melhor o funcionamento, vamos fazer uma aplicação prática. Desenvolveremos um cadastro de 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 cadastro cd cadastro jar -xvf ../struts-blank.war • Agora temos uma aplicação web (em branco) baseada na template da Struts para começar a brincar. • Mova este diretório para o local que mais lhe convier, uma vez que os fontes da sua aplicação ficarã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 de negócio). | | | +-- java | | | +-- resources
  • 4. | | | +-- application.properties | Contém as mensagens (textos fixos) da aplicação, | inclusive as mensagens de erros. | Este arquivo é responsável pela internacionalização da 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ção web. | +--*.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 Web Container. 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>
  • 5. <!-- 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 por http://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 MySql pode 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
  • 6. 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 Connection Pool (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 para consultar/manipular dados é um processo muito dispendioso (conexão e verificação de permissões do usuá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 se reconectar a cada solicitação que chega, pois ele fará o gerenciamento da coleção de conexões prontas para serem usadas, e "marcará" as conexões em uso. Se por acaso você pegar uma conexão e ficar um determinado tempo sem fazer nada (timeout), o Connection Pool regata esta conexão para uso, e invalida o objeto de conexão que você pegou anteriormente. Tamanha é a importância deste tópico, que acabou entrando na especificação JDBC (javax.sql.DataSource). Praticamente todos os Containers possuem um mecanismo que fornecem um Connection Pool. Embora o nosso projeto seja baseado no MySQL, que provavelmente muitos dirão que não há necessidade de se fazer isto com o MySQL, pois o processo de conexão é extremamente rápido, não podemos dizer o mesmo de outros bancos. Mesmo assim, é interessante usar um Connection Pool, pois pode parecer imperceptível para uma só solicitação chegando, mas em um ambiente de produção, com a sua aplicação sendo 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 era obtida do ActionServlet. No entanto, nas nos betas e release candidate da versão 1.1 o metodo para obtenção de conexões ficou deprecated, e passaram esta tarefa para o Action. Por fim no release 1.1 de produção, as classes que tratam do DataSource foram parar no arquivo struts-legacy.jar, indicando claramente 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 uma implementaçã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.BasicData SourceFactory</value></parameter> <parameter><name>driverClassName</name><value>com.mysql.jdbc.Driver</va lue></parameter> <parameter><name>url</name><value>jdbc:mysql://localhost/strutsdemo</va lue></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 ao Connection Pool, o qual irá marcar uma conexão no Pool, como sendo usada, e lhe dará algum tempo para fazer 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 para você e a resgata para o pool). Para fazer isto, basta executar o método close(), que na verdade não a fecha,
  • 7. mas devolve para o Pool (dependendo da implementação do Connection Pool, poderá ter variações da maneira de devolver ao pool, algo do tipo invocar um metodo do tipo releaseConnection, do objeto Connection Pool). Definindo a Camada de Negócio Para listar os usuários cadastrados precisaremos definir as classes que farão parte da nossa camada de Negócio. Devemos ter duas classes. Uma classe que representa o registro do usuário "UserData" (value object) , e outra que irá gerenciar o cadastro dos usuários "AdminUsers". Segue abaixo o código das duas classes: 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() {
  • 8. 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 {
  • 9. 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(); } } }
  • 10. 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 Model para executar algum processo retornando um resultado que servirá de base para que o Controller possa direcionar 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 um JSP.
  • 11. Para incluir, alterar ou excluir um usuário, precisamos exibir todos os usuários cadastrados para saber o que fazer. 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 classe deve estender de org.apache.struts.action.Action (vamos entrar em mais detalhes sobre esta classe na seçã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és do método process, e se este objeto retornar um ActionForward com o valor "sucess", O controller encaminhará a solicitação para o arquivo "/pages/listUsers.jsp". Se retornar "failure", será encaminhado para o 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á uma certa discussão sobre que parte pertence o Action e o ActionForm no padrão MVC (vamos entrar em maiores detalhes mais adiante em ActionForm, por hora ainda não é necessário). Na realidade tanto o Action, quanto o ActionForm são Helper Classes. A grosso modo podemos entender como classes auxiliadores para execuçã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;
  • 12. 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 maioria baseada em JSPs e alguns servlets envolvidos na geração da interface com o usuário ou com outros sistemas. A Struts framework fornece suporte para construir aplicações multi-idiomas, interação com formulá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.properties no diretório cadastro/WEB-INF/classes/java/resources. Este arquivo deve conter as chaves e os valores no formato: chave.subchave=texto que pertence ao idioma padrão da aplicação. Vamos adicionar algumas chaves que serão usadas em nosso projeto. Obs: Este arquivo pode ter qualquer nome, desde que termine com .properties. No entanto existe um certo padrão, geralmente é chamado de ApplicationResources.properties. A única ressalva, é que se você mudar o nome deste arquivo, também deverá ser mudado no arquivo struts-config.xml. welcome.title=Bem Vindo ao Projeto Tutorial Struts welcome.heading=Bem vindo! welcome.message=Projeto Tutorial Struts
  • 13. application.title= Struts Demo - Cadastro index.header=Bem vindo ao Demo da Strutus Framework - Cadastro users.title=Cadastro de Usuários editUser.title=Alteração de Usuário insertUser.title=Inclusão de Usuário prompt.idUsuario=Código prompt.nome=Nome prompt.login=Login prompt.senha=Senha prompt.confirmacaoSenha=Confirmação da Senha prompt.sexo=Sexo prompt.ativo=Ativo prompt.status=Status prompt.faixaIdade=Faixa Etária prompt.excluir=Excluir prompt.incluir=Incluir prompt.voltar=Voltar prompt.Masculino=Masculino prompt.Feminino=Feminino prompt.ate20=Até 20 anos prompt.de21a30=De 21 a 30 anos prompt.de31a40=De 31 a 40 anos prompt.de41a50=De 41 a 50 anos prompt.de51a60=De 51 a 60 anos prompt.acima60=Acima de 60 anos prompt.senhaAntiga=Senha Antiga prompt.novaSenha=Nova Senha prompt.confirmacaoNovaSenha=Confirmação da Senha button.send=Enviar button.reset=Cancelar error.title=Erro Inesperado error.user.list=Erro obtendo a lista de usuários error.idUsuario.required=O identificador do usuário é um campo obrigatório error.login.required=O login do usuário é um campo obrigatório error.nome.required=O nome do usuário é um campo obrigatório error.get.user=Erro ao carregar o usuário error.senhaAntiga.required=A senha antiga é um campo obrigatório error.novaSenha.required=A nova senha é um campo obrigatório error.confirmacaoNovaSenha.required=A confirmação da nova senha é um campo obrigatório error.ConfirmacaoSenha=Erro na confirmação da nova senha error.user.notFound=Usuário não encontrado error.senhaAntiga=A senha Antiga não confere error.update.user=Erro alterando o usuário error.update.user=Erro incluindo o usuário error.delete.user=Erro excluindo o usuário error.idUsuario.duplicateKey=Este código de usuário já existe Para cada idioma alternativo, devemos adicionar um novo arquivo (no mesmo diretório do arquivo onde temos o arquivo do idioma padrão) no formato "application_xx.properties", onde xx é o código ISO do idioma. 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: ...
  • 14. <h3><bean:message key="application.title"/></h3> ... Por default, a Struts acessa o idioma principal da aplicação. Devemos utilizar a tag <html:html locale="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 idiomas suportados, 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 respeito do assunto, veja a documentação oficial da Sun disponível em http://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:message key="users.title"/></font></h3> <table width="80%" border="1"> <tr> <th width="10%"><bean:message key="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>
  • 15. </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 clicar em algum link, irá ocorrer um erro, pois ainda não temos os ActionBeanss necessários para invocar a camada de negócio. Neste momento para facilitar o entendimento, vamos implementar apenas os Beans necessários para Alterar o usuário. Devemos criar um ActionBean que deverá invocar a camada de negócio e popular um bean com os dados do usuário a ser alterado, e enviar para a camada de apresentação para que os 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,
  • 16. 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 basta adicionar 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ódigo JSP 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:message key="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:message key="prompt.idUsuario"/>: </td> <td align="left"><b><bean:write property="idUsuario" name="editUserBean"/></b></td> </tr> <tr> <td align="right"><bean:message
  • 17. key="prompt.login"/>: </td> <td align="left"><html:text property="login" name="editUserBean" size="20"/></td> </tr> <tr> <td align="right"><bean:message key="prompt.nome"/></td> <td align="left"><html:text property="nome" name="editUserBean" size="60"/></td> </tr> <tr> <td align="right"><bean:message key="prompt.senhaAntiga"/>: </td> <td align="left"><html:password property="senhaAntiga" size="16" maxlength="20" redisplay="false" value="zzzzz"/></td> </tr> <tr> <td align="right"><bean:message key="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:message key="prompt.confirmacaoNovaSenha"/>: </td> <td align="left"><html:password property="confirmacaoNovaSenha" size="16" maxlength="20" redisplay="false" value="zzzzz"/></td> </tr> <tr> <td align="right"><bean:message key="prompt.faixaIdade"/>: </td> <td align="left"> <html:select property="faixaIdade" name="editUserBean"> <html:option value="1"><bean:message key="prompt.ate20"/></html:option></html:option> <html:option value="2"><bean:message key="prompt.de21a30"/></html:option></html:option> <html:option value="3"><bean:message key="prompt.de31a40"/></html:option></html:option> <html:option value="4"><bean:message key="prompt.de41a50"/></html:option></html:option> <html:option value="5"><bean:message key="prompt.de51a60"/></html:option></html:option> <html:option value="6"><bean:message key="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>
  • 18. </tr> <tr> <td align="right"><bean:message key="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:message key="button.send"/></html:submit> <html:reset><bean:message key="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, para se alterar e obter nova informação. As validações, o tratamento de erros, a apresentação, e o mesmo a entrada de dados do form pelo usuário e mensagens de erros, são contempladas pela Struts, o que torna a vida um pouco mais fácil. Todo trabalho de validação e geração de mensagens de erros serão implementados 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á conter todos os campos (variaveis privadas com os devidos metodos gets e sets), coincidindo com o nome dos inputs do formulário html. Toda validação de dados pela Struts passa por um FormBean. O FormBean é a primeira classe (quando definida 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 um FormBean quando necessitarmos de validação dos dados. No nosso caso, quando precisarmos salvar os dados que foram alterados pelo usuário. No entanto, antes de devemos fazer uma validação para que não vá besteira para o banco de dados. Um ActionForm possui dois mé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;
  • 19. 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;
  • 20. } 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 Collection de erros. Se este collection tiver algum erro, o FormBean devolve para o jsp que entrou com os dados, com os campos devidamente preenchidos, e com as mensagens dos erros ocorridos. Caso contrário, ou seja, se não ocorrer nenhum erro, então o fluxo segue para um ActionBean para invocar a camada de negócio para gravar estes dados no banco de dados. Logo, precisamos criar este bean. Segue abaixo o código do nosso ActionBean. 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,
  • 21. 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>
  • 22. ... </action-mappings> Obs: Até a versão 1.0 da Struts, a única maneira de validar os dados era herdando do ActionForm, e colocando as regras de validação no método validate. No entanto com a Struts 1.1 é possível fazer a validaçã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 de javascript definidos no arquivo validator.xml. Assim, podemos evitar o overread gerado pelas solicitações desnecessárias no servidor, pois quando a solicitação chega ao web server, estaremos tratando com os dados previamente tratados pelo javascript do lado client. Só pra constar como lembrete para os novatos em internet. Pode parecer tentador, mas nunca deixe de validar os dados no lado servidor se tiver tudo tratado no lado client, pois o usuário pode desabilitar o javascript do browser e causar erros imprevisíveis na sua aplicação. Conclusão: Use javascript para validar se puder, 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 no arquivo 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 da template struts-blank.war, pois serão usados no javascript. # Mensagens de erro padrão para as validações errors.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.
  • 23. 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 ainda fazer 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 a introdução dos DynamicForms. Assim você não é mais "obrigado" a criar um Form para validar as entradas de cada formulário HTML. O Dynamic Form é configurado apenas no struts-config.xml e a Struts já tem uma classe "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 que já foram feitos antes. ou seja, se você chegou até aqui, só falta um pouco de pratica para você se tornar um expert 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:message key="welcome.title"/></font></h1> <logic:notPresent name="org.apache.struts.action.MESSAGE" scope="application"> <font color="red"> ERROR: Application resources not loaded -- check servlet 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:wbsouza@yahoo.com.br">Welington B.Souza</html:link> <br>01/07/2003 </font></p> </p> </font>
  • 24. </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">
  • 25. <center> <h3><font color="blue"><bean:message key="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:message key="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:message key="prompt.login"/>: </td> <td align="left"><html:text property="login" size="20" name="insertUserBean"/></td> </tr> <tr> <td align="right"><bean:message key="prompt.nome"/></td> <td align="left"><html:text property="nome" size="60" name="insertUserBean"/></td> </tr> <tr> <td align="right"><bean:message key="prompt.senha"/>: </td> <td align="left"> <html:password property="senha" size="16" maxlength="20" redisplay="false"/> </td> </tr> <tr> <td align="right"><bean:message key="prompt.confirmacaoSenha"/>: </td> <td align="left"> <html:password property="confirmacaoSenha" size="16" maxlength="20" redisplay="false"/> </td> </tr> <tr> <td align="right"><bean:message key="prompt.faixaIdade"/>: </td> <td align="left"> <html:select property="faixaIdade" name="insertUserBean"> <html:option value="1"><bean:message
  • 26. key="prompt.ate20"/></html:option></html:option> <html:option value="2"><bean:message key="prompt.de21a30"/></html:option></html:option> <html:option value="3"><bean:message key="prompt.de31a40"/></html:option></html:option> <html:option value="4"><bean:message key="prompt.de41a50"/></html:option></html:option> <html:option value="5"><bean:message key="prompt.de51a60"/></html:option></html:option> <html:option value="6"><bean:message key="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:message key="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:message key="button.send"/></html:submit> <html:reset><bean:message key="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;
  • 27. 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()) {
  • 28. 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")); }
  • 29. } } 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ções entre produtos pagos e open source (EasyStruts, Struts Console). No entanto, é recomendável familiarizar-se primeiro com a configuração manual antes de utilizar estas ferramentas, pois caso ocorra algum problema imprevisto, possa ser corrigido manualmente. Você pode encontrar mais detalhes em buscas no SourceForge.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 o efeito 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. • •