【问题标题】:How can I make a Spring Converter throw a custom exception instead of a ConversionFailedException?如何让 Spring Converter 抛出自定义异常而不是 ConversionFailedException?
【发布时间】:2018-07-09 13:02:27
【问题描述】:

我的代码库中有一堆自定义弹簧转换器,例如:

public class ElasticSearchConverter implements Converter<RequestModel, ResponseModel> {
  @Override
  public final ResponseModel convert(RequestModel requestModel) {
    if(!requestModel.isValid()) {
      throw new ElasticSearchException("Request Model is not valid");
    }

    ... Implement converter
  }
}

我使用 spring ConversionService 从服务中调用这些转换器

@Service
public class ElasticService {
  @Autowired
  private ConversionService conversionService;

  public ResponseModel getResponse(RequestModel requestModel) {

    //Throws ConversionFailedException instead of ElasticSearchException
    ResponseModel responseModel = conversionService.convert(requestModel, ResponseModel.class);

    return responseModel;
  }
}

我的问题是,当我将ElasticSearchException 扔进我的ElasticSearchConverter 中时,它会被困在弹簧ConversionUtils 类中并转换为ConversionFailedException。我想捕捉我在转换器中投入的特定ElasticSearchException

如何从我的服务类中的 spring Converter 类中捕获特定异常?

【问题讨论】:

    标签: java spring spring-mvc spring-boot converter


    【解决方案1】:

    您需要实现将处理您的异常的类

    @ControllerAdvice
    public class ExceptionTranslator {
    
    
        @ExceptionHandler(ConversionFailedException.class) //handle your Exception
        @ResponseStatus(HttpStatus.BadRequest) // Define the status you want to return
        @ResponseBody
        public ErrorDTO processElasticSearchException(ConversionFailedException ex) {
            return new ErrorDTO(); 
            /* Format your response as you need*/
        }
    }
    

    @ControllerAdvice“带有(注解)的类可以显式声明为 Spring bean 或通过类路径扫描自动检测”show documentation
    @ExceptionHandler 定义了您要捕获的异常
    @ResponseStatus定义http响应状态
    @ResponseBody序列化自动响应为json对象

    对于我的项目,我定义了一个 ErrorDTO 来格式化响应,你可以这样做,你只需要构造你的对象并返回它
    您也可以将要执行的代码放入该方法中,并在需要时引发其他异常

    【讨论】:

    • 不幸的是,因为 conversionService.convert 只抛出 ConversionFailedException 这对我没有帮助。我确实有一个带有 @ExceptionHandler(ElasticSearchException.class) 的 ControllerAdvice,但它从未被调用,因为它只看到 ConversionFailedException
    • 您是否尝试处理 ConversionFailedException 而不是 ElasticSearchException?
    • 是的,这行得通。但我试图捕捉特定的异常并以不同的方式处理它们,而不是笼统地捕捉 ConversionFailedException 并将该异常转换为正确的异常。
    • 我不知道它是否可以帮助您,但您可以从参数异常中获取错误消息以获取更多详细信息。您还可以使用 try catch 块捕获 ConversionFailedException 并将您自己的异常抛出到 catch 块中
    • 不幸的是,这是我试图避免的,我想单独捕获每个异常,而不必重新抛出
    【解决方案2】:

    您可以编写一个简单的适配器类来包装 Spring ConversionService。在该类中,您将拥有一个 convert() 方法,该方法委托给 try/catch 中包装的 ConversionService 方法,捕获 ConversionFailedException,检查它(例如使用 getRootCause())并作为您选择的异常重新抛出。然后对于所有将使用 ConversionService 的类,您将使用您的包装类。

    【讨论】:

    • 你可以通过提供一个代码示例来改进你的答案,很多人都懒得看解释。
    【解决方案3】:

    您违反了Single Responsibility Principle。验证转换后的对象不是转换器的工作。如果您能够成功进行转换,则应使用here 中描述的一种方式单独进行验证。

    例如,假设您将字符串转换为纬度。如果字符串可以解析成双精度,转换器应该很高兴。如果要验证双精度值是否在 [-90,+90] 范围内,则应在验证器而非转换器中进行。

    当您处理异常时,例如@ControllerAdvice,不要混淆不同的关注点会有很大帮助。

    【讨论】:

    • 例如,如果您想将某些内容转换为枚举会发生什么?
    • @LakatosGyula Spring 可以根据名称转换枚举,您不必这样做。自己试试吧。
    猜你喜欢
    • 1970-01-01
    • 2017-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-27
    • 2021-03-11
    • 2017-04-20
    相关资源
    最近更新 更多