使用Spring Boot + WebFlux进行全局错误处理

时间:2019-06-26 16:58:07

标签: spring-boot exception spring-webflux project-reactor

我在问自己一个问题,在Spring Boot Rest Controller中使用反应式编程时,我们如何全局处理异常。

我认为@ControllerAdvice无法正常工作,因为我已经尝试过了,但未成功。

我的其他尝试当前是此选项: 使用自定义属性:

@Component
public class OsvcErrorAttributes extends DefaultErrorAttributes {

public OsvcErrorAttributes() {
    super(true);
}

@Override
public Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
    return assembleError(request);
}

private Map<String, Object> assembleError(ServerRequest request) {
    ServerException serverException = (ServerException)getError(request);

    Map<String, Object> errorAttributes = new HashMap<>();
    errorAttributes.put("message", serverException.getMessage());
    errorAttributes.put("errors", serverException.getErrorMap());
    return errorAttributes;
}

}

和WebExceptionHandler像这样:

@Component
@Order(-2)
public class OsvcErrorHandler extends AbstractErrorWebExceptionHandler {
public OsvcErrorHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
                        ApplicationContext applicationContext) {
    super(errorAttributes, resourceProperties, applicationContext);

    // TODO: 25.06.2019 temporary workaround
    ServerCodecConfigurer serverCodecConfigurer = new DefaultServerCodecConfigurer();
    setMessageWriters(serverCodecConfigurer.getWriters());
    setMessageReaders(serverCodecConfigurer.getReaders());
}

@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
    return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}

private Mono<ServerResponse> renderErrorResponse(ServerRequest serverRequest) {

    final Map<String, Object> errorAttributes = getErrorAttributes(serverRequest, true);
    return ServerResponse.status(HttpStatus.BAD_REQUEST)
            .contentType(MediaType.APPLICATION_JSON_UTF8)
            .body(BodyInserters.fromObject(errorAttributes));
}

}

产生错误的代码:

@Data
@Service
public class ContactService {

private final ContactRepository contactRepository;

public Mono<Business> saveNewContact(Business business) {
    return contactRepository.save(business)
            .onErrorMap(throwable ->
                ServerException.create(throwable.getMessage())
                    .persistError("ico", business.getIco(), "ICO is probably duplicate"));
}

}

问题是这也不起作用。我确实按照本教程进行操作,但是看不到是否有问题。任何帮助或解决方案表示赞赏。谢谢

2 个答案:

答案 0 :(得分:0)

尝试注入ServerCodecConfigurer而不是实例化它。我这样做时也会注入ViewResolversProvider,尽管可能没有必要。

    public OsvcErrorHandler(
            final CustomErrorAttributes customAttributes,
            final ResourceProperties resourceProperties,
            final ObjectProvider<List<ViewResolver>> viewResolversProvider,
            final ServerCodecConfigurer serverCodecConfigurer,
            final ApplicationContext applicationContext
    ) {
        super(customAttributes, resourceProperties, applicationContext);

        this.setViewResolvers(viewResolversProvider.getIfAvailable(Collections::emptyList));
        this.setMessageWriters(serverCodecConfigurer.getWriters());
        this.setMessageReaders(serverCodecConfigurer.getReaders());
    }

答案 1 :(得分:0)

您只需在这样的全局错误处理程序构造函数中使用ServerCodecConfigurer注入即可。

public OsvcErrorHandler(GlobalErrorAttributes errorAttributes, ApplicationContext applicationContext, 
                ServerCodecConfigurer serverCodecConfigurer) {
   super(errorAttributes, new ResourceProperties(), applicationContext);
   super.setMessageWriters(serverCodecConfigurer.getWriters());
   super.setMessageReaders(serverCodecConfigurer.getReaders());
}