Apache Struts 2

Alguém usou em projetos, já está estável ?? poderiam me passar alguma informação.

SDS.
William Silva

Estamos iniciando um projeto aqui na empresa com o Struts 2.0.1 beta pois acreditamos na evolução dessa versão do framework. O projeto já havia começado com o Struts 1.2.9 e estamos migrando o que já havia sido desenvolvido para a versão 2.0.1. Até o momento só tivemos problemas na composição das telas com o Tiles (daí estamos migrando para Freemarker) e na validação dinâmica (então estamos construindo a validação dentro das actions mesmo).

Olá alexandremlima ,
Diga o que está achando do novo Struts (WebWork2.0), passe suas impressões sobre ele

  • está sentindo falta das ActionsForms e DynaForms ??
  • pretende integra-lo com o Spring ??
  • etc.
    Dei uma olhada ontem a noite em uma app exemplo e tive a impressão que ele está bem mais produtivo que os Struts 1.xx , mais ainda preciso analizar a documentação e ver os recursos possíveis.

Eu não somente tive a impressão de que agora está bem mais produtivo como senti isso ao migrar o projeto que estava em desenvolvimento aqui para o novo framework.

Não sinto falta nenhuma dos dynaforms que usava na aplicação. Agora o trabalho ficou muito melhor e mais fácil. Repetição de código praticamente não existe com o novo framework o que está tornando o código mais limpo e fácil de compreender.

Não pretendo integrá-lo com Spring porque nunca usei este framework. Aqui sempre utilizamos Actions (Struts) + Façade + Model + DAO (sem e com Hibernate). Mas com o Spring já integrado ao Struts 2 talvez eu passe a olhar mais para esse lado.

Nesta versão nova, tive dificuldades em fazer a validação apenas para alguns métodos das minhas actions e em usar o Tiles. Então acabei fazendo a validação dentro de um método específico da action (implementando uma interface do framework) e retirando o tiles para usar includes nos JSPs.

Olá alexandremlima, você poderia colocar o exemplo de uma action sua antes e depois da migração? Estão usando o que no lugar dos seus antigos DynaActions?

Atendendo ao seu pedido, vou colocar aqui um exemplo de como se transformaram as minhas Actions.

Antes gostaria de explicar que na minha aplicação, o Model e o Façade são uma única peça. Os métodos get e set funcionam como todos já sabemos e os métodos estáticos funcionam como serviços para a aplicação relativos ao assunto daquele model. Portanto, a aplicação tem a seguinte estrutura: JSP+Action -&gt Model (método estático) -&gt DAO e o Model (métodos get e set) transitando nas 3 camadas.

Meu struts-config.xml (Struts 1) estava assim anteriormente:

<struts-config>

	<form-beans>
		<form-bean name="formTabelasAtividades" type="org.apache.struts.validator.DynaValidatorForm">
			<form-property name="act" type="java.lang.String" />
			<form-property name="actGrid" type="java.lang.String" />
			<form-property name="pagRegPorPagina" type="java.lang.Long" />
			<form-property name="pagRegAtual" type="java.lang.Long" />
			<form-property name="pagRegQtdTotal" type="java.lang.Long" />
			<form-property name="gridRegistros" type="java.util.List" />
			<form-property name="gridSelecao" type="java.lang.String" />
			<form-property name="campoDescricao" type="java.lang.String" />
			<form-property name="campoTipo" type="java.lang.String" />
			<form-property name="todosTipos" type="java.util.List" />
			<form-property name="filtroDescricao" type="java.lang.String" />
			<form-property name="filtroTipo" type="java.lang.String" />
		</form-bean>
	</form-beans>
	
	<global-exceptions>
		<exception type="java.lang.Exception" 
				key="errors.detail" path="/Erro.do" />
	</global-exceptions>
	
	<global-forwards>
		<forward name="irParaLogin" path="/ActLogin.do?act=visualizar" />
	</global-forwards>
	
	<action-mappings>
		<action path="/Erro"
				type="org.apache.struts.actions.ForwardAction" parameter="erro" />

		<action path="/Login"
				type="org.apache.struts.actions.ForwardAction" parameter="login" />
				
		<action path="/ActLogin" scope="request"
				type="embasa.jsime.view.action.LoginConsultaAction" 
				name="formLogin" validate="true"
				input="/Erro.do" parameter="act">
			<forward name="concluirVisualizar" path="/Login.do" />
			<forward name="concluirProcessarPesquisar" path="/ActHome.do?act=visualizar" />
			<forward name="concluirDesconectar" path="/Login.do" />
		</action>
		
		<action path="/TabelasAtividades"
			type="org.apache.struts.actions.ForwardAction" parameter="tabelasAtividades" />
			
		<action path="/TabelasAtividadesCadastro"
			type="org.apache.struts.actions.ForwardAction" parameter="tabelasAtividadesCadastro" />
			
		<action path="/TabelasAtividadesDetalhes"
			type="org.apache.struts.actions.ForwardAction" parameter="tabelasAtividadesDetalhes" />
			
		<action path="/ActTabelasAtividades" scope="request"
			type="embasa.jsime.view.action.tabelas.TabelasAtividadesConsultaAction"
			name="formTabelasAtividades" validate="true"
			input="/Erro.do" parameter="act">
			<forward name="concluirVisualizar" path="/TabelasAtividades.do" />
			<forward name="concluirProcessarPesquisar" path="/TabelasAtividades.do" />
			<forward name="concluirProcessarDetalhes" path="/TabelasAtividadesDetalhes.do" />
		</action>
		
		<action path="/ActTabelasAtividadesCadastro" scope="request"
			type="embasa.jsime.view.action.tabelas.TabelasAtividadesCadastroAction"
			name="formTabelasAtividades" validate="true"
			input="/Erro.do" parameter="act">
			<forward name="concluirIniciarNovo" path="/TabelasAtividadesCadastro.do" />
			<forward name="concluirProcessarNovo" path="/ActTabelasAtividades.do?act=visualizar" />
			<forward name="concluirIniciarEditar" path="/TabelasAtividadesCadastro.do" />
			<forward name="concluirProcessarEditar" path="/ActTabelasAtividades.do?act=visualizar" />
			<forward name="concluirProcessarExcluir" path="/ActTabelasAtividades.do?act=visualizar" />
		</action>
	</action-mappings>
	
</struts-config>

Todos os meus DynaForms tem as propriedades pag* para realizar a paginação dos registros na tela (a nível de banco de dados). A propriedade act é para execução dinâmica de métodos nas Actions do tipo DispatchAction.
As Actions do tipo ForwardAction são para integração com o Tiles.
As demais Actions que são descendentes de DispatchAction agrupam funcionalidades semelhantes em dois grupos separados. *ConsultaAction são os métodos para visualizar a tela, processar pesquisa (filtragem) e ver detalhes de um registro. *CadastroAction são os métodos para iniciar a inclusão de um registro, processar a inclusão do registro, iniciar a edição do registro, processar a edição do registro e processar a exclusão do registro.

Meu validation.xml estava assim:

<form-validation>
	<formset>
		<form name="formTabelasAtividades">
			<field property="act" depends="required">
				<arg key="App.VariavelAct" />
			</field>
			<field property="gridSelecao" depends="validwhen">
				<arg key="App.GridSelecao" />
				<var>
					<var-name>test</var-name>
					<var-value>
						( ( ((act != "iniciarEditar") and (act != "processarExcluir")) and (act != "processarDetalhes") ) or (*this* != null) )
					</var-value>
				</var>
			</field>
			<field property="campoDescricao" depends="validwhen,maxlength">
				<arg0 key="Tabelas.Atividades.CampoDescricao" />
				<arg1 name="maxlength" key="${var:maxlength}" resource="false" />
				<var>
					<var-name>test</var-name>
					<var-value>
						( ( (act != "processarNovo") and (act != "processarEditar") ) or (*this* != null) )
					</var-value>
				</var>
				<var>
        			<var-name>maxlength</var-name>
        			<var-value>100</var-value>
        		</var>
			</field>
			<field property="campoTipo" depends="validwhen">
				<arg key="Tabelas.Atividades.CampoTipo" />
				<var>
					<var-name>test</var-name>
					<var-value>
						( ( (act != "processarNovo") and (act != "processarEditar") ) or ( (*this* != null) and (*this* != "-1") ) )
					</var-value>
				</var>
			</field>
		</form>
	</formset>
</form-validation>

Meu tiles-defs.xml estava assim:

