自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

實(shí)戰(zhàn)技巧!Spring Boot 非常有用的五個(gè)開發(fā)技巧,請(qǐng)收藏

開發(fā) 開發(fā)工具
Spring提供一個(gè)專門處理異步請(qǐng)求的攔截器AsyncWebRequestInterceptor,該接口包含一個(gè)在處理異步請(qǐng)求期間被調(diào)用的回調(diào)方法。

環(huán)境:SpringBoot3.2.5

1. 獲取請(qǐng)求/響應(yīng)對(duì)象

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

@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中注入對(duì)象,你也可以在方法參數(shù)中獲?。?/span>

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

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

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

直接通過ThreadLocal獲取,而這個(gè)數(shù)據(jù)的存入則是由DispatcherServlet完成,不過默認(rèn)還有一個(gè)RequestContextFilter也會(huì)做這個(gè)事,但是會(huì)被該Servlet覆蓋。

ThreadLocal綁定當(dāng)前線程,如果遇到子線程怎么辦呢?

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

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

測(cè)試接口

@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") ;
}

控制臺(tái)輸出如下

圖片圖片

成功獲取。

警告!如下方式操作,你將收獲一個(gè)錯(cuò)誤

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中獲取數(shù)據(jù),將拋出如下錯(cuò)誤

圖片圖片

這是因?yàn)橹骶€程已經(jīng)將Request,Response對(duì)象回收了。

總結(jié):不建議開啟子線程共享。

2. 異步攔截器

Spring提供一個(gè)專門處理異步請(qǐng)求的攔截器AsyncWebRequestInterceptor,該接口包含一個(gè)在處理異步請(qǐng)求期間被調(diào)用的回調(diào)方法。

當(dāng)處理器開始處理異步請(qǐng)求時(shí),DispatcherServlet會(huì)像平常一樣退出,而不調(diào)用postHandle和afterCompletion方法,因?yàn)檎?qǐng)求處理的結(jié)果(例如ModelAndView)在當(dāng)前線程中不可用,且處理尚未完成。在這種情況下,會(huì)調(diào)用afterConcurrentHandlingStarted(WebRequest)方法,允許實(shí)現(xiàn)執(zhí)行諸如清理線程綁定屬性之類的任務(wù)。

當(dāng)異步處理完成時(shí),請(qǐng)求會(huì)被分發(fā)到容器中進(jìn)行進(jìn)一步處理。在這個(gè)階段,DispatcherServlet會(huì)像平常一樣調(diào)用preHandle、postHandle和afterCompletion方法。

public class LogInterceptor implements AsyncWebRequestInterceptor {


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

注冊(cè)異步攔截器:

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

下面通過如下異步接口進(jìn)行測(cè)試

@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 - 執(zhí)行任務(wù)%n", System.currentTimeMillis(), Thread.currentThread().getName()) ;
      TimeUnit.SECONDS.sleep(3) ;
      return "異步數(shù)據(jù)" ;
    }
  };
}

輸出結(jié)果

圖片圖片

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

實(shí)際整個(gè)異步請(qǐng)求從開始到結(jié)束,preHandle是執(zhí)行了兩回。

3. 獲取當(dāng)前請(qǐng)求相關(guān)信息

Spring MVC在處理一個(gè)請(qǐng)求時(shí),會(huì)為我們做很多的事,其中會(huì)往Request對(duì)象設(shè)置一些非常有用的數(shù)據(jù),如下所示:

獲取當(dāng)前的請(qǐng)求路徑

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

獲取當(dāng)前請(qǐng)求最佳匹配的路徑(Controller中定義的路徑)

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

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

獲取當(dāng)前請(qǐng)求中的路徑參數(shù)值

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

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

4. 類型轉(zhuǎn)換器注冊(cè)方式

Spring 本身提供了非常多的類型轉(zhuǎn)換器,絕大多數(shù)情況下我們是不需要再自定義類型轉(zhuǎn)換器的。如果確實(shí)需要自定義類型轉(zhuǎn)換器,那么我們通常會(huì)通過如下的方法進(jìn)行注冊(cè)自定義的轉(zhuǎn)換器:

@Component
public class TypeConvertConfig implements WebMvcConfigurer {


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

感覺是不是有點(diǎn)麻煩。其實(shí)我們可以直接定義類型轉(zhuǎn)換器為Bean對(duì)象即可,并且支持:GenericConverter,ConverterPrinter,Parser類型的轉(zhuǎn)換器。

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


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

注意:這里的自定義轉(zhuǎn)換器并不支持有關(guān)屬性配置的類型轉(zhuǎn)換。

5. 接口不存在時(shí)特殊處理

當(dāng)我們?cè)L問的接口不存在時(shí),默認(rèn)輸出如下:

圖片圖片

或者我們也可以在如下位置提供對(duì)應(yīng)的404.html或4xx.html頁(yè)面

圖片圖片

如上位置添加頁(yè)面后,當(dāng)出現(xiàn)404錯(cuò)誤,將會(huì)調(diào)轉(zhuǎn)到該頁(yè)面。

其實(shí),我們還可以通過如下全局異常的方式處理404錯(cuò)誤,默認(rèn)如果出現(xiàn)404錯(cuò)誤會(huì)拋出NoHandlerFoundException異常。

@RestControllerAdvice
public class GlobalExceptionAdvice {


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

當(dāng)發(fā)生404后,頁(yè)面展示:

圖片圖片


責(zé)任編輯:武曉燕 來源: Spring全家桶實(shí)戰(zhàn)案例源碼
相關(guān)推薦

2020-10-29 10:00:55

Python函數(shù)文件

2023-02-19 15:22:22

React技巧

2020-06-15 10:29:10

JavaScript開發(fā) 技巧

2009-02-09 11:20:06

Windows7Windows

2025-04-07 02:33:00

項(xiàng)目開發(fā)Spring

2022-06-27 19:01:04

Python應(yīng)用程序數(shù)據(jù)

2025-02-21 16:00:00

SpringBoot代碼開發(fā)

2020-05-28 08:59:40

Python機(jī)器學(xué)習(xí)開發(fā)

2022-05-10 09:33:50

Pandas技巧代碼

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

開發(fā)者設(shè)計(jì)原則

2009-03-24 14:23:59

PHP類庫(kù)PHP開發(fā)PHP

2023-09-21 12:37:34

IDEA

2012-05-25 14:20:08

JavaScript

2022-09-02 23:08:04

JavaScript技巧開發(fā)

2009-05-18 16:58:56

Java代碼片段

2024-11-19 15:22:37

2023-06-13 15:15:02

JavaScript前端編程語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)