亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么在Spring中使用MVC接口防止數據重復提交

發布時間:2021-03-09 16:22:52 來源:億速云 閱讀:176 作者:Leah 欄目:編程語言

怎么在Spring中使用MVC接口防止數據重復提交?相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

一、自定義一個注解,此注解可以使用在方法上或類上

  • 使用在方法上,表示此方法需要數據校驗

  • 使用在類上,表示此類下的所有方法需要數據校驗

  • 此注解對無參數方法不起作用

import org.springframework.stereotype.Component;
 
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface DataValidate {
 
}

二、自定義攔截,攔截前端所有請求

1、檢查此接口調用的方法或方法所在的類是否使用了DataValidate注解,若沒有使用,表示此接口不需要校驗數據;
2、若使用了注解,再檢查此方法有沒有入參,若沒有入參,不需要校驗數據,否在需要校驗;
3、把前端傳來的所有參數 (除了簽名參數)按照參數升序生成一個json字符串(使用TreeMap方式自動排序);
4、把生成的json字符串通過MD5加密的結果和前端傳的簽名值對比,若不相等,表示此數據被篡改過,否在沒有被篡改過;
5、數據是否被篡改校驗完畢,若前端傳了用戶唯一標示(token),表示需要校驗數據是否重復提交;
6、若簽名和上次提交的數據的簽名相等,表示是重復提交數據,若不相等,把簽名保存下來,表示數據不是重復提交。

import java.security.MessageDigest;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
 
import javax.annotation.PreDestroy;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.MethodParameter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
import com.alibaba.fastjson.JSON;
 
/**
 * 防數據被篡改和重復提交
 */
 
public class DataValidateInterceptor extends HandlerInterceptorAdapter implements Runnable {
 
 public static Map<String, TokenValue> userToken = new ConcurrentHashMap<>();
 
 // 過期時間
 private static long EXPIRED_TIME = 3600000;
 
 private static String TOKEN_NAME = "token";
 
 private static String SIGN_NAME = "sign";
 
 private volatile boolean shutDown;
 
 public DataValidateInterceptor(@Value("${data_interceptor.expired_time}") String expiredTime,
 @Value("${data_interceptor.token_name}") String tokenName,
 @Value("${data_interceptor.sign_name}") String signName) {
 if (null != expiredTime && !"".equals(expiredTime)) {
 EXPIRED_TIME = Long.parseLong(expiredTime);
 }
 if (null != tokenName && !"".equals(tokenName)) {
 TOKEN_NAME = tokenName;
 }
 if (null != signName && !"".equals(signName)) {
 SIGN_NAME = signName;
 }
 }
 
 @Override
 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
 throws Exception {
 if (validate(request, response, handler)) {
 /**
 * 實現返回提示數據
 */
 response.setContentType("application/json");
 response.setCharacterEncoding("UTF-8");
 response.getWriter().write("參數驗證失敗!");
 return false;
 }
 return true;
 }
 
 private boolean validate(HttpServletRequest request, HttpServletResponse response, Object handler) {
 
 if (handler instanceof HandlerMethod) {
 Class<?> clazz = ((HandlerMethod) handler).getBeanType();
 DataValidate dataValidate = clazz.getAnnotation(DataValidate.class);
 if (null == dataValidate) {
 dataValidate = ((HandlerMethod) handler).getMethodAnnotation(DataValidate.class);
 }
 
 if (dataValidate != null) {
 MethodParameter[] methodParameters = ((HandlerMethod) handler).getMethodParameters();
 if (null == methodParameters || methodParameters.length <=0) {
  // 方法沒有入參不需要校驗
  return false;
 }
 
 // 需要校驗
 String sign = request.getParameter(SIGN_NAME);
 Map<String, String[]> params = request.getParameterMap();
 Set<String> paramNames = params.keySet();
 Map<String, String> paramsMap = new TreeMap<>();
 for (String paramName : paramNames) {
  if (paramName.equals(SIGN_NAME)) {
  continue;
  }
  paramsMap.put(paramName, request.getParameter(paramName));
 }
 String paramString = JSON.toJSONString(paramsMap).replaceAll(" ", "");
 String MD5Sign = MD5.getMD5(paramString);
 if (!sign.equals(MD5Sign)) {
  // 數據被篡改
  return true;
 }
 
 String token = request.getParameter(TOKEN_NAME);
 if (token != null) {
  if (userToken.containsKey(token)) {
  TokenValue tokenValue = userToken.get(token);
  if (tokenValue.getValue().equals(sign)) {
  // 數據已經提交過
  return true;
  } else {
  tokenValue.setValue(sign);
  }
  } else {
  userToken.put(token, new TokenValue(sign));
  }
 }
 
 }
 }
 return false;
 }
 
 @Override
 public void run() {
 try {
 while (!shutDown) {
 synchronized (this) {
  wait(EXPIRED_TIME);
  Set<String> keys = userToken.keySet();
  for (String key : keys) {
  if ((userToken.get(key).getExpiredTime() + EXPIRED_TIME) <= System.currentTimeMillis()) {
  userToken.remove(key);
  }
  }
 }
 }
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 
 @PreDestroy
 public void custDestroy() {
 shutDown = true;
 synchronized (this) {
 notifyAll();
 }
 }
 
 private static class MD5 {
 
 /**
  * 向getMD5方法傳入一個你需要轉換的原始字符串,將返回字符串的MD5碼
  * 
  * @param code 原始字符串
  * @return 返回字符串的MD5碼
  */
  private static String getMD5(String code) {
   try {
    MessageDigest messageDigest = MessageDigest.getInstance("MD5");
 
    byte[] bytes = code.getBytes();
 
    byte[] results = messageDigest.digest(bytes);
 
    StringBuilder stringBuilder = new StringBuilder();
 
    for (byte result : results) {
     // 將byte數組轉化為16進制字符存入stringbuilder中
     stringBuilder.append(String.format("%02x", result));
    }
 
    return stringBuilder.toString();
   } catch (Exception e) {
    e.printStackTrace();
    return "";
   }
  }
 }
 
}
 
public class TokenValue {
 
 private String value;
 private long expiredTime;
 
 public TokenValue(String value) {
 this.value = value;
 this.expiredTime = System.currentTimeMillis();
 }
 
 public String getValue() {
 return value;
 }
 public void setValue(String value) {
 this.value = value;
 this.expiredTime = System.currentTimeMillis();
 }
 public long getExpiredTime() {
 return expiredTime;
 }
}

三、使用

后端使用:

1.在需要數據校驗的方法或類上使用DataValidate注解(若在類上使用,表示此類下的所有方法需要驗證)

2.配置 DataValidateInterceptor 攔截器

3.配置前端簽名參數,默認是sign

4.配置用戶唯一標示參數,默認是token(防止數據重復提交需要)

5.配置用戶唯一標示過期時間,默認是1h,單位是ms(防止數據重復提交需要)

前端使用:

1.獲取用戶唯一標示(防止數據重復提交需要)

2.把需要提交的數據根據參數(包括用戶唯一標示)升序排序然后生成一個json字符串(不能有空格),最后把json字符串進行MD5加密生成32位小寫加密結果簽名

eg:需要提交的數據為{messageType: "userQueryWait", companyCode: "test_app", token:"123213213"},排序后生成json字符串 {"companyCode":"test_app","messageType":"userQueryWait","token":"123213213"}, md5生成簽名

3.把簽名和需要提交的數據一起傳到后臺

eg:{messageType: "userQueryWait", companyCode: "test_app", token:"123213213", sign:"719bdb1fb769efb68e40440d1628ed5b"}

看完上述內容,你們掌握怎么在Spring中使用MVC接口防止數據重復提交的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

化州市| 县级市| 邢台县| 江口县| SHOW| 左云县| 收藏| 革吉县| 枝江市| 左权县| 北流市| 湖口县| 郸城县| 大同县| 碌曲县| 兖州市| 长春市| 肇源县| 多伦县| 永德县| 塔城市| 静乐县| 阿尔山市| 大兴区| 泸州市| 玉树县| 平武县| 会东县| 平顶山市| 舞钢市| 钟祥市| 高青县| 玉屏| 田东县| 和林格尔县| 舟曲县| 商城县| 北辰区| 鄂州市| 沿河| 方正县|