Informações

Tipo: Tutorial
Data de Publicação: 12/05/2004
Revisado em: 12/05/2004

Vote!

  • Currently 4,4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags Relacionadas

framework struts

Comentários ( 19 )

Imprimir

Struts Framework

por:

Welington B. Souza (javasouza@yahoo.com.br)

Este artigo contempla uma visão geral do Framework Struts, usado no desenvolvimento de aplicações WEB.

Introdução

O objetivo deste tutorial é dar uma visão geral sobre o funcionamento da Struts Framework, com base na versão 1.3. Aqui você irá aprender o necessário para começar a desenvolver uma aplicação web usando a Struts. Pressupõe-se que o leitor tenha os conceitos básicos sobre a linguagem Java, bem como o funcionamento de uma aplicação web escrita em Java.

Embora esta framework implemente o padrão MVC, não vamos entrar em detalhes sobre padões de projeto, mas sim expor 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 idéia aqui é simplificar!

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 web java. 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 Framework foi criada 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 para 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, XHTML, 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/licenses/).

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 método 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 no request ou sessã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 do request ou 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 acessando a documentação

A Struts Framework pode ser baixada em http://struts.apache.org/. Neste tutorial vamos usar a versão 1.3.8 (atual versão estável). No site tem algumas opções de download. Baixe o arquivo struts-1.3.8-all.zip. Após o download e descompactar o arquivo, a documentação estará disponível no diretório docs

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"

Antes de começar, certifique-se de que o diretório de binários do JDK está configurado na variável de ambiente PATH, pois usaremos o utilitário jar que se encontra neste local. Considerando que você já tenha a variável de ambiente JAVA_HOME (local onde se encontra o JDK instalado) você deverá adicionar na variável de ambiente PATH a localização do diretório de binários do java:

  • Em sistemas Unix like utilize $JAVA_HOME/bin no script de inicialização do interpretador de comandos.
  • No Windows adicione %JAVA_HOME%\bin

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 apps;
  • 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 de uma aplicação web baseada no template struts-blank:
RootDir
|
+-- META-INF
|   Contém metadados que podem ser utilizados pelo container, utilitários, etc.
|
+-- WEB-INF
|     |
|     +-- src
|     |     +-- java  Este diretório contém o código fonte da aplicação.
|     |         |	 
|     |         +-- MessageResources.properties
|     |             Contém as mensagens (textos fixos) da aplicação, 
|     |             inclusive as mensagens de erros.
|     |             Este arquivo é responsável pela internacionalização.
|     +-- classes
|     |         Este diretório contém o código compilado da sua aplicação.
|     +--- lib
|     |     |
|     |     +-- *.jar
|     |         Contém as classes da Struts (Controller, Helper classes, 
|     |         Biblioteca de Tags, etc) e suas dependências
|     |
|     +-- validation.xml
|     |   Contém os fomulários dinâmicos, bem como regras de validação
|     |   para entrada de dados.
|     |
|     +-- 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.
|
+-- pages
       Contém as paginas JSP da aplicação web
			  

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.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
    <display-name>Struts Blank Application</display-name>

  
    <!-- Standard Action Servlet Configuration -->
    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
        <init-param>

            <param-name>config</param-name>
            <param-value>/WEB-INF/struts-config.xml</param-value>
        </init-param>
        <load-on-startup>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>

</web-app>

Temos no arquivo web.xml, duas importantes seções:

  • A definição da Servlet que representa o Controller (ActionServlet)
  • O URL mapping da servlet, para informar como chamar esta servlet

Podemos ver pelo servlet-mapping que a nossa servlet será invocada por http://localhost:8080/cadastro/NomeAcao.do
Substituindo-se NomeAcao pela ação desejada.

Banco de dados

Por questões de facilidade de obtenção e configuração, vamos utilizar o MySQL como banco de dados. O MySql pode ser baixado em http://dev.mysql.com/downloads/

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://dev.mysql.com/downloads/connector/j/. Após baixá-lo, descompactar e copiar o arquivo mysql-connector-java-3.0.8-stable-bin.jar para diretório lib do seu web container, tornando estas classes acessíveis para qualquer aplicação em execução no web container.

Pool de Conexões

A maioria das aplicações para web que usam banco de dados podem ser beneficiadas por um Pool de Conexões (coleção de conexões que ficam permanentemente abertas com o banco de dados).

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 Pool de Conexões 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 Pool de Conexões resgata esta conexão de volta, e invalida o objeto de conexão que você pegou anteriormente. Hoje em dia, praticamente todos os Containers fornecem suporte para Pool de Conexões.

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 Pool de Conexões, pois pode parecer imperceptível para uma só solicitação chegando, mas em um ambiente de produção, com a sua aplicação sendo massivamente solicitada para manipular e consultar dados, haverá uma grande diferença.

A Struts Framework implementa um Pool de Conexões usando DataSource. Na versão 1.0, a Conexão era obtida do ActionServlet. No entanto, nas versões beta e release candidate da versão 1.1 o método 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 padronizada (JCA), ou seja, implementada pelo container;

Mostraremos passo a passo como configurar o Pool de Conexões no tomcat 6.0. Caso esteja utilizando outro web container, siga as recomendações do fabricante.

Vá para o diretório conf do tomcat e modifique o arquivo server.xml adicionando o trecho abaixo:

<Server port="8005" shutdown="SHUTDOWN">
    ...
    <GlobalNamingResources>
        ...
        <Resource auth="Container" 
            description="DataSource para fornecer o Pool de Conexoes" 
            name="jdbc/StrutsDemoDS" type="javax.sql.DataSource" 
            driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://localhost/strutsdemo"
            username="root" password="root"
            maxActive="30" maxIdle="10" maxWait="4000"  />

        ...
    </GlobalNamingResources>
    ...
</Server>
Na aplicação web, vá para o final do arquivo WEB-INF/web.xml, logo após a ultima tag dentro de <web-app>, e adicione o recurso do Pool de Conexões que sera utilizado pela aplicação web.
<web-app>

    ...
    <resource-ref>
        <description>
            Referencia de Recurso para o Pool de Conexoes
            configurado no arquivo server.xml 
        </description>
        <res-ref-name>jdbc/StrutsDemoDS</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>

        <res-auth>Container</res-auth>
    </resource-ref>
</web-app>
Crie um arquivo chamado context.xml no diretório META-INF da aplicação web com o conteúdo abaixo.

<?xml version="1.0" encoding="ISO-8859-1"?>
<Context path="cadastro" debug="1" reloadable="true" 
    docBase="${catalina.home}/server/webapps/cadastro">
    <ResourceLink global="jdbc/StrutsDemoDS" name="jdbc/StrutsDemoDS" 
        type="javax.sql.Datasource" />
</Context>

No código Java, quando precisar de uma conexão de banco de dados, você irá solicitar uma conexão ao Pool de Conexões, o qual irá marcar uma conexão no Pool, como sendo usada, e lhe dará algum tempo para fazer alguma coisa. Tão logo tenha utilizado 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 Pool de Conexões 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, pois o DataSource fornece um objeto que implementa a interface Connection que é um wrapper para a conexão real do banco de dados.

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" (usado para transferir dados para a camada de negócio), e outra que irá gerenciar o cadastro dos usuários "AdminUsers". Segue abaixo o código das classes:

strutsdemo.model.UserData

package strutsdemo.model;

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;
    }

}

strutsdemo.model.AdminUsers

