当前位置: 首页 > 知识库问答 >
问题:

处理从自定义转换器引发的Spring Boot REST中的异常

萧懿轩
2023-03-14

我是Spring Boot的新手,但在阅读了Spring Boot REST中关于异常handlig的帖子和博客几个小时之后,我决定在这里写一些关于如何处理自定义转换器抛出的异常的文章。

我开发了一个基于Spring Boot的小型REST应用程序,简单地从IntelliJ生成。示例性方法如下所示

@RestController
@RequestMapping("/resources")
public class CVResourceService {

    private final TechnologyRepository technologyRepository;
    private final ProjectRepository projectRepository;

    @Autowired
    public CVResourceService(TechnologyRepository technologyRepository,     ProjectRepository projectRepository) {
        this.technologyRepository = technologyRepository;
        this.projectRepository = projectRepository;
    }

    @RequestMapping(value = "/users/{guid}/projects/langs/{lang}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public Collection getUserProjects(@PathVariable("guid") GUID userGUID,         @PathVariable("lang") Language language) {
        return  ProjectDTOAssembler.toDTOs(projectRepository.findOne(userGUID, language));
    }
}
public final class GUIDConverter implements Converter{

    @Override
    public GUID convert(String source) {
        return GUID.fromString(source);
    }
}

public class LanguageConverter implements Converter{

    @Override
    public Language convert(String source) {
        Language language = Language.of(source);
        if (language == null) { throw new WrongLanguagePathVariableException(); }

        return language;
    }
}
...
public static GUID fromString(String string) {
    String[] components = string.split("-");

    if (components.length != 5)
        throw new IllegalArgumentException("Invalid GUID string: " + string);

    return new GUID(string);
}
...
@SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {

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

    public static void main(String[] args) {
       SpringApplication.run(Application.class, args);
   }
}

使用@responsestatus@controlleradvice@expectationhandler的所有类型的处理异常,我无法捕获控制器中转换器的异常,从而将json错误响应原始字段的“status”、“error”、“exception”和“message”重写(或更好地映射)到我的值。可能是因为异常是在调用REST方法之前抛出的。我尝试了ResponseEntityExceptionHandler解决方案,但它根本不起作用。

对于正确的语言为en请求http://localhost:8080/resources/users/620e643f-406f-4c69-3f4c-3f2c303f3f3f/projects/langs/end,异常响应为:

{
    "timestamp": 1458812172976,
    "status": 400,
    "error": "Bad Request",
    "exception":   "org.springframework.web.method.annotation.MethodArgumentTypeMismatchException",
    "message": "Failed to convert value of type [java.lang.String] to required type [com.cybercom.cvdataapi.domain.Language]; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.PathVariable com.cybercom.cvdataapi.domain.Language] for value 'end'; nested exception is com.cybercom.cvdataapi.interfaces.rest.converter.WrongLanguagePathVariableException",
    "path": "/resources/users/620e643f-406f-4c69-3f4c-3f2c303f3f3f/projects/langs/end"

}

其中自定义异常仅在message字段的最后一个位置,但当然应该与我的自定义消息交换。自定义异常应该在exception字段中,现在是Spring exception。当然,这是目标,但不知道如何在这种情况下实现它。

请解决我的问题:捕获从转换器抛出的异常并将它们映射成@controlleradvice和从控制器抛出的异常。Thx提前。

共有1个答案

冷正信
2023-03-14

您是对的-@controlleradvice等只捕获源自Controller方法内部的异常-老实说,我发现需要花点心思来理解所有的错误处理,并组合出一致的错误处理方法(而不必在不同的地方重复错误处理)。

因为在我的应用程序中,我不可避免地需要捕获像这些(或自定义404等)在控制器之外的错误,所以我只需要进行应用程序范围的错误映射--假设您在应用程序中定义了main()方法,就可以将应用程序作为一个JAR运行。

为了可读性,我希望有一个特定的错误配置文件,但如果需要,您可以将它定义为配置中的一个普通bean

@Configuration
class ErrorConfiguration implements EmbeddedServletContainerCustomizer {

   /**
     * Set error pages for specific error response codes
     */
   @Override public void customize( ConfigurableEmbeddedServletContainer container ) {
       container.addErrorPages( new ErrorPage( HttpStatus.NOT_FOUND, "/errors/404" ) )
   }

}

您可以根据特定的异常类型和Http响应代码映射错误页,所以它相当灵活--但我通常所做的是定义自定义异常并将Http响应代码附加到异常--这样我就可以在错误配置中映射HttpStatus代码,然后如果我想在代码中的任何地方,对于exaple,404请求,我可以抛出新的PageNotFoundException()(但这是个人偏好)。

@ResponseStatus(value = HttpStatus.NOT_FOUND)
class PageNotFoundException extends Exception { }

映射路径(在上面的示例“/errors/404”中)映射到一个普通控制器,这很好,因为它允许您对给定的错误进行任何错误日志记录/处理/电子邮件等操作--其缺点是,由于它是一个处理错误的标准控制器,您可能会有一个像/errors/404这样的暴露endpoint--这并不理想(有几个选项--模糊URL以便不太可能被发现,或者使用类似apache的东西来阻止对这些endpoint的直接访问等)

我在这里简要地介绍了它--包括在传统的tomcat服务器中作为WAR托管应用程序时它是如何工作的细节

 类似资料:
  • 我正试图自己解决参数问题。 我可以很容易地从NativeWebRequest获取输入参数,并将它们分派到相应的自定义@Param注释参数中。 问题是我还想在这方面做一些语法检查/验证。但如果我在“resolveArgument”中抛出异常,则会向用户显示完整的堆栈跟踪。这将是过度和不安全的。我只想向用户返回一条JSON格式的消息,以显示哪个输入参数语法有错误。

  • 我是Spring Security的新手。 我有一段代码,我检查是否在请求中传递了授权头,如果缺少,我抛出一个异常。 我的目标是在全球范围内处理所有异常,因此我使用@ControllerAdvice。 注意:我知道@ControllerAdvice对于从这个和这个抛出的控制器之外的异常不起作用,所以我也遵循了这些链接中的建议。 重新验证入口点。Java语言 这是我配置authenticationE

  • 我在我的Android应用程序中使用了一个自定义的和改型客户端,它在某些特定情况下会引发异常。我正试着用Kotlin Coroutines来让它工作。

  • 我使用的是Nifi 0.4.1版本。我写自定义代码转换CSV到avro格式。我已经创建了类文件,并能够生成nar文件。将nar文件放置在lib目录中,并重新启动nifi服务器。 任何帮助都很感激.. 谢谢,

  • 我来找你是因为我需要你的帮助。 在我的文件camel-context.xml中,我调用了一个存储过程来获取用户的信息。我需要解决的是: 如果存储过程不返回数据,则发送带有超文本传输协议代码404的UserNot的异常(我已经拥有该类)。 我一直在寻找如何做这件事,但找不到任何可以帮助我的东西。我刚刚开始使用这个框架,所以提前非常感谢您的帮助。 这里我的代码:

  • 我使用netbeans创建了这个异常类: 当我尝试编译时,问题变得更加突出,在setter方法中,我得到以下消息: 错误:未报告异常异常;必须捕获或声明被抛出抛出新车辆异常(2,matricula);C:\users\ivan\desktop\examen isidrer\m03-uf5\exmaenm03uf5\src\info\infomila\vehicle.java:55:错误:未报告的异