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

cc.shacocloud.mirage.web.AbstractMessageConverterMethodArgumentResolver Maven / Gradle / Ivy

package cc.shacocloud.mirage.web;

import cc.shacocloud.mirage.utils.SelfSortList;
import cc.shacocloud.mirage.web.exception.HttpMediaTypeNotSupportedException;
import cc.shacocloud.mirage.web.exception.InvalidMediaTypeException;
import cc.shacocloud.mirage.web.http.GenericHttpMessageConverter;
import cc.shacocloud.mirage.web.http.HttpMessageConverter;
import cc.shacocloud.mirage.web.http.MediaType;
import io.vertx.core.Future;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.OrderUtils;

import java.lang.reflect.Type;
import java.util.*;

/**
 * 基类,用于通过从与请求的主体读取解决方法参数值 HttpMessageConverters
 */
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandleMethodArgumentResolver {

    private static final Set SUPPORTED_METHODS = new HashSet<>(Arrays.asList(HttpMethod.POST, HttpMethod.PUT, HttpMethod.PATCH));

    protected final Log logger = LogFactory.getLog(getClass());

    protected final List> messageConverters
        = new SelfSortList<>(n -> OrderUtils.getOrder(n.getClass(), Ordered.LOWEST_PRECEDENCE));

    protected final List allSupportedMediaTypes;

    protected AbstractMessageConverterMethodArgumentResolver(List> messageConverters) {
        this.messageConverters.addAll(messageConverters);
        this.allSupportedMediaTypes = getAllSupportedMediaTypes(messageConverters);
    }


    /**
     * 通过从给定的 VertXRoutingContext 中读取来创建预期参数类型的方法参数值
     *
     * @param         要创建的参数值的预期类型
     * @param request    当前请求对象
     * @param parameter  方法参数描述符
     * @param targetType 目标类型,不一定与方法参数类型相同
     * @return 创建的方法参数值
     */
    @SuppressWarnings("unchecked")
    protected  Future readWithMessageConverters(HttpRequest request,
                                                      MethodParameter parameter,
                                                      Type targetType) {
        MediaType contentType;
        boolean noContentType = false;
        try {
            contentType = request.headers().getContentType();

            if (logger.isDebugEnabled()) {
                logger.debug("从请求中找到预设的 'Content-Type' : " + contentType);
            }

        } catch (InvalidMediaTypeException ex) {
            return Future.failedFuture(new HttpMediaTypeNotSupportedException(ex.getMessage()));
        }

        if (contentType == null) {
            noContentType = true;
            contentType = MediaType.APPLICATION_OCTET_STREAM;

            if (logger.isDebugEnabled()) {
                logger.debug("请求中未预设 'Content-Type' 使用默认值: " + contentType);
            }
        }

        Class contextClass = parameter.getContainingClass();
        Class targetClass = (targetType instanceof Class ? (Class) targetType : null);
        if (targetClass == null) {
            ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
            targetClass = (Class) resolvableType.resolve();
        }

        HttpMethod httpMethod = request.method();

        Future bodyFuture = null;

        // 循环所有的消息转换器
        for (HttpMessageConverter converter : this.messageConverters) {
            // 如果是 基于 GenericHttpMessageConverter 的实现 则使用 GenericHttpMessageConverter来判断
            GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter) converter : null);
            if (genericConverter != null ? genericConverter.canRead(parameter, targetType, contextClass, contentType) :
                (targetClass != null && converter.canRead(parameter, targetClass, contentType))) {

                if (logger.isDebugEnabled()) {
                    logger.debug("匹配到参数解析处理类:" + (genericConverter != null ? genericConverter : converter));
                }

                // 读取数据
                bodyFuture = (genericConverter != null ? genericConverter.read(parameter, targetType, contextClass, request) :
                    ((HttpMessageConverter) converter).read(parameter, targetClass, request));

                if (bodyFuture != null) break;
            }
        }

        // 如果消息主体为空
        if (bodyFuture == null) {

            if (logger.isDebugEnabled()) {
                logger.debug("方法参数 '" + parameter.getParameterName() + "' 未匹配到参数解析处理类!");
            }

            Buffer requestBody = request.getBody();
            if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod)
                || (noContentType && (requestBody == null || requestBody.length() == 0))) {
                return Future.succeededFuture();
            }
            return Future.failedFuture(new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes));
        }

        return bodyFuture;
    }


    /**
     * 通过{@link MediaType#sortBySpecificity(List)}返回所有提供的按特异性排序*的消息转换器支持的媒体类型。
     */
    private static List getAllSupportedMediaTypes(List> messageConverters) {
        Set allSupportedMediaTypes = new LinkedHashSet<>();
        for (HttpMessageConverter messageConverter : messageConverters) {
            allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
        }
        List result = new ArrayList<>(allSupportedMediaTypes);
        MediaType.sortBySpecificity(result);
        return Collections.unmodifiableList(result);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy