成人免费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

2011-07-07 17:16:43

PHP

2017-08-02 13:32:18

編程Java程序片段

2009-03-24 14:23:59

PHP類庫PHP開發PHP

2012-04-17 09:44:08

JavaScript

2015-08-12 11:09:42

開發者設計原則

2012-05-25 14:20:08

JavaScript

2022-09-02 23:08:04

JavaScript技巧開發

2009-05-18 16:58:56

Java代碼片段

2018-08-03 10:02:05

Linux命令

2023-06-13 15:15:02

JavaScript前端編程語言
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产高清视频在线播放 | 亚洲高清在线观看 | 欧美激情一区 | 欧美三级成人理伦 | 日日夜夜精品视频 | 国产一区二区三区在线 | 日韩中文一区二区 | 久久亚洲一区二区三区四区 | 成人欧美一区二区三区1314 | 国产精品日韩在线观看 | 嫩草研究影院 | 成人在线一区二区三区 | 国产你懂的在线观看 | 国产丝袜一区二区三区免费视频 | 欧美精选一区二区 | 欧美日韩成人影院 | 久久久久www| 日韩欧美在线视频 | 久久精品毛片 | 国产色网站 | 中文福利视频 | 国产污视频在线 | 国产乱码久久久 | av毛片| 午夜爱爱毛片xxxx视频免费看 | 欧美成人第一页 | 国产区高清 | 九色www| 91偷拍精品一区二区三区 | 黄色av免费 | 国产综合欧美 | 久久久久久久久99 | 国产欧美性成人精品午夜 | 国产成人影院 | 无人区国产成人久久三区 | 亚洲一区二区精品视频在线观看 | 成人欧美一区二区 | 综合亚洲视频 | 日本高清视频在线播放 | 欧洲毛片| 国产在线一区二区三区 |