⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 https://www.jianshu.com/p/9cf4563ee1e1 「一颗懒能」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

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

img

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;
}
}

}

666. 彩蛋

如果你对 Spring Webflux 感兴趣,欢迎加入我的知识星球一起交流。

知识星球

文章目录
  1. 1. 接口
  2. 2. RequestedContentTypeResolver
  3. 3.
  4. 4. org.springframework.web.reactive.accept.FixedContentTypeResolver
  5. 5. org.springframework.web.reactive.accept.HeaderContentTypeResolver
  6. 6. org.springframework.web.reactive.accept.ParameterContentTypeResolver
  7. 7. org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder
  • 666. 彩蛋