成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

實戰技巧!Spring Boot 非常有用的五個開發技巧,請收藏

開發 開發工具
Spring提供一個專門處理異步請求的攔截器AsyncWebRequestInterceptor,該接口包含一個在處理異步請求期間被調用的回調方法。

環境:SpringBoot3.2.5

1. 獲取請求/響應對象

在編寫Controller中,我們通常可以通過如下的2種方式直接獲取Request和Response對象,如下示例:

@RestController
public class UserController {
  private final HttpServletRequest request ;
  private final HttpServletResponse response ;
  public ContextFilterController(HttpServletRequest request, HttpServletResponse response) {
    this.request = request;
    this.response = response;
  }
}

直接在Controller中注入對象,你也可以在方法參數中獲取:

@GetMapping
public ResponseEntity<Object> query(HttpServletRequest request, 
  HttpServletResponse response)
  // ...
}

如果你需要在其它組件中獲取該對象,如果通過方法參數傳遞那就太麻煩了,這時候我們就可以使用如下方式:

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes() ;
HttpServletRequest request = attributes.getRequest() ;
HttpServletResponse response = attributes.getResponse() ;

直接通過ThreadLocal獲取,而這個數據的存入則是由DispatcherServlet完成,不過默認還有一個RequestContextFilter也會做這個事,但是會被該Servlet覆蓋。

ThreadLocal綁定當前線程,如果遇到子線程怎么辦呢?

如果希望在子線程中也能獲取當前上下文,那么你需要進行如下的配置才可:

@Bean(name = "dispatcherServletRegistration")
DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
    WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
  DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
      webMvcProperties.getServlet().getPath());
  // 設置從父線程中繼承
  dispatcherServlet.setThreadContextInheritable(true) ;
  // ...
  return registration;
}

測試接口

@GetMapping
public ResponseEntity<Object> context() throws Exception {
  ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes() ;
  HttpServletRequest request = attributes.getRequest() ;
  HttpServletResponse response = attributes.getResponse() ;
  System.err.printf("%s - %s, %s%n", Thread.currentThread().getName(), request, response) ;
  Thread t = new Thread(() -> {
    ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes() ;
    HttpServletRequest req = attr.getRequest() ;
    HttpServletResponse resp = attr.getResponse() ;
    System.err.printf("%s - %s, %s%n", Thread.currentThread().getName(), req, resp) ;
  }, "T1") ;
  t.start() ;
  return ResponseEntity.ok("success") ;
}

控制臺輸出如下

圖片圖片

成功獲取。

警告!如下方式操作,你將收獲一個錯誤

Thread t = new Thread(() -> {
  try {
    TimeUnit.SECONDS.sleep(1) ;
  } catch (Exception e) {
    e.printStackTrace();
  }
  ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes() ;
  HttpServletRequest req = attr.getRequest() ;
  System.err.println(req.getParameter("token")) ;
}, "T1") ;

如上代碼,休眠1s后,在從request中獲取數據,將拋出如下錯誤

圖片圖片

這是因為主線程已經將Request,Response對象回收了。

總結:不建議開啟子線程共享。

2. 異步攔截器

Spring提供一個專門處理異步請求的攔截器AsyncWebRequestInterceptor,該接口包含一個在處理異步請求期間被調用的回調方法。

當處理器開始處理異步請求時,DispatcherServlet會像平常一樣退出,而不調用postHandle和afterCompletion方法,因為請求處理的結果(例如ModelAndView)在當前線程中不可用,且處理尚未完成。在這種情況下,會調用afterConcurrentHandlingStarted(WebRequest)方法,允許實現執行諸如清理線程綁定屬性之類的任務。

當異步處理完成時,請求會被分發到容器中進行進一步處理。在這個階段,DispatcherServlet會像平常一樣調用preHandle、postHandle和afterCompletion方法。

public class LogInterceptor implements AsyncWebRequestInterceptor {


  // 請求一開始會執行一次
  @Override
  public void preHandle(WebRequest request) throws Exception {
    System.err.printf("AsyncWebRequestInterceptor >>> %s, %s, 開始處理%n", System.currentTimeMillis(), Thread.currentThread().getName()) ;
  }
  // 當異步請求結束時執行
  @Override
  public void postHandle(WebRequest request, ModelMap model) throws Exception {
    System.err.printf("AsyncWebRequestInterceptor >>> %s, postHandle%n", Thread.currentThread().getName()) ;
  }
  // 當異步請求結束時執行
  @Override
  public void afterCompletion(WebRequest request, Exception ex) throws Exception {
    System.err.printf("AsyncWebRequestInterceptor >>> %s afterCompletion%n", Thread.currentThread().getName()) ;
  }
  // 異步請求開始時執行
  @Override
  public void afterConcurrentHandlingStarted(WebRequest request) {
    System.err.printf("AsyncWebRequestInterceptor >>> %s, %s, 異步處理%n", System.currentTimeMillis(), Thread.currentThread().getName()) ;
  }
}

注冊異步攔截器:

@Component
public class WebInterceptorConfig implements WebMvcConfigurer{
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addWebRequestInterceptor(new LogInterceptor()).addPathPatterns("/admin/**") ;
  }
}

下面通過如下異步接口進行測試

@GetMapping("/async")
public Callable<String> async() {
  System.err.println("async interface...") ;
  return new Callable<String>() {
    public String call() throws Exception {
      System.err.printf("%s, %s - 執行任務%n", System.currentTimeMillis(), Thread.currentThread().getName()) ;
      TimeUnit.SECONDS.sleep(3) ;
      return "異步數據" ;
    }
  };
}

輸出結果

圖片圖片

等待異步處理完成以后再執行preHandle、postHandle和afterCompletion方法。

實際整個異步請求從開始到結束,preHandle是執行了兩回。

3. 獲取當前請求相關信息

Spring MVC在處理一個請求時,會為我們做很多的事,其中會往Request對象設置一些非常有用的數據,如下所示:

獲取當前的請求路徑

String key = ServletRequestPathUtils.PATH ;
String requestPath = request.getAttribute(key) ;

獲取當前請求最佳匹配的路徑(Controller中定義的路徑)

String key = HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE;
String pathPattern = request.getAttribute(key) ;

返回:/params/{type}/{id}

獲取當前請求中的路徑參數值

String key = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE ;
String pathPattern = request.getAttribute(key) ;

返回:{id=666, type=s0}

4. 類型轉換器注冊方式

Spring 本身提供了非常多的類型轉換器,絕大多數情況下我們是不需要再自定義類型轉換器的。如果確實需要自定義類型轉換器,那么我們通常會通過如下的方法進行注冊自定義的轉換器:

@Component
public class TypeConvertConfig implements WebMvcConfigurer {


  @Override
  public void addFormatters(FormatterRegistry registry) {
    registry.addConverter(new EnumConverter()) ;
  }
}

感覺是不是有點麻煩。其實我們可以直接定義類型轉換器為Bean對象即可,并且支持:GenericConverterConverterPrinterParser類型的轉換器。

@Component
public class EnumConverter implements Converter<Sex, Integer> {


  public Integer convert(Sex source) {
    if (source == null) {
      return 0 ;
    }
    return source.getCode() ;
  }
}

注意:這里的自定義轉換器并不支持有關屬性配置的類型轉換。

5. 接口不存在時特殊處理

當我們訪問的接口不存在時,默認輸出如下:

圖片圖片

或者我們也可以在如下位置提供對應的404.html或4xx.html頁面

圖片圖片

如上位置添加頁面后,當出現404錯誤,將會調轉到該頁面。

其實,我們還可以通過如下全局異常的方式處理404錯誤,默認如果出現404錯誤會拋出NoHandlerFoundException異常。

@RestControllerAdvice
public class GlobalExceptionAdvice {


  @ExceptionHandler(NoHandlerFoundException.class)
  public ResponseEntity<Object> noHandlerFount(NoHandlerFoundException e) {
    return ResponseEntity.ok(Map.of("code", -1, "message", "接口不存在")) ;
  }
}

當發生404后,頁面展示:

圖片圖片


責任編輯:武曉燕 來源: Spring全家桶實戰案例源碼
相關推薦

2020-10-29 10:00:55

Python函數文件

2023-02-19 15:22:22

React技巧

2020-06-15 10:29:10

JavaScript開發 技巧

2009-02-09 11:20:06

Windows7Windows

2025-04-07 02:33:00

項目開發Spring

2022-06-27 19:01:04

Python應用程序數據

2025-02-21 16:00:00

SpringBoot代碼開發

2020-05-28 08:59:40

Python機器學習開發

2022-05-10 09:33:50

Pandas技巧代碼

2023-09-21 12:37:34

IDEA

2009-03-24 14:23:59

PHP類庫PHP開發PHP

2011-07-07 17:16:43

PHP

2017-08-02 13:32:18

編程Java程序片段

2012-04-17 09:44:08

JavaScript

2015-08-12 11:09:42

開發者設計原則

2024-11-19 15:22:37

2025-06-11 09:28:22

2012-05-25 14:20:08

JavaScript

2023-06-13 15:15:02

JavaScript前端編程語言

2018-08-03 10:02:05

Linux命令
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲高清在线 | 国产精品视频区 | 99这里只有精品视频 | 成人国产精品 | 日本视频免费观看 | 一区二区久久电影 | 国产视频中文字幕在线观看 | 午夜视频一区 | 激情欧美日韩一区二区 | 久久国产精品久久 | 日韩电影中文字幕 | pacopacomama在线| 国产精品黄视频 | 国产精品无码久久久久 | 日韩网站在线观看 | 亚洲一区精品在线 | 99精品视频在线观看免费播放 | 99国产欧美| 亚洲 欧美 另类 综合 偷拍 | 国产精品久久久久久久久久久新郎 | 亚洲一区中文字幕在线观看 | 三级黄视频在线观看 | 毛片毛片毛片毛片 | 欧美日韩成人一区二区 | 亚洲网站在线播放 | 亚洲国产成人精品一区二区 | 91精品国产综合久久久久久漫画 | 午夜影院 | 狠狠狠干 | 在线观看免费av片 | 亚洲欧美在线一区 | 羞羞色网站| 成人免费视频久久 | 国产免费一区二区三区网站免费 | 国产成人小视频 | 综合九九 | 伊人免费视频二 | 欧美日韩在线播放 | 麻豆精品一区二区三区在线观看 | 日本精品一区二区 | 欧美日韩视频在线 |