防止一再提交java解决
& E _8 Q2 H# M. v# p* X. M- U8 }. t B/S结构的软件开发中,出格是在越大型的分布式应用中浮现的越较着,后端的措置往往会因为呈现较多的时刻耗损而引起延迟,这种延迟有可能过长而最终使用户认为是自己的操作错误,导致他们从头提交请求,因为使命的一再提交,处事器资本大部门被占用,情节严重可能呈现近似死机现象。
. A0 s u% s6 T6 K' J) Z' F 预期达到方针: ; N; x+ B. U+ J& K1 F7 a6 l
1、当用户进行的是Refresh/Reload/Back/Forward操作、以及先Back再Submit操作时,仅仅是reloading先前的结不美观页。
) c- H* l' a5 ~9 m 2、当用户一再提交统一个使命操作时,后台处事领受并措置第一次提交的使命,后面提交不起浸染(不转向也不提醒)。 0 P# l1 P+ q+ V5 z
3、该功能具有公用性。 ' M; N: a3 [7 c3 t0 Q6 K) w
根基形成思绪: 5 r8 {+ D+ K% u2 G6 e; }
1、在basic filter中实现公用性
, G: S' n( j) g+ y* | if(true){//问题1:若何确定是否为一再提交 + C/ V7 u9 j% q+ }( {" T
...
$ G: e) k7 V: t$ O. `: }1 \5 x chain.doFilter(request,response);
' \* k4 I& ^) V1 ?! _0 ~5 G4 V }else{
# h3 R; Y. x$ X6 }* t" ^1 a4 S/ \ //问题2:若何实现不转向、不提醒也不显示空白页
- Y8 ]% c* @: C2 x1 S }
8 E q7 Y6 R; U( O- S 2、网上资料归纳综合
# F2 P' M4 h( Z; d" |6 H1 m* X; c a、提交表单后按钮变灰/潜匿提交按钮
# k) }0 p! S' J6 E) O- f7 n4 S b、在js里设置全局变量,提交后改削该变量的值,依据变量的值判定是否一再提交
; s; G: e" M. W6 U3 _4 i2 O var flag=true; , X% S+ Q7 A$ J% h; j$ J8 w
function checkForm(){
/ t6 Y- P; i6 _ if (flag==false){
6 j" `) ]/ ], H% f! s return; # o5 d# n' r+ q+ P" g6 }
}
+ n A5 p7 g$ d& e, }) Q6 ~. F flag=false; `0 H- Z B& X9 o0 p- O
document.form1.submit(); ) G1 F7 }- E% T& \4 p/ ^7 ]8 ^
}
0 I1 J! Y) }6 _- t2 O c、struts (webwork没有找到这个资料) 4 ^6 H. z" t4 H
//验证事务节制令牌,会自动按照session中标识生成一个隐含input代表令牌,防止两次提交 % o% b0 m* U, b% [9 r
在action中:
; i2 C+ J) Q; W' o% U5 T6 | //
& t- I) b+ U. z- ~1 A$ D if (!isTokenValid(request))
. ~' k1 H/ | J: |$ b- L errors.add(ActionErrors.GLOBAL_ERROR, 6 g# z& |) p, b9 D2 J0 d( N2 M
new ActionError("error.transaction.token")); 6 ^3 r+ }1 v) o0 m
resetToken(request); //删除session中的令牌 * e1 a# P7 S/ ~) J: Z
action有这样的一个体例生成令牌华 % Z8 o* s; }# T& _9 H0 o
protected String generateToken(HttpServletRequest request) {
6 A! f: i0 Y/ ~7 L9 S HttpSession session = request.getSession();
0 \/ t7 Z# V/ f5 N" ]: |! I/ D2 z try { # M& L! h r N4 ~- P
byte id[] = session.getId().getBytes();
3 `* b' s9 U, g6 ]0 Q6 F* P byte now[] =
h" F, g5 s7 }0 } J new Long(System.currentTimeMillis()).toString().getBytes(); ; D% ]2 S( [) V, q
MessageDigest md = MessageDigest.getInstance("MD5"); ; _& j8 W1 E) M2 T- {; s
md.update(id); ! {7 W2 d) `4 J) [. I& T$ d
md.update(now); / H6 D, m9 f% U6 G3 C9 M9 E: T
return (toHex(md.digest()));
1 ?0 X( V% t g5 U" v x% E0 l } catch (IllegalStateException e) {
" ? Y; c( n$ Z1 S# _2 @) p return (null); 4 [/ U4 ~2 f5 d
} catch (NoSuchAlgorithmException e) { . h0 a0 O( g" Y0 b* _
return (null); 0 P- Z! D: Q: n
} 1 G& G$ X: [& s
}
4 p6 C) f: v6 q, q d、用户使用浏览器时,可以经常使用向后的按钮,是以就有可能一再提交一个他们已经提交过的form,这样就会带来一个一再事务措置的问题。同样,一个用户也可能在领受到一个确认的页面之前按下遏制的按钮,接着再次提交统一个form。对于这些情形,我们都想跟踪而且禁止这些一再的提交,我们可以使用一个节制servlet来供给一个节制点,以解决这个问题。
( u' |# x7 w2 u$ v8 x 同步记号(Synchronizer (or Dvu) Token) ( j+ r$ L8 `$ ?( y- o
这个策略是为体味决一再的form提交问题。一个同步的记号被设置在一个用户的Session中,而且包含在返回到客户的每一个form中。当form被提交时,form中的同步标识表记标帜就和Session中的同步标识表记标帜作对比。在form初度提交的时辰,这两个标识表记标帜应该是一样的。如不美观标识表记标帜纷歧样,那么该form就会禁止提交,一个错误就会返回给用户。在用户提交一个form时,如不美观按下浏览器中的猬缩后退按钮并考试考试从头提交统一个form时,标识表记标帜就会呈现不匹配的现象。 2 ~1 q( T [1 K) d; O% |
另一方面,如不美观两个标识表记标帜值匹配,那么我们就可以确信整个流程是正确的。在这种情形下, 7 z6 i+ r+ q/ g/ }$ n. n
另一方面,如不美观两个标识表记标帜值匹配,那么我们就可以确信整个流程是正确的。在这种情形下,Session中的标识表记标帜值就会被改削为一个新的值,同时许可提交该form。 ) Z! b" e- n7 E/ {. p& o, ?# z
你也可以使用这个策略来节制对某些页面的直接访谒,就好象膳缦沔资本呵护中描述的一样。例如,假设一个用户将某个应用的页面A保藏到保藏夹中,而页面A只许可经由过程页面B和C访谒。当用户直接经由过程保藏夹来访谒页面A,这时页面的访谒挨次就是不正确的,这样同步标识表记标帜将处在一个分歧步的状况,或者它根柢就不存在。非论若何,访谒都被禁止了。 + m q z6 M$ n- a! b1 j' N4 w
e、做一个hidden框,名字自己定,提交后获得这个值放入session,提交前判定session是否为空 % S2 f2 s7 B7 }
解决方案: $ g: ?5 k" I& u, x4 g$ R: X* U
1、后台公共嘌扌实现前台的Form中自动生成两个hidden文本功能,一个是作page是否一再提交判定,并由系统自动附上关头值(如struts采用的方案);另一个作为button是否一再提交判定(struts中仿佛没有)。由后台公共类实现界面两个hidden text自动生成的益处在于公用性。 3 [ d9 _$ N8 B5 ]' @; t' u
2、在basic filter中按照两个hidden text值判定是否为一再提交。 # D, Q5 j5 l+ p+ m, H# f, h4 G
3、javascript中作一个公共体例,实现功能:如不美观需要判定是否一再提交,就给第二个hidden text附上关头值,并使该功能不成用。 |