accept包
RequestedContentTypeResolver
处理mediaType的接口。
public interface RequestedContentTypeResolver {
List<MediaType> MEDIA_TYPE_ALL_LIST = Collections.singletonList(MediaType.ALL);
/**将给定的请求解析为请求的媒体类型列表。返回的列表首先按特异性排序,然后按质量参数排序。*/
List<MediaType> resolveMediaTypes(ServerWebExchange exchange);
}

FixedContentTypeResolver
解析器始终解析为固定列表的MediaType。这可以用作“最后一行”策略,当客户端没有请求任何媒体类型时提供解析。
public class FixedContentTypeResolver implements RequestedContentTypeResolver {
private final List<MediaType> contentTypes;
}
HeaderContentTypeResolver
根据请求的“Accept” header 解析。
public class HeaderContentTypeResolver implements RequestedContentTypeResolver {
@Override
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException {
try {
//Accept header。
List<MediaType> mediaTypes = exchange.getRequest().getHeaders().getAccept();
MediaType.sortBySpecificityAndQuality(mediaTypes);
return (!CollectionUtils.isEmpty(mediaTypes) ? mediaTypes : MEDIA_TYPE_ALL_LIST);
}
catch (InvalidMediaTypeException ex) {
String value = exchange.getRequest().getHeaders().getFirst("Accept");
throw new NotAcceptableStatusException(
"Could not parse 'Accept' header [" + value + "]: " + ex.getMessage());
}
}
}
ParameterContentTypeResolver
根据查询参数解析MediaType。参数自定义。
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";
@Override
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException {
String key = exchange.getRequest().getQueryParams().getFirst(getParameterName());
if (!StringUtils.hasText(key)) {
return MEDIA_TYPE_ALL_LIST;
}
//通过map 查找对应MediaType
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);
}
}
result包
HandlerResultHandlerSupport
HandlerResultHandler的基类,支持内容协商和访问ReactiveAdapter注册表。
public abstract class HandlerResultHandlerSupport implements Ordered {
private static final List<MediaType> ALL_APPLICATION_MEDIA_TYPES =
Arrays.asList(MediaType.ALL, new MediaType("application"));
private final RequestedContentTypeResolver contentTypeResolver;
private final ReactiveAdapterRegistry adapterRegistry;
private int order = LOWEST_PRECEDENCE;
/** 获取最合适的mediaType*/
@Nullable
protected MediaType selectMediaType(
ServerWebExchange exchange, Supplier<List<MediaType>> producibleTypesSupplier) {
//如果header中有contentType,直接返回。
MediaType contentType = exchange.getResponse().getHeaders().getContentType();
if (contentType != null && contentType.isConcrete()) {
if (logger.isDebugEnabled()) {
logger.debug(exchange.getLogPrefix() + "Found 'Content-Type:" + contentType + "' in response");
}
return contentType;
}
//查找合适的Mediatype
List<MediaType> acceptableTypes = getAcceptableTypes(exchange);
List<MediaType> producibleTypes = getProducibleTypes(exchange, producibleTypesSupplier);
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<>();
for (MediaType acceptable : acceptableTypes) {
for (MediaType producible : producibleTypes) {
if (acceptable.isCompatibleWith(producible)) {
compatibleMediaTypes.add(selectMoreSpecificMediaType(acceptable, producible));
}
}
}
List<MediaType> result = new ArrayList<>(compatibleMediaTypes);
MediaType.sortBySpecificityAndQuality(result);
MediaType selected = null;
for (MediaType mediaType : result) {
if (mediaType.isConcrete()) {
selected = mediaType;
break;
}
else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {
selected = MediaType.APPLICATION_OCTET_STREAM;
break;
}
}
if (selected != null) {
selected = selected.removeQualityValue();
... LOG ....
}
else if (logger.isDebugEnabled()) {
... LOG ...
}
return selected;
}
}
View包
View
View接口用于渲染HandlerResult。视图通常是通过名称来选择的,并使用ViewResolver来解析,例如将其与HTML模板匹配。此外,视图可以基于模型中包含的多个属性呈现。视图还可以选择从模型中选择一个属性,使用任何现有的编码器来呈现替代媒体类型。
public interface View {
String BINDING_CONTEXT_ATTRIBUTE = View.class.getName() + ".bindingContext";
/**
* Return the list of media types this View supports, or an empty list.
*/
default List<MediaType> getSupportedMediaTypes() {
return Collections.emptyList();
}
/**
* Whether this View does rendering by performing a redirect.
*/
default boolean isRedirectView() {
return false;
}
/** 渲染 HandlerResult*/
Mono<Void> render(@Nullable Map<String, ?> model, @Nullable MediaType contentType, ServerWebExchange exchange);
}
Diagram

AbstractView
ublic abstract class AbstractView implements View, BeanNameAware, ApplicationContextAware {
/** Well-known name for the RequestDataValueProcessor in the bean factory. */
public static final String REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME = "requestDataValueProcessor";
protected final Log logger = LogFactory.getLog(getClass());
private final ReactiveAdapterRegistry adapterRegistry;
private final List<MediaType> mediaTypes = new ArrayList<>(4);
private Charset defaultCharset = StandardCharsets.UTF_8;
@Nullable
private String requestContextAttribute;
@Nullable
private String beanName;
@Nullable
private ApplicationContext applicationContext;
/**渲染Model*/
@Override
public Mono<Void> render(@Nullable Map<String, ?> model, @Nullable MediaType contentType,
ServerWebExchange exchange) {
... ...
//设置contentType
if (contentType != null) {
exchange.getResponse().getHeaders().setContentType(contentType);
}
return getModelAttributes(model, exchange).flatMap(mergedModel -> {
// Expose RequestContext?
if (this.requestContextAttribute != null) {
mergedModel.put(this.requestContextAttribute, createRequestContext(exchange, mergedModel));
}
//渲染model
return renderInternal(mergedModel, contentType, exchange);
});
}
}
AbstractUrlBasedView
基于Url的视图渲染
public abstract class AbstractUrlBasedView extends AbstractView implements InitializingBean {
@Nullable
private String url;
}
RedirectView
重定向到一个Url。
ScriptTemplateView
解释性模板视图。
FreeMarkerView
FreeMarker视图
ViewResolver
ViewResolver
通过name解析成View。
public interface ViewResolver {
Mono<View> resolveViewName(String viewName, Locale locale);
}
Diagram

Rendering
/**Public API for HTML rendering
*/
public interface Rendering {
Object view();
/**
* Return attributes to add to the model.
*/
Map<String, Object> modelAttributes();
/**
* Return the HTTP status to set the response to.
*/
@Nullable
HttpStatus status();
/**
* Return headers to add to the response.
*/
HttpHeaders headers();
}
condition包
RequestCondition
RequestCondition
对一个请求匹配条件的概念建模。最终的实现类可能是针对以下情况之一:路径匹配,头部匹配,请求参数匹配,可产生MIME
匹配,可消费MIME
匹配,请求方法匹配,或者是以上各种情况的匹配条件的一个组合。
public interface RequestCondition<T> {
T combine(T other);
@Nullable
T getMatchingCondition(ServerWebExchange exchange);
int compareTo(T other, ServerWebExchange exchange);
}
method包
类似Mvc,用于处理 Method类型的handler。
function包
一些常用的函数式接口及实现。
socket包
反应式WebSocket交互的抽象和支持类。
WebSocketHandler
public interface WebSocketHandler {
default List<String> getSubProtocols() {
return Collections.emptyList();
}
Mono<Void> handle(WebSocketSession session);
}