当前位置:网站首页>Several methods to prevent repeated form submission + actual measurement

Several methods to prevent repeated form submission + actual measurement

2022-06-22 08:22:00 Hanxiaozhi

1. Front-end processing ( scene : Used when the user clicks many times in case of network delay submit Button causes the form to be submitted repeatedly )

①: After the form submission is controlled by an identifier , Submitting again will directly return to processing .

Var isCommitted = false;  // Identification of whether the form should be submitted , The default is false
function dosubmit() {
    
    //start hzj
	If(isCommitted == false){
    
	 // After submitting the form , Set whether the form has been submitted to true
	isCommitted = true;
	 // return true Let the form submit normally 
	return true;
	}else{
    
	return false; // return false Form not submitted 
	  }
	//end hzj
	
}

** summary :** Add the above judgment logic before submitting the business and after the business processing

②: After clicking the submit button once , Set this button to unavailable processing .

function dosubmit() {
    
// Get the form submit button 

Var btnSubmit = documen.getElementById(“sumit”);

// Set the form submit button to unavailable , It can prevent users from clicking the submit button again to submit 

btnSubmit.disabled = “disabled”;

// return true Make the form available for submission 

return true;

}

** summary :** Put this method after the first submit button succeeds , The button will be set to the non clickable state .

2. The back-end processing ( scene 1: After the form is submitted , The user clicks - Refresh - Button causes the form to be submitted repeatedly . scene 2: After the user form is submitted , Click on the browser's - back off - Button , Go back to the form submission page , The resubmit button causes the form to be resubmitted .)

①: Add a single key constraint to the database ( Simple and crude )

 When creating tables in the database ID Field add primary key constraint , user name 、 mailbox 、 Telephone and other fields plus uniqueness constraints . Make sure that only one piece of data can be added to the database .
 Database plus uniqueness constraint sql:
alter table tableName_xxx add unique key uniq_xxx(field1, field2)
 The server catches the inserted data exception in time :
		try {
    
	            xxxMapper.insert(user);
	        } catch (DuplicateKeyException e) {
    
	            logger.error("user already exist");
	        }

** summary :** For adding stock in to fields in the table

②:session Technical realization
a. Generate a unique random identification number on the server side , The technical term is called Token( token ), At the same time in the current user's Session Save this in the domain Token.
b. And then Token Sent to client Form In the form , stay Form The form uses hidden fields to store this Token, The form is submitted with this Token Submit to the server together .
c. Then, the server side judges the information submitted by the client Token And server-side generated Token Is it consistent , If it's not consistent , That's repeated submission , At this point, the server can not handle the form submitted repeatedly . If the same, process the form submission , Clear the current user's after processing Session The ID number stored in the domain .

//1. Sign in controller layer 
    String token = TokenProccessor.getInstance().makeToken();// Create token 
    request.getSession().setAttribute("token", token);  // Use on the server session preservation token( token )
    return data;// Return success data , Jump to the home page of the seat side ( take token Put in data in , The return page will token Put it in the form label in the hidden field )
//2. Put... In the front page form token
<input type="hidden" name="token" value="token value "/> 
//3. The logical layer that actually handles the submission business 
boolean b = isRepeatSubmit(request);// Determine whether the user is submitting repeatedly 
             if(b==true){
    
                 System.out.println(" Please do not repeat the submission ");
                 return;
             }
             request.getSession().removeAttribute("token");// remove session Medium token
             System.out.println(" Handle user submitted requests !!");
         }
         
         /** *  Judge whether the token submitted by the client is consistent with the token generated by the server  * @param request * @return * true  The user repeatedly submitted the form  * false  The user did not submit the form repeatedly  */
         private boolean isRepeatSubmit(HttpServletRequest request) {
    
             String client_token = request.getParameter("token");
             //1、 If there is no... In the form data submitted by the user token, Then the user repeatedly submitted the form 
             if(client_token==null){
    
                 return true;
             }
            // Take out and store in Session Medium token
            String server_token = (String) request.getSession().getAttribute("token");
             //2、 If the current user's Session Does not exist in the Token( token ), Then the user repeatedly submitted the form 
             if(server_token==null){
    
                 return true;
             }
             //3、 Stored in Session Medium Token( token ) With the form submitted Token( token ) Different , Then the user repeatedly submitted the form 
             if(!client_token.equals(server_token)){
    
                 return true;
             }
             
             return false;
         }
//4. Generate token Tool class of 
public class TokenProccessor {
    
  
     /* * Singleton design pattern ( Ensure that there is only one object of the class in memory ) *1、 Private the constructor of the class  *2、 Create a class object by yourself  *3、 Provide a public approach to the outside world , Returns the object of the class  */
     private TokenProccessor(){
    }
     
     private static final TokenProccessor instance = new TokenProccessor();
     
     /** *  Returns the object of the class  * @return */
     public static TokenProccessor getInstance(){
    
         return instance;
     }
     
