1. 程式人生 > >企業實戰之Spring攔截器《統一引數校驗》

企業實戰之Spring攔截器《統一引數校驗》

在前面的一些文章中我們有講到,通過攔截器我們可以做很多的事情,包括介面統一的 引數校驗、 登入校驗、許可權校驗等,也可以做一些HTTP響應體寫入邏輯,比如我們另一篇文章所說的《解決跨域問題》,本篇我們也就是講解下,使用攔截器對開放的介面做公共引數校驗功能實現。

下面我以我們實際開發中所遇到的問題,來舉例說明。

需求描述

在對外開放介面的時候,我們的呼叫端是很多的,比如:APP/PC/WECHAT公眾號or小程式 等等,當線上環境某一個使用者出現問題時,如果這個問題僅僅是後端還好,但是如果是前後端需要配合解決的錯誤,我們就需要更多的呼叫客戶端的一些資訊,這個時候你去問客戶app什麼版本、什麼手機這顯然是不妥的,所以我們應該收集更多的呼叫資訊,以便我們做後續業務處理、日誌記錄等等的一些操作,通常需要對客戶端統一收集的資訊比如 呼叫來源、app版本號、api的版本號、安全驗證資訊 等等。

解決方式

我們將這些資訊放入頭資訊(HTTP HEAD中),下面給出在引數命名的例子:

  • X-Token 使用者的登入token(用於兌換使用者登入資訊)
  • Api-Version api的版本號
  • App-Version app版本號
  • Call-Source 呼叫來源(IOS、ANDROID、PC、WECHAT、WEB)
  • Authorization 安全校驗引數(後面會有文章詳細介紹該如何做安全校驗)

然後我們將該些資訊在攔截器中做統一的引數校驗,下面我們給出響應的程式碼,給大家一個寫法上的參考O(∩_∩)O~

我們為這些請求頭引數變數定義常量類:

package com.zhuma.demo.constant;

import com.zhuma.demo.enums.CallSource;


/**
 * @desc Header的key羅列
 * 
 * @author zhumaer
 * @since 8/31/2017 3:00 PM
 */
public class HeaderConstants {

    /**
     * 使用者的登入token
     */
    public static final String X_TOKEN = "X-Token";

    /**
     * api的版本號
     */
public static final String API_VERSION = "Api-Version"; /** * app版本號 */ public static final String APP_VERSION = "App-Version"; /** * 呼叫來源 {@link CallSource} */ public static final String CALL_SOURCE = "Call-Source"; }

對於呼叫的來源我們可以定義一個列舉類:

package com.zhuma.demo.enums;

/**
 * @desc 呼叫來源列舉類
 * 
 * @author zhumaer
 * @since 8/31/2017 3:00 PM
 */
public enum CallSource {
    WEB,
    PC,
    WECHAT,
    IOS,
    ANDROID;

    public static boolean isValid(String name) {
        for (CallSource callSource : CallSource.values()) {
            if (callSource.name().equals(name)) {
                return true;
            }
        }
        return false;
    }

}

攔截器類:

package com.zhuma.demo.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.zhuma.demo.constant.HeaderConstants;
import com.zhuma.demo.enums.CallSource;
import com.zhuma.demo.enums.ResultCode;
import com.zhuma.demo.exception.BusinessException;
import com.zhuma.demo.util.StringUtil;

/**
 * @desc HEADER頭引數校驗
 * 
 * @author zhumaer
 * @since 8/29/2017 3:00 PM
 */
@Component
public class HeaderParamsCheckInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            String callSource = request.getHeader(HeaderConstants.CALL_SOURCE);
            String apiVersion = request.getHeader(HeaderConstants.API_VERSION);
            String appVersion = request.getHeader(HeaderConstants.APP_VERSION);

            if (StringUtil.isAnyBlank(callSource, apiVersion)) {
                throw new BusinessException(ResultCode.PARAM_NOT_COMPLETE);
            }

            try {
                Double.valueOf(apiVersion);
            } catch (NumberFormatException e) {
                throw new BusinessException(ResultCode.PARAM_IS_INVALID);
            }

            if ((CallSource.ANDROID.name().equals(callSource) || CallSource.IOS.name().equals(callSource)) && StringUtil.isEmpty(appVersion)) {
                throw new BusinessException(ResultCode.PARAM_NOT_COMPLETE);
            }

            if (!CallSource.isValid(callSource)) {
                throw new BusinessException(ResultCode.PARAM_IS_INVALID);
            }

        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // nothing to do
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // nothing to do
    }

}

說明
上述校驗邏輯其實很簡單,如果校驗不通過直接以一個異常丟擲,交由統一的異常處理器去處理後續事情,對於app版本資訊可能只有android、ios才會有所以我們根據這種特殊情況做了下判斷。

攔截器配置類(以spring boot為例):

package com.zhuma.demo.config.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.zhuma.demo.interceptor.HeaderParamsCheckInterceptor;
import com.zhuma.demo.interceptor.LoginedAuthInterceptor;

@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private LoginedAuthInterceptor loginedAuthInterceptor;

    @Autowired
    private HeaderParamsCheckInterceptor headerParamsCheckInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        String apiUri = "/**";
        //請求頭引數校驗
        registry.addInterceptor(headerParamsCheckInterceptor).addPathPatterns(apiUri);
        //登入攔截(這個上一篇文章講過了,這裡說明下兩個攔截器前後呼叫順序就是本配置類程式碼的配置順序)
        registry.addInterceptor(loginedAuthInterceptor).addPathPatterns(apiUri);
    }

}

最後

讀完文章你會發現,文章跟前兩遍文章對攔截器的使用上基本上沒有什麼創新,只是在使用例子也就是業務的邏輯上程式碼的變化,其實是的,攔截器使用起來還是蠻簡單的,但是該在什麼地方去使用它,這個還是要過考慮下的,所以在這篇文章中我們主要是以實際開發中所用到的問題做舉例,這可能引出你對攔截器更好使用的一些想法,希望你在以後的使用中能夠更好的利用攔截器的特性,寫出更美觀、更好維護的程式碼O(∩_∩)O~

歡迎關注我們的公眾號或加群,等你哦!

相關推薦

企業實戰Spring攔截統一引數

在前面的一些文章中我們有講到,通過攔截器我們可以做很多的事情,包括介面統一的 引數校驗、 登入校驗、許可權校驗等,也可以做一些HTTP響應體寫入邏輯,比如我們另一篇文章所說的《解決跨域問題》,本篇我們也就是講解下,使用攔截器對開放的介面做公共引數校驗功能實現。

企業實戰spring專案《介面響應體格式統一封裝》

前言 在之前的文章中我們有介紹過,如何更好、更簡單的寫好一個介面(介面返回值篇),今天的這篇文章我們主要介紹,怎麼統一處理下介面的返回格式問題。 ###問題分析 我們先來分析下我們所面臨的問題在哪裡,然後接著給出解決方案。在寫一個介面時,我們通常會先統一定義一下

企業實戰切面程式設計《統一列印日誌》

前言 面向切面程式設計是spring裡一種很不錯的程式設計思想,簡單來講就是可以將一段功能程式碼在程式執行時,動態地將該段程式碼切入到目標方法前或後插入去執行,這種方式可以實現程式碼的可插拔性,之前我們在攔截器實戰篇中說過的攔截器其實就是切面程式設計的一種實現

spring aop攔截Controller做引數

       在專案中,我們會對入參做校驗,這些引數的校驗邏輯我們會寫很多次.能不能將這些引數的校驗邏輯提出來呢?答案是可以.Spring 有自己的validate工具方法,我個人感覺不是太好遠,想自己定製更加契合自己專案的校驗機制.經過哆哆嗦嗦的研究,有點結果,現在貼出來

springboot 統一引數配置

採坑 1號坑: 引數長度校驗時特殊字元經過url編碼時 1位變3位長度校驗會出現問題 思路 通過全域性異常處理器 來攔截引數校驗的異常 進行統一的引數校驗處理 步驟 匯入jar包 <dependency> <groupId>org.springframework.b

在springboot中使用統一引數

開發web專案有時候我們需要對controller層傳過來的引數進行一些基本的校驗,比如非空,非null,整數值的範圍,字串的個數,日期,郵箱等等。最常見的就是我們直接寫程式碼校驗,這樣以後比較繁瑣,而且不夠靈活。 Bean Validation 1.0(JSR

Springboot @Valid 用AOP統一引數以及日誌輸出

程式碼如下 package com.st.user.config; import com.alibaba.fastjson.JSONObject; import com.st.common.base.exception.helper.CompanyEnum; impor

關於怎麼解決從ajax傳入的json引數注入到Controller的接收物件 以及如何在Spring Boot專案使用引數

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <tit

Spring Boot專案使用引數

開發web專案有時候我們需要對controller層傳過來的引數進行一些基本的校驗,比如非空,非null,整數值的範圍,字串的個數,日期,郵箱等等。最常見的就是我們直接寫程式碼校驗,這樣以後比較繁瑣,而且不夠靈活。 Bean Validation 1.0(JSR-303

如何在 Spring/Spring Boot 中做引數?你需要了解的都在這裡!

本文為作者原創,如需轉載請在文首著名地址,公眾號轉載請申請開白。 springboot-guide : 適合新手入門以及有經驗的開發人員查閱的 Spring Boot 教程(業餘時間維護中,歡迎一起維護)。 資料的校驗的重要性就不用說了,即使在前端對資料進行校驗的情況下,我們還是要對傳入後端的資料再進行一

測試開發專題:如何在spring-boot中進行引數

上文我們討論了spring-boot如何去獲取前端傳遞過來的引數,那傳遞過來總不能直接使用,需要對這些引數進行校驗,符合程式的要求才會進行下一步的處理,所以本篇文章我們主要討論spring-boot中如何進行引數校驗。 ### lombok使用介紹 在介紹引數校驗之前,先來了解一下lombok的使用,因為

更加靈活的引數Spring-boot自定義引數註解

上文[測試開發專題:如何在spring-boot中進行引數校驗](https://www.immortalp.com/articles/2020/05/15/1589509696197.html),我們討論瞭如何使用@Min、@Max等註解進行引數校驗,主要是針對基本資料型別和級聯物件進行引數校驗的演示,但是

Spring Boot 攔截 請求引數MD5簽名校

攔截器定義 /** * 攔截器 請求引數簽名校驗 * Created by jiyang on 14:47 2017/12/14 */ @Component @Slf4j public class ParameterInterceptor implements Han

Spring MVC攔截配置以及統一登陸實現

攔截器概念 這裡引用百度百科裡面的說法,java裡的攔截器是動態攔截Action呼叫的物件。它提供了一種機制可以使開發者可以定義在一個action執行的前後執行的程式碼,也可以在一個action執行前阻止其執行,同時也提供了一種可以提取action中可重

精盡Spring MVC原始碼分析 - HandlerMapping 元件(二) HandlerInterceptor 攔截

> 該系列文件是本人在學習 Spring MVC 的原始碼過程中總結下來的,可能對讀者不太友好,請結合我的原始碼註釋 [Spring MVC 原始碼分析 GitHub 地址](https://github.com/liu844869663/spring-framework) 進行閱讀 > > Spring

angularinterceptors攔截

sta port 按鈕 jsonp 做的 parse 顯示 cto 響應 <!DOCTYPE html> <html ng-app="nickApp"> <head> <meta charset="UTF-8"&g

j2eestruts2攔截()

xtend 導入 ati cat imp color row 針對 所有 struts2的基本配置以及jar包的導入就不說了只寫關鍵部分: <struts> <package name="userPackage" extends="struts-

Openswan企業實戰ipsec vpn加速ERP系統

openswan ipsec vpn 公司ERP系統是放在IDC機房,租用的別人的雲服務器,因雲服務器供應商的限制,不能直接拉電路專線,又因服務器數量不夠,remoteapp方案也放棄了,只能通過軟件VPN方案來解決問題,之前搭建了一個openvpn,使用route模式,但是用戶反饋使用效果並不理

AWS企業實戰CloudFront的配置

aws cloudfront cdn akamai對於本文,開始並不打算寫出來,因為aws有非常詳細的官方文檔,但是對於我本人在使用過程中的體會來說,官網文檔並不好理解和閱讀,英文難啃,而中文翻譯往往又不是完全正確,往往給學習帶來誤解,有甄別能力的童鞋或許會提個case或者電話咨詢一下aws的工程師,而大部分

Spring 攔截——HandlerInterceptor

反向代理 實例化 自動 版本 打開 edi 允許 spring攔截器 -m 采用Spring攔截器的方式進行業務處理。HandlerInterceptor攔截器常見的用途有: 1、日誌記錄:記錄請求信息的日誌,以便進行信息監控、信息統計、計算PV(Page Vie