package strutsdemo.model;


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

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 ctx = new InitialContext();
                dataSource = (DataSource) 
                    ctx.lookup("java:comp/env/jdbc/StrutsDemoDS");
            } 
            catch (NamingException ex) {
                System.err.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 UserData getUserById(int idUsuario) throws SQLException {
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            conn = getConnection();
            stmt = conn.prepareStatement(
                "SELECT * FROM usuario WHERE id_usuario = ?");
            stmt.setInt(1, idUsuario);
            rs = stmt.executeQuery();
            if (rs.next()) {
                UserData user = new UserData();
                user.setIdUsuario(idUsuario);
                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"));
                return user;
            }
        }
        finally {
            closeConnection(conn, stmt, rs);
        }
        return null;
    }
    
    public List getUserList() throws SQLException {
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        ArrayList users  = new ArrayList();
        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);
            }
        }
        finally {
            closeConnection(conn, stmt, rs);
        }
        return users;
    }
	
    private int getNextUserId(Connection conn) throws SQLException {
        int result = -1;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            conn = getConnection();
            stmt = conn.prepareStatement("SELECT max(id_usuario) FROM usuario");
            rs = stmt.executeQuery();
            if (rs.next()) {
                result = rs.getInt(1) + 1;
            }
            else result = 1;
        }
        finally {
            if (rs != null) {
                rs.close();
            }
            if (stmt != null) {
                stmt.close();
            }
        }
        return result;
    }	

    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, getNextUserId(conn));
            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();
        }
        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();
        }
        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();
        }
        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, decidir qual classe da camada de negócio deverá ser invocada para tratar a solicitação em questão. Assim, ele irá preparar os dados de acordo com as necessidades da camada de negócio e invocar métodos da camada de negócio (Model), a qual irá fornecer um ou mais objetos (coleção). Dependendo do resultado da execução da camada de negócio, o Controller irá decidir qual 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, apresenta os dados em 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.action, 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").
  • strutsdemo.action.ListUsersAction

    package strutsdemo.action;
    
    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>
        ...
        <global-forwards>
            ...
            <forward name="failure" path="/pages/Error.jsp" />
    
        </global-forwards>
    
        <action-mappings>
            ...
            <action
                path="/ListUsers"
                type="strutsdemo.action.ListUsersAction">
                <forward name="success" path="/pages/ListUsers.jsp" />
            </action>
    
        </action-mappings>
        ...
    </struts-config>
    

    Neste caso, quando for solicitado pelo browser ListUsers.do a Servlet Controller da Struts irá invocar o método execute da classe ListUsersAction. 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 auxiliares para execução no padrão MVC. Basicamente, os ActionBeans realizam as seguintes ações:

  • Obtém os valores necessários do ActionForm, JavaBean, request, session ou de outro local;
  • Invoca métodos da camada de negócio (model);
  • Analisa o resultado da chamada para camada de negócio, e com base nisso, retorna o ActionForward correspondente (indicando qual JSP irá apresentar os dados)
  • O Código da nossa Action ficará assim:

    strutsdemo.action.ListUsersAction

    package strutsdemo.action;
    
    import java.sql.SQLException;
    import java.util.List;
    
    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;
    import org.apache.struts.action.ActionMessage;
    import org.apache.struts.action.ActionMessages;
    
    import strutsdemo.model.AdminUsers;
    
    public class ListUsersAction extends Action {
    
        public ActionForward execute(ActionMapping mapping, 
            ActionForm form, HttpServletRequest request, 
            HttpServletResponse response) throws Exception {
    
            List users = null;
            ActionMessages errors = new ActionMessages();
            try {
                AdminUsers adminUsers = new AdminUsers();
                users = adminUsers.getUserList();
                request.setAttribute("userListBean", users);
            }
            catch (SQLException e) {
                errors.add(ActionMessages.GLOBAL_MESSAGE, 
                    new ActionMessage("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-línguas, interação com formulários e outras utilidades através de tags personalizadas (Custom Tags).

    Internacionalização

    No projeto (baseado no template struts-blank ), possui um arquivo de chamado MessageResources.properties no diretório /WEB-INF/src/java. 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 MessageResources.properties. A única ressalva, é que se você mudar o nome deste arquivo, também deverá ser mudado no arquivo struts-config.xml.

    src/java/MessageResources.properties

    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.acao=Ação
    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 é 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 "MessageResources_xx.properties", onde xx é o código ISO do idioma. Ex: (MessageResources_en.properties).

    Nos JSPs que utilizaremos a internacionalização deveremos incluir:

    ...
    <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>
    ...
    
    

    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(Globals.LOCALE_KEY, new 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/javase/technologies/core/basic/intl/.

    Por questões de organização vamos colocar todos os nossos JSPs no diretório cadastro/pages/. Assim, faremos uma modificação no arquivo Welcome.jsp já existente para dar uma cara para a página inicial

    /pages/Welcome.jsp

    <%@ page language="java" contentType="text/html; charset=ISO-8859-1"%>
    
    <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>
    <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
    <%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic"%>
    
    <html:html lang="true">
    <head>
    <title><bean:message key="welcome.title" /></title>
    </head>
    
    <body>
        <center>
        <h1>
            <font face="Comic Sans MS" size="3" />
            <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>
        
        <p>
        <font color="darkblue"> Autor: 
            <html:link href="mailto:wbsouza@yahoo.com.br">
    
                Welington B.Souza
            </html:link>
            <br>
            20/11/2007
        </font>
        </p>
        
        </center>
    
    </body>
    </html:html>
    
    


    Além disso, é necessário criar uma página de erro genérica para apresentar os erros que possam ocorrer na aplicação web. Segue abaixo o código da página JSP Error.jsp.

    /pages/Error.jsp

    <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>
    <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
    <%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic"%>
    
    <%@ page pageEncoding="ISO-8859-1"%>
    <html:html lang="true">
    <head>
        <title><bean:message key="error.title" /></title>
    </head>
    <body bgcolor="white">
        <center>
    
        <font face="Comic Sans MS" size="3">
        <h1><bean:message key="error.title" /></h1>
        </font>
        <font color="red">
        <logic:messagesPresent>
    
            <ul>
                <html:messages id="error">
                    <li><bean:write name="error" /></li>
                </html:messages>
            </ul>
    
        </logic:messagesPresent>
        </font>
        <br/>
        <html:link page="/Welcome.do">Página Inicial</html:link>
        </center>
    
        </body>
    </html:html>
    


    Agora, já podemos escrever o nosso primeiro JSP para listar os usuários:

    /pages/ListUsers.jsp

    
    <%@ page language="java" contentType="text/html; charset=ISO-8859-1"%>
    <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>
    <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
    <%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic"%>
    
    <logic:notPresent name="userListBean" scope="request">
        <logic:redirect forward="error" />
    </logic:notPresent>
    
    <html:html lang="true">
    <head>
        <title><bean:message key="users.title" /></title>
    </head>
    
    <body>
        <center>
    
        <h3><font face="Comic Sans MS" size="3"><font color="blue">
    	    <bean:message key="users.title" />
        </font></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%"><bean:message key="prompt.acao" /></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">
            <bean:message key="prompt.incluir" />
        </html:link> 
        <html:link page="/Welcome.do">Home</html:link>
    
        </center>
    </body>
    </html:html>
    

    Neste ponto, após o deploy, já temos a aplicação funcionando parcialmente. Para realizar o deploy é necessário empacotar a aplicação já compilada num WAR (Web Application Archive) e publicá-lo no Web Container (tomcat, jboss, etc). Para automatizar esta tarefa, você poderá utilizar a ferramenta ANT. No nosso caso já existe o script cadastro/WEB-INF/src/build.xml que veio com a struts-blank, e pode ser modificado de acordo com o Web Container que você tiver utilizando.O foco deste tutorial não é entrar em detalhes de funcionamento do ANT. A grosso modo, podemos entender que o script ANT é equivalente a um Makefile otimizado para trabalhar com Java. Você poderá encontrar facilmente materiais a respeito do ANT no Google.


    Para testar a aplicação (listagem de usuários), acesse via browser a url http://localhost:8080/cadastro/ListUsers.do. Conforme mencionado anteriormente, a aplicação está funcionando parcialmente. Assim, se você clicar em algum link desta página, irá ocorrer um erro, pois ainda não temos os ActionBeans 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.

    strutsdemo.action.EditUserAction

    package strutsdemo.action;
    
    import java.util.Iterator;
    import java.util.LinkedList;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.struts.action.Action;
    import org.apache.struts.action.ActionMessage;
    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.action.ActionMessages;
    
    import strutsdemo.model.AdminUsers;
    import strutsdemo.model.UserData;
    
    public class EditUserAction extends Action {
    
        public ActionForward execute(
            ActionMapping mapping,
            ActionForm form,
            HttpServletRequest request,
            HttpServletResponse response)
            throws Exception {
            ActionErrors errors = new ActionErrors();
            try {
                AdminUsers adminUsers = new AdminUsers();
                int idUsuario = Integer.parseInt(
                    request.getParameter("idUsuario"));
                UserData user = adminUsers.getUserById(idUsuario);
                if (user == null) {
                    errors.add(
                        ActionMessages.GLOBAL_MESSAGE, 
                       new ActionMessage("error.user.notFound"));
                }
                else {
                    request.getSession().setAttribute("userBean", user);
                }
            }
            catch (Exception e) {
                errors.add(
                        ActionMessages.GLOBAL_MESSAGE, 
                    new ActionMessage("error.get.user"));
                getServlet().log("Erro carregando o Usuário", e);
            }
    
            if (errors.isEmpty()) {
                return (mapping.findForward("success"));
            }
            else {
                saveErrors(request, errors);
                return (mapping.findForward("failure"));
            }
        }
    }
    
    

    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>

    </struts-config>
        ...    
    
        <action-mappings>
            ...
            <action path="/EditUser" 
                type="strutsdemo.action.EditUserAction">
                <forward name="success" path="/pages/EditUser.jsp" /> 
            </action>
        </action-mappings>
    
    </struts-config>
    

    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.

    /pages/EditUser.jsp

    <%@ page language="java" contentType="text/html; charset=ISO-8859-1"%>
    <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>
    <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
    
    <%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic"%>
    
    <logic:notPresent name="userBean" scope="session">
        <logic:redirect forward="error" />
    </logic:notPresent>
    
    <html:html lang="true">
    <head>
        <title><bean:message key="editUser.title" /></title>
    
    </head>
    <body>
        <center>
        <h3><font face="Comic Sans MS" size="3"><font color="blue">
            <bean:message key="editUser.title" /></font></font>
    
        </h3>
        <html:form action="/SaveEditUser.do" method="post" 
            onsubmit="return validateSaveEditUserForm(this);" focus="login">
            <html:hidden property="idUsuario" name="userBean" />
            <table width="80%" border="0">
                <tr>
                    <td width="30%"></td>
    
                    <td width="70%"> 
                        <logic:messagesPresent>
                            <font color="red">
                                <ul>
                                    <html:messages id="error">
                                        <li><bean:write name="error" /></li>
    
                                    </html:messages>
                                </ul>
                            </font>
                        </logic:messagesPresent>
                    </td>
                <tr>
    
                <tr>
                    <td align="right"><bean:message key="prompt.idUsuario" />:</td>
                    <td align="left">
                        <b><bean:write property="idUsuario" name="userBean" /></b>
    
                    </td>
                </tr>
        
                <tr>
                    <td align="right"><bean:message key="prompt.login" />:</td>
                    <td align="left">
    
                        <html:text property="login" name="userBean" size="20" />
                    </td>
                </tr>
                <tr>
                    <td align="right"><bean:message key="prompt.nome" /></td>
    
                    <td align="left">
                        <html:text property="nome" name="userBean" 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="userBean">
                        <html:option value="1">
                            <bean:message key="prompt.ate20" />
                        </html:option>
                        <html:option value="2">
                            <bean:message key="prompt.de21a30" />
    
                        </html:option>
                        <html:option value="3">
                            <bean:message key="prompt.de31a40" />
                        </html:option>
                        <html:option value="4">
                            <bean:message key="prompt.de41a50" />
    
                        </html:option>
                        <html:option value="5">
                            <bean:message key="prompt.de51a60" />
                        </html:option>
                        <html:option value="6">
                            <bean:message key="prompt.acima60" />
    
                        </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="userBean">
                            <bean:message key="prompt.Masculino" />
                        </html:radio> 
                        <html:radio property="sexo" value="F" name="userBean">
                            <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="userBean" 
                            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">
    
            <bean:message key="prompt.voltar" />
        </html:link>
        </center>
    </body>
    <html:javascript formName="SaveEditUserForm"/>
    </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 métodos 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, devemos antes fazer uma validação para que não vá dados inconsistentes 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.

    strutsdemo.form.SaveEditUserForm

    package strutsdemo.form;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.apache.struts.action.ActionErrors;
    import org.apache.struts.action.ActionForm;
    import org.apache.struts.action.ActionMapping;
    import org.apache.struts.action.ActionMessage;
    
    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 ActionMessage("error.idUsuario.required"));
            }
            if ((login == null) || (login.length() < 1)) {
                errors.add("login", new ActionMessage("error.login.required"));
            }
            if ((nome == null) || (nome.length() < 1)) {
                errors.add("nome", new ActionMessage("error.nome.required"));
            }
            if ((novaSenha == null) || (novaSenha.length() < 1)) {
                errors.add("nome", new ActionMessage("error.novaSenha.required"));
            }
            if ((confirmacaoNovaSenha == null) || 
                (confirmacaoNovaSenha.length() < 1)) {
                errors.add("confirmacaoNovaSenha", 
                    new ActionMessage("error.confirmacaoNovaSenha.required"));
            }
            if ((senhaAntiga == null) || (senhaAntiga.length() < 1)) {
                errors.add("senhaAntiga", 
                    new ActionMessage("error.senhaAntiga.required"));
            }
            if (errors.isEmpty()) {
                if (!novaSenha.equals(confirmacaoNovaSenha)) {
                    errors.add("senhaAntiga", 
                        new ActionMessage("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.

    strutsdemo.action.SaveEditUserAction

    package strutsdemo.action;
    
    import java.sql.SQLException;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.beanutils.BeanUtils;
    import org.apache.struts.action.Action;
    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.action.ActionMessage;
    
    import strutsdemo.form.SaveEditUserForm;
    import strutsdemo.model.AdminUsers;
    import strutsdemo.model.UserData;
    
    public class SaveEditUserAction extends Action {
    
        public ActionForward execute(ActionMapping mapping, 
            ActionForm form, 
            HttpServletRequest request, 
            HttpServletResponse response) throws Exception {
            
            ActionErrors errors = new ActionErrors();
            try {
                SaveEditUserForm editUserForm = (SaveEditUserForm) form;
                int idUsuario = Integer.parseInt(editUserForm.getIdUsuario());
                AdminUsers adminUsers = new AdminUsers();
                UserData user = adminUsers.getUserById(idUsuario);
                if (user != null) {
                    // se a senha foi modificada ...
                    if (!editUserForm.getSenhaAntiga().equals("zzzzz")) {
                        if (!user.getSenha().equals(
                            editUserForm.getSenhaAntiga())) {
                            errors.add(ActionErrors.GLOBAL_MESSAGE, 
                                new ActionMessage("error.senhaAntiga"));
                        }
                    }
                    if (errors.isEmpty()) {
                        BeanUtils.copyProperties(user, editUserForm);
                        adminUsers.updateUser(user);
                    }
                }
                else {
                    errors.add(ActionErrors.GLOBAL_MESSAGE, 
                        new ActionMessage("error.user.notFound"));
                }
            }
            catch (SQLException e) {
                errors.add(ActionErrors.GLOBAL_MESSAGE, 
                    new ActionMessage("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.

    </struts-config>
    
        ...
        <form-beans>
            <form-bean name="SaveEditUserForm" 
                type="strutsdemo.form.SaveEditUserForm"/>
        </form-beans>
        ...
        <action-mappings>
            ...
            <action  path="/SaveEditUser" 
                type="strutsdemo.action.SaveEditUserAction" 
                name="SaveEditUserForm" input="/pages/EditUser.jsp" > 
                <forward name="success" path="/ListUsers.do" />
    
                <forward name="failure" path="/pages/EditUser.jsp" />
            </action>
            ...
        </action-mappings>
        ...
    </struts-config>
    

    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 após a versão 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 que veio na Struts 1.1 foi 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 cliente (browser) via javascript devemos acrescentar as regras no arquivo no arquivo validation.xml. Adicionar o trecho de código conforme exemplo abaixo na seção <formset>.

    <form-validation>
        ...
        <formset>
            ...
            <form name="SaveEditUserForm">
                <field property="idUsuario" depends="required">
                    <arg key="prompt.idUsuario" />
    
                </field>
                <field property="login" depends="required">
                    <arg key="prompt.login" />
                </field>
                <field property="nome" depends="required">
                    <arg key="prompt.nome" />
    
                </field>
                <field property="novaSenha" depends="required">
                    <arg 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">
                    <arg 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">
                    <arg key="prompt.confirmacaoNovaSenha" />
                    <var>
                        <var-name>mask</var-name>
                        <var-value>^[0-9a-zA-Z]*$</var-value>
    
                    </var>
                </field>
            </form>
            ...
        </formset>
        ...
    </form-validation>
    
    

    Também precisaremos "traduzir" algumas mensagens que já vieram no arquivo application.properties da template struts-blank.war, pois serão usados no javascript.

    # -- validator --
    errors.invalid={0} é Inválido.
    errors.maxlength={0} não pode ser maior que {1} caracteres.
    errors.minlength={0} não pode ser menor que {1} caracteres.
    errors.range={0} não está entre o intervalo {1} e {2}.
    errors.required={0} é obrigatório.
    errors.byte={0} deve ser byte.
    errors.date={0} deve ser uma data.
    errors.double={0} deve ser double.
    errors.float={0} deve ser float.
    errors.integer={0} deve ser integer.
    errors.long={0} deve ser long.
    errors.short={0} deve ser short.
    errors.creditcard={0} não é um cartão de crédito válido.
    errors.email={0} é um endereço de email invá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:

    </struts-config>
        ...
        <form-beans>
            ...
            <form-bean name="SaveInsertUserForm" 
                type="org.apache.struts.validator.DynaValidatorForm" >
    
                <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>
            ....
        </form-beans>
        ...
    </struts-config>
    

    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:

    strutsdemo.action.InsertUserAction

    package strutsdemo.action;
    
    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;
    
    import strutsdemo.model.UserData;
    
    public class InsertUserAction extends Action {
    
        public ActionForward execute(
            ActionMapping mapping, 
            ActionForm form, 
            HttpServletRequest request, 
            HttpServletResponse response) throws Exception {
            UserData user = new UserData();
            request.getSession().setAttribute("userBean", user);
            return (mapping.findForward("success"));
        }
    }
    

    /pages/InsertUser.jsp

    <%@ page language="java" contentType="text/html; charset=ISO-8859-1"%>
    <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean"%>
    
    <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
    <%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic"%>
    
    <html:html lang="true">
    <head>
        <title><bean:message key="insertUser.title" /></title>
    </head>
    <body>
    
        <center><font face="Comic Sans MS" size="3" />
        <h3><font color="blue"><bean:message key="insertUser.title" /></font></h3>
        </font> <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>
                            <font color="red">
    
                                <ul>
                                    <html:messages id="error">
                                        <li><bean:write name="error" /></li>
                                    </html:messages>
                                </ul>
    
                            </font>
                        </logic:messagesPresent>
                    </td>
                <tr>
                <tr>
                    <td align="right"><bean:message key="prompt.login" />:</td>
    
                    <td align="left"><html:text property="login" size="20"
                        name="userBean" /></td>
                </tr>
                <tr>
                    <td align="right"><bean:message key="prompt.nome" /></td>
                    <td align="left">
    
                        <html:text property="nome" size="60" name="userBean" />
                    </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="userBean">
                            <html:option value="1">
    
                                <bean:message key="prompt.ate20" />
                            </html:option>
                            <html:option value="2">
                                <bean:message key="prompt.de21a30" />
                            </html:option>
                            <html:option value="3">
    
                                <bean:message key="prompt.de31a40" />
                            </html:option>
                            <html:option value="4">
                                <bean:message key="prompt.de41a50" />
                            </html:option>
                            <html:option value="5">
    
                                <bean:message key="prompt.de51a60" />
                            </html:option>
                            <html:option value="6">
                                <bean:message key="prompt.acima60" />
                            </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="userBean">
                            <bean:message key="prompt.Masculino" />
                        </html:radio> 
                        <html:radio property="sexo" value="F" name="userBean">
                            <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="userBean" />
                    </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">
            <bean:message key="prompt.voltar" />
    
        </html:link>
        </center>
    </body>
    <html:javascript formName="SaveInsertUserForm" />
    </html:html>
    
    


    strutsdemo.action.SaveInsertUserAction

    package strutsdemo.action;
    
    import java.sql.SQLException;
    
    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.ActionErrors;
    import org.apache.struts.action.ActionForm;
    import org.apache.struts.action.ActionForward;
    import org.apache.struts.action.ActionMapping;
    import org.apache.struts.action.ActionMessage;
    import org.apache.struts.validator.DynaValidatorForm;
    
    import strutsdemo.model.AdminUsers;
    import strutsdemo.model.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");
            
            if (senha1.equals(senha2)) {
                
                try {
                    HttpSession session = request.getSession();
                    UserData user = (UserData) 
                        session.getAttribute("userBean");
                    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);
                    session.removeAttribute("userBean");
                }
                catch (SQLException e) {
                    if (e.getErrorCode() == 1062) {
                        errors.add(ActionErrors.GLOBAL_MESSAGE, 
                            new ActionMessage("error.idUsuario.duplicateKey"));
                    }
                    else {
                        errors.add(ActionErrors.GLOBAL_MESSAGE,
                            new ActionMessage("error.insert.user"));
                    }
                }
            }
            else {
                errors.add(ActionErrors.GLOBAL_MESSAGE, 
                    new ActionMessage("error.ConfirmacaoSenha"));
            }
            if (!errors.isEmpty()) {
                saveErrors(request, errors);
                return (mapping.findForward("failure"));
            }
            else {
                return (mapping.findForward("success"));
            }
        }
    }
    

    strutsdemo.action.DeleteUserAction

    package strutsdemo.action;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.struts.action.Action;
    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.action.ActionMessage;
    
    import strutsdemo.model.AdminUsers;
    
    public class DeleteUserAction extends Action {
    
        public ActionForward execute(
            ActionMapping mapping, 
            ActionForm form, HttpServletRequest request, 
            HttpServletResponse response) throws Exception {
            
            int idUsuario = Integer.parseInt(request.getParameter("idUsuario"));
            ActionErrors errors = new ActionErrors();
            try {
                AdminUsers adminUsers = new AdminUsers();
                adminUsers.deleteUser(idUsuario);
            }
            catch (Exception e) {
                errors.add(ActionErrors.GLOBAL_MESSAGE, 
                    new ActionMessage("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"));
            }
        }
    }
    

    /WEB-INF/struts-config.xml

    <?xml version="1.0" encoding="ISO-8859-1" ?>
    <!DOCTYPE struts-config PUBLIC
              "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
              "http://struts.apache.org/dtds/struts-config_1_3.dtd">
    
    <struts-config>
    
        <!-- =========================================== Form Bean Definitions -->
        <form-beans>
        
            <form-bean name="SaveInsertUserForm" 
                type="org.apache.struts.validator.DynaValidatorForm" >
                <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>
    
            
            <!-- SaveEditUserForm - formulario baseado em uma classe -->
            <form-bean name="SaveEditUserForm" 
                type="strutsdemo.form.SaveEditUserForm"  />
    			
        </form-beans>
    
    
        <!-- ==================================== Global Exception Definitions -->
        <global-exceptions>
    
            <!-- sample exception handler
                <exception
                key="expired.password"
                type="app.ExpiredPasswordException"
                path="/changePassword.jsp"/>
                end sample -->
        </global-exceptions>
    
    
        <!-- ====================================== Global Forward Definitions -->
    
        <global-forwards>
    
            <!-- Default forward to "Welcome" action -->
            <!-- Demonstrates using index.jsp to forward -->
            <forward name="welcome" path="/Welcome.do" />
            <forward name="failure" path="/pages/Error.jsp" />
        </global-forwards>
    
    
        <!-- ====================================== Action Mapping Definitions -->
    
        <action-mappings>
    
            <action path="/Welcome" forward="/pages/Welcome.jsp" />
    
            <action path="/ListUsers" type="strutsdemo.action.ListUsersAction">
                <forward name="success" path="/pages/ListUsers.jsp" />
    
            </action>
    
            <action path="/EditUser" type="strutsdemo.action.EditUserAction">
                <forward name="success" path="/pages/EditUser.jsp" /> 
            </action>
    
            <action  path="/SaveEditUser" 
                type="strutsdemo.action.SaveEditUserAction" 
                name="SaveEditUserForm" input="/pages/EditUser.jsp" > 
                <forward name="success" path="/ListUsers.do" />
    
                <forward name="failure" path="/pages/EditUser.jsp" />
            </action>
            
            <action path="/InsertUser" type="strutsdemo.action.InsertUserAction">
                <forward name="success" path="/pages/InsertUser.jsp" /> 
            </action>
                    
            <action path="/DeleteUser" type="strutsdemo.action.DeleteUserAction">
    
                <forward name="success"  path="/ListUsers.do"/> 
            </action>
                            
            <action  path="/SaveInsertUser" 
                type="strutsdemo.action.SaveInsertUserAction" 
                name="SaveInsertUserForm" input="/pages/InsertUser.jsp" > 
                <forward name="success" path="/ListUsers.do" />
                <forward name="failure" path="/pages/InsertUser.jsp" />
            </action>        
            
        </action-mappings>
    
    
        <!-- =================================== Message Resources Definitions -->
        <message-resources parameter="MessageResources" />
    
    
        <!-- ============================================= Validator plugin -->
        <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
            <set-property property="pathnames"
                value="/org/apache/struts/validator/validator-rules.xml,
    			/WEB-INF/validation.xml" />
    
        </plug-in>
    
    </struts-config>
    


    /WEB-INF/validation.xml

    <?xml version="1.0" encoding="ISO-8859-1" ?>
    <!DOCTYPE form-validation PUBLIC
         "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.3.0//EN"
         "http://jakarta.apache.org/commons/dtds/validator_1_3_0.dtd">
    
    <form-validation>
    
        <global>
    
            <!-- An example global constant
                <constant>
                <constant-name>postalCode</constant-name>
    
                <constant-value>^\d{5}\d*$</constant-value>
                </constant>
                end example-->
    
        </global>
    
        <formset>
    
            <!-- SaveEditUserForm -->
            <form name="SaveEditUserForm">
                <field property="idUsuario" depends="required">
                    <arg key="prompt.idUsuario" />
                </field>
                <field property="login" depends="required">
    
                    <arg key="prompt.login" />
                </field>
                <field property="nome" depends="required">
                    <arg key="prompt.nome" />
                </field>
                <field property="novaSenha" depends="required">
    
                    <arg 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">
                    <arg 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">
                    <arg key="prompt.confirmacaoNovaSenha" />
    
                    <var>
                        <var-name>mask</var-name>
                        <var-value>^[0-9a-zA-Z]*$</var-value>
                    </var>
                </field>
    
            </form>
    
            <form name="SaveInsertUserForm">
                <field property="login" depends="required">
                    <arg key="prompt.login" />
                </field>
                <field property="nome" depends="required">
    
                    <arg key="prompt.nome" />
                </field>
                <field property="senha" depends="required,mask">
                    <arg key="prompt.senha" />
                    <var>
                        <var-name>mask</var-name>
    
                        <var-value>^[0-9a-zA-Z]*$</var-value>
                    </var>
                </field>
                <field property="confirmacaoSenha" depends="required,mask">
                    <arg key="prompt.confirmacaoSenha" />
    
                    <var>
                        <var-name>mask</var-name>
                        <var-value>^[0-9a-zA-Z]*$</var-value>
                    </var>
                </field>
    
            </form>
    
        </formset>
    
    </form-validation>
    
    

    Outras fontes de pesquisa

    Ferramentas para a Struts

    Como a Struts se tornou um padrão de fato, praticamente toda IDE tem algum suporte integrado. No entanto, é recomendável familiarizar-se primeiro com a configuração manual antes de utilizar estas ferramentas, pois caso ocorra algum problema imprevisto, você será capaz de corrigir manualmente.

    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.

    Boa sorte nos seus projetos com a Struts Framework !

    Baixe os fontes deste tutorial.

    Comentários (19)

    Estou com um erro e não consigo encontrá-lo, é o seguinte. 1- Ao rodar o tomcat 4.1 e inserir a url: http://localhost:8080/cadastro/pages/listUsers.jsp Aparece o seguinte erro: javax.servlet.ServletException: Cannot create redirect URL: java.net.MalformedURLException: Cannot retrieve ActionForward named error at org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:495) at org.apache.jsp.listUsers_jsp._jspService(listUsers_jsp.java:167) at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:92) at javax.servlet.http.HttpServlet.service(HttpServlet.java:809)
    postado por Altamiro Júnior em 30/10/2006 às 23:21
    Muito Bom, bem objetivo. Parabens
    postado por Carlos Henrique Nonnemacher em 13/11/2006 às 23:21
    Olá amigos, este tuto esta muito bugado, e meu problema tambem nao teve solucao ate agora, A conexao com o pooling é dificil de ser feita e no tutorial, ele da um erro eterno de URL que nao tive solucao ate agora, acho que deveria ter o fonte do projeto zipado para analizarnos se realmente é a forma de se fazer em que esta errado. Grato. Kleber Gracia
    postado por Kleber Gracia em 27/11/2006 às 23:21
    Muito bcom esse artigo, bem simples e explicativo passo a passo... é bem dividido, faltou apenas a exibição das telas que os códigos geram !!! Parabéns
    postado por Anderson Bellini em 27/12/2006 às 23:21
    Muito bom o tuto, maravilhoso :D , mas acho que podia ter alguns comentarios no codigo indicando algumas coisas e o arquivo .zip para nos familiarizarmos melhor com o projeto . mesmo assim muito bom !!!!
    postado por Marcus Menezes em 08/02/2007 às 23:21
    Esse tuto é legal, esclarece algumas coisas, mas os arquivos não funcionam, parece que para essa aplicação rodar, exige alguns procedimentos a mais, que não estão citados no tuto, pois eu baixei os fontes, criei toda a estrutura certinho, criei o banco e as tabelas, consigo enxegar a primeira página, mas quando clico no link para exibir os usuarios, no caso a classe ListUsersAction, ele dá o seguinte erro: javax.servlet.ServletException: Name jdbc is not bound in this Context E to quebrando a cabeça pra resolveeeerrrrr....
    postado por Felipe em 28/02/2007 às 23:21
    Muito bom mesmo. Muito bem explicado. Voto para que este tuto não sai do ar. Tem ajudado muitos iniciantes como eu.
    postado por Jonas Francisco em 28/03/2007 às 23:21
    OI gostei do tutorial, mas também estou com esses erros: Olá amigos, este tuto esta muito bugado, e meu problema tambem nao teve solucao ate agora, A conexao com o pooling é dificil de ser feita e no tutorial, ele da um erro eterno de URL que nao tive solucao ate agora, acho que deveria ter o fonte do projeto zipado para analizarnos se realmente é a forma de se fazer em que esta errado. Grato. Kleber Gracia postado por Kleber Gracia em 27/11/2006 às 23:21
    postado por Helber em 14/05/2007 às 23:21
    Ótimo tutorial! Parabéns!
    postado por Cristiano Goiano em 28/06/2007 às 23:21
    Este artigo ficou muito bom, hoje temos poucos artigos de java EE, eu mesmo custo achar, e esse está tudo muito bem esplicado...
    postado por Liniker em 11/07/2007 às 23:21
    Muito bem elaborado este tutorial, estava procurando entender o struts, pois estou entrando no mundo java e estou facinado pelas facilidades, porém tem muito chão pela frente, estou iniciando a programação JSE 5 .0 e ainda chegarei no Struts. Parabéns a vocês que fazem a comunidade JEE e ao Wellington Souza pelo tutorial !!!!
    postado por wendel tadeu em 21/07/2007 às 23:21
    Tutorial para quem já tem um bom conhecimento da linguagem, peca neste quesito.
    postado por Joaquim Pereira em 10/09/2007 às 23:21
    Olá, Alguém aqui conseguiu colocar para funcionar este projeto, resolvendo todos os seus problemas listados aqui? Solicito, por favor, enviar-me resposta para o meu e-mail.
    postado por llton Barbosa em 03/10/2007 às 23:21
    Cara o tuto é legal por que demonstra a tecnologia struts, mas ao meu ver ele tem uma pequena deficiencia ... Ele deveria ter a explicação das tags (funcionalidades, onde podem ser usadas, etc ...) pois isso iria ajudar bastante os iniciantes nessa tecnologia ... Se isso for feito por favor mandar p/ o meu e-mail ...
    postado por Magrelo em 05/10/2007 às 23:21
    Olá pessoal, este tutorial está um pouco desatualizado com as versões da Struts. Este é o principal motivo dos erros, pois as classes mudaram de nome, os validators sofreram uma mudança sutil que foi o suficiente para fazer com que o javascript parasse de funcionar. Estou meio sem tempo, mas estou trabalhando para colocar tudo funcionando novamente com a ultima versao do Struts 1.x []s, W
    postado por Welington B. Souza em 24/10/2007 às 23:21
    parabens.. tutorial muito bem detalhado... ;D
    postado por 3B0L4 em 06/05/2008 às 23:21
    Eu gostei muito deste tutorial, ele me ajudou a entender alguns conceitos de struts. Os bugs que estão achando, dever em relação ao arquivo server.xml que está incompleto, impossibilitando a conexão com o banco de dados. Eu fiz o projeto com algumas alterações para que ele funcione, e ele está rodando blz. Qualquer coisa me mandem um e-mail que lhes envio o projeto zippado. Abraço e fiquem com Deus.
    postado por Annibal Lucas C. Costa e Silva em 05/06/2008 às 23:21
    Annibal Lucas C. Costa e Silva, me mande o seu arquivo zipado, preciso com urgencia
    postado por Celina em 03/07/2008 às 23:21
    Fiz e o meu rodou beleza. Para rodar tem que ter as mesmas versões do tutorial. Parabéns pelo trabalho.
    postado por Jamil Oliveira em 08/08/2008 às 23:21
    Comente!

    Observações

    Os campos em negrito são obrigatórios.

    Para evitar problemas, este espaço é moderado. Após o envio do comentário será necessário aguardar pela sua aprovação.