<tiles-definitions>
	<definition name="template_geral" path="/pages/TemplateGeral.jsp">
		<put name="processando" value="/pages/Processando.jsp" />
		<put name="cabecalho" value="/pages/Cabecalho.jsp" />
		<put name="menu" value="/pages/Menu.jsp" />
		<put name="conteudo" value="" />
	</definition>
	
	<definition name="erro" extends="template_reduzido">
		<put name="conteudo"   value="/pages/Erro.jsp" />
    </definition>
    
	<definition name="login" extends="template_reduzido">
		<put name="conteudo" value="/pages/Login.jsp" />
	</definition>
	
	<definition name="tabelasAtividades" extends="template_geral">
		<put name="conteudo" value="/pages/TabelasAtividades.jsp" />
	</definition>
	<definition name="tabelasAtividadesCadastro" extends="template_geral">
		<put name="conteudo" value="/pages/TabelasAtividadesCadastro.jsp" />
	</definition>
	<definition name="tabelasAtividadesDetalhes" extends="template_geral">
		<put name="conteudo" value="/pages/TabelasAtividadesDetalhes.jsp" />
	</definition>
	
</tiles-definitions>

Agora vou começar a mostrar como estavam os JSP’s da aplicação. As páginas são sempre em grupos de 3: uma para visualizar e pesquisar registros (exibindo uma grid), uma para visualizar os detalhes de um registro, e outra para visualizar o formulário de cadastro (inclusão e edição).

TabelasAtividades.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" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<h1><bean:message key="App.TituloSistema"/></h1>
<h3><bean:message key="Tabelas.Atividades.CaminhoTela"/></h3>

<html:form action="ActTabelasAtividades.do" onsubmit="javascript: return false;">
<html:hidden property="act"/>
<html:hidden property="actGrid"/>
<table class="grid" cellpadding="0" cellspacing="0">
<tr>
	<td class="gridFiltro">
		<span class="gridCampo">
			<bean:message key="Tabelas.Atividades.CampoDescricao"/>: 
			<html:text property="filtroDescricao" size="30"/>
		</span>
		<span class="gridCampo">
			<bean:message key="Tabelas.Atividades.CampoTipo"/>: 
			<html:select property="filtroTipo">
				<html:option value="-1"> </html:option>
				<logic:notEmpty name="formTabelasAtividades" property="todosTipos">
				<html:optionsCollection property="todosTipos" label="descricao" value="id"/>
				</logic:notEmpty>
			</html:select>
		</span>
		<span class="gridCampo">
			<html:image src="images/ico_atualizar.gif" altKey="App.BotaoRecarregarTabela" onclick="javascript:processando(true);this.form.pagRegAtual.value=1;submitFormTo(this.form,'ActTabelasAtividades.do','processarPesquisar');"/>
		</span>
	</td>
</tr>
<tr>
	<td class="gridTopo">
		<html:hidden property="pagRegPorPagina" />
		<html:hidden property="pagRegAtual" />
		<html:hidden property="pagRegQtdTotal" />
		<bean:define id="regPorPagina" name="formTabelasAtividades" property="pagRegPorPagina" type="java.lang.Long"/>
		<bean:define id="regAtual" name="formTabelasAtividades" property="pagRegAtual" type="java.lang.Long"/>
		<bean:define id="regQtdTotal" name="formTabelasAtividades" property="pagRegQtdTotal" type="java.lang.Long"/>
		<logic:notEmpty name="formTabelasAtividades" property="gridRegistros">
			<c:if test="${regAtual > regPorPagina}">
				<html:image src="images/grid_primeiro.gif" altKey="App.Paginador.BotaoPrimeiro" onclick="javascript:processando(true);this.form.pagRegAtual.value=1;submitFormTo(this.form,'ActTabelasAtividades.do',this.form.actGrid.value);"/>
				 
				<html:image src="images/grid_anterior.gif" altKey="App.Paginador.BotaoAnterior" onclick="javascript:processando(true);this.form.pagRegAtual.value=pagRegAtual.value-pagRegPorPagina.value;submitFormTo(this.form,'ActTabelasAtividades.do',this.form.actGrid.value);"/>
				 
			</c:if>
			<c:out value="${regQtdTotal}"/> <bean:message key="App.Paginador.RegistrosEncontrados"/>
			<c:if test="${regAtual <= regQtdTotal-regPorPagina}">
				 
				<html:image src="images/grid_proximo.gif" altKey="App.Paginador.BotaoProximo" onclick="javascript:processando(true);this.form.pagRegAtual.value=parseInt(pagRegAtual.value)+parseInt(pagRegPorPagina.value);submitFormTo(this.form,'ActTabelasAtividades.do',this.form.actGrid.value);"/>
				 
				<c:if test="${regQtdTotal%regPorPagina != 0}">
				<html:image src="images/grid_ultimo.gif" altKey="App.Paginador.BotaoUltimo" onclick="javascript:processando(true);this.form.pagRegAtual.value=pagRegQtdTotal.value-(pagRegQtdTotal.value%pagRegPorPagina.value)+1;submitFormTo(this.form,'ActTabelasAtividades.do',this.form.actGrid.value);"/>
				</c:if>
				<c:if test="${regQtdTotal%regPorPagina == 0}">
				<html:image src="images/grid_ultimo.gif" altKey="App.Paginador.BotaoUltimo" onclick="javascript:processando(true);this.form.pagRegAtual.value=pagRegQtdTotal.value-(pagRegPorPagina.value)+1;submitFormTo(this.form,'ActTabelasAtividades.do',this.form.actGrid.value);"/>
				</c:if>
			</c:if>
		</logic:notEmpty>
	</td>
</tr>
<tr>
	<td>
		<table class="gridConteudo">
		<tr>
			<th width="20"> </th>
			<th><bean:message key="Tabelas.Atividades.CampoDescricao"/></th>
			<th width="20%"><bean:message key="Tabelas.Atividades.CampoTipo"/></th>
		</tr>
		<logic:notEmpty name="formTabelasAtividades" property="gridRegistros">
		<logic:iterate id="reg" name="formTabelasAtividades" property="gridRegistros" indexId="n">
		<tr class="linha<%=(n.intValue()%2==0)?"1":"2"%>"&gt
			<bean:define id="idReg" name="reg" property="id" type="java.lang.Long"/>
			<td><html:radio property="gridSelecao" value="<%=idReg.toString()%>"/></td>
			<td><bean:write name="reg" property="descricao"/></td>
			<td><bean:write name="reg" property="tipo.descricao"/></td>
		</tr>
		</logic:iterate>
		</logic:notEmpty>
		<logic:empty name="formTabelasAtividades" property="gridRegistros">
		<tr class="linha1">
			<td colspan="3" align="center"><bean:message key="App.SemRegistros"/></td>
		</tr>
		</logic:empty>
		</table>
	</td>
</tr>
<tr>
	<td class="gridRodape">
		<html:image src="images/ico_novo.gif" altKey="App.BotaoNovo" onclick="javascript:processando(true);submitFormTo(this.form,'ActTabelasAtividadesCadastro.do','iniciarNovo');"/>
		<logic:notEmpty name="formTabelasAtividades" property="gridRegistros">
		 
		<html:image src="images/ico_alterar.gif" altKey="App.BotaoAlterar" onclick="javascript:processando(true);submitFormTo(this.form,'ActTabelasAtividadesCadastro.do','iniciarEditar');"/>
		 
		<html:image src="images/ico_excluir.gif" altKey="App.BotaoExcluir" onclick="javascript:processando(true);submitFormTo(this.form,'ActTabelasAtividadesCadastro.do','processarExcluir');"/>
		 
		<html:image src="images/ico_detalhes.gif" altKey="App.BotaoDetalhes" onclick="javascript:processando(true);submitFormTo(this.form,'ActTabelasAtividades.do','processarDetalhes');"/>
		</logic:notEmpty>
	</td>
</tr>
</table>
</html:form>

TabelasAtividadesCadastro.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" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<h1><bean:message key="App.TituloSistema"/></h1>
<h3><bean:message key="Tabelas.Atividades.CaminhoTela"/></h3>

<html:form action="ActTabelasAtividadesCadastro.do" onsubmit="javascript: return false;">
<logic:equal name="formTabelasAtividades" property="act" value="iniciarNovo">
	<html:hidden property="act" value="processarNovo"/>
</logic:equal>
<logic:equal name="formTabelasAtividades" property="act" value="iniciarEditar">
	<html:hidden property="act" value="processarEditar"/>
</logic:equal>
<html:hidden property="gridSelecao"/>
<table class="formulario" cellpadding="0" cellspacing="0">
<tr>
	<td class="formularioTopo">
		<bean:message key="Tabelas.Atividades.CadastroTexto"/>
	</td>
</tr>
<tr>
	<td class="formularioConteudo">
		<span class="formularioCampo">
			&lt;bean:message key="Tabelas.Atividades.CampoDescricao"/&gt;: <br />
			&lt;html:text property="campoDescricao" size="80"/&gt;
		&lt;/span&gt;
		&lt;span class="formularioCampo"&gt;
			&lt;bean:message key="Tabelas.Atividades.CampoTipo"/&gt;: <br />
			&lt;html:select property="campoTipo"&gt;
				&lt;html:option value="-1"&gt;&nbsp;&lt;/html:option&gt;
				&lt;html:optionsCollection property="todosTipos" label="descricao" value="id"/&gt;
			&lt;/html:select&gt;
		&lt;/span&gt;
	&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td class="formularioRodape"&gt;
		&lt;html:image src="images/ico_salvar.gif" altKey="App.BotaoSalvar" onclick="javascript:processando(true);submitFormTo(this.form,'ActTabelasAtividadesCadastro.do',this.form.act.value);"/&gt;
		&nbsp;
		&lt;html:image src="images/ico_cancelar.gif" altKey="App.BotaoCancelar" onclick="javascript:processando(true);this.form.reset();submitFormTo(this.form,'ActTabelasAtividades.do','visualizar');"/&gt;
	&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/html:form&gt;

TabelasAtividadesDetalhes.jsp

&lt;%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %&gt;
&lt;%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %&gt;
&lt;%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %&gt;
&lt;%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %&gt;

&lt;h1&gt;&lt;bean:message key="App.TituloSistema"/&gt;&lt;/h1&gt;
&lt;h3&gt;&lt;bean:message key="Tabelas.Atividades.CaminhoTela"/&gt;&lt;/h3&gt;

&lt;html:form action="ActTabelasAtividades.do" onsubmit="javascript: return false;"&gt;
&lt;html:hidden property="act"/&gt;
&lt;html:hidden property="gridSelecao"/&gt;
&lt;table class="registro" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
	&lt;td class="registroTopo"&gt;
		&lt;bean:message key="Tabelas.Atividades.CadastroTexto"/&gt;
	&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td class="registroConteudo"&gt;
		<p>
			&lt;span class="registroLabel"&gt;
			&lt;bean:message key="Tabelas.Atividades.CampoDescricao"/&gt;:
			&lt;/span&gt;
			<br />
			&lt;span class="registroDado"&gt;
			&lt;bean:write name="formTabelasAtividades" property="campoDescricao"/&gt;
			&lt;/span&gt;
		</p>
		<p>
			&lt;span class="registroLabel"&gt;
			&lt;bean:message key="Tabelas.Atividades.CampoTipo"/&gt;:
			&lt;/span&gt;
			<br />
			&lt;span class="registroDado"&gt;
			&lt;logic:iterate id="tipo" name="formTabelasAtividades" property="todosTipos"&gt;
				&lt;bean:define id="regTipoId" name="formTabelasAtividades" property="campoTipo"/&gt;
				&lt;c:if test="${regTipoId == tipo.id}"&gt;
					&lt;bean:write name="tipo" property="descricao"/&gt;
				&lt;/c:if&gt;
			&lt;/logic:iterate&gt;
			&lt;/span&gt;
		</p>
	&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td class="registroRodape"&gt;
		&lt;html:image src="images/ico_voltar.gif" altKey="App.BotaoRetornar" onclick="javascript:processando(true);submitFormTo(this.form,'ActTabelasAtividades.do','visualizar');"/&gt;
	&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/html:form&gt;

Como citei anteriormente, as minhas Actions combinam dois grupos de funcionalidades. Para este grupos eu tenho duas classes genéricas de Actions. E estas duas ainda extendem de uma mais genérica ainda.

GenericAction.java

package embasa.jsime.view.action;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts.actions.DispatchAction;

import embasa.jsime.model.Usuario;
import embasa.jsime.view.util.IAction;
import embasa.jsime.view.util.RecursosSessao;

/**
 * Classe pai de todas as Actions do sistema, possui todos os métodos úteis para
 * as Actions trabalharem com segurança e integridade.
 * 
 * @author Alexandre Mendonça Lima
 * 
 */
public class GenericAction extends DispatchAction implements IAction {

	protected Usuario __usuarioAutenticado;

	protected Long __qtdRegistrosEncontrados;

	protected static String FWD_IR_PARA_LOGIN = "irParaLogin";

	/**
	 * Verifica se o usuário está autenticado na sessão.
	 * 
	 * @param request
	 *            O request vindo da tela, para acessar a sessão do visitante.
	 * @return <i>true</i> se o usuário está autenticado, <i>false</i> caso
	 *         contrário.
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	protected boolean verificarUsuarioAutenticado(HttpServletRequest request)
			throws Exception {
		__usuarioAutenticado = (Usuario) request.getSession().getAttribute(
				RecursosSessao.USUARIO_LOGADO);
		if (__usuarioAutenticado == null) {
			return false;
		} else {
			return true;
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see embasa.jsime.view.util.IAction#setQtdRegistrosEncontrados(java.lang.Long)
	 */
	public void setQtdRegistrosEncontrados(Long qtd) {
		__qtdRegistrosEncontrados = qtd;
	}
}

GenericConsultaAction.java

package embasa.jsime.view.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

/**
 * Classe que apresenta as ações básicas para visualização de uma tela, para uma
 * tela de busca com grid e filtro e para uma tela de visualização de detalhes
 * de um registro (tela ou impressora).
 * 
 * @author Alexandre Mendonça Lima
 * 
 */
public abstract class GenericConsultaAction extends GenericAction {

	public static String FWD_VISUALIZAR = &quot;concluirVisualizar&quot;;

	public static String FWD_PROCESSAR_PESQUISAR = &quot;concluirProcessarPesquisar&quot;;

	public static String FWD_PROCESSAR_DETALHES = &quot;concluirProcessarDetalhes&quot;;

	public static String FWD_PROCESSAR_IMPRESSAO = &quot;concluirProcessarImpressao&quot;;

	/**
	 * Ação executada para visualizar a tela de busca com filtro.
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	public ActionForward visualizar(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		String direcao = interceptarVisualizar(mapping, form, request, response);
		if (direcao != null && !direcao.equals(&quot;&quot;))
			return mapping.findForward(direcao);
		else
			return mapping.findForward(FWD_VISUALIZAR);
	}

	/**
	 * Este método intercepta a execução de visualizar(), executa tarefas
	 * específicas e retorna a execução de visualizar().
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return O direcionamento que se deseja dar depois da execução. Se for
	 *         nulo ou branco, usará o direcionamento default.
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	protected abstract String interceptarVisualizar(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception;

	/**
	 * Ação executada para processar a pesquisa de registros a partir de um
	 * filtro.
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	public ActionForward processarPesquisar(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String direcao = interceptarProcessarPesquisar(mapping, form, request,
				response);
		if (direcao != null && !direcao.equals(&quot;&quot;))
			return mapping.findForward(direcao);
		else
			return mapping.findForward(FWD_PROCESSAR_PESQUISAR);
	}

	/**
	 * Este método intercepta a execução de processarPesquisar(), executa
	 * tarefas específicas e retorna a execução de processarPesquisar().
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return O direcionamento que se deseja dar depois da execução. Se for
	 *         nulo ou branco, usará o direcionamento default.
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	protected abstract String interceptarProcessarPesquisar(
			ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception;

	/**
	 * Ação executada para processar a visualização de detalhes de um registro
	 * específico.
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	public ActionForward processarDetalhes(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String direcao = interceptarProcessarDetalhes(mapping, form, request,
				response);
		if (direcao != null && !direcao.equals(&quot;&quot;))
			return mapping.findForward(direcao);
		else
			return mapping.findForward(FWD_PROCESSAR_DETALHES);
	}

	/**
	 * Este método intercepta a execução de processarDetalhes(), executa tarefas
	 * específicas e retorna a execução de processarDetalhes().
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return O direcionamento que se deseja dar depois da execução. Se for
	 *         nulo ou branco, usará o direcionamento default.
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	protected abstract String interceptarProcessarDetalhes(
			ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception;

	/**
	 * Ação executada para processar a impressão de um relatório sobre o
	 * registro específico.
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	public ActionForward processarImpressao(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String direcao = interceptarProcessarImpressao(mapping, form, request,
				response);
		if (direcao != null && !direcao.equals(&quot;&quot;))
			return mapping.findForward(direcao);
		else
			return mapping.findForward(FWD_PROCESSAR_IMPRESSAO);
	}

	/**
	 * Este método intercepta a execução de processarImpressao(), executa
	 * tarefas específicas e retorna a execução de processarImpressao().
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return O direcionamento que se deseja dar depois da execução. Se for
	 *         nulo ou branco, usará o direcionamento default.
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	protected abstract String interceptarProcessarImpressao(
			ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception;
}

TabelasAtividadesConsultaAction.java

package embasa.jsime.view.action.tabelas;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;

import embasa.jsime.model.Atividade;
import embasa.jsime.util.RecursosMensagens;
import embasa.jsime.util.RecursosSetup;
import embasa.jsime.view.action.GenericConsultaAction;

/**
 * @author Alexandre Mendonça Lima
 * 
 */
public class TabelasAtividadesConsultaAction extends GenericConsultaAction {

	/*
	 * (non-Javadoc)
	 * 
	 * @see embasa.jsime.mvc.action.GenericConsultaAction#interceptarVisualizar(org.apache.struts.action.ActionMapping,
	 *      org.apache.struts.action.ActionForm,
	 *      javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse)
	 */
	protected String interceptarVisualizar(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		if (!verificarUsuarioAutenticado(request)) {
			return FWD_IR_PARA_LOGIN;
		}
		Long pagRegPorPagina = RecursosSetup.getPagRegPorPagina();
		DynaActionForm dadosForm = (DynaActionForm) form;
		String act = dadosForm.getString(&quot;act&quot;);

		Long pagRegAtual = (Long) dadosForm.get(&quot;pagRegAtual&quot;);
		if (pagRegAtual == null || pagRegAtual.longValue() &lt= 0) {
			pagRegAtual = new Long(1);
		}

		// inicializando os campos do formulário com os valores default
		dadosForm.initialize(mapping);

		Atividade.registrarObservadorQtdRegistrosEncontrados(this);
		List gridRegistros = Atividade.obterTodos(__usuarioAutenticado,
				pagRegAtual, pagRegPorPagina);

		dadosForm.set(&quot;gridRegistros&quot;, gridRegistros);

		List todosTipos = Atividade.Tipo.obterTodos(__usuarioAutenticado);
		dadosForm.set(&quot;todosTipos&quot;, todosTipos);

		dadosForm.set(&quot;pagRegPorPagina&quot;, pagRegPorPagina);
		dadosForm.set(&quot;pagRegAtual&quot;, pagRegAtual);
		dadosForm.set(&quot;pagRegQtdTotal&quot;, __qtdRegistrosEncontrados);
		dadosForm.set(&quot;actGrid&quot;, act);
		dadosForm.set(&quot;act&quot;, act);
		return null; // redireciona para o default
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see embasa.jsime.mvc.action.GenericConsultaAction#interceptarProcessarPesquisar(org.apache.struts.action.ActionMapping,
	 *      org.apache.struts.action.ActionForm,
	 *      javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse)
	 */
	protected String interceptarProcessarPesquisar(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		if (!verificarUsuarioAutenticado(request)) {
			return FWD_IR_PARA_LOGIN;
		}
		Long pagRegPorPagina = RecursosSetup.getPagRegPorPagina();
		DynaActionForm dadosForm = (DynaActionForm) form;
		String act = dadosForm.getString(&quot;act&quot;);

		String filtroDescricao = dadosForm.getString(&quot;filtroDescricao&quot;);
		String filtroTipo = dadosForm.getString(&quot;filtroTipo&quot;);

		Long pagRegAtual = (Long) dadosForm.get(&quot;pagRegAtual&quot;);
		if (pagRegAtual == null || pagRegAtual.longValue() &lt= 0) {
			pagRegAtual = new Long(1);
		}

		// inicializando os campos do formulário com os valores default
		dadosForm.initialize(mapping);

		List gridRegistros = null;
		Atividade.registrarObservadorQtdRegistrosEncontrados(this);
		if ((filtroDescricao != null && !filtroDescricao.equals(&quot;&quot;))
				|| (filtroTipo != null && !filtroTipo.equals(&quot;-1&quot;))) {
			gridRegistros = Atividade.obterPorDescricaoOuTipoId(
					filtroDescricao, filtroTipo, __usuarioAutenticado,
					pagRegAtual, pagRegPorPagina);
		} else {
			gridRegistros = Atividade.obterTodos(__usuarioAutenticado,
					pagRegAtual, pagRegPorPagina);
		}
		dadosForm.set(&quot;gridRegistros&quot;, gridRegistros);

		List todosTipos = Atividade.Tipo.obterTodos(__usuarioAutenticado);
		dadosForm.set(&quot;todosTipos&quot;, todosTipos);

		dadosForm.set(&quot;filtroDescricao&quot;, filtroDescricao);
		dadosForm.set(&quot;filtroTipo&quot;, filtroTipo);

		dadosForm.set(&quot;pagRegPorPagina&quot;, pagRegPorPagina);
		dadosForm.set(&quot;pagRegAtual&quot;, pagRegAtual);
		dadosForm.set(&quot;pagRegQtdTotal&quot;, __qtdRegistrosEncontrados);
		dadosForm.set(&quot;actGrid&quot;, act);
		dadosForm.set(&quot;act&quot;, act);
		return null; // redireciona para o default
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see embasa.jsime.mvc.action.GenericConsultaAction#interceptarProcessarDetalhes(org.apache.struts.action.ActionMapping,
	 *      org.apache.struts.action.ActionForm,
	 *      javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse)
	 */
	protected String interceptarProcessarDetalhes(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		if (!verificarUsuarioAutenticado(request)) {
			return FWD_IR_PARA_LOGIN;
		}
		DynaActionForm dadosForm = (DynaActionForm) form;
		String act = dadosForm.getString(&quot;act&quot;);
		String regId = dadosForm.getString(&quot;gridSelecao&quot;);
		// inicializando os campos do formulário com os valores default
		dadosForm.initialize(mapping);

		Atividade reg = Atividade.obterPorId(new Long(regId),
				__usuarioAutenticado);
		if (reg != null) {
			dadosForm.set(&quot;campoDescricao&quot;, reg.getDescricao());
			dadosForm.set(&quot;campoTipo&quot;, reg.getTipo().getId());
		}

		dadosForm.set(&quot;gridSelecao&quot;, regId);

		List todosTipos = Atividade.Tipo.obterTodos(__usuarioAutenticado);
		dadosForm.set(&quot;todosTipos&quot;, todosTipos);

		dadosForm.set(&quot;act&quot;, act);
		return null; // redireciona para o default
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see embasa.jsime.mvc.action.GenericConsultaAction#interceptarProcessarImpressao(org.apache.struts.action.ActionMapping,
	 *      org.apache.struts.action.ActionForm,
	 *      javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse)
	 */
	protected String interceptarProcessarImpressao(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		// Este método não é utilizado na tela correspondente a esta action.
		throw new Exception(RecursosMensagens
				.getMensagem(&quot;Exception.MetodoNaoImplementado&quot;));
	}

}

GenericCadastroAction.java

package embasa.jsime.view.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

/**
 * Classe que apresenta as ações básicas para um cadastro com inclusão, edição e
 * exclusão.
 * 
 * @author Alexandre Mendonça Lima
 * 
 */
public abstract class GenericCadastroAction extends GenericAction {

	public static String FWD_CONCLUIR_INICIAR_NOVO = &quot;concluirIniciarNovo&quot;;

	public static String FWD_CONCLUIR_PROCESSAR_NOVO = &quot;concluirProcessarNovo&quot;;

	public static String FWD_CONCLUIR_INICIAR_EDITAR = &quot;concluirIniciarEditar&quot;;

	public static String FWD_CONCLUIR_PROCESSAR_EDITAR = &quot;concluirProcessarEditar&quot;;

	public static String FWD_CONCLUIR_PROCESSAR_EXCLUIR = &quot;concluirProcessarExcluir&quot;;

	/**
	 * Ação executada ao iniciar o procedimento de inclusão de um registro.
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	public ActionForward iniciarNovo(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		String direcao = interceptarIniciarNovo(mapping, form, request,
				response);
		if (direcao != null && !direcao.equals(&quot;&quot;))
			return mapping.findForward(direcao);
		else
			return mapping.findForward(FWD_CONCLUIR_INICIAR_NOVO);
	}

	/**
	 * Este método intercepta a execução de iniciarNovo(), executa tarefas
	 * específicas e retorna a execução de iniciarNovo().
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return O direcionamento que se deseja dar depois da execução. Se for
	 *         nulo ou branco, usará o direcionamento default.
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	protected abstract String interceptarIniciarNovo(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception;

	/**
	 * Ação executada para processar a inclusão de um registro.
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	public ActionForward processarNovo(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		String direcao = interceptarProcessarNovo(mapping, form, request,
				response);
		if (direcao != null && !direcao.equals(&quot;&quot;))
			return mapping.findForward(direcao);
		else
			return mapping.findForward(FWD_CONCLUIR_PROCESSAR_NOVO);
	}

	/**
	 * Este método intercepta a execução de processarNovo(), executa tarefas
	 * específicas e retorna a execução de processarNovo().
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return O direcionamento que se deseja dar depois da execução. Se for
	 *         nulo ou branco, usará o direcionamento default.
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	protected abstract String interceptarProcessarNovo(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception;

	/**
	 * Ação executada ao iniciar o procedimento de edição de um registro.
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	public ActionForward iniciarEditar(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		String direcao = interceptarIniciarEditar(mapping, form, request,
				response);
		if (direcao != null && !direcao.equals(&quot;&quot;))
			return mapping.findForward(direcao);
		else
			return mapping.findForward(FWD_CONCLUIR_INICIAR_EDITAR);
	}

	/**
	 * Este método intercepta a execução de iniciarEditar(), executa tarefas
	 * específicas e retorna a execução de iniciarEditar().
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return O direcionamento que se deseja dar depois da execução. Se for
	 *         nulo ou branco, usará o direcionamento default.
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	protected abstract String interceptarIniciarEditar(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception;

	/**
	 * Ação executada para processar a edição de um registro.
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	public ActionForward processarEditar(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String direcao = interceptarProcessarEditar(mapping, form, request,
				response);
		if (direcao != null && !direcao.equals(&quot;&quot;))
			return mapping.findForward(direcao);
		else
			return mapping.findForward(FWD_CONCLUIR_PROCESSAR_EDITAR);
	}

	/**
	 * Este método intercepta a execução de processarEditar(), executa tarefas
	 * específicas e retorna a execução de processarEditar().
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return O direcionamento que se deseja dar depois da execução. Se for
	 *         nulo ou branco, usará o direcionamento default.
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	protected abstract String interceptarProcessarEditar(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception;

	/**
	 * Ação executada para processar a exclusão de um registro.
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	public ActionForward processarExcluir(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String direcao = interceptarProcessarExcluir(mapping, form, request,
				response);
		if (direcao != null && !direcao.equals(&quot;&quot;))
			return mapping.findForward(direcao);
		else
			return mapping.findForward(FWD_CONCLUIR_PROCESSAR_EXCLUIR);
	}

	/**
	 * Este método intercepta a execução de processarExcluir(), executa tarefas
	 * específicas e retorna a execução de processarExcluir().
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return O direcionamento que se deseja dar depois da execução. Se for
	 *         nulo ou branco, usará o direcionamento default.
	 * @throws AplicacaoException
	 * @throws AmbienteException
	 */
	protected abstract String interceptarProcessarExcluir(
			ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception;

}

TabelasAtividadesCadastroAction.java

package embasa.jsime.view.action.tabelas;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;

import embasa.jsime.model.Atividade;
import embasa.jsime.view.action.GenericCadastroAction;

/**
 * @author Alexandre Mendonça Lima
 * 
 */
public class TabelasAtividadesCadastroAction extends GenericCadastroAction {

	/*
	 * (non-Javadoc)
	 * 
	 * @see embasa.jsime.mvc.action.GenericCadastroAction#interceptarIniciarNovo(org.apache.struts.action.ActionMapping,
	 *      org.apache.struts.action.ActionForm,
	 *      javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse)
	 */
	protected String interceptarIniciarNovo(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		if (!verificarUsuarioAutenticado(request)) {
			return FWD_IR_PARA_LOGIN;
		}
		DynaActionForm dadosForm = (DynaActionForm) form;
		String act = dadosForm.getString(&quot;act&quot;);
		// inicializando os campos do formulário com os valores default
		dadosForm.initialize(mapping);
		List todosTipos = Atividade.Tipo.obterTodos(__usuarioAutenticado);
		dadosForm.set(&quot;todosTipos&quot;, todosTipos);
		dadosForm.set(&quot;act&quot;, act);
		return null; // redireciona para o default
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see embasa.jsime.mvc.action.GenericCadastroAction#interceptarProcessarNovo(org.apache.struts.action.ActionMapping,
	 *      org.apache.struts.action.ActionForm,
	 *      javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse)
	 */
	protected String interceptarProcessarNovo(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		if (!verificarUsuarioAutenticado(request)) {
			return FWD_IR_PARA_LOGIN;
		}
		DynaActionForm dadosForm = (DynaActionForm) form;
		String act = dadosForm.getString(&quot;act&quot;);
		String campoDescricao = dadosForm.getString(&quot;campoDescricao&quot;);
		String campoTipo = dadosForm.getString(&quot;campoTipo&quot;);
		Atividade.inserirNovo(campoDescricao, campoTipo, __usuarioAutenticado);
		// inicializando os campos do formulário com os valores default
		dadosForm.initialize(mapping);
		dadosForm.set(&quot;act&quot;, act);
		return null; // redireciona para o default
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see embasa.jsime.mvc.action.GenericCadastroAction#interceptarIniciarEditar(org.apache.struts.action.ActionMapping,
	 *      org.apache.struts.action.ActionForm,
	 *      javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse)
	 */
	protected String interceptarIniciarEditar(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		if (!verificarUsuarioAutenticado(request)) {
			return FWD_IR_PARA_LOGIN;
		}
		DynaActionForm dadosForm = (DynaActionForm) form;
		String act = dadosForm.getString(&quot;act&quot;);
		String regId = dadosForm.getString(&quot;gridSelecao&quot;);
		// inicializando os campos do formulário com os valores default
		dadosForm.initialize(mapping);

		Atividade reg = Atividade.obterPorId(new Long(regId),
				__usuarioAutenticado);
		if (reg != null) {
			dadosForm.set(&quot;campoDescricao&quot;, reg.getDescricao());
			dadosForm.set(&quot;campoTipo&quot;, reg.getTipo().getId());
		}

		dadosForm.set(&quot;gridSelecao&quot;, regId);

		List todosTipos = Atividade.Tipo.obterTodos(__usuarioAutenticado);
		dadosForm.set(&quot;todosTipos&quot;, todosTipos);
		dadosForm.set(&quot;act&quot;, act);
		return null; // redireciona para o default
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see embasa.jsime.mvc.action.GenericCadastroAction#interceptarProcessarEditar(org.apache.struts.action.ActionMapping,
	 *      org.apache.struts.action.ActionForm,
	 *      javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse)
	 */
	protected String interceptarProcessarEditar(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		if (!verificarUsuarioAutenticado(request)) {
			return FWD_IR_PARA_LOGIN;
		}
		DynaActionForm dadosForm = (DynaActionForm) form;
		String act = dadosForm.getString(&quot;act&quot;);
		String regId = dadosForm.getString(&quot;gridSelecao&quot;);
		String campoDescricao = dadosForm.getString(&quot;campoDescricao&quot;);
		String campoTipo = dadosForm.getString(&quot;campoTipo&quot;);
		Atividade.atualizarPorId(new Long(regId), campoDescricao, campoTipo,
				__usuarioAutenticado);
		// inicializando os campos do formulário com os valores default
		dadosForm.initialize(mapping);
		dadosForm.set(&quot;act&quot;, act);
		return null; // redireciona para o default
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see embasa.jsime.mvc.action.GenericCadastroAction#interceptarProcessarExcluir(org.apache.struts.action.ActionMapping,
	 *      org.apache.struts.action.ActionForm,
	 *      javax.servlet.http.HttpServletRequest,
	 *      javax.servlet.http.HttpServletResponse)
	 */
	protected String interceptarProcessarExcluir(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		if (!verificarUsuarioAutenticado(request)) {
			return FWD_IR_PARA_LOGIN;
		}
		DynaActionForm dadosForm = (DynaActionForm) form;
		String act = dadosForm.getString(&quot;act&quot;);
		String regId = dadosForm.getString(&quot;gridSelecao&quot;);
		Atividade.excluirPorId(new Long(regId), __usuarioAutenticado);
		// inicializando os campos do formulário com os valores default
		dadosForm.initialize(mapping);
		dadosForm.set(&quot;act&quot;, act);
		return null; // redireciona para o default
	}

}

Este é um exemplo para ter uma idéia de como estava o meu código com o Struts 1.
No próximo post eu vou colocar como ficou o código como Struts 2.

Convertendo para o Struts 2, a aplicação manteve a mesma estrutura: JSP+Action -&gt Model (método estático) -&gt DAO e o Model (métodos get e set) transitando nas 3 camadas. Esta estrutura já havia sido pensada assim para poder trocar o framework no nível JSP+Action no futuro.

Reaproveitei todos os Models e DAO’s, sem mexer em nenhuma linha de código destes. Reaproveitei também os JSP’s mas estes tiveram que ser reajustados para as novas tags do Struts 2.

Meu struts.xml agora ficou assim:

&lt;struts&gt;

	&lt;package name="jsime-default" extends="struts-default" abstract="true"&gt;
	
		&lt;interceptors&gt;
		
			&lt;interceptor name="autenticacao" class="embasa.jsime.view.interceptor.AutenticacaoInterceptor"/&gt;
			
			&lt;interceptor-stack name="stackReduzido"&gt;
				&lt;interceptor-ref name="defaultStack"/&gt;
			&lt;/interceptor-stack&gt;
			
			&lt;interceptor-stack name="stackGeral"&gt;
                &lt;interceptor-ref name="stackReduzido"/&gt;
                &lt;interceptor-ref name="autenticacao"/&gt;
            &lt;/interceptor-stack&gt;
			
		&lt;/interceptors&gt;
		
		&lt;default-interceptor-ref name="stackGeral"/&gt;
		
		&lt;global-results&gt;
			&lt;result name="login" type="redirect-action"&gt;Login_visualizar&lt;/result&gt;
			&lt;result name="error"&gt;/pages/Erro.jsp&lt;/result&gt;
			&lt;result name="input"&gt;/pages/Erro.jsp&lt;/result&gt;
			&lt;result name="rootException"&gt;/pages/Erro.jsp&lt;/result&gt;
		&lt;/global-results&gt;
		
		&lt;global-exception-mappings&gt;
			&lt;exception-mapping exception="java.lang.Exception" result="rootException"/&gt;
		&lt;/global-exception-mappings&gt;

	&lt;/package&gt;
	
	&lt;package name="tabelas" extends="jsime-default"&gt;

		&lt;action name="Atividade_*" class="embasa.jsime.view.action.tabelas.AtividadeAction" method="{1}"&gt;
			&lt;result name="visualizar"&gt;/pages/TabelasAtividades.jsp&lt;/result&gt;
			&lt;result name="detalhes"&gt;/pages/TabelasAtividadesDetalhes.jsp&lt;/result&gt;
			&lt;result name="cadastro"&gt;/pages/TabelasAtividadesCadastro.jsp&lt;/result&gt;
		&lt;/action&gt;
		
	&lt;/package&gt;
	
&lt;/struts&gt;

Como falei antes, não consegui fazer o Tiles funcionar no Struts 2 apesar do que está escrito na documentação. Pode ser um bug que seja resolvido na próxima versão beta. Então resolvi voltar a fazer includes nos JSP’s com a tag <s:include/> do novo framework.
Consegui também fazer o código de paginação ficar isolado e genérico num JSP separado e funcionar em todas as telas sem precisar reescrever nada.

Paginacao.jsp

&lt;%@ taglib uri="/struts-tags" prefix="s" %&gt;
&lt;s:hidden name="pagRegPorPagina" /&gt;
&lt;s:hidden name="pagRegAtual" /&gt;
&lt;s:hidden name="pagRegQtdTotal" /&gt;
&lt;s:if test="%{gridRegistros != null && !gridRegistros.isEmpty()}"&gt;
	&nbsp;
	&lt;s:if test="%{pagRegAtual &gt; pagRegPorPagina}"&gt;
		&lt;s:url id="icoPrimeiro" value="/pages/images/grid_primeiro.gif"/&gt;
		&lt;s:submit type="image"
			src="%{icoPrimeiro}"
			label="%{getText('App.Paginador.BotaoPrimeiro')}" 
			onclick="javascript:processando(true);this.form.pagRegAtual.value=1;submitFormTo(this.form,'%{actionName}');"/&gt;
		&nbsp;
		&lt;s:url id="icoAnterior" value="/pages/images/grid_anterior.gif"/&gt;
		&lt;s:submit type="image"
			src="%{icoAnterior}"
			label="%{getText('App.Paginador.BotaoAnterior')}" 
			onclick="javascript:processando(true);this.form.pagRegAtual.value=pagRegAtual.value-pagRegPorPagina.value;submitFormTo(this.form,'%{actionName}');"/&gt;
		&nbsp;
	&lt;/s:if&gt;
	&lt;s:property value="pagRegQtdTotal"/&gt; &lt;s:text name="App.Paginador.RegistrosEncontrados"/&gt;
	&lt;s:if test="%{pagRegAtual &lt;= pagRegQtdTotal-pagRegPorPagina}"&gt;
		&nbsp;
		&lt;s:url id="icoProximo" value="/pages/images/grid_proximo.gif"/&gt;
		&lt;s:submit type="image"
			src="%{icoProximo}"
			label="%{getText('App.Paginador.BotaoProximo')}" 
			onclick="javascript:processando(true);this.form.pagRegAtual.value=parseInt(pagRegAtual.value)+parseInt(pagRegPorPagina.value);submitFormTo(this.form,'%{actionName}');"/&gt;
		&nbsp;
		&lt;s:url id="icoUltimo" value="/pages/images/grid_ultimo.gif"/&gt;
		&lt;s:if test="%{regQtdTotal%regPorPagina == 0}"&gt;
			&lt;s:submit type="image"
				src="%{icoUltimo}"
				label="%{getText('App.Paginador.BotaoUltimo')}" 
				onclick="javascript:processando(true);this.form.pagRegAtual.value=pagRegQtdTotal.value-(pagRegPorPagina.value)+1;submitFormTo(this.form,'%{actionName}');"/&gt;
		&lt;/s:if&gt;
		&lt;s:else&gt;
			&lt;s:submit type="image"
				src="%{icoUltimo}"
				label="%{getText('App.Paginador.BotaoUltimo')}" 
				onclick="javascript:processando(true);this.form.pagRegAtual.value=pagRegQtdTotal.value-(pagRegQtdTotal.value%pagRegPorPagina.value)+1;submitFormTo(this.form,'%{actionName}');"/&gt;
		&lt;/s:else&gt;
	&lt;/s:if&gt;
&lt;/s:if&gt;
&lt;s:else&gt;
&nbsp;
&lt;/s:else&gt;

TabelasAtividades.jsp

&lt;%@ taglib uri="/struts-tags" prefix="s" %&gt;

&lt;s:include value="TemplateGeralHeader.jsp"/&gt;

&lt;h3&gt;&lt;s:text name="Tabelas.Atividades.CaminhoTela"/&gt;&lt;/h3&gt;

&lt;s:form onsubmit="javascript: return false;"&gt;
&lt;table class="grid" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
	&lt;td class="gridFiltro"&gt;
		&lt;span class="gridCampo"&gt;
			&lt;s:text name="Tabelas.Atividades.CampoDescricao"/&gt;: 
			&lt;s:textfield name="filtroDescricao" size="30"/&gt;
		&lt;/span&gt;
		&lt;span class="gridCampo"&gt;
			&lt;s:text name="Tabelas.Atividades.CampoTipo"/&gt;: 
			&lt;s:select name="filtroTipo" 
				list="todosTipos" 
				listKey="id" listValue="descricao" 
				headerKey="-1" headerValue=" "/&gt;
		&lt;/span&gt;
		&lt;span class="gridCampo"&gt;
			&lt;s:url id="icoAtualizar" value="/pages/images/ico_atualizar.gif"/&gt;
			&lt;s:submit type="image"
				src="%{icoAtualizar}"
				label="%{getText('App.BotaoRecarregarTabela')}" 
				onclick="javascript:processando(true);submitFormTo(this.form,'%{actionName}');"/&gt;
		&lt;/span&gt;
	&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td class="gridTopo"&gt;
		&lt;s:include value="Paginacao.jsp"/&gt;
	&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td&gt;
		&lt;table class="gridConteudo"&gt;
		&lt;tr&gt;
			&lt;th width="20"&gt;&nbsp;&lt;/th&gt;
			&lt;th&gt;&lt;s:text name="Tabelas.Atividades.CampoDescricao"/&gt;&lt;/th&gt;
			&lt;th width="20%"&gt;&lt;s:text name="Tabelas.Atividades.CampoTipo"/&gt;&lt;/th&gt;
		&lt;/tr&gt;
		&lt;s:if test="%{gridRegistros != null && !gridRegistros.isEmpty()}"&gt;
		&lt;s:iterator id="reg" value="gridRegistros" status="gridStatus"&gt;
			&lt;tr class="linha&lt;s:if test="#gridStatus.odd == true"&gt;1&lt;/s:if&gt;&lt;s:else&gt;2&lt;/s:else&gt;&quot;&gt
				&lt;td&gt;&lt;input type="radio" name="gridSelecao" value="&lt;s:property value='id'/&gt;"&gt;&lt;/td&gt;
				&lt;td&gt;&lt;s:property value="descricao"/&gt;&lt;/td&gt;
				&lt;td&gt;&lt;s:property value="tipo.descricao"/&gt;&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/s:iterator&gt;
		&lt;/s:if&gt;
		&lt;s:else&gt;
			&lt;tr class="linha1"&gt;
				&lt;td colspan="3" align="center"&gt;&lt;s:text name="App.SemRegistros"/&gt;&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/s:else&gt;
		&lt;/table&gt;
	&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td class="gridRodape"&gt;
		&lt;s:url id="icoNovo" value="/pages/images/ico_novo.gif"/&gt;
		&lt;s:submit type="image"
				src="%{icoNovo}"
				label="%{getText('App.BotaoNovo')}" 
				onclick="javascript:processando(true);submitFormTo(this.form,'Atividade','iniciarNovo');"/&gt;
		&lt;s:if test="%{gridRegistros != null && !gridRegistros.isEmpty()}"&gt;
			&lt;s:url id="icoAlterar" value="/pages/images/ico_alterar.gif"/&gt;
			&lt;s:submit type="image"
				src="%{icoAlterar}"
				label="%{getText('App.BotaoAlterar')}" 
				onclick="javascript:processando(true);submitFormTo(this.form,'Atividade','iniciarEditar');"/&gt;
			&lt;s:url id="icoExcluir" value="/pages/images/ico_excluir.gif"/&gt;
			&lt;s:submit type="image"
				src="%{icoExcluir}"
				label="%{getText('App.BotaoExcluir')}" 
				onclick="javascript:processando(true);submitFormTo(this.form,'Atividade','processarExcluir');"/&gt;
			&lt;s:url id="icoDetalhes" value="/pages/images/ico_detalhes.gif"/&gt;
			&lt;s:submit type="image"
				src="%{icoDetalhes}"
				label="%{getText('App.BotaoDetalhes')}" 
				onclick="javascript:processando(true);submitFormTo(this.form,'Atividade','processarDetalhes');"/&gt;
		&lt;/s:if&gt;
	&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/s:form&gt;

&lt;s:include value="TemplateGeralFooter.jsp"/&gt;

TabelasAtividadesCadastro.jsp

&lt;%@ taglib uri="/struts-tags" prefix="s" %&gt;

&lt;s:include value="TemplateGeralHeader.jsp"/&gt;

&lt;h3&gt;&lt;s:text name="Tabelas.Atividades.CaminhoTela"/&gt;&lt;/h3&gt;

&lt;s:form onsubmit="javascript: return false;"&gt;
&lt;table class="formulario" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
	&lt;td class="formularioTopo"&gt;
		&lt;s:text name="Tabelas.Atividades.CadastroTexto"/&gt;
	&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td class="formularioConteudo"&gt;
		&lt;s:hidden name="gridSelecao"/&gt;
		&lt;span class="formularioCampo"&gt;
			&lt;s:text name="Tabelas.Atividades.CampoDescricao"/&gt;: <br />
			&lt;s:textfield name="atividade.descricao" size="80"/&gt;
		&lt;/span&gt;
		&lt;span class="formularioCampo"&gt;
			&lt;s:text name="Tabelas.Atividades.CampoTipo"/&gt;: <br />
			&lt;s:select name="atividade.tipo.id" 
				list="todosTipos" 
				listKey="id" listValue="descricao" 
				headerKey="-1" headerValue=" "/&gt;
		&lt;/span&gt;
	&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td class="formularioRodape"&gt;
		&lt;s:if test="%{actionName == 'Atividade_iniciarNovo'}"&gt;
			&lt;s:set name="metodoDestino" value="%{'processarNovo'}"/&gt;
		&lt;/s:if&gt;
		&lt;s:if test="%{actionName == 'Atividade_iniciarEditar'}"&gt;
			&lt;s:set name="metodoDestino" value="%{'processarEditar'}"/&gt;
		&lt;/s:if&gt;
		&lt;s:url id="icoSalvar" value="/pages/images/ico_salvar.gif"/&gt;
		&lt;s:submit type="image"
				src="%{icoSalvar}"
				label="%{getText('App.BotaoSalvar')}" 
				onclick="javascript:processando(true);submitFormTo(this.form,'Atividade','%{metodoDestino}');"/&gt;
		&nbsp;
		<a >
			<img /pages/images/ico_cancelar.gif"/>" border="0" align="absmiddle" alt="&lt;s:text name="App.BotaoCancelar"/&gt;&quot;/&gt
		</a>
	&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/s:form&gt;

&lt;s:include value="TemplateGeralFooter.jsp"/&gt;

TabelasAtividadesDetalhes.jsp

&lt;%@ taglib uri="/struts-tags" prefix="s" %&gt;

&lt;s:include value="TemplateGeralHeader.jsp"/&gt;

&lt;h3&gt;&lt;s:text name="Tabelas.Atividades.CaminhoTela"/&gt;&lt;/h3&gt;

&lt;s:form onsubmit="javascript: return false;"&gt;
&lt;table class="registro" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
	&lt;td class="registroTopo"&gt;
		&lt;s:text name="Tabelas.Atividades.CadastroTexto"/&gt;
	&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td class="registroConteudo"&gt;
		<p>
			&lt;span class="registroLabel"&gt;
			&lt;s:text name="Tabelas.Atividades.CampoDescricao"/&gt;:
			&lt;/span&gt;
			<br />
			&lt;span class="registroDado"&gt;
			&lt;s:property value="atividade.descricao"/&gt;
			&lt;/span&gt;
		</p>
		<p>
			&lt;span class="registroLabel"&gt;
			&lt;s:text name="Tabelas.Atividades.CampoTipo"/&gt;:
			&lt;/span&gt;
			<br />
			&lt;span class="registroDado"&gt;
			&lt;s:property value="atividade.tipo.descricao"/&gt;
			&lt;/span&gt;
		</p>
	&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
	&lt;td class="registroRodape"&gt;
		<a >
			<img /pages/images/ico_voltar.gif"/>" border="0" align="absmiddle" alt="&lt;s:text name="App.BotaoRetornar"/&gt;&quot;/&gt
		</a>
	&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/s:form&gt;

&lt;s:include value="TemplateGeralFooter.jsp"/&gt;

Antes, para saber se um usuário estava logado no sistema, eu tinha que ter um if em cada método das Actions. Agora o Struts já vem com o conceito de interceptador e eu aproveitei ele para fazer isso.

AutenticacaoInterceptor.java

package embasa.jsime.view.interceptor;

import java.util.Map;

import org.apache.struts2.ResultNames;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

import embasa.jsime.model.Usuario;
import embasa.jsime.view.util.ActionUtil;

/**
 * @author Alexandre Mendonça Lima
 * 
 */
public class AutenticacaoInterceptor implements Interceptor {

	public void destroy() {

	}

	public void init() {

	}

	public String intercept(ActionInvocation invocation) throws Exception {
		ActionContext contexto = invocation.getInvocationContext();
		Map sessao = contexto.getSession();
		Usuario usuarioLogado = (Usuario) sessao.get(ActionUtil.USUARIO_LOGADO);
		if (usuarioLogado == null) {
			return ResultNames.LOGIN;
		}

		return invocation.invoke();
	}

}

Minha GenericAction ficou assim:

package embasa.jsime.view.util;

import java.util.Map;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

import embasa.jsime.model.Usuario;

/**
 * Classe pai de todos as Actions da aplicação. Extende a classe
 * com.opensymphony.xwork2.ActionSupport do framework Struts.
 * 
 * @author Alexandre Mendonça Lima
 * 
 */
public abstract class GenericAction extends ActionSupport {

	/**
	 * Obtém do objeto com.opensymphony.xwork2.ActionContext o nome da Action
	 * atualmente em uso.
	 * 
	 * @return O nome da Action em uso no ciclo de vida de execução do
	 *         framework.
	 */
	public String getActionName() {
		return ActionContext.getContext().getName();
	}

	/**
	 * Obtém o usuário atualmente autenticado na aplicação.
	 * 
	 * @return Um objeto da classe Usuario ou nulo se não tiver nenhum usuário
	 *         autenticado no momento.
	 */
	protected Usuario getUsuarioLogado() {
		Map session = (Map) ActionContext.getContext().get(&quot;session&quot;);
		Usuario usuarioLogado = (Usuario) session
				.get(ActionUtil.USUARIO_LOGADO);
		return usuarioLogado;
	}

	private Long pagRegPorPagina;

	private Long pagRegAtual;

	private Long pagRegQtdTotal;

	public Long getPagRegAtual() {
		return pagRegAtual;
	}

	public void setPagRegAtual(Long pagRegAtual) {
		this.pagRegAtual = pagRegAtual;
	}

	public Long getPagRegPorPagina() {
		return pagRegPorPagina;
	}

	public void setPagRegPorPagina(Long pagRegPorPagina) {
		this.pagRegPorPagina = pagRegPorPagina;
	}

	public Long getPagRegQtdTotal() {
		return pagRegQtdTotal;
	}

	public void setPagRegQtdTotal(Long pagRegQtdTotal) {
		this.pagRegQtdTotal = pagRegQtdTotal;
	}
}

Criei uma classe para auxiliar as Actions:

package embasa.jsime.view.util;

/**
 * Esta classe auxilia as Actions do sistema, as quais são extendidas do
 * framework Struts.
 * 
 * @author Alexandre Mendonça Lima
 * 
 */
public abstract class ActionUtil {

	/**
	 * Constante que define a chave da sessão em que está guardado o usuário
	 * autenticado na aplicação.
	 */
	public static final String USUARIO_LOGADO = &quot;usuarioLogado&quot;;

	/**
	 * Constante que define o nome do Result para a visualização da tela de
	 * entrada em uma funcionalidade da aplicação.
	 */
	public static final String VISUALIZAR = &quot;visualizar&quot;;

	/**
	 * Constante que define o nome do Result para a visualização da tela de
	 * detalhes de um registro de uma funcionalidade da aplicação.
	 */
	public static final String DETALHES = &quot;detalhes&quot;;

	/**
	 * Constante que define o nome do Result para a visualização da tela de
	 * cadastro de registro de uma funcionalidade da aplicação.
	 */
	public static final String CADASTRO = &quot;cadastro&quot;;

}

E finalmente, assim ficou minha AtividadeAction.java:

package embasa.jsime.view.action.tabelas;

import java.util.List;

import embasa.jsime.model.Atividade;
import embasa.jsime.model.Atividade.Tipo;
import embasa.jsime.util.RecursosSetup;
import embasa.jsime.view.util.ActionUtil;
import embasa.jsime.view.util.GenericAction;

/**
 * @author Alexandre Mendonça Lima
 * 
 */
public class AtividadeAction extends GenericAction {

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.opensymphony.xwork2.Validateable#validate()
	 */
	public void validate() {

		if (getActionName().equals(&quot;Atividade_processarDetalhes&quot;)
				|| getActionName().equals(&quot;Atividade_iniciarEditar&quot;)
				|| getActionName().equals(&quot;Atividade_processarExcluir&quot;)) {

			if (getGridSelecao() == null) {
				String msg = getText(&quot;Validation.Obrigatorio&quot;,
						new String[] { getText(&quot;App.GridSelecao&quot;) });
				addFieldError(&quot;gridSelecao&quot;, msg);
			}

		}

		if (getActionName().equals(&quot;Atividade_processarNovo&quot;)
				|| getActionName().equals(&quot;Atividade_processarEditar&quot;)) {

			if (getAtividade().getDescricao() == null
					|| getAtividade().getDescricao().trim().equals(&quot;&quot;)) {
				String msg = getText(
						&quot;Validation.Obrigatorio&quot;,
						new String[] { getText(&quot;Tabelas.Atividades.CampoDescricao&quot;) });
				addFieldError(&quot;atividade.descricao&quot;, msg);
			}

			if (getAtividade().getTipo() == null
					|| getAtividade().getTipo().getId() == null
					|| getAtividade().getTipo().getId().equals(&quot;-1&quot;)) {
				String msg = getText(
						&quot;Validation.Obrigatorio&quot;,
						new String[] { getText(&quot;Tabelas.Atividades.CampoTipo&quot;) });
				addFieldError(&quot;atividade.tipo&quot;, msg);
			}

		}
	}

	public void prepararListas() throws Exception {
		setTodosTipos(Tipo.obterTodos(getUsuarioLogado()));
	}

	public String visualizar() throws Exception {
		if (getPagRegAtual() == null || getPagRegAtual().longValue() &lt= 0) {
			setPagRegAtual(new Long(1));
		}
		setPagRegPorPagina(RecursosSetup.getPagRegPorPagina());

		prepararListas();

		List registros = null;
		if ((getFiltroDescricao() != null && !getFiltroDescricao().equals(&quot;&quot;))
				|| (getFiltroTipo() != null && !getFiltroTipo().equals(&quot;-1&quot;))) {
			registros = Atividade.obterPorDescricaoOuTipoId(
					getFiltroDescricao(), getFiltroTipo(), getUsuarioLogado(),
					getPagRegAtual(), getPagRegPorPagina());
		} else {
			registros = Atividade.obterTodos(getUsuarioLogado(),
					getPagRegAtual(), getPagRegPorPagina());
		}
		setGridRegistros(registros);

		setPagRegQtdTotal(Atividade.getQtdRegistrosEncontrados());

		return ActionUtil.VISUALIZAR;
	}

	public String processarDetalhes() throws Exception {
		setAtividade(Atividade.obterPorId(getGridSelecao(), getUsuarioLogado()));
		return ActionUtil.DETALHES;
	}

	public String iniciarNovo() throws Exception {
		prepararListas();
		setAtividade(new Atividade());
		return ActionUtil.CADASTRO;
	}

	public String processarNovo() throws Exception {
		Atividade.inserirNovo(getAtividade().getDescricao(), getAtividade()
				.getTipo().getId(), getUsuarioLogado());
		return visualizar();
	}

	public String iniciarEditar() throws Exception {
		prepararListas();
		setAtividade(Atividade.obterPorId(getGridSelecao(), getUsuarioLogado()));
		return ActionUtil.CADASTRO;
	}

	public String processarEditar() throws Exception {
		Atividade.atualizarPorId(getGridSelecao(), getAtividade()
				.getDescricao(), getAtividade().getTipo().getId(),
				getUsuarioLogado());
		return visualizar();
	}

	public String processarExcluir() throws Exception {
		Atividade.excluirPorId(getGridSelecao(), getUsuarioLogado());
		return visualizar();
	}

	private List gridRegistros;

	private Long gridSelecao;

	private Atividade atividade;

	private List todosTipos;

	private String filtroDescricao;

	private String filtroTipo;

	public List getGridRegistros() {
		return gridRegistros;
	}

	public void setGridRegistros(List gridRegistros) {
		this.gridRegistros = gridRegistros;
	}

	public Long getGridSelecao() {
		return gridSelecao;
	}

	public void setGridSelecao(Long gridSelecao) {
		this.gridSelecao = gridSelecao;
	}

	public Atividade getAtividade() {
		return atividade;
	}

	public void setAtividade(Atividade atividade) {
		this.atividade = atividade;
	}

	public List getTodosTipos() {
		return todosTipos;
	}

	public void setTodosTipos(List todosTipos) {
		this.todosTipos = todosTipos;
	}

	public String getFiltroDescricao() {
		return filtroDescricao;
	}

	public void setFiltroDescricao(String filtroDescricao) {
		this.filtroDescricao = filtroDescricao;
	}

	public String getFiltroTipo() {
		return filtroTipo;
	}

	public void setFiltroTipo(String filtroTipo) {
		this.filtroTipo = filtroTipo;
	}

}

Também não consegui fazer a validação funcionar para os métodos separadamente, então optei por não usar a validação em XML e sim na action. Com isso ganhei debug mas tô tendo um pouco mais de copy-paste.

Qualquer dúvida, é só perguntar.

Olá alexandremlima ,
Muito legal a sua explicação acho que já deu para tirar uma conclusão só mais uma pergunta pessoal com relação a IDE, qual delas vc. está usando e os auto completar, code-editor ,help e demais recursos funcionam de acordo pois pelo que vi ainda não temos plugins para o Struts 2.
Mais uma vez obrigado.
att.
William Silva
wos.silva@uol.com.br

Eu uso o Eclipse 3.1.2 com o plugin WTP 1.0.2 e com o plugin Tomcat Launcher da Sysdeo. Fazemos todos os sistemas somente com esse ambiente.
Estou aprendendo o Struts 2 somente com a documentação do website da Apache e pesquisando nos fóruns usando o Google.

Beleza… 8)

Olá alexandremlima !

Me explica uma questão, por favor. Qual a razão do action genérico ?
Há tempos à atrás, pensei em algo para uso de polimorfismo, para criar dinamismo na condução das ações, mas não consegui uma conclusão coesa.

Bye !!

Ah !! Queria agradecê-lo pelo material. Estou fazendo testes com struts2 e vai me ajudar muito.

Obrigado !

A GenericAction é apenas para diminuição de código. Todas as minhas Actions tem os gets e sets da paginação e um get para obter o usuário logado na aplicação. Então, deixei isso numa action genérica e todas as actions herdam dela estes métodos.

Estou utilizando o Struts 2 e estou achando bem mais "“organizado” doque o anterior.

Quanto ao Tiles? Como anda isso? Já funciona para a versão 2 ? Estava verificando que já existe um tal de Tiles 2.

T+

Sim, o Tiles não estava funcionando muito bem na versão 2.0.1 mas a partir da 2.0.2 está ok.
Sugiro que baixem no momento a versão 2.0.3 em http://people.apache.org/builds/struts/2.0.3/ . É uma versão mais estável do Struts 2 e quase foi promovida a versão GA (produção). Existe já uma versão 2.0.4 em andamento para ser lançada nos próximos dias.

Opá…

[quote]Existe já uma versão 2.0.4 em andamento para ser lançada nos próximos dias.[/quote] Agora vai…rs…rs…

Peguei uma aplicação que estava funcionando com a versão do Struts 2.0.1, baixei o pacote para a versão 2.0.3… atualizei a aplicação e BINGO… parou de funcionar… :frowning:

Dá um erro no web.xml !!! voltei os pacotes da versão 2.0.1 tá funcionando novamente !!! Que coisa heim !!!

Segue o meu web.xml

<web-app>
    <display-name>appStruts2.x</display-name>
    <filter>
        <filter-name>filtroStruts</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filtroStruts</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <welcome-file-list>
        <welcome-file>/pages/index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Estou utilizando o JBOSS, e no log, quando da o erro diz que é na linha 6, neste caso reclama que a tag: não existe !!!

Alguma sugestão !!?!?

t+

alexandremlima

Conforme o exemplo que vc. mostrou acima queria saber se tem como chamar o método de uma action via url, até agora só consigo chamar um método chamado INPUT, criei outros métodos (ex. listaRegistros) e não consigo chamar via URL.

Apresenta o seguinte erro : [Dispatcher] Could not find action or result

mas o método esta lá !!!

Será que pode ser uma implementação futura?

t+

Versão 2.05 Quentinha…
http://people.apache.org/repo/m2-snapshot-repository/org/apache/struts/struts2-core/2.0.5-SNAPSHOT/

Baixei a versão 2.0.5 e ainda não consigo chamar um método de uma action.

ex: http://localhost:8080/appStruts2x/Setor_visualizar.action

Será que isso é “bug” da versão ainda !?!?!?!