JSP避免Form重复提交的三种方案
1 javascript ,设置一个变量,只允许提交一次。
/ Z# \5 @. M& ^. [5 c% r" D
! @/ B; r+ u0 E9 o5 C2 G <script language="javascript">
' {0 W9 [8 w; g! u' O% f& u0 b4 i- `* ]& S& U% N( A7 V# ~
var checkSubmitFlg = false; 8 F# L& L1 ~$ @, J
; k2 ^9 a: _* v4 T
function checkSubmit() {
1 n0 R, H! T1 j9 t1 H( v0 g$ S# h5 i. d/ Y
if (checkSubmitFlg == true) {
v7 t3 `" ^; `$ e. }& S- s" }" T0 C' Z* y* ?
return false;
1 D& ], {0 R9 y) o
5 i& @% a6 d" ^( ?- ] }
0 l; Q; S: c2 a& E2 i; P T9 {7 H* B6 c2 }
checkSubmitFlg = true; $ ^+ n$ S: ^. T( F" q \! ?/ F% }7 c% a
' ?0 o* Z4 i- ~0 ~3 n return true; # u5 D5 |; ~5 n) f
" o$ } P1 b& F6 {, i9 m
} , P2 h2 ], J! I$ s
* `3 A. U6 D0 H+ K. Z- D+ K
document.ondblclick = function docondblclick() { . E- A, A, k. _
v4 U( q N- E0 Z: g window.event.returnValue = false;
' h g3 v* s1 |/ S; b
: [& K1 Z0 N; [1 Z+ D, T# j& s } ' E% |5 A% ], ^; V+ t- g
0 G0 i+ s; Q! o8 U* V document.onclick = function doconclick() {
1 @5 U9 H# O$ m, O y! m) P; T) Z8 i* q8 r) \$ F2 y
if (checkSubmitFlg) { % s+ U! M( m+ y" X
# |! Z D* m5 ?$ N
window.event.returnValue = false;
) C' A0 P9 [1 P5 Z2 O: r6 n9 q! |6 s
} 8 l+ S @0 `( r. F6 X2 D% R
/ ?8 c1 {* r* [1 S2 O5 n }
8 Z0 b p; P% H9 e! Z6 L# \9 A2 }1 w! W# U
</script> ! G6 Q" E1 C4 E, ]( @
8 K0 l# P$ m U' h$ w
# ^. f& N+ L/ u9 A9 K8 x, I
/ e: _) U# f! X. g! D$ }7 F <html:form action="myAction.do" method="post" onsubmit="return checkSubmit();">
/ X* D6 Z, [$ \1 Z+ s9 z
! j% f" B v$ t; p$ ^ 2 还是javascript,将提交按钮或者image置为disable
' ]# B* W7 t8 _' V2 C8 d1 o9 C2 y9 c3 h0 {2 `2 e
<html:form action="myAction.do" method="post"
! r3 s6 b; B. ~& N2 x+ N/ I O! `* x" N: u' B7 R
onsubmit="getElById('submitInput').disabled = true; return true;">
, c; {! ^- O' u9 z& O @" H" n
/ l) ~8 X Z2 J8 X2 S4 L <html:image styleId="submitInput" src="images/ok_b.gif" border="0" />
0 \. k8 X& A7 [3 ^2 x0 r
& H1 L* e0 n6 r. I6 M- S </html:form> , I8 N, B8 d2 U5 u8 u/ K
' l) I3 d1 o" N/ |- }% K* E( z$ l6 b
3 利用struts的同步令牌机制
( l4 ~* x1 A; l2 A6 P
* g4 z/ P0 r# i- @( g) s 利用同步令牌(Token)机制来解决Web应用中重复提交的问题,Struts也给出了一个参考实现。
2 T" @6 j0 G9 W. g0 ^" D0 m4 f2 S9 m* u) {' U
基本原理: ( T+ m D1 m# [& G1 X( @! i
- o( i7 z$ r" Q* P/ x p [% Y
服务器端在处理到达的请求之前,会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较,看是否匹配。在处理完该请求后,且在答复发送给客户端之前,将会产生一个新的令牌,该令牌除传给客户端以外,也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次提交的话,客户端传过来的令牌就和服务器端的令牌不一致,从而有效地防止了重复提交的发生。
! V: x! Q! v5 V3 _% I
* F% m, r ~" `0 N; g7 I! P if (isTokenValid(request, true)) { 6 z- v& Y/ \: K; G3 D+ y) w
- p" R7 R/ R$ w. j# d
// your code here & D. O" s( Y+ h+ G2 m' V6 M9 t( d) T
% z: A! }/ Y" c4 [5 f0 p! A0 p; _ return mapping.findForward("success"); 7 J' K8 M" n: l( i/ S
* {* \' N: B( S } else {
) I! W4 i/ p) C4 p
' m' \) q7 U- d3 V# G. d) x saveToken(request);
2 ~7 D. W7 X% L) W
6 ?8 E1 H3 D! Z# t3 u return mapping.findForward("submitagain"); 0 Q- N }' }$ ~- F w. [
& u1 W3 o% }2 P3 c: T$ t
} 2 F b3 Y( m; B* ? M3 K8 T n" ^' i v
4 [4 K$ o2 U% Z6 W
Struts根据用户会话ID和当前系统时间来生成一个唯一(对于每个会话)令牌的,具体实现可以参考TokenProcessor类中的generateToken()方法。 . C. a. b: ~, w
8 E0 Q) ^9 ^ I7 Q- v
1. //验证事务控制令牌,<html:form >会自动根据session中标识生成一个隐含input代表令牌,防止两次提交
H' Y# q7 w/ F3 z5 ~ N6 v. f0 _2 q/ V7 w* L! V; r2 i5 y0 }
2. 在action中: ! V7 z! f% q/ o. E$ p: C' o7 R5 Z: W
( a* M% U7 ?6 c, D3 V
//<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" % W1 s4 X2 S0 U
! O* Y0 _& O3 s V2 a
// value="6aa35341f25184fd996c4c918255c3ae"> . F4 g9 c- o; \9 D* B1 `
8 J( [7 c+ I! h: B' R u if (!isTokenValid(request)) * S" _$ O3 V( }$ O( n' B
v! D- e% q- }0 q( A5 \0 \4 m+ p
errors.add(ActionErrors.GLOBAL_ERROR,
/ C5 q/ \2 j* D$ m# x5 x9 T* G1 S
new ActionError("error.transaction.token"));
4 F) h* L: w8 o7 U# n+ N9 i/ D }# N- f
resetToken(request); //删除session中的令牌 5 O- Q' q2 x5 E5 V" {9 l( Q
G- ?0 ^4 U% K7 c9 j2 m4 j4 M 3. action有这样的一个方法生成令牌 , |4 D0 O6 \1 ^
: X4 L8 j$ `+ b: B S/ j7 s protected String generateToken(HttpServletRequest request) { ; L( N4 ~/ g2 A7 C' S; s w/ q
: Q4 V s5 \% H2 A8 q5 ?
HttpSession session = request.getSession(); / U9 g% i: j3 {8 R1 i' @" @4 X" E' w
1 F4 D$ H# y" q: M
try { & Y# B# p' r( t3 J
7 A: f7 ~ e* @! |
byte id[] = session.getId().getBytes(); ) u& E" C# M, K1 ]6 T7 C
: W p2 Q' n* B* t byte now[] = * w# p ]8 y& y& U9 T
+ I/ D. f1 k2 ^9 a* [ d; V new Long(System.currentTimeMillis()).toString().getBytes(); # Q) A* Y& H9 _% W' k$ o z0 t) |
+ j; P7 y& J/ V- {( F# M& y9 g
MessageDigest md = MessageDigest.getInstance("MD5"); 2 t2 @% }; s. _0 @6 N. a
9 g6 C" A+ J: ~# J
md.update(id); / a. |4 S. |' E
2 }; X4 F+ h: }
md.update(now); 1 i0 F1 S4 \% r Z% @
( ~2 s& ^/ B' v5 I
return (toHex(md.digest()));
# H7 q& z- c L
, t/ E+ C5 N' W& @ } catch (IllegalStateException e) {
4 x8 j \/ `) {6 G+ j; q
/ o |8 I) z+ |9 h4 i9 ^ return (null);
& d% d# O* b/ x0 Y% S* G# t9 |% M' e/ {' w, \ l$ m6 X; U2 s/ P' K5 H
} catch (NoSuchAlgorithmException e) {
3 t- p' z0 T* n
1 l2 L5 s6 O! V- Y( v c r+ K4 @ return (null); ' E7 K8 ^& O! Q: @' i
3 s- q) G3 }, W) n$ z
}
# F* G1 p8 M7 N& p) J
) G7 L# k0 W. t& [ }