
cc.shacocloud.mirage.restful.HandlerExecutionChain Maven / Gradle / Ivy
package cc.shacocloud.mirage.restful;
import cc.shacocloud.mirage.restful.bind.annotation.PathPatterns;
import cc.shacocloud.mirage.restful.exception.HttpRequestBindingException;
import cc.shacocloud.mirage.restful.http.MediaType;
import cc.shacocloud.mirage.restful.util.PathUtil;
import cc.shacocloud.mirage.restful.util.RoutingContextUtils;
import cc.shacocloud.mirage.utils.FutureUtils;
import cc.shacocloud.mirage.utils.LogFormatUtils;
import cc.shacocloud.mirage.utils.PathMatcher;
import cc.shacocloud.mirage.utils.collection.ArrayUtil;
import cc.shacocloud.mirage.utils.collection.CollUtil;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 请求响应处理器
*
* 为整个请求响应出入口的处理器类
*/
@Slf4j
public class HandlerExecutionChain {
public static final Buffer EMPTY = Buffer.buffer(Unpooled.EMPTY_BUFFER);
private final VertxInvokeHandler invokeHandler;
/**
* 异常解析组合处理程序
*/
@Setter
@Nullable
protected HandlerExceptionResolverComposite exceptionResolverComposite;
@Nullable
private Set mediaTypes;
/**
* 当前接口匹配的拦截器,如果接口路径模式为正则模式当前参数为空,使用 {@link #interceptorMappingInfos}
*/
@Nullable
private List interceptors;
/**
* 当接口模式为正则模式时,该属性生效,在运行时间进行接口拦截器匹配
*/
@Nullable
private List interceptorMappingInfos;
/**
* 路径匹配器
*/
@Setter
private PathMatcher pathMatcher = PathUtil.DEFAULT_PATH_MATCHER;
public HandlerExecutionChain(VertxInvokeHandler invokeHandler,
RequestMappingInfo requestMapping,
@Nullable HandlerInterceptorComposite interceptorComposite) {
this.invokeHandler = invokeHandler;
if (interceptorComposite != null) {
// 如果是正则模式在运行时匹配拦截器
if (PathPatterns.REGEX.equals(requestMapping.getPathPatterns())) {
this.interceptorMappingInfos = interceptorComposite.getInterceptorMappings();
} else {
this.interceptors = interceptorComposite.match(requestMapping.getPaths());
}
}
String[] produces = requestMapping.getProduces();
if (ArrayUtil.isNotEmpty(produces)) {
this.mediaTypes = new HashSet<>(MediaType.parseMediaTypes(Arrays.asList(produces)));
}
}
/**
* 处理请求,请求的入口方法
*
* @param ctx 请求上下文
*/
public void handle(io.vertx.ext.web.RoutingContext ctx) {
final RoutingContext routingContext = createVertXRoutingContext(ctx);
routingContext.put(RoutingContext.RECEIVE_REQUEST_TIME, System.currentTimeMillis());
if (log.isDebugEnabled()) {
log.debug("路由器收到待处理请求:{} {}", routingContext.request().method(), routingContext.normalizedPath());
log.debug("当前请求实际绑定的处理器方法:" + this.invokeHandler);
}
if (CollUtil.isNotEmpty(mediaTypes)) {
routingContext.put(VertxInvokeHandler.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
}
AtomicInteger interceptorIndex = new AtomicInteger(0);
// 注册响应释放后的处理
ctx.addEndHandler(res -> {
if (log.isDebugEnabled()) {
long receiveRequestTime = routingContext.get(RoutingContext.RECEIVE_REQUEST_TIME, System::currentTimeMillis);
long handleTime = System.currentTimeMillis() - receiveRequestTime;
log.debug(routingContext.normalizedPath() + " 请求处理完成,耗时:" + handleTime + "ms");
}
triggerAfterCompletion(routingContext, interceptorIndex, res.cause());
});
try {
// 执行拦截器的 preHandle 方法
applyPreHandle(routingContext, interceptorIndex)
.compose(goOn -> {
if (goOn) { // 如果拦截器返回true则继续调用具体方法
return invokeHandler.invokeAndHandleRoutingContext(routingContext);
}
return Future.succeededFuture();
})
.onFailure(cause -> processExceptionHandler(routingContext, cause))
.onSuccess(res -> processResult(routingContext, res));
} catch (Exception e) {
processExceptionHandler(routingContext, e);
}
}
/**
* 委派给 {@link #processExceptionHandler} 方法执行,用于{@link io.vertx.ext.web.Route#failureHandler(Handler)}方法使用
*/
void processException(io.vertx.ext.web.RoutingContext ctx) {
RoutingContext routingContext = createVertXRoutingContext(ctx);
processExceptionHandler(routingContext, ctx.failure());
}
/**
* 处理异常情况
*/
void processExceptionHandler(@NotNull RoutingContext context, Throwable cause) {
final HttpRequest request = context.request();
final HttpResponse response = context.response();
if (log.isDebugEnabled()) {
log.debug("请求 '" + request.context().normalizedPath() + "' 处理发生例外,进行异常解析处理逻辑...");
}
Future