     /** *  Generate Token * Token:Nv6RRuGEVvmGjB+jimI/gw== * @return */
     public String makeToken(){
      //checkException
         // 7346734837483 834u938493493849384 43434384
         String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
         // Data fingerprint  128 Bit length  16 Bytes  md5
         try {
    
             MessageDigest md = MessageDigest.getInstance("md5");
             byte md5[] =  md.digest(token.getBytes());
             //base64 code -- Any binary coded plaintext character  adfsdfsdfsf
             BASE64Encoder encoder = new BASE64Encoder();
             return encoder.encode(md5);
         } catch (NoSuchAlgorithmException e) {
    
             throw new RuntimeException(e);
         }
     }
 }

** summary :** Use session technology , One user corresponds to one session Containers

③: Use AOP Custom cut in implementation
1. Custom prevent duplicate submission flag (@AvoidRepeatableCommit).
2. For those that need to prevent repeated submission Congtroller Inside mapping Method with this annotation .
3. newly added Aspect The breakthrough point , by @AvoidRepeatableCommit Join the entry point .
4. Every time a form is submitted ,Aspect Will save the current key To reids( The expiration time must be set ).
5. When submitting repeatedly Aspect Will judge the present redis Is there any right to key, Intercept if any .

// First, customize the annotations 
/** *  Avoid duplicate submissions  * @author * @version * @since */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AvoidRepeatableCommit {
    

    /** *  Cannot submit repeatedly within the specified time , Unit millisecond , Default 10000 millisecond  */
    long timeout()  default 10000 ;
}
// Create the section class 
/** *  Repeated submission aop */
@Aspect//
@Component
public class AvoidRepeatableCommitAspect {
    
	private static final Logger logger = Logger.getLogger(AvoidRepeatableCommitAspect.class);
    @SuppressWarnings("rawtypes")
	@Autowired
    private RedisTemplate redisTemplate;

    /** * @param point  Connection point  */
    @SuppressWarnings("unchecked")
	@Around("@annotation(com.***.annotation.AvoidRepeatableCommit)")// Cut in the face 
    public Object around(ProceedingJoinPoint point) throws Throwable {
    
    	ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    	HttpServletRequest request = attributes.getRequest();
        String ip = IPUtil.getIP(request);
        // here method Get the proxy object ( Generated by proxy pattern ) Methods 
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        // here realMethod It's the target ( The original ) Methods 
		// Method realMethod = point.getTarget().getClass().getDeclaredMethod(signature.getName(),method.getParameterTypes()); 
        		
        // Target class 、 Method 
        String className = method.getDeclaringClass().getName();
        String name = method.getName();
        String ipKey = String.format("%s#%s",className,name);
        int hashCode = Math.abs(ipKey.hashCode());
        String key = String.format("%s_%d",ip,hashCode);
		//logger.info("ipKey={},hashCode={},key={}",ipKey,hashCode,key);
        logger.info(String.format("ipKey={},hashCode={},key={}",ipKey,hashCode,key));
        // Get annotation objects through reflection technology 
        AvoidRepeatableCommit avoidRepeatableCommit =  method.getAnnotation(AvoidRepeatableCommit.class);
        long timeout = avoidRepeatableCommit.timeout();
        if (timeout < 0){
    
            // Expiration time 10 second 
            timeout = 10000;
        }
        // obtain key The value of the key 
        String value = (String) redisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(value)){
    
            return new Message(1," Do not submit again !");
        }
        // Add a value of string type ,key It's a key ,value Is the value .
        redisTemplate.opsForValue().set(key, UUIDUtil.uuid(),timeout,TimeUnit.MILLISECONDS);
        
        // Return to continue executing the intercepted method  
        return point.proceed();
    }

}

Be careful :
This class has two annotations , Namely @Component and @Aspect,
@Component Is making AvoidRepeatableCommitAspect suffer Spring Hosting and instantiating .
@Aspect Is to make this class have AOP function ( You can think of it this way ) Both notes are indispensable
There is only one method in the class , The name is called around, In fact, it is to prevent repeated submission !

// Add... To the method I need to prevent duplicate submission   Custom annotation 
//  newly added 
	@AvoidRepeatableCommit // Custom annotation 
	@RequestMapping(method = RequestMethod.POST)
	public @ResponseBody Message create(SourceEntity sourceEntity) {
    
		// Set creation time 
		sourceEntity.setGmt_create(new Date());
		// Save database 
		sourceEntity.save(sourceEntity);
		return MessageUtil.message("sourceEntity.create.success");
	}

** summary :** It's done here , The main step is to submit the form every time ,Aspect Will save the current key To reids( Set the expiration time first ). When submitting repeatedly Aspect Will judge the present redis Is there any right to key, Intercept if any . Let go if you don't .

原网站

版权声明
本文为[Hanxiaozhi]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202220528499714.html