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

net.guerlab.cloud.web.webflux.response.ResponseBodyResultWrapperHandler Maven / Gradle / Ivy

There is a newer version: 2024.11.1
Show newest version
/*
 * Copyright 2018-2025 guerlab.net and other contributors.
 *
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.gnu.org/licenses/lgpl-3.0.html
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.guerlab.cloud.web.webflux.response;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

import jakarta.annotation.Nullable;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapter;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.RequestEntity;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler;
import org.springframework.web.server.ServerWebExchange;

import net.guerlab.cloud.core.result.Result;
import net.guerlab.cloud.core.result.Succeed;
import net.guerlab.cloud.web.core.response.ResponseBodyWrapperSupport;
import net.guerlab.cloud.web.webflux.utils.RequestUtils;
import net.guerlab.commons.exception.ApplicationException;

/**
 * 响应内容结果包装处理.
 *
 * @author guer
 */
@Slf4j
public class ResponseBodyResultWrapperHandler extends ResponseBodyResultHandler {

	private static final MethodParameter METHOD_PARAMETER_WITH_MONO_RESULT;

	private static final MethodParameter METHOD_PARAMETER_WITH_MONO_STRING;

	static {
		try {
			METHOD_PARAMETER_WITH_MONO_RESULT = new MethodParameter(
					ResponseBodyResultWrapperHandler.class.getDeclaredMethod("methodForParamsWithResult"), -1);
			METHOD_PARAMETER_WITH_MONO_STRING = new MethodParameter(
					ResponseBodyResultWrapperHandler.class.getDeclaredMethod("methodForParamsWithString"), -1);
		}
		catch (NoSuchMethodException e) {
			throw new ApplicationException(e);
		}
	}

	private final ResponseBodyWrapperSupport support;

	/**
	 * 初始化响应内容结果包装处理.
	 *
	 * @param writers  HttpMessageWriter列表
	 * @param resolver RequestedContentTypeResolver
	 * @param support  响应对象包装支持
	 */
	public ResponseBodyResultWrapperHandler(List> writers, RequestedContentTypeResolver resolver,
			ResponseBodyWrapperSupport support) {
		super(writers, resolver);
		this.support = support;
		setOrder(-10);
	}

	@SuppressWarnings("SameReturnValue")
	@Nullable
	private static Mono> methodForParamsWithResult() {
		return null;
	}

	@SuppressWarnings("SameReturnValue")
	@Nullable
	private static Mono methodForParamsWithString() {
		return null;
	}

	private static Class resolveReturnValueType(HandlerResult result) {
		Class valueType = result.getReturnType().toClass();
		Object value = result.getReturnValue();
		if (valueType == Object.class && value != null) {
			valueType = value.getClass();
		}
		return valueType;
	}

	@Override
	public boolean supports(HandlerResult result) {
		Class valueType = resolveReturnValueType(result);
		if (isIgnoreType(valueType)) {
			return false;
		}

		ReactiveAdapter adapter = getAdapter(result);
		if (adapter != null && !adapter.isNoValue() && isIgnoreType(result.getReturnType().getGeneric().toClass())) {
			return false;
		}

		return super.supports(result) && support.supports(result.getReturnTypeSource());
	}

	private boolean isIgnoreType(@Nullable Class clazz) {
		return (clazz != null && (
				(HttpEntity.class.isAssignableFrom(clazz) && !RequestEntity.class.isAssignableFrom(clazz))
						|| HttpHeaders.class.isAssignableFrom(clazz)));
	}

	@Override
	public Mono handleResult(ServerWebExchange exchange, HandlerResult result) {
		Object body = result.getReturnValue();
		MethodParameter bodyTypeParameter = result.getReturnTypeSource();

		if (support.noConvertObject(bodyTypeParameter)) {
			log.debug("un wrapper with noConvertObject");
			return super.handleResult(exchange, result);
		}
		else if (matchExcluded(exchange, bodyTypeParameter.getMethod())) {
			log.debug("un wrapper with matchExcluded");
			return super.handleResult(exchange, result);
		}

		boolean returnTypeIsString = Objects.equals(Objects.requireNonNull(bodyTypeParameter.getMethod())
				.getReturnType(), String.class);

		if (returnTypeIsString) {
			if (body == null) {
				return writeBody(new Succeed<>(), METHOD_PARAMETER_WITH_MONO_RESULT, exchange);
			}
			else {
				return writeBody(body, METHOD_PARAMETER_WITH_MONO_RESULT, METHOD_PARAMETER_WITH_MONO_STRING, exchange);
			}
		}
		else {
			if (body == null) {
				log.debug("wrapper with null body");
				return writeBody(new Succeed<>(), METHOD_PARAMETER_WITH_MONO_RESULT, exchange);
			}
			else {
				Mono mono = null;
				if (body instanceof Mono) {
					mono = (Mono) body;
					log.debug("wrapper with Mono");
				}
				else if (body instanceof Flux flux) {
					mono = flux.collectList();
					log.debug("wrapper with Flux");
				}

				if (mono != null) {
					body = mono.map(Succeed::new).defaultIfEmpty(new Succeed<>());
				}
				else {
					body = new Succeed<>(body);
				}

				return writeBody(body, METHOD_PARAMETER_WITH_MONO_RESULT, exchange);
			}
		}
	}

	private boolean matchExcluded(ServerWebExchange exchange, @Nullable Method method) {
		return support.matchExcluded(getRequestPath(exchange), method);
	}

	private String getRequestPath(ServerWebExchange exchange) {
		return RequestUtils.parseRequestUri(exchange.getRequest());
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy