Avoid repeated submission of forms in Java and repeated submission of java forms
Repeated submission of forms:Not complete once. Request the form page first-> then submit the form process to complete data submission
Root cause:The process of submitting a form is not complete.
Repeated submission:
- Note: After the rollback, refresh the form page and submit again. In this case, a new request is sent instead of repeated submission. In Firefox, repeated submission to the same address is invalid.
Case:
1 @ WebServlet ("/trans") 2 public class TransferServlet extends HttpServlet {3 private static final long serialVersionUID = 1L; 4 5 protected void service (HttpServletRequest req, HttpServletResponse resp) 6 throws ServletException, IOException {7 req. setCharacterEncoding ("UTF-8"); 8 resp. setContentType ("text/html; charset = UTF-8"); 9 PrintWriter out = resp. getWriter (); 10 String money = req. getParameter ("money"); 11 // simulate network latency through sleep 12 try {13 Thread. sleep (3000); 14} catch (InterruptedException e) {15 e. printStackTrace (); 16} 17 System. out. println ("transfer amount:" + money); 18 out. print ("transfer amount:" + money); 19} 20}
In the wild, we can find that the jsp page will not change, but we can see it through the background print output. It will not stop outputting, indicating that it has been being executed.
Solution:
Before the submission is guaranteed, you must first request the form interface, in the same principle as the verification code. ---- token mechanism
In the first request, a token is created when the form interface is requested. When you click transfer and send the request, this token is taken and sent to the next interface, verify the token in the servlet. This token is in the session and in the form. Equal indicates that the form is correct and the token in the session is destroyed.
Code on the jsp page
1 <% 2 // Create token 3 String token = java. util. UUID. randomUUID (). toString (); 4 // a portion of the session exists, and then judge 5 sessions. setAttribute ("TOKEN_IN_SESSION", token ); 6%>
Code in TransferServlet
1 @ WebServlet ("/trans") 2 public class TransferServlet extends HttpServlet {3 private static final long serialVersionUID = 1L; 4 5 protected void service (HttpServletRequest req, HttpServletResponse resp) 6 throws ServletException, IOException {7 req. setCharacterEncoding ("UTF-8"); 8 resp. setContentType ("text/html; charset = UTF-8"); 9 PrintWriter out = resp. getWriter (); 10 // get the token value 11 String token = req. getParameter ("token"); 12 // get the token value 13 String sessionToken = (String) req in the session. getSession (). getAttribute ("TOKEN_IN_SESSION"); 14 // the token in the session is easy to be empty, because the token in the session is the 15 16 if (token. equals (sessionToken) {17 // indicates that the token is the same as 18 req. getSession (). removeAttribute ("TOKEN_IN_SESSION"); 19 String money = req. getParameter ("money"); 20 System. out. println ("transfer amount:" + money); 21 out. print ("transfer amount:" + money); 22 // the token 23} 24 in the last session is destroyed // If the token is different, it is submitted repeatedly, and cannot be submitted 25} 26}
Then, in order not to show the Java code in the jsp file, create and redirect the token to another servlet.
1 @ WebServlet ("/transfer") 2 public class CopyOfTransferServlet extends HttpServlet {3 private static final long serialVersionUID = 1L; 4 5 protected void service (HttpServletRequest req, HttpServletResponse resp) 6 throws ServletException, IOException {7 // Create a token and jump to submit. jsp 8 String token = UUID. randomUUID (). toString (); 9 System. out. println (token); 10 req. getSession (). setAttribute ("TOKEN_IN_SESSION", token); 11 req. setAttribute ("token", token); 12 req. getRequestDispatcher ("/views/repeatsubmit/submit. jsp "). forward (req, resp); 13 14} 15}
In this case, the jsp file looks like this.
1
It is much cleaner and more neat than above, but it still feels bad, because if you need to use it elsewhere, you also need to create a token, verify the token, and delete the token, therefore, a tool class is extracted.
TokenUtil. java
1 // token tool class 2 // Create Token 3 // verify token 4 // destroy token 5 public class TokenUtil {6 private final static String TOKEN_IN_SESSION = "TOKEN_IN_SESSION "; 7 public static void savaToken (HttpServletRequest req) {8 String token = UUID. randomUUID (). toString (); 9 System. out. println (token); 10 req. getSession (). setAttribute (TOKEN_IN_SESSION, token); 11 req. setAttribute ("token", token); 12} 13 14 public static boolean validateToken (HttpServletRequest req, 15 String tokenInrequest) {16 // get the token value in the session 17 String sessionToken = (String) req. getSession (). getAttribute (18 TOKEN_IN_SESSION); 19 if (tokenInrequest. equals (sessionToken) {20 req. getSession (). removeAttribute (TOKEN_IN_SESSION); 21 return true; 22} 23 return false; 24} 25}
In this way, the user only needs to call this tool class, and does not need to write a series of operations such as creating tokens.