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

cc.shacocloud.mirage.web.bind.converter.AbstractHttpMessageConverter Maven / Gradle / Ivy

package cc.shacocloud.mirage.web.bind.converter;

import cc.shacocloud.mirage.web.HttpRequest;
import cc.shacocloud.mirage.web.HttpResponse;
import cc.shacocloud.mirage.web.http.HttpHeaderMap;
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.HttpHeaders;
import org.springframework.core.MethodParameter;
import org.jetbrains.annotations.Nullable;
import org.springframework.util.Assert;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * {@link HttpMessageConverter}实现的抽象基类。
 *
 * 

* 这个基类通过 {@link #setSupportedMediaTypes(List) supportedMediaTypes} bean属性添加了对设置{@code MediaTypes}的支持。 * 它还在写入输出消息时增加了对{@link HttpHeaders#CONTENT_TYPE}和{@link HttpHeaders#CONTENT_LENGTH}的支持。 * * @param 转换后的对象类型 */ public abstract class AbstractHttpMessageConverter implements HttpMessageConverter { private List supportedMediaTypes = Collections.emptyList(); @Nullable private Charset defaultCharset; /** * 构造一个不支持媒体类型的{@code AbstractHttpMessageConverter}。 * * @see #setSupportedMediaTypes */ protected AbstractHttpMessageConverter() { } /** * 构造具有一种支持的媒体类型的{@code AbstractHttpMessageConverter}。 * * @param supportedMediaType 支持的媒体类型 */ protected AbstractHttpMessageConverter(MediaType supportedMediaType) { setSupportedMediaTypes(Collections.singletonList(supportedMediaType)); } /** * 构造具有多种支持媒体类型的{@code AbstractHttpMessageConverter}。 * * @param supportedMediaTypes 支持的媒体类型 */ protected AbstractHttpMessageConverter(MediaType... supportedMediaTypes) { setSupportedMediaTypes(Arrays.asList(supportedMediaTypes)); } /** * 构造带有默认字符集和多种支持的媒体类型的{@code AbstractHttpMessageConverter}。 * * @param defaultCharset 默认字符集 * @param supportedMediaTypes 支持的媒体类型 */ protected AbstractHttpMessageConverter(Charset defaultCharset, MediaType... supportedMediaTypes) { this.defaultCharset = defaultCharset; setSupportedMediaTypes(Arrays.asList(supportedMediaTypes)); } /** * 设置此转换器支持的{@link MediaType}对象列表 */ public void setSupportedMediaTypes(List supportedMediaTypes) { Assert.notEmpty(supportedMediaTypes, "MediaType 列表不能为空"); this.supportedMediaTypes = new ArrayList<>(supportedMediaTypes); } @Override public List getSupportedMediaTypes() { return Collections.unmodifiableList(this.supportedMediaTypes); } /** * 设置默认字符集(如果有的话)。 */ public void setDefaultCharset(@Nullable Charset defaultCharset) { this.defaultCharset = defaultCharset; } /** * 如果有的话,返回默认字符集。 */ @Nullable public Charset getDefaultCharset() { return this.defaultCharset; } /** * 这个实现检查给定的类是否为{@linkplain #supports }, * 以及{@linkplain #getSupportedMediaTypes } {@linkplain MediaType#includes }给定的媒体类型。 */ @Override public boolean canRead(MethodParameter parameter, Class clazz, @Nullable MediaType mediaType) { return supports(clazz) && canRead(mediaType); } /** * 如果任何{@linkplain #setSupportedMediaTypes }媒体类型包括{@link MediaType#includes}给定的媒体类型,返回{@code true} * * @param mediaType 要读取的媒体类型,如果没有指定,可以是{@code null}。通常是{@code Content-Type}头的值。 * @return 支持的媒体类型与媒体类型兼容或媒体类型为{@code null}则为{@code true} */ protected boolean canRead(@Nullable MediaType mediaType) { if (mediaType == null) { return true; } for (MediaType supportedMediaType : getSupportedMediaTypes()) { if (supportedMediaType.includes(mediaType)) { return true; } } return false; } /** * 这个实现检查给定的类是否 {@linkplain #supports }, * 以及 {@linkplain #getSupportedMediaTypes}媒体类型 {@linkplain MediaType#includes}包含给定的媒体类型。 */ @Override public boolean canWrite(Class clazz, @Nullable MediaType mediaType) { return supports(clazz) && canWrite(mediaType); } /** * 如果给定的媒体类型包括任何{@linkplain #setSupportedMediaTypes(List) },则返回{@code true}。 * * @param mediaType 要写入的媒体类型,如果没有指定,可以是{@code null}。通常是{@code Accept}头的值。 * @return 支持的媒体类型与媒体类型兼容或媒体类型为{@code null}则为{@code true} */ protected boolean canWrite(@Nullable MediaType mediaType) { if (mediaType == null || MediaType.ALL.equalsTypeAndSubtype(mediaType)) { return true; } for (MediaType supportedMediaType : getSupportedMediaTypes()) { if (supportedMediaType.isCompatibleWith(mediaType)) { return true; } } return false; } /** * 这个实现简单地委托给{@link #readInternal(Class, HttpRequest)}。以后的实现可能会添加一些默认行为。 */ @Override public final Future read(MethodParameter parameter, Class clazz, HttpRequest request) { return readInternal(clazz, request); } /** * 这个实现通过调用{@link #addDefaultHeaders}来设置默认的头,然后调用{@link #writeInternal}。 */ @Override public final Future write(final T t, @Nullable MediaType contentType, HttpResponse response) { final HttpHeaderMap headers = response.headers(); // 设置默认头 addDefaultHeaders(headers, t, contentType); return writeInternal(t, response); } /** * 向输出消息添加默认标题。 *

* 如果没有提供内容类型,此实现将委托给{@link #getDefaultContentType(Object)},必要时设置默认字符集。 * 调用{@link #getContentLength},并设置相应的头部。 * * @since 4.2 */ protected void addDefaultHeaders(HttpHeaderMap headers, T t, @Nullable MediaType contentType) { if (headers.getContentType() == null) { MediaType contentTypeToUse = contentType; if (contentType == null || !contentType.isConcrete()) { contentTypeToUse = getDefaultContentType(t); } else if (MediaType.APPLICATION_OCTET_STREAM.equals(contentType)) { MediaType mediaType = getDefaultContentType(t); contentTypeToUse = (mediaType != null ? mediaType : contentTypeToUse); } if (contentTypeToUse != null) { if (contentTypeToUse.getCharset() == null) { Charset defaultCharset = getDefaultCharset(); if (defaultCharset != null) { contentTypeToUse = new MediaType(contentTypeToUse, defaultCharset); } } headers.setContentType(contentTypeToUse); } } if (headers.getContentLength() < 0 && !headers.contains(HttpHeaders.TRANSFER_ENCODING)) { Long contentLength = getContentLength(t, headers.getContentType()); if (contentLength != null) { headers.setContentLength(contentLength); } } } /** * 返回给定类型的默认内容类型。 *

*

* 默认情况下,它返回{@link #setSupportedMediaTypes(List)}属性的第一个元素(如果有的话)。 * 可以在子类中被重写。 * * @param t the type to return the content type for * @return the content type, or {@code null} if not known */ @Nullable protected MediaType getDefaultContentType(T t) { List mediaTypes = getSupportedMediaTypes(); return (!mediaTypes.isEmpty() ? mediaTypes.get(0) : null); } /** * 返回给定类型的内容长度 *

* 默认情况下,这会返回{@code null},这意味着内容长度是未知的。可以在子类中被重写。 * * @param t 返回内容长度的类型 * @return 内容长度, (如果不知道{@code null}) */ @Nullable protected Long getContentLength(T t, @Nullable MediaType contentType) { return null; } /** * 指示此转换器是否支持给定的类。 * * @param clazz 要测试以获得支持的类 * @return 如果支持则为{@code true}反之为{@code false} */ protected abstract boolean supports(Class clazz); /** * 读取实际对象的抽象模板方法。从{@link HttpMessageConverter#read}调用。 * * @param clazz 要返回的对象类型 * @param request 要从中读取的HTTP输入消息 * @return 转换对象 */ protected abstract Future readInternal(Class clazz, HttpRequest request); /** * 编写实际主体的抽象模板方法。从{@link HttpMessageConverter#write}调用。 * * @param t 要写入输出消息的对象 * @param response 要写入的HTTP输出消息 * @return {@link } 解析后的结果 */ protected abstract Future writeInternal(T t, HttpResponse response); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy