在WEB開發中都會碰見這樣的情況,就是用戶在進行了一項操作后按F5刷新頁面會重復提交頁面的問題。
先了解下瀏覽器按F5會發生什么事,在按下F5后瀏覽器并不是簡單的刷新頁面,而是模擬上一次的請求一模一樣的再向服務器請求一次,加入上一次的請求
是向服務器請求保存數據,那按F5后就會再一次請求保存數據,這樣就等于重復提交了一次保存數據,如果我們系統中不做判斷的話,很容易在用戶不小心按F5
后再一次把數據保存進數據庫了。
方案:
因為按F5是完全模擬上次的請求再請求一次,可以說發送的數據和上次請求的是一樣的,就想到可以在客戶端和服務器端各保存一個標識狀態,然后在請求中比較2個表示狀態就好了。
解決方法做成1個組件,這樣就可以在所有需要使用的頁面上使用該組件了,下面就直接看組件的代碼吧
package com.byd.jsfcomponents.Refresh;
import java.io.IOException;
import jaax.faces.component.UIComponentBase;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.servlet.http.HttpSession;
/** *//**
* JSF中防刷新的控件 同時在客戶端和服務端保存一樣的值,
* 每次請求都改變2個的值(和以前的值相反),如果是刷新,取到的客戶端的值將服務端的值不一樣。
*/
public class HtmlRefresh extends UIComponentBase...{
private boolean m_refreshState;
private boolean m_isRefresh;
/** *//**
* 當前請求是否是刷新
* @return true 是;false 不是;
*/
public boolean IsRefresh()...{
return m_isRefresh;
}
/** *//**
* 返回對應的渲染器,這里沒有單獨的渲染器,所以返回null
*/
public String getFamily()...{
return null;
}
//
/** *//**
* 保存視圖
*/
public Object saveState(FacesContext context)...{
Object values[] = new Object[2];
values[0] = super.saveState(context); // 系統自己的State
// 保存客戶端的值
values[1] = !m_refreshState;
// 服務器的值保存到session中
ExternalContext exContext = FacesContext.getCurrentInstance().getExternalContext();
HttpSession session = (HttpSession)exContext.getSession(true);
session.setAttribute("ServerRefresh",m_refreshState);
return values;
}
/** *//**
* 恢復視圖
*/
public void restoreState(FacesContext context, Object state)...{
Object values[] = (Object[]) state;
super.restoreState(context, values[0]);
this.m_refreshState = (Boolean)values[1];
// 取服務器端值
ExternalContext exContext = FacesContext.getCurrentInstance().getExternalContext();
HttpSession session = (HttpSession)exContext.getSession(true);
Boolean _bRefresh = false;
if(session.getAttribute("ServerRefresh") != null)...{
_bRefresh = Boolean.valueOf(session.getAttribute("ServerRefresh").toString());
}
m_isRefresh = m_refreshState == _bRefresh;
}
//
}
在頁面中使用如下:
JAVABEAN代碼:
private HtmlRefresh htmlRefresh1 = new HtmlRefresh();
public HtmlRefresh getHtmlRefresh1() {
return htmlRefresh1;
}
public void setHtmlRefresh1(HtmlRefresh htmlRefresh1) {
this.htmlRefresh1 = htmlRefresh1;
}
public String button1_action() {
// 先判斷是否刷新
if(htmlRefresh1.IsRefresh()){
this.label1.setText("請別刷新提交");
}else{
this.label1.setText("正常提交");
}
return null;
}