国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術|正則表達式|

服務器之家 - 編程語言 - JAVA教程 - SpringCloud通用請求字段攔截處理方法

SpringCloud通用請求字段攔截處理方法

2020-07-08 14:25清茶豆奶 JAVA教程

這篇文章主要介紹了SpringCloud通用請求字段攔截處理,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

背景

SpringCloud構建的微服務系統為例,使用前后端分離的架構,每個系統都會提供一些通用的請求參數,例如移動端的系統版本信息、IMEI信息,Web端的IP信息,瀏覽器版本信息等,這些參數可能放在header里,也可以放在參數里,如果這些參數需要在每個方法內聲明定義,一來工作量太大,二是這些通用參數與業務接口方法耦合過緊,本身就是一個不好的設計。

這個問題該如何優雅地解決呢?

最佳實踐

  • 利用SpringMVC提供攔截器,對匹配的請求,抽取通用的header信息(假設通用字段全部放在header里)
  • 將每個請求的信息單獨隔離開,互不干擾。
  • Controller層使用時,可以將在該請求線程(http線程)里將通用的header信息提取出來使用。
  • 請求線程完成時,相應的header頭信息對象需要回收銷毀。
  • 實現方式SpringMVA提供的HandlerInterceptorAdapter可以拿來使用,繼承實現即可。
  • 使用ThreadLocal記錄每個請求的信息,ThreadLocal有隔離線程變量的作用。

HandlerInterceptorAdapter的源碼實現及注釋

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
    // 在業務接口方法處理之前被調用,可以在這里對通用的header信息進行提取
        return true;
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable ModelAndView modelAndView) throws Exception {
        // 這個方法在業務接口方法執行完成后,生成SpringMVC ModelAndView之前被調用
        // 今天這個案例我們不用此方法,故可以不實現。
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable Exception ex) throws Exception {
        // 這個方法在DispatcherServlet完全處理完成后被調用,可以在這里對ThreadLocal的內容進行釋放
    }
 
    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response,
            Object handler) throws Exception {
        // 這個方法用來處理異步主動,但也會先行調用preHandle,然后執行此方法,異步線程完成后會執行postHandle和afterCompletion兩方法,這里暫時用不上。
    }
}

ThreadLocal的源碼主要實現及注釋

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class ThreadLocal<T> {
  
  protected T initialValue() {
    return null;
  }
 
  public T get() {
        // 獲取當前的線程
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
      ThreadLocalMap.Entry e = map.getEntry(this);
      if (e != null) {
        @SuppressWarnings("unchecked")
        T result = (T)e.value;
        return result;
      }
    }
    return setInitialValue();
  }
 
  private T setInitialValue() {
    T value = initialValue();
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
      map.set(this, value);
    else
      createMap(t, value);
    return value;
  }
 
  public void set(T value) {
        // 獲取當前的線程
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
      map.set(this, value);
    else
      createMap(t, value);
  }
 
   public void remove() {
     ThreadLocalMap m = getMap(Thread.currentThread());
     if (m != null)
       m.remove(this);
   }
 
  ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
  }
 
  void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
  }
}

簡單來說,ThreadLocal最關鍵的get()和set()方法,都是針對當前線程來操作的,調用set()方法時把值放到ThreadMap(Map的一種實現)中,以當前線程的hash值為key,get()方法則對應以當前線程作為key來取值,從而實現每個線程的數據是隔離的效果。

另附上ThreadLocal類源碼解讀的導圖,僅供參考

SpringCloud通用請求字段攔截處理方法

案例實戰

我們對實際業務系統進行簡化處理,假定header信息固定有ip,uid,deviceId三個信息,按照上文的實現思路,開始案例演示。

DTO定義

通用的header信息,使用Dto對象進行封裝:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Data
public class CommonHeader implements Serializable {
 
    private static final long serialVersionUID = -3949488282201167943L;
    
    /**
     * 真實ip
     */
    private String ip;
 
    /**
     * 設備id
     */
    private String deviceId;
 
    /**
     * 用戶uid
     */
    private Long uid;
    
    // 省略getter/setter/構造器
}

定義Request請求的封裝類Dto,并引入ThreadLocal:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
 * 將公共請求頭信息放在ThreadLocal中去
 */
public class RequestWrap {
 
    private static ThreadLocal<CommonHeader> current = new ThreadLocal<>();
 
  /**
     * 獲取靜態的ThreadLocal對象
     * @return
     */
    public static ThreadLocal<CommonHeader> getCurrent() {
        return current;
    }
    
