美文网首页
Spring Webflux 源码阅读之 accept包

Spring Webflux 源码阅读之 accept包

作者: 一颗懒能 | 来源:发表于2017-11-05 23:03 被阅读0次

    Spring Webflux --accept

    RequestedContentTypeResolver策略和实现来解析给定请求的请求内容类型。

    typeResovle.jpg

    接口

    RequestedContentTypeResolver

    为ServerWebExchange解决请求的媒体类型的策略。

    
    public interface RequestedContentTypeResolver {
    
        /**
         * Resolve the given request to a list of requested media types. The returned
         * list is ordered by specificity first and by quality parameter second.
         * @param exchange the current exchange
         * @return the requested media types or an empty list
         * @throws NotAcceptableStatusException if the requested media type is invalid
         */
        List<MediaType> resolveMediaTypes(ServerWebExchange exchange);
    
    }
    
    

    将给定的请求解析为请求的媒体类型列表。返回的列表首先按特异性排序,然后按质量参数排序。

    org.springframework.web.reactive.accept.FixedContentTypeResolver

    解析器始终解析为媒体类型的固定列表。这可以用作“最后一行”策略,当客户端没有请求任何媒体类型时提供回调

    
    public class FixedContentTypeResolver implements RequestedContentTypeResolver {
    
        private static final Log logger = LogFactory.getLog(FixedContentTypeResolver.class);
    
    
        private final List<MediaType> mediaTypes;
    
    
        /**
         * 具有单个默认MediaType的构造函数。.
         */
        public FixedContentTypeResolver(MediaType mediaType) {
            this(Collections.singletonList(mediaType));
        }
    
        /**
         * 使用默认的MediaType排序列表的构造函数返回用于支持各种内容类型的应用程序。
         如果目标不存在,并且不支持任何其他默认媒体类型,请考虑在最后附加MediaType.ALL。
         */
        public FixedContentTypeResolver(List<MediaType> mediaTypes) {
            this.mediaTypes = Collections.unmodifiableList(mediaTypes);
        }
    
    
        /**
         * 返回配置的媒体类型列表。
         */
        public List<MediaType> getContentTypes() {
            return this.mediaTypes;
        }
    
    
        @Override
        public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) {
            if (logger.isDebugEnabled()) {
                logger.debug("Requested media types: " + this.mediaTypes);
            }
            return this.mediaTypes;
        }
    
    }
    
    

    org.springframework.web.reactive.accept.HeaderContentTypeResolver

    解析器查看请求的“Accept”标头。

    
    
    public class HeaderContentTypeResolver implements RequestedContentTypeResolver {
    
        @Override
        public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException {
            try {
                List<MediaType> mediaTypes = exchange.getRequest().getHeaders().getAccept();
                MediaType.sortBySpecificityAndQuality(mediaTypes);
                return mediaTypes;
            }
            catch (InvalidMediaTypeException ex) {
                String value = exchange.getRequest().getHeaders().getFirst("Accept");
                throw new NotAcceptableStatusException(
                        "Could not parse 'Accept' header [" + value + "]: " + ex.getMessage());
            }
        }
    
    }
    
    

    org.springframework.web.reactive.accept.ParameterContentTypeResolver

    解析查询参数并使用它查找匹配的MediaType的解析器。查找键可以注册,也可以作为一个后备的MediaTypeFactory执行查找。

    
    public class ParameterContentTypeResolver implements RequestedContentTypeResolver {
    
        /** Primary lookup for media types by key (e.g. "json" -> "application/json") */
        private final Map<String, MediaType> mediaTypes = new ConcurrentHashMap<>(64);
    
        private String parameterName = "format";
    
    
        public ParameterContentTypeResolver(Map<String, MediaType> mediaTypes) {
            mediaTypes.forEach((key, value) -> this.mediaTypes.put(formatKey(key), value));
        }
    
        private static String formatKey(String key) {
            return key.toLowerCase(Locale.ENGLISH);
        }
    
    
        /**
         * Set the name of the parameter to use to determine requested media types.
         * <p>By default this is set to {@literal "format"}.
         */
        public void setParameterName(String parameterName) {
            Assert.notNull(parameterName, "'parameterName' is required");
            this.parameterName = parameterName;
        }
    
        public String getParameterName() {
            return this.parameterName;
        }
    
    
        @Override
        public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException {
            String key = exchange.getRequest().getQueryParams().getFirst(getParameterName());
            if (!StringUtils.hasText(key)) {
                return Collections.emptyList();
            }
            key = formatKey(key);
            MediaType match = this.mediaTypes.get(key);
            if (match == null) {
                match = MediaTypeFactory.getMediaType("filename." + key)
                        .orElseThrow(() -> {
                            List<MediaType> supported = new ArrayList<>(this.mediaTypes.values());
                            return new NotAcceptableStatusException(supported);
                        });
            }
            this.mediaTypes.putIfAbsent(key, match);
            return Collections.singletonList(match);
        }
    
    
    
    

    org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder

    Builder的复合RequestedContentTypeResolver代表其他解析器实现一个不同的策略来确定请求的内容类型,例如Accept标头,查询参数,或其他。
    使用生成器方法在所需的顺序中添加解析器。对于给定的请求,他首先解析返回一个非空的列表,并且不包含只是MediaType。将使用。
    默认情况下,如果没有显式解析器配置,构建器将添加HeaderContentTypeResolver。

    
    public class RequestedContentTypeResolverBuilder {
    
        private final List<Supplier<RequestedContentTypeResolver>> candidates = new ArrayList<>();
    
    
        /**
         * Add a resolver to get the requested content type from a query parameter.
         * By default the query parameter name is {@code "format"}.
         */
        public ParameterResolverConfigurer parameterResolver() {
            ParameterResolverConfigurer parameterBuilder = new ParameterResolverConfigurer();
            this.candidates.add(parameterBuilder::createResolver);
            return parameterBuilder;
        }
    
        /**
         * Add resolver to get the requested content type from the
         * {@literal "Accept"} header.
         */
        public void headerResolver() {
            this.candidates.add(HeaderContentTypeResolver::new);
        }
    
        /**
         * Add resolver that returns a fixed set of media types.
         * @param mediaTypes the media types to use
         */
        public void fixedResolver(MediaType... mediaTypes) {
            this.candidates.add(() -> new FixedContentTypeResolver(Arrays.asList(mediaTypes)));
        }
    
        /**
         * Add a custom resolver.
         * @param resolver the resolver to add
         */
        public void resolver(RequestedContentTypeResolver resolver) {
            this.candidates.add(() -> resolver);
        }
    
        /**
         * Build a {@link RequestedContentTypeResolver} that delegates to the list
         * of resolvers configured through this builder.
         */
        public RequestedContentTypeResolver build() {
    
            List<RequestedContentTypeResolver> resolvers =
                    this.candidates.isEmpty() ?
                            Collections.singletonList(new HeaderContentTypeResolver()) :
                            this.candidates.stream().map(Supplier::get).collect(Collectors.toList());
    
            return exchange -> {
                for (RequestedContentTypeResolver resolver : resolvers) {
                    List<MediaType> type = resolver.resolveMediaTypes(exchange);
                    if (type.isEmpty() || (type.size() == 1 && type.contains(MediaType.ALL))) {
                        continue;
                    }
                    return type;
                }
                return Collections.emptyList();
            };
        }
    
    
        /**
         * Helper to create and configure {@link ParameterContentTypeResolver}.
         */
        public static class ParameterResolverConfigurer {
    
            private final Map<String, MediaType> mediaTypes = new HashMap<>();
    
            @Nullable
            private String parameterName;
    
            /**
             * Configure a mapping between a lookup key (extracted from a query
             * parameter value) and a corresponding {@code MediaType}.
             * @param key the lookup key
             * @param mediaType the MediaType for that key
             */
            public ParameterResolverConfigurer mediaType(String key, MediaType mediaType) {
                this.mediaTypes.put(key, mediaType);
                return this;
            }
    
            /**
             * Map-based variant of {@link #mediaType(String, MediaType)}.
             * @param mediaTypes the mappings to copy
             */
            public ParameterResolverConfigurer mediaType(Map<String, MediaType> mediaTypes) {
                this.mediaTypes.putAll(mediaTypes);
                return this;
            }
    
            /**
             * Set the name of the parameter to use to determine requested media types.
             * <p>By default this is set to {@literal "format"}.
             */
            public ParameterResolverConfigurer parameterName(String parameterName) {
                this.parameterName = parameterName;
                return this;
            }
    
            /**
             * Private factory method to create the resolver.
             */
            private RequestedContentTypeResolver createResolver() {
                ParameterContentTypeResolver resolver = new ParameterContentTypeResolver(this.mediaTypes);
                if (this.parameterName != null) {
                    resolver.setParameterName(this.parameterName);
                }
                return resolver;
            }
        }
    
    }
    

    相关文章

      网友评论

          本文标题:Spring Webflux 源码阅读之 accept包

          本文链接:https://www.haomeiwen.com/subject/qwfkmxtx.html