Imagine o seguinte cenário: Você termina de preencher os campos de uma página de inclusão. Ao clicar em OK, o sistema envia o formulário e executa um forward para a página de listagem do seu cadastro com a mensagem: “Registro incluído com sucesso.”
No JSF (e imagino que em várias outras soluções MVC) quando você dá um refresh (F5), o sistema reenvia os dados que você preencheu na tela de cadastro e acaba incluindo um novo registro (ou tentando incluir, caso tenha problema com algum campo que não pode se repetir), e na atual listagem aparece dois dados iguais.
Andei pesquisando a maneira mais simples de não dar um forward após a inclusão do dado. Acabei caindo numa boa explicação do Rafael Pontes sobre a diferença entre o forward e redirect.
Vamos a solução:
Na regra de navegação, agora foi usada uma tag (<redirect />)na passagem do cadastro para a listagem:
<navigation-rule>
<from-view-id>/empresa/cadastroEmpresa.jsp</from-view-id>
<navigation-case>
<from-outcome>listagem</from-outcome>
<to-view-id>/empresa/listagemEmpresa.jsp</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
Com isso perdemos as nossas mensagens adicionadas ao messages através do método FacesContext.getCurrentInstance().addMessage(), já que essas mensagens são válidas só por requisição. A solução para contornar esse problema foi a utilização de alguma classe que tem o escopo de sessão. A escolhida no meu caso, foi a classe de login do usuário, que é a classe que ele carrega para “provar” que é um usuário cadastrado e logado no sistema. Dentro dessa classe incluí:
private List<String> mensagens;
public void showMensagens() {
if(this.mensagens==null)
this.mensagens = new ArrayList<String>();
for(String msg : this.mensagens)
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, msg, null));
this.mensagens = new ArrayList<String>();
}
public void addMensagens(String mensagem) {
if(this.mensagens==null)
this.mensagens = new ArrayList<String>();
this.mensagens.add(mensagem);
}
e na classe ancestral dos backbeans o seguinte método:
protected void addNewMessage(String msg) {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
HttpSession session = (HttpSession) externalContext.getSession(false);
LoginCodebehind login = (LoginCodebehind) session.getAttribute("login");
login.addMensagens(msg);
}
protected void showMessages() {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
HttpSession session = (HttpSession) externalContext.getSession(false);
LoginCodebehind login = (LoginCodebehind) session.getAttribute("login");
login.showMensagens();
}
O primeiro método busca no contexto o meu objeto de sessão login e adiciona a mensagem. Esse método será chamado após uma inclusão com sucesso como por exemplo:
public void actionGravar(ActionEvent event) {
try {
EmpresaBO.getInstance().create(empresaTO);
this.addNewMessage("Empresa cadastrada com sucesso.");
} catch (RegraNegocioException e) {
e.printStackTrace();
this.addErrorMessage(e);
throw new AbortProcessingException();
}
E o segundo método será chamado pelas telas de listagem, para exibirem as mensagem quando houverem.
public ListagemEmpresa() {
try {
this.showMessages();
empresaList = EmpresaBO.getInstance().findAll();
} catch (RegraNegocioException e) {
this.addErrorMessage(e);
}
}
Esse solução foi feito para exibir somente as mensagens de sucesso, já que teoricamente são as únicas que passam de uma página para a outra. Quando houver a necessidade de exibir mensagem de erro, não deverá mudar de tela, então vai exibir no mesmo request. Mas é possível adicionar um parâmetro nas chamadas para que seja acrescentada o tipo da mensagem.
[]’s
Setembro 29, 2008
Sempre acreditei que a ordem das cláusulas numa consulta comum não interfere em nada no resultado. Porém, passei um dia investigando uma consulta que estava dando erro. A correção veio como de uma simples alteração na ordem das cláusulas. Difícil acreditar, né?
Esse erro aconteceu no Oracle, ao chegar em casa fui testar em outro e banco e pimba, aconteceu novamente. No SqlServer aconteceu o erro, já no mysql não consegui retratar.
Chega de embromação e vamos ao erro.
Vamos criar um simples tabela.
CREATE TABLE [tabela] (
[TIPO] [varchar](1),
[valor] [varchar] (3)
)
Na primeira coluna armazenaremos o tipo de dado que tem na seguda.
insert into tabela1 (tipo, valor) values (‘N’, ‘1′);
insert into tabela1 (tipo, valor) values (‘N’, ‘2′);
insert into tabela1 (tipo, valor) values (‘A’, ‘A’);
insert into tabela1 (tipo, valor) values (‘A’, ‘B’);
Agora uma simples consulta do tipo:
select * from tabela1
where 1=1
and convert(numeric, valor) > 0
and tipo = ‘N’
Gera o seguinte resultado:
Server: Msg 8114, Level 16, State 5, Line 1
Error converting data type varchar to numeric.
Mas mudando a ordem para :
select * from tabela1
where 1=1
and tipo = ‘N’
and convert(numeric, valor) > 0
Obtemos:
TIPO valor
—- —–
N 1
N 2
(2 row(s) affected)
Ou no Oracle:
select * from tabela
where 1=1
and to_number(valor) > 0
and tipo = ‘N’
Detalhes: Isso aconteceu na versão do Oracle do trabalho e não na versão da minha casa.
Qual a possível explicação?
O mais perto que conseguimos acreditar, é no famoso curto circuito que estudamos em PD1. Ou seja, as cláusulas são avaliadas em algum sentido (no sqlserver de cima para baixo e no oracle de baixo para cima) e quando encontram alguma expressão que é falsa, ele já descarta o registro que está sendo avaliado. No nosso caso ele corre o risco de gerar um erro antes da primeira cláusula falsa, o que corre o risco de parar todo um processamento envolvido.
Soluções?
Fazer subconsultas para que não corra o risco de encontrar um erro, causa overhead mas não causa erro.
Outra coisa que aprendi sobre esse assunto, é que a ordem das tabelas no FROM da consulta também interfere em algumas consultas. Pelo menos no oracle ele olha as tabelas de trás para frente, então o ideal é colocar as tabelas com menos registros no final da lista, para que ele possa diminuir o trabalho de juntar tudo.
Estou a espera de melhores explicações e melhores soluções.
[]’s
Agosto 27, 2008
Agora tenho um blog. Grande merda. Pretendo colocar dicas e descobertas do mundo da programação (leia-se java) e outras coisas da computação.
[]’s
Agosto 27, 2008