    /**
     * 獲取ip
     * @return
     */
    public static String getIp() {
        CommonHeader request = current.get();
        if (request == null) {
            return StringUtils.EMPTY;
        }
        return request.getIp();
    }
 
    /**
     * 獲取uid
     * @return
     */
    public static Long getUid() {
        CommonHeader request = current.get();
        if (request == null) {
            return null;
        }
        return request.getUid();
    }
 
    /**
     * 獲取封裝對象
     * @return
     */
    public static CommonHeader getCommonReq() {
        CommonHeader request = current.get();
        if (request == null) {
            return new CommonHeader(StringUtils.EMPTY, StringUtils.EMPTY,0L);
        }
        return request;
    }
}

工具類

這里添加一個簡單的工具類,將HttpServletRequest通過getHeader方法,生成CommonHeader類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class HttpUtil {
    /**
     * 獲取請求頭信息
     *
     * @param request
     * @return
     */
    public static CommonHeader getCommonHeader(HttpServletRequest request) {
        String UID = request.getHeader("uid");
        Long uid = null;
        if (StringUtils.isNotBlank(UID)) {
            uid = Long.parseLong(UID);
        }
        return new CommonHeader(HttpUtil.getIp(request), request.getHeader("deviceId"), uid);
    }
 
    /**
     * 獲取IP
     *
     * @param request
     * @return
     */
    public static String getIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
 
        if (null != ip && !"".equals(ip.trim()) && !"unknown".equalsIgnoreCase(ip)) {
            int index = ip.indexOf(',');
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        }
        ip = request.getHeader("X-Real-IP");
        if (null != ip && !"".equals(ip.trim()) && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        return request.getRemoteAddr();
    }
}

攔截器類實現

最核心的實現終于出場了,這里繼承HandlerInterceptorAdapter,這里作了簡化處理:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
 * 請求頭處理
 *
 * @author yangfei
 */
@Component
public class BaseInterceptor extends HandlerInterceptorAdapter {
 
    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BaseInterceptor.class);
 
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        RequestWrap.getThreadLocal().set(HttpUtil.getCommonHeader(request));
        return true;
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
    }
 
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        RequestWrap.getThreadLocal().remove();
    }
 
    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
    }
}

如上一章節描述的邏輯,在preHandle方法內將request中的ip,uid,deviceId封裝到RequestWrap對象里,在afterCompletion中對該線程的ThreadLocal值進行釋放。

業務接口方法的使用

在Controller類的接口方法中,如要獲取uid信息,只需要調用RequestWrap.getUid()方法即可,再也不需要在每個接口上聲明uid參數了,如下示例:

?
1
2
3
4
5
6
7
/**
 * 獲取用戶基礎信息
 */
@PostMapping(value = "/user/info")
public Response<UserInfo> getUserInfo() {
    return userManager.getUserInfo(RequestWrap.getUid());
}

總結

這個實戰的目標是解決通用header信息的在接口的重復定義問題,基于HandlerInterceptorAdapter攔截器的實現,ThreadLocal對線程訪問數據的隔離來實現的,在實際生產項目應用中有很好的借鑒意義,希望對你有幫助。

到此這篇關于SpringCloud通用請求字段攔截處理方法的文章就介紹到這了,更多相關SpringCloud請求字段攔截內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/huangying2124/p/13264753.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美一区二区三区在线观看视频 | 天堂av在线免费观看 | 亚洲精品一级 | 国产精品综合久久 | 伦理午夜电影免费观看 | 97色婷婷成人综合在线观看 | 欧美va视频 | 国产精品毛片久久久久久久 | 国产精品视频免费 | 亚洲免费视频一区二区 | 亚洲精品在线视频 | 国产成人午夜 | 天堂av在线免费观看 | 一级特黄录像免费播放全99 | 色欧美片视频在线观看 | 久久99精品久久久久久国产越南 | 国产久 | 欧美日本韩国一区二区 | 国产目拍亚洲精品99久久精品 | 欧美成人免费 | 日韩大片免费看 | 污污视频网站免费 | 黄色电影免费在线观看 | 久久免费99精品久久久久久 | 久久久夜色精品亚洲 | 国产精品久久久久久久久久99 | 中文字幕成人 | 九色在线 | 激情综合网激情 | 日韩亚洲 | 亚洲一区二区美女 | 国产精品69毛片高清亚洲 | 91精品国产综合久久久久久 | 精品视频久久 | 日操干 | 毛片真人毛毛片毛片 | 亚洲一区二区 | 午夜视频在线免费观看 | 成人免费网视频 | 亚洲一区二区三区四区五区午夜 | 一区二区国产在线观看 |