All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pro.chenggang.plugin.springcloud.gateway.response.JsonExceptionHandler Maven / Gradle / Ivy

There is a newer version: 2.1.SR2.2.RELEASE
Show newest version
package pro.chenggang.plugin.springcloud.gateway.response;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.Assert;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import pro.chenggang.plugin.springcloud.gateway.response.factory.ExceptionHandlerStrategyFactory;
import pro.chenggang.plugin.springcloud.gateway.response.strategy.DefaultExceptionHandlerStrategy;
import pro.chenggang.plugin.springcloud.gateway.response.strategy.ExceptionHandlerStrategy;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.List;

/**
 * Json Exception Handler{@link org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler}
 * @author chenggang
 * @date 2019/01/29
 */
@Slf4j
public class JsonExceptionHandler implements ErrorWebExceptionHandler {

    /**
     * MessageReader
     */
    private List> messageReaders = Collections.emptyList();

    /**
     * MessageWriter
     */
    private List> messageWriters = Collections.emptyList();

    /**
     * ViewResolvers
     */
    private List viewResolvers = Collections.emptyList();

    /**
     * temporary cache exception handler result for another method
     */
    private ThreadLocal exceptionHandlerResult = new ThreadLocal<>();

    /**
     * Strategy Factory
     */
    private ExceptionHandlerStrategyFactory exceptionHandlerStrategyFactory;

    public JsonExceptionHandler(ExceptionHandlerStrategyFactory exceptionHandlerStrategyFactory) {
        Assert.notNull(exceptionHandlerStrategyFactory, "'ExceptionHandlerStrategyFactory' must not be null");
        this.exceptionHandlerStrategyFactory = exceptionHandlerStrategyFactory;
    }

    public void setMessageReaders(List> messageReaders) {
        Assert.notNull(messageReaders, "'messageReaders' must not be null");
        this.messageReaders = messageReaders;
    }

    public void setViewResolvers(List viewResolvers) {
        this.viewResolvers = viewResolvers;
    }

    public void setMessageWriters(List> messageWriters) {
        Assert.notNull(messageWriters, "'messageWriters' must not be null");
        this.messageWriters = messageWriters;
    }

    @Override
    public Mono handle(ServerWebExchange exchange, Throwable ex) {
        ServerHttpRequest request = exchange.getRequest();
        /*
         * get strategy
         */
        ExceptionHandlerStrategy strategy = exceptionHandlerStrategyFactory.getStrategy(ex.getClass());
        ExceptionHandlerResult result = strategy.handleException(ex);
        /*
         * log error
         */
        log.warn("[Global Exception Handler]Request Path:{},Exception Msg:{}",request.getPath(),ex.getMessage());
        /*
         * if is Default Strategy Print Stack Trace
         */
        if(strategy instanceof DefaultExceptionHandlerStrategy && log.isDebugEnabled()){
            log.debug("[Global Exception Handler]Request Path:{},Exception Detail:{}",request.getPath(), ExceptionUtils.getStackTrace(ex));
        }
        exceptionHandlerResult.set(result);
        ServerRequest newRequest = ServerRequest.create(exchange, this.messageReaders);
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse).route(newRequest)
                .switchIfEmpty(Mono.error(ex))
                .flatMap((handler) -> handler.handle(newRequest))
                .flatMap((response) -> write(exchange, response));

    }

    private Mono renderErrorResponse(ServerRequest request) {
        ExceptionHandlerResult result = exceptionHandlerResult.get();
        return ServerResponse.status(result.getHttpStatus())
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .body(BodyInserters.fromObject(result.getResponseResult()));
    }

    private Mono write(ServerWebExchange exchange,
                                       ServerResponse response) {
        exchange.getResponse().getHeaders()
                .setContentType(response.headers().getContentType());
        return response.writeTo(exchange, new ResponseContext());
    }

    private class ResponseContext implements ServerResponse.Context {

        @Override
        public List> messageWriters() {
            return JsonExceptionHandler.this.messageWriters;
        }

        @Override
        public List viewResolvers() {
            return JsonExceptionHandler.this.viewResolvers;
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy