java接口防重提交如何處理

1.什么是接口防重?

在一定的時間內(nèi)請求同一接口,同一參數(shù)洲押。由于請求是健康請求戈抄,會執(zhí)行正常的業(yè)務(wù)邏輯席噩,從而產(chǎn)生大量的廢數(shù)據(jù)。

2.處理方法

第一種:前臺在請求接口的時候,傳遞一個唯一值桌肴,然后在對應(yīng)接口判斷該唯一值寸潦,在一定的時間內(nèi)是否被消費過
第二種:采用Spring AOP理念色鸳,實現(xiàn)請求的切割,在請求執(zhí)行到某個方法或某層時候见转,開始攔截進行命雀,獲取該請求的參數(shù),用戶信息斩箫,請求地址吏砂,存入redis中并放置過期時間,進行防重(推薦使用)

3.談?wù)勔陨蟽煞N處理方法的利弊

第一種:局限性太高乘客,前臺必須傳遞一個唯一值狐血,就算請求到達指定后臺服務(wù),寫一個攔截器易核,需要配置太多不需要攔截的方法匈织,也許你會說,可以攔截有規(guī)則的請求地址耸成,這樣真的好嗎?
第二種:作為一名JAVA后臺開發(fā)报亩,Spring應(yīng)該是熟悉的不能再熟悉了,Spring核心AOP又用了多少井氢,針對以上請求,只需要寫一個注解類岳链,然后切面到該注解上花竞,在需要防重的方法上只需添加注解即可

4.具體代碼(采用第二種)

注解類

import java.lang.annotation.*;

/**
 * 防重
 * @author haodongdong
 * @date 2020/8/12
 * @return
 */
//標識該注解用于方法上
@Target({ElementType.METHOD})
//申明該注解為運行時注解,編譯后改注解不會被遺棄
@Retention(RetentionPolicy.RUNTIME)
//javadoc工具記錄
@Documented
public @interface PreventSubmit 
{
}

切面類

import com.qianxian.common.exception.AppException;
import com.qianxian.common.util.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * 防重復(fù)提交
 * @author haodongdong
 * @date 2020/8/12
 * @return
 */
@Component
@Aspect
@Slf4j
public class PreventSubmitAspect {

    /**
     * 放重redis前綴
     */
    private static String API_PREVENT_SUBMIT = "api:preventSubmit:";

    /**
     * 放重分布式鎖前綴
     */
    private static String API_LOCK_PREVENT_SUBMIT = "api:preventSubmit:lock:";

    /**
     * 失效時間
     */
    private static Integer INVALID_NUMBER = 3;

    /**
     * redis
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 分布式鎖
     */
    @Autowired
    private RedissonClient redissonClient;


    /**
     * 防重
     * @author haodongdong
     * @date 2020/8/12
     * @return
     */
    @Around("@annotation(com.qianxian.user.annotation.PreventSubmit)")
    public Object preventSubmitAspect(ProceedingJoinPoint joinPoint) throws Throwable {

        RLock lock = null;

        try {

            //獲取目標方法的參數(shù)
            Object[] args = joinPoint.getArgs();

            //獲取當(dāng)前request請求
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);

            //獲取請求地址
            String requestUri = request.getRequestURI();

            //獲取用戶ID
            Long userId = null;
            try {
                userId = TokenUtil.getUserId(request);
            }catch (Exception e){}

            //拼接鎖前綴掸哑,采用同一方法约急,同一用戶,同一接口
            String temp = requestUri.concat(Arrays.asList(args).toString()) + (userId != null ? userId : "");
            temp = temp.replaceAll("/","");

            //拼接rediskey
            String lockPrefix = API_LOCK_PREVENT_SUBMIT.concat(temp);
            String redisPrefix = API_PREVENT_SUBMIT.concat(temp);

            /**
             * 對同一方法同一用戶同一參數(shù)加鎖,即使獲取不到用戶ID,每個用戶請求數(shù)據(jù)也會不一致,不會造成接口堵塞
             */
            lock = this.redissonClient.getLock(lockPrefix);
            lock.lock();

            String flag = this.stringRedisTemplate.opsForValue().get(redisPrefix);
            if(StringUtils.isNotEmpty(flag)){
                throw new AppException("您當(dāng)前的操作太頻繁了,請稍后再試!");
            }

            //存入redis,設(shè)置失效時間
            this.stringRedisTemplate.opsForValue().set(redisPrefix,redisPrefix,INVALID_NUMBER, TimeUnit.SECONDS);

            //執(zhí)行目標方法
            Object result = joinPoint.proceed(args);
            return result;

        }finally {
            if(lock != null){
                lock.unlock();
            }
        }

    }

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末苗分,一起剝皮案震驚了整個濱河市厌蔽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌摔癣,老刑警劉巖奴饮,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異择浊,居然都是意外死亡戴卜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門琢岩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來投剥,“玉大人,你說我怎么就攤上這事担孔〗牵” “怎么了吃警?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長啄育。 經(jīng)常有香客問我汤徽,道長,這世上最難降的妖魔是什么灸撰? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任谒府,我火速辦了婚禮,結(jié)果婚禮上浮毯,老公的妹妹穿的比我還像新娘完疫。我一直安慰自己,他們只是感情好债蓝,可當(dāng)我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布壳鹤。 她就那樣靜靜地躺著,像睡著了一般饰迹。 火紅的嫁衣襯著肌膚如雪芳誓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天啊鸭,我揣著相機與錄音锹淌,去河邊找鬼。 笑死赠制,一個胖子當(dāng)著我的面吹牛赂摆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播钟些,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼烟号,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了政恍?” 一聲冷哼從身側(cè)響起汪拥,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎篙耗,沒想到半個月后迫筑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡鹤树,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年铣焊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罕伯。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡曲伊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情坟募,我是刑警寧澤岛蚤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站懈糯,受9級特大地震影響涤妒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赚哗,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一她紫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧屿储,春花似錦贿讹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至疯潭,卻和暖如春赊堪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背竖哩。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工哭廉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人期丰。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓群叶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親钝荡。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,925評論 2 344