【问题标题】:Java duplicated Exception handling in a separate methodJava 在单独的方法中重复异常处理
【发布时间】:2017-08-02 12:42:12
【问题描述】:

我正在开发一个 Spring webStart 应用程序...

我有 2 个(可能还有更多)处理多层异常子句的方法,如:

...
    try {
        employeeService.updateEmployeePartner(employeeId, partner);
        LOG.info("partner details updated for partner id {}", employeeId);
        result = new ResponseEntity<>(partner.getId(), HttpStatus.OK);
    } catch (EmployeePartnerNotFoundException ex) {
        LOG.error(ex.getMessage() + " employee id: ", employeeId);
        errorResponse = new ErrorResponse("500", ex.getMessage());
    } catch (ReadOperationDeniedException ex) {
        LOG.error("User doesn't have permissions to update employee's {} details: {}", employeeId, ex.getMessage());
        errorResponse = new ErrorResponse("403", "User doesn't have permissions to update employee's details");
    } catch (Exception ex) {
        LOG.error("something went wrong while updating employee's {} partner details: {}", employeeId, ex.getMessage());
        errorResponse = new ErrorResponse("500", "unspecified server error");
    } finally {
        result = (result != null) ? result : new ResponseEntity<>(errorResponse, HttpStatus.I_AM_A_TEAPOT); // should be INTERNAL_SERVER_ERROR
    }
...

另一个方法几乎相同,除了这个变化: employeeService.updateEmployeePartner(employeeId, partner); => employeeService.createEmployeePartner(employeeId, partner); 并在该块中捕获EmployeePartnerAlreadyExistsException

现在,为了减少代码重复,我想将所有错误处理代码集中在一个地方(方法),所以我用下面的代码替换了上面的代码

...
        try {
            employeeService.updateEmployeePartner(employeeId, partner);
            LOG.info("partner details updated for partner id {}", employeeId);
            result = new ResponseEntity<>(partner.getId(), HttpStatus.OK);
        } catch (Exception ex) {
            errorResponse = processException(ex, employeeId, "update");
        } finally {
            result = (result != null) ? result : new ResponseEntity<>(errorResponse, HttpStatus.I_AM_A_TEAPOT); // should be INTERNAL_SERVER_ERROR
        }
...
    private ErrorResponse processException(Exception ex, Long employeeId, String operation) {
        ErrorResponse errorResponse;
        if (ex.getClass().equals(EmployeePartnerNotFoundException.class) ||
                ex.getClass().equals(EmployeePartnerExistsException.class)) {
            LOG.error(ex.getMessage() + " employee id: ", employeeId);
            errorResponse = new ErrorResponse("500", ex.getMessage());
        } else if (ex.getClass().isInstance(ReadOperationDeniedException.class)) {
            LOG.error("User doesn't have permissions to " + operation + " employee's {} details: {}", employeeId, ex.getMessage());
            errorResponse = new ErrorResponse("403", "User doesn't have permissions to " + operation + " employee's details");
        } else { // Exception
            LOG.error("something went wrong while trying to " + operation + "  employee's {} partner details: {}", employeeId, ex.getMessage());
            errorResponse = new ErrorResponse("500", "unspecified server error");
        }
        return errorResponse;
    }

这是一种足够好的方法,还是有任何模式可以通过将处理外包给单独的方法/类来处理上述场景中的异常?

由于是spring应用,我也考虑使用Spring异常处理,如:

 @ExceptionHandler(Exception.class)

,但这只会满足我的部分要求。

【问题讨论】:

    标签: java spring error-handling


    【解决方案1】:

    将 @ControllerAdvice 与您的自定义 ErrorResponse 和每个 Handler 一起使用以处理单独的异常。参考Custom error response Spring

    示例代码:

        @ControllerAdvice
        public class GlobalExceptionHandlers {
    
            private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandlers.class);
    
    
            /***************** User Defined Exceptions *************************/
    
            @ExceptionHandler({ EmployeePartnerNotFoundException.class })
            public ResponseEntity<Object> handleEmployeePartnerNotFoundException(EmployeePartnerNotFoundException ex) {
    
            logger.error("EmployeePartnerNotFoundException : ", ex);
    
            ErrorResponse errorResponse = new ErrorResponse("500", ex.getMessage());
    
            return new ResponseEntity<Object>(errorResponse, new HttpHeaders(), HttpStatus.BAD_REQUEST);
            }
    
            // other exception handlers
    
    }
    

    【讨论】:

      【解决方案2】:

      这就是我最终所做的,以及Sangam的回复:

      单独的异常处理程序运行良好;请注意,无需将它们放在单独的类中。

      但我还是想知道有没有类似的模式,应用不是Spring MVC?

          public ResponseEntity<?> updatePartnerDetails(@PathVariable("employeeId") Long employeeId,
                                                        @RequestBody PersonDetails partnerDto) {
              LOG.info("Updating partner details for employee {}, partner details {}", employeeId, partnerDto);
              validateRequestValues(partnerDto);
              // Try-catches were around this call
              Person partner = PersonMapper.fromPersonDetails(partnerDto);
              employeeService.updateEmployeePartner(employeeId, partner);
              LOG.info("partner details updated for partner id {}", employeeId);
              return new ResponseEntity<>(partner.getId(), HttpStatus.OK);
          }
      
          @ResponseStatus(HttpStatus.I_AM_A_TEAPOT)  // TODO: BAD_REQUEST
          @ExceptionHandler({EmployeePartnerExistsException.class, EmployeePartnerNotFoundException.class})
          public ResponseEntity<?> employeePartnerError(Exception ex) {
              LOG.error(ex.getMessage());
              return new ResponseEntity<Object>(new ErrorResponse(400, ex.getMessage()), HttpStatus.OK);
          }
      
          @ResponseStatus(HttpStatus.I_AM_A_TEAPOT)  // TODO: BAD_REQUEST
          @ExceptionHandler(IllegalArgumentException.class)
          public ResponseEntity<?> validationError(Exception ex) {
              LOG.error(ex.getMessage());
              return new ResponseEntity<Object>(new ErrorResponse(400, ex.getMessage()), HttpStatus.OK);
          }
      
          @ResponseStatus(HttpStatus.I_AM_A_TEAPOT)  // TODO: FORBIDDEN
          @ExceptionHandler(ReadOperationDeniedException.class)
          public ResponseEntity<?> forbidden(Exception ex) {
              LOG.error("User doesn't have permissions to amend employee's details");
              return new ResponseEntity<Object>(new ErrorResponse(403, "User doesn't have permissions to amend employee's details"), HttpStatus.OK);
          }
      
          @ResponseStatus(HttpStatus.I_AM_A_TEAPOT)  // TODO: INTERNAL_SERVER_ERROR
          @ExceptionHandler(Exception.class)
          public ResponseEntity<?> unspecifiedError(Exception ex) {
              LOG.error("User doesn't have permissions to amend employee's details");
              return new ResponseEntity<Object>(new ErrorResponse(500, "Something went wrong while editing employee's details"), HttpStatus.OK);
          }
      

      【讨论】:

      • ControllerAdvice 比在同一个控制器中定义异常处理程序更好。因为 ExceptionHandler 注解的方法只对特定的 Controller 有效,而不是对整个应用程序全局有效。当然,将它添加到每个控制器会使其不太适合一般的异常处理机制。
      猜你喜欢
      • 1970-01-01
      • 2015-05-21
      • 1970-01-01
      • 2015-09-11
      • 1970-01-01
      • 1970-01-01
      • 2011-05-01
      • 2012-04-08
      • 2013-03-15
      相关资源
      最近更新 更多