التعامل مع الاستثناءات في أدوات التحكم في الربيع

صورة



من الناحية العملية ، غالبًا ما يكون من الضروري معالجة الاستثناءات مركزيًا داخل وحدة تحكم أو حتى تطبيق بأكمله. في هذه المقالة ، سنحلل الميزات الرئيسية التي يوفرها Spring Framework لحل هذه المشكلة ، وباستخدام أمثلة بسيطة ، دعنا نرى كيف يعمل كل شيء. من يهتم بهذا الموضوع - مرحبًا بك تحت الخفض!



في الأصل ، قبل Spring 3.2 ، كانت الطرق الرئيسية للتعامل مع الاستثناءات في التطبيق هي HandlerExceptionResolver و ExceptionHandler الشرح التوضيحي . سنقوم بتحليلها بمزيد من التفصيل أدناه ، لكن لها بعض العيوب. بدءًا من الإصدار 3.2 ، ظهر التعليق التوضيحي ControllerAdvice ، والذي يزيل القيود من الحلول السابقة. وفي ربيع 5 ، تمت إضافة فئة ResponseStatusException جديدة والتي تكون مفيدة جدًا لمعالجة الأخطاء الأساسية لواجهات برمجة تطبيقات REST .



والآن ، أول الأشياء أولاً ، دعنا نذهب!



معالجة استثناء وحدة التحكم --ExceptionHandler



@ExceptionHandler . , , .



:



@RestController
public class Example1Controller {

    @GetMapping(value = "/testExceptionHandler", produces = APPLICATION_JSON_VALUE)
    public Response testExceptionHandler(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws BusinessException {
        if (exception) {
            throw new BusinessException("BusinessException in testExceptionHandler");
        }
        return new Response("OK");
    }

    @ExceptionHandler(BusinessException.class)
    public Response handleException(BusinessException e) {
        return new Response(e.getMessage());
    }

}


testExceptionHandler, BusinessException, — . , , .



handleException . @ExceptionHandler(BusinessException.class), BusinessException. @ExceptionHandler , : @ExceptionHandler({BusinessException.class, ServiceException.class}).



— 200 JSON . , @ResponseStatus, @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR).



:





:





@ExceptionHandler , . @ExceptionHandler , , , .



HandlerExceptionResolver



HandlerExceptionResolver Spring. HandlerExceptionResolver. , , Spring . :



ExceptionHandlerExceptionResolver @ExceptionHandler, .



DefaultHandlerExceptionResolver — Spring , :



Exception HTTP Status Code
BindException 400 (Bad Request)
ConversionNotSupportedException 500 (Internal Server Error)
HttpMediaTypeNotAcceptableException 406 (Not Acceptable)
HttpMediaTypeNotSupportedException 415 (Unsupported Media Type)
HttpMessageNotReadableException 400 (Bad Request)
HttpMessageNotWritableException 500 (Internal Server Error)
HttpRequestMethodNotSupportedException 405 (Method Not Allowed)
MethodArgumentNotValidException 400 (Bad Request)
MissingServletRequestParameterException 400 (Bad Request)
MissingServletRequestPartException 400 (Bad Request)
NoSuchRequestHandlingMethodException 404 (Not Found)
TypeMismatchException 400 (Bad Request)


, REST API . . ModelAndView, , .



ResponseStatusExceptionResolver @ResponseStatus.



ServiceException:



@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public class ServiceException extends Exception {

    public ServiceException(String message) {
        super(message);
    }

}


ServiceException @ResponseStatus value INTERNAL_SERVER_ERROR, - 500.



:



@RestController
public class Example2Controller {

    @GetMapping(value = "/testResponseStatusExceptionResolver", produces = APPLICATION_JSON_VALUE)
    public Response testResponseStatusExceptionResolver(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws ServiceException {
        if (exception) {
            throw new ServiceException("ServiceException in testResponseStatusExceptionResolver");
        }
        return new Response("OK");
    }

}


GET- exception=true, 500- :





— . , @ResponseStatus .



HandlerExceptionResolver , - JSON XML . , .



:



@Component
public class CustomExceptionResolver extends AbstractHandlerExceptionResolver {

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
        if (ex instanceof CustomException) {
            modelAndView.setStatus(HttpStatus.BAD_REQUEST);
            modelAndView.addObject("message", "CustomException was handled");
            return modelAndView;

        }
        modelAndView.setStatus(HttpStatus.INTERNAL_SERVER_ERROR);
        modelAndView.addObject("message", "Another exception was handled");
        return modelAndView;
    }

}


, . , : , ModelAndView. JSON, .



-, . . , . , — :



@RestController
public class Example3Controller {

    @GetMapping(value = "/testCustomExceptionResolver", produces = APPLICATION_JSON_VALUE)
    public Response testCustomExceptionResolver(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws CustomException {
        if (exception) {
            throw new CustomException("CustomException in testCustomExceptionResolver");
        }
        return new Response("OK");
    }

}


:





200 JSON .



@ControllerAdvice



— . Spring 3.2 @ControllerAdvice.



:



@ControllerAdvice
public class DefaultAdvice {

    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Response> handleException(BusinessException e) {
        Response response = new Response(e.getMessage());
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

}


, @ControllerAdvice , .

DefaultAdvice handleException. handleException @ExceptionHandler, , , . BusinessException.



: @ExceptionHandler({BusinessException.class, ServiceException.class}). @ExceptionHandler .

, handleException ResponseEntity Response:



public class Response {

    private String message;

    public Response() {
    }

    public Response(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}


, JSON . message HttpStatus.OK, 200.



:



@RestController
public class Example4Controller {

    @GetMapping(value = "/testDefaultControllerAdvice", produces = APPLICATION_JSON_VALUE)
    public Response testDefaultControllerAdvice(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws BusinessException {
        if (exception) {
            throw new BusinessException("BusinessException in testDefaultControllerAdvice");
        }
        return new Response("OK");
    }

}


, , JSON 200:





?

! :



@ControllerAdvice(annotations = CustomExceptionHandler.class)
public class CustomAdvice {

    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Response> handleException(BusinessException e) {
        String message = String.format("%s %s", LocalDateTime.now(), e.getMessage());
        Response response = new Response(message);
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

}


@ControllerAdvice(annotations = CustomExceptionHandler.class). CustomAdvice , @CustomExceptionHandler.



@CustomExceptionHandler :



@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomExceptionHandler {
}


:



@RestController
@CustomExceptionHandler
public class Example5Controller {

    @GetMapping(value = "/testCustomControllerAdvice", produces = APPLICATION_JSON_VALUE)
    public Response testCustomControllerAdvice(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws BusinessException {
        if (exception) {
            throw new BusinessException("BusinessException in testCustomControllerAdvice");
        }
        return new Response("OK");
    }

}


Example5Controller @CustomExceptionHandler, Example4Controller . BusinessException CustomAdvice, DefaultAdvice, .



CustomAdvice — :





. @ControllerAdvice, . .



ResponseStatusException.



ResponseStatusException:



@RestController
public class Example6Controller {

    @GetMapping(value = "/testResponseStatusException", produces = APPLICATION_JSON_VALUE)
    public Response testResponseStatusException(@RequestParam(required = false, defaultValue = "false") boolean exception) {
        if (exception) {
            throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "ResponseStatusException in testResponseStatusException");
        }
        return new Response("OK");
    }

}


ResponseStatusException , , . @ResponseStatus — -. , .



:





ملخص : لقد رأينا طرقًا مختلفة للتعامل مع الاستثناءات ، ولكل منها خصائصها الخاصة. في تطبيق كبير ، يمكنك العثور على عدة طرق في وقت واحد ، ولكن عليك أن تكون حذرًا للغاية ومحاولة عدم المبالغة في تعقيد منطق معالجة الخطأ. خلاف ذلك ، سيتضح أنه سيتم التعامل مع بعض الاستثناءات في المعالج الخطأ وستختلف الاستجابة عن الاستجابة المتوقعة. على سبيل المثال ، إذا كان للتطبيق العديد من المستشارين ، فعند إنشاء مستشار جديد ، تحتاج إلى التأكد من أنه لا يكسر الترتيب الحالي للتعامل مع الاستثناءات من وحدات التحكم القديمة.

لذا كن حذرا وكل شيء سيعمل بشكل رائع!



رابط لمصادر من المقال




All Articles