簡體   English   中英

如何在Spring Boot中處理DeferredResult中的異常?

[英]How to handle exception in DeferredResult in Spring Boot?

我有一個休息方法:

@RequestMapping(value = "wash/washHistory", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
    @ResponseBody
    public DeferredResult<String> getWashHistory(@RequestParam(value = "sid", required = true, defaultValue = "") String sid,
            HttpServletResponse response, HttpServletRequest request,
            @RequestParam(value = "sort", defaultValue = "") String sortType,
            @RequestParam(value = "order", defaultValue = "") String order,
            @RequestParam(value = "limit", defaultValue = "") String limit,
            @RequestParam(value = "offset", defaultValue = "") String offset) {

        System.out.println("Thread: "+Thread.currentThread());
        final Integer managerId = checkSession(sid);      
        DeferredResult<String> defResult = new DeferredResult<>();
        new Thread(() -> {
                final String result = washController.getWashHistory( managerId, order, sortType, limit, offset);
                defResult.setResult(result);            
        }).start();
    return defResult;
    }

在“getWashHistory”中我拋出以下自定義異常:

throw new InvalidUserInputException("Wrong offset", this.getClass().getSimpleName(), "getWashHist", params);

為了處理這個異常我正在使用以下類:

@ControllerAdvice
@EnableWebMvc
public class GlobalExceptionHandler {
 @ExceptionHandler(value = InvalidUserInputException.class)
    public ResponseEntity<String> invalidUserInputExc(InvalidUserInputException e) {
          logger.log("GMoika", e.error().getClassName(), e.error().getMethodName(), e.error().getParams(), e.error().getCause());
        return ResponseEntity.
                status(HttpStatus.BAD_REQUEST).
                body(e.error().getErrorCode());  
    }
}

只要我不使用DeferredResult,它就可以正常工作,但是當我想使用非阻塞方式時,會發生超時異常。 我找到了一種解決方法:

defResult.onTimeout(new Runnable() {
        @Override
        public void run() {
            defResult.setErrorResult("Explanation goes here.");
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); //or SC_NO_CONTENT
        }
    });

但它不是我正在尋找的東西,因為我用特定的構造函數拋出我自己的異常來寫入引發此異常的類內部的原因。 在GlobalExceptionHandler類中是否還有其他可能的方法來處理DeferredResult中的異常?

DeferredResult有方法setErrorResult ,它可以采用Exception並根據文檔

該值可以是Exception或Throwable,在這種情況下,它將被處理,就像處理程序引發異常一樣。

在大多數情況下@jny決定是正確的,但對我來說,我找到了另一種方法在我的休息控制器中,我添加了以下代碼:

new Thread(() -> {          
            Thread.currentThread().setUncaughtExceptionHandler(new SeparateThreadsExceptionHandler(defResult));
            final String result = washController.getWashHistory(managerId, order, sortType, limit, offset);
            defResult.setResult(result);
        }).start();

還有一個SeparateThreadsExceptionHandler類:

public class SeparateThreadsExceptionHandler implements Thread.UncaughtExceptionHandler{
    private DeferredResult<String> dr;
    public SeparateThreadsExceptionHandler(DeferredResult<String> dr){
        this.dr = dr;
    }
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        if(e instanceof InvalidUserInputException){
           InvalidUserInputException throwableException =  (InvalidUserInputException)e;
            dr.setResult(throwableException.error().getErrorCode());
        } else {
            dr.setResult(UnknownException.UNKNOWN_ERROR_CODE);
        }
    }

}

當我拋出自定義異常時,我可以為DeferredResult設置一些字符串錯誤消息。 在我的例子中,它是前端的錯誤代碼。

在GlobalExceptionHandler類中是否還有其他可能的方法來處理DeferredResult中的異常

我使用了@jny指出的setErrorResult方法

這是我的控制器方法的主體:

DeferredResult<Wrapper<Object>> deferredResult = new DeferredResult<>();

ForkJoinPool.commonPool().submit(() -> {
    try {
        Wrapper<Object> response = ...
        deferredResult.setResult(response);
    } catch (Exception e) {
        deferredResult.setErrorResult(e);
    }
});

return deferredResult;

在這種情況下,新線程中拋出的異常被傳遞給global @ExceptionHandler

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM