类org.springframework.http.codec.ResourceHttpMessageWriter源码实例Demo

下面列出了怎么用org.springframework.http.codec.ResourceHttpMessageWriter的API类实例代码及写法,或者点击链接到github查看源代码。


@Override
public void afterPropertiesSet() throws Exception {
	resolveResourceLocations();

	if (logger.isWarnEnabled() && CollectionUtils.isEmpty(this.locations)) {
		logger.warn("Locations list is empty. No resources will be served unless a " +
				"custom ResourceResolver is configured as an alternative to PathResourceResolver.");
	}

	if (this.resourceResolvers.isEmpty()) {
		this.resourceResolvers.add(new PathResourceResolver());
	}

	initAllowedLocations();

	if (getResourceHttpMessageWriter() == null) {
		this.resourceHttpMessageWriter = new ResourceHttpMessageWriter();
	}

	// Initialize immutable resolver and transformer chains
	this.resolverChain = new DefaultResourceResolverChain(this.resourceResolvers);
	this.transformerChain = new DefaultResourceTransformerChain(this.resolverChain, this.resourceTransformers);
}
 

private ResponseEntityResultHandler createHandler(HttpMessageWriter<?>... writers) {
	List<HttpMessageWriter<?>> writerList;
	if (ObjectUtils.isEmpty(writers)) {
		writerList = new ArrayList<>();
		writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
		writerList.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()));
		writerList.add(new ResourceHttpMessageWriter());
		writerList.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder()));
		writerList.add(new EncoderHttpMessageWriter<>(new Jackson2JsonEncoder()));
		writerList.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes()));
	}
	else {
		writerList = Arrays.asList(writers);
	}
	RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
	return new ResponseEntityResultHandler(writerList, resolver);
}
 

private AbstractMessageWriterResultHandler initResultHandler(HttpMessageWriter<?>... writers) {
	List<HttpMessageWriter<?>> writerList;
	if (ObjectUtils.isEmpty(writers)) {
		writerList = new ArrayList<>();
		writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
		writerList.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes()));
		writerList.add(new ResourceHttpMessageWriter());
		writerList.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder()));
		writerList.add(new EncoderHttpMessageWriter<>(new Jackson2JsonEncoder()));
	}
	else {
		writerList = Arrays.asList(writers);
	}
	RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
	return new AbstractMessageWriterResultHandler(writerList, resolver) {};
}
 

/**
 * Return writers that support specific types.
 * @param forMultipart whether to returns writers for general use ("false"),
 * or for multipart requests only ("true"). Generally the two sets are the
 * same except for the multipart writer itself.
 */
@SuppressWarnings("unchecked")
final List<HttpMessageWriter<?>> getTypedWriters(boolean forMultipart) {
	if (!this.registerDefaults) {
		return Collections.emptyList();
	}
	List<HttpMessageWriter<?>> writers = new ArrayList<>();
	writers.add(new EncoderHttpMessageWriter<>(new ByteArrayEncoder()));
	writers.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
	writers.add(new EncoderHttpMessageWriter<>(new DataBufferEncoder()));
	writers.add(new ResourceHttpMessageWriter());
	writers.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()));
	// No client or server specific multipart writers currently..
	if (!forMultipart) {
		extendTypedWriters(writers);
	}
	if (protobufPresent) {
		Encoder<?> encoder = this.protobufEncoder != null ? this.protobufEncoder : new ProtobufEncoder();
		writers.add(new ProtobufHttpMessageWriter((Encoder) encoder));
	}
	return writers;
}
 

@Test
public void defaultWriters() {
	List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
	assertEquals(11, writers.size());
	assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ByteBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertStringEncoder(getNextEncoder(writers), true);
	assertEquals(ProtobufHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jackson2SmileEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass());
	assertSseWriter(writers);
	assertStringEncoder(getNextEncoder(writers), false);
}
 

@Test
public void defaultWriters() {
	List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
	assertEquals(11, writers.size());
	assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ByteBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertStringEncoder(getNextEncoder(writers), true);
	assertEquals(MultipartHttpMessageWriter.class, writers.get(this.index.getAndIncrement()).getClass());
	assertEquals(ProtobufHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jackson2SmileEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass());
	assertStringEncoder(getNextEncoder(writers), false);
}
 

@Override
public void afterPropertiesSet() throws Exception {
	resolveResourceLocations();

	if (logger.isWarnEnabled() && CollectionUtils.isEmpty(this.locations)) {
		logger.warn("Locations list is empty. No resources will be served unless a " +
				"custom ResourceResolver is configured as an alternative to PathResourceResolver.");
	}

	if (this.resourceResolvers.isEmpty()) {
		this.resourceResolvers.add(new PathResourceResolver());
	}

	initAllowedLocations();

	if (getResourceHttpMessageWriter() == null) {
		this.resourceHttpMessageWriter = new ResourceHttpMessageWriter();
	}

	// Initialize immutable resolver and transformer chains
	this.resolverChain = new DefaultResourceResolverChain(this.resourceResolvers);
	this.transformerChain = new DefaultResourceTransformerChain(this.resolverChain, this.resourceTransformers);
}
 

private ResponseEntityResultHandler createHandler(HttpMessageWriter<?>... writers) {
	List<HttpMessageWriter<?>> writerList;
	if (ObjectUtils.isEmpty(writers)) {
		writerList = new ArrayList<>();
		writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
		writerList.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()));
		writerList.add(new ResourceHttpMessageWriter());
		writerList.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder()));
		writerList.add(new EncoderHttpMessageWriter<>(new Jackson2JsonEncoder()));
		writerList.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes()));
	}
	else {
		writerList = Arrays.asList(writers);
	}
	RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
	return new ResponseEntityResultHandler(writerList, resolver);
}
 

private AbstractMessageWriterResultHandler initResultHandler(HttpMessageWriter<?>... writers) {
	List<HttpMessageWriter<?>> writerList;
	if (ObjectUtils.isEmpty(writers)) {
		writerList = new ArrayList<>();
		writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
		writerList.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes()));
		writerList.add(new ResourceHttpMessageWriter());
		writerList.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder()));
		writerList.add(new EncoderHttpMessageWriter<>(new Jackson2JsonEncoder()));
	}
	else {
		writerList = Arrays.asList(writers);
	}
	RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
	return new AbstractMessageWriterResultHandler(writerList, resolver) {};
}
 

/**
 * Return writers that support specific types.
 * @param forMultipart whether to returns writers for general use ("false"),
 * or for multipart requests only ("true"). Generally the two sets are the
 * same except for the multipart writer itself.
 */
@SuppressWarnings("unchecked")
final List<HttpMessageWriter<?>> getTypedWriters(boolean forMultipart) {
	if (!this.registerDefaults) {
		return Collections.emptyList();
	}
	List<HttpMessageWriter<?>> writers = new ArrayList<>();
	writers.add(new EncoderHttpMessageWriter<>(new ByteArrayEncoder()));
	writers.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
	writers.add(new EncoderHttpMessageWriter<>(new DataBufferEncoder()));
	writers.add(new ResourceHttpMessageWriter());
	writers.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()));
	// No client or server specific multipart writers currently..
	if (!forMultipart) {
		extendTypedWriters(writers);
	}
	if (protobufPresent) {
		Encoder<?> encoder = this.protobufEncoder != null ? this.protobufEncoder : new ProtobufEncoder();
		writers.add(new ProtobufHttpMessageWriter((Encoder) encoder));
	}
	return writers;
}
 

@Test
public void defaultWriters() {
	List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
	assertEquals(11, writers.size());
	assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ByteBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertStringEncoder(getNextEncoder(writers), true);
	assertEquals(ProtobufHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jackson2SmileEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass());
	assertSseWriter(writers);
	assertStringEncoder(getNextEncoder(writers), false);
}
 

@Test
public void defaultWriters() {
	List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
	assertEquals(11, writers.size());
	assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ByteBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertStringEncoder(getNextEncoder(writers), true);
	assertEquals(MultipartHttpMessageWriter.class, writers.get(this.index.getAndIncrement()).getClass());
	assertEquals(ProtobufHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jackson2SmileEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass());
	assertStringEncoder(getNextEncoder(writers), false);
}
 

@Before
public void createContext() {
	final List<HttpMessageWriter<?>> messageWriters = new ArrayList<>();
	messageWriters.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
	messageWriters.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()));
	messageWriters.add(new ResourceHttpMessageWriter());
	messageWriters.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder()));
	Jackson2JsonEncoder jsonEncoder = new Jackson2JsonEncoder();
	messageWriters.add(new EncoderHttpMessageWriter<>(jsonEncoder));
	messageWriters.add(new ServerSentEventHttpMessageWriter(jsonEncoder));
	messageWriters.add(new FormHttpMessageWriter());
	messageWriters.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes()));
	messageWriters.add(new MultipartHttpMessageWriter(messageWriters));

	this.context = new BodyInserter.Context() {
		@Override
		public List<HttpMessageWriter<?>> messageWriters() {
			return messageWriters;
		}
		@Override
		public Optional<ServerHttpRequest> serverRequest() {
			return Optional.empty();
		}
		@Override
		public Map<String, Object> hints() {
			return hints;
		}
	};
	this.hints = new HashMap<>();
}
 

@Before
public void setup() throws Exception {
	List<HttpMessageWriter<?>> writerList = new ArrayList<>(5);
	writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
	writerList.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes()));
	writerList.add(new ResourceHttpMessageWriter());
	writerList.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder()));
	writerList.add(new EncoderHttpMessageWriter<>(new Jackson2JsonEncoder()));
	RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
	this.resultHandler = new ResponseBodyResultHandler(writerList, resolver);
}
 

/**
 * Constructor with a default list of part writers (String and Resource).
 */
public MultipartHttpMessageWriter() {
	this(Arrays.asList(
			new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()),
			new ResourceHttpMessageWriter()
	));
}
 

@Test
public void defaultWriters() {
	List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
	assertEquals(10, writers.size());
	assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ByteBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertStringEncoder(getNextEncoder(writers), true);
	assertEquals(ProtobufHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jackson2SmileEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass());
	assertStringEncoder(getNextEncoder(writers), false);
}
 

@Test
public void defaultAndCustomWriters() {
	Encoder<?> customEncoder1 = mock(Encoder.class);
	Encoder<?> customEncoder2 = mock(Encoder.class);

	given(customEncoder1.canEncode(ResolvableType.forClass(Object.class), null)).willReturn(false);
	given(customEncoder2.canEncode(ResolvableType.forClass(Object.class), null)).willReturn(true);

	HttpMessageWriter<?> customWriter1 = mock(HttpMessageWriter.class);
	HttpMessageWriter<?> customWriter2 = mock(HttpMessageWriter.class);

	given(customWriter1.canWrite(ResolvableType.forClass(Object.class), null)).willReturn(false);
	given(customWriter2.canWrite(ResolvableType.forClass(Object.class), null)).willReturn(true);

	this.configurer.customCodecs().encoder(customEncoder1);
	this.configurer.customCodecs().encoder(customEncoder2);

	this.configurer.customCodecs().writer(customWriter1);
	this.configurer.customCodecs().writer(customWriter2);

	List<HttpMessageWriter<?>> writers = this.configurer.getWriters();

	assertEquals(14, writers.size());
	assertSame(customEncoder1, getNextEncoder(writers));
	assertSame(customWriter1, writers.get(this.index.getAndIncrement()));
	assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ByteBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertEquals(CharSequenceEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ProtobufHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertSame(customEncoder2, getNextEncoder(writers));
	assertSame(customWriter2, writers.get(this.index.getAndIncrement()));
	assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jackson2SmileEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(CharSequenceEncoder.class, getNextEncoder(writers).getClass());
}
 

@Before
public void createContext() {
	final List<HttpMessageWriter<?>> messageWriters = new ArrayList<>();
	messageWriters.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
	messageWriters.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()));
	messageWriters.add(new ResourceHttpMessageWriter());
	messageWriters.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder()));
	Jackson2JsonEncoder jsonEncoder = new Jackson2JsonEncoder();
	messageWriters.add(new EncoderHttpMessageWriter<>(jsonEncoder));
	messageWriters.add(new ServerSentEventHttpMessageWriter(jsonEncoder));
	messageWriters.add(new FormHttpMessageWriter());
	messageWriters.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes()));
	messageWriters.add(new MultipartHttpMessageWriter(messageWriters));

	this.context = new BodyInserter.Context() {
		@Override
		public List<HttpMessageWriter<?>> messageWriters() {
			return messageWriters;
		}
		@Override
		public Optional<ServerHttpRequest> serverRequest() {
			return Optional.empty();
		}
		@Override
		public Map<String, Object> hints() {
			return hints;
		}
	};
	this.hints = new HashMap<>();
}
 

@Before
public void setup() throws Exception {
	List<HttpMessageWriter<?>> writerList = new ArrayList<>(5);
	writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
	writerList.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes()));
	writerList.add(new ResourceHttpMessageWriter());
	writerList.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder()));
	writerList.add(new EncoderHttpMessageWriter<>(new Jackson2JsonEncoder()));
	RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
	this.resultHandler = new ResponseBodyResultHandler(writerList, resolver);
}
 

/**
 * Constructor with a default list of part writers (String and Resource).
 */
public MultipartHttpMessageWriter() {
	this(Arrays.asList(
			new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()),
			new ResourceHttpMessageWriter()
	));
}
 

@Test
public void defaultWriters() {
	List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
	assertEquals(10, writers.size());
	assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ByteBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertStringEncoder(getNextEncoder(writers), true);
	assertEquals(ProtobufHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jackson2SmileEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass());
	assertStringEncoder(getNextEncoder(writers), false);
}
 

@Test
public void defaultAndCustomWriters() {
	Encoder<?> customEncoder1 = mock(Encoder.class);
	Encoder<?> customEncoder2 = mock(Encoder.class);

	when(customEncoder1.canEncode(ResolvableType.forClass(Object.class), null)).thenReturn(false);
	when(customEncoder2.canEncode(ResolvableType.forClass(Object.class), null)).thenReturn(true);

	HttpMessageWriter<?> customWriter1 = mock(HttpMessageWriter.class);
	HttpMessageWriter<?> customWriter2 = mock(HttpMessageWriter.class);

	when(customWriter1.canWrite(ResolvableType.forClass(Object.class), null)).thenReturn(false);
	when(customWriter2.canWrite(ResolvableType.forClass(Object.class), null)).thenReturn(true);

	this.configurer.customCodecs().encoder(customEncoder1);
	this.configurer.customCodecs().encoder(customEncoder2);

	this.configurer.customCodecs().writer(customWriter1);
	this.configurer.customCodecs().writer(customWriter2);

	List<HttpMessageWriter<?>> writers = this.configurer.getWriters();

	assertEquals(14, writers.size());
	assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ByteBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertEquals(CharSequenceEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(ProtobufHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
	assertSame(customEncoder1, getNextEncoder(writers));
	assertSame(customWriter1, writers.get(this.index.getAndIncrement()));
	assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jackson2SmileEncoder.class, getNextEncoder(writers).getClass());
	assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass());
	assertSame(customEncoder2, getNextEncoder(writers));
	assertSame(customWriter2, writers.get(this.index.getAndIncrement()));
	assertEquals(CharSequenceEncoder.class, getNextEncoder(writers).getClass());
}
 

/**
 * Return the configured resource message writer.
 */
@Nullable
public ResourceHttpMessageWriter getResourceHttpMessageWriter() {
	return this.resourceHttpMessageWriter;
}
 

/**
 * Processes a resource request.
 * <p>Checks for the existence of the requested resource in the configured list of locations.
 * If the resource does not exist, a {@code 404} response will be returned to the client.
 * If the resource exists, the request will be checked for the presence of the
 * {@code Last-Modified} header, and its value will be compared against the last-modified
 * timestamp of the given resource, returning a {@code 304} status code if the
 * {@code Last-Modified} value  is greater. If the resource is newer than the
 * {@code Last-Modified} value, or the header is not present, the content resource
 * of the resource will be written to the response with caching headers
 * set to expire one year in the future.
 */
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
	return getResource(exchange)
			.switchIfEmpty(Mono.defer(() -> {
				logger.debug(exchange.getLogPrefix() + "Resource not found");
				return Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND));
			}))
			.flatMap(resource -> {
				try {
					if (HttpMethod.OPTIONS.matches(exchange.getRequest().getMethodValue())) {
						exchange.getResponse().getHeaders().add("Allow", "GET,HEAD,OPTIONS");
						return Mono.empty();
					}

					// Supported methods and required session
					HttpMethod httpMethod = exchange.getRequest().getMethod();
					if (!SUPPORTED_METHODS.contains(httpMethod)) {
						return Mono.error(new MethodNotAllowedException(
								exchange.getRequest().getMethodValue(), SUPPORTED_METHODS));
					}

					// Header phase
					if (exchange.checkNotModified(Instant.ofEpochMilli(resource.lastModified()))) {
						logger.trace(exchange.getLogPrefix() + "Resource not modified");
						return Mono.empty();
					}

					// Apply cache settings, if any
					CacheControl cacheControl = getCacheControl();
					if (cacheControl != null) {
						exchange.getResponse().getHeaders().setCacheControl(cacheControl);
					}

					// Check the media type for the resource
					MediaType mediaType = MediaTypeFactory.getMediaType(resource).orElse(null);

					// Content phase
					if (HttpMethod.HEAD.matches(exchange.getRequest().getMethodValue())) {
						setHeaders(exchange, resource, mediaType);
						exchange.getResponse().getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
						return Mono.empty();
					}

					setHeaders(exchange, resource, mediaType);
					ResourceHttpMessageWriter writer = getResourceHttpMessageWriter();
					Assert.state(writer != null, "No ResourceHttpMessageWriter");
					return writer.write(Mono.just(resource),
							null, ResolvableType.forClass(Resource.class), mediaType,
							exchange.getRequest(), exchange.getResponse(),
							Hints.from(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix()));
				}
				catch (IOException ex) {
					return Mono.error(ex);
				}
			});
}
 

@Test
public void ofResourceRange() throws IOException {
	final int rangeStart = 10;
	Resource body = new ClassPathResource("response.txt", getClass());
	BodyInserter<Resource, ReactiveHttpOutputMessage> inserter = BodyInserters.fromResource(body);

	MockServerHttpRequest request = MockServerHttpRequest.get("/foo")
			.range(HttpRange.createByteRange(rangeStart))
			.build();
	MockServerHttpResponse response = new MockServerHttpResponse();
	Mono<Void> result = inserter.insert(response, new BodyInserter.Context() {
		@Override
		public List<HttpMessageWriter<?>> messageWriters() {
			return Collections.singletonList(new ResourceHttpMessageWriter());
		}

		@Override
		public Optional<ServerHttpRequest> serverRequest() {
			return Optional.of(request);
		}

		@Override
		public Map<String, Object> hints() {
			return hints;
		}
	});
	StepVerifier.create(result).expectComplete().verify();

	byte[] allBytes = Files.readAllBytes(body.getFile().toPath());
	byte[] expectedBytes = new byte[allBytes.length - rangeStart];
	System.arraycopy(allBytes, rangeStart, expectedBytes, 0, expectedBytes.length);

	StepVerifier.create(response.getBody())
			.consumeNextWith(dataBuffer -> {
				byte[] resultBytes = new byte[dataBuffer.readableByteCount()];
				dataBuffer.read(resultBytes);
				DataBufferUtils.release(dataBuffer);
				assertArrayEquals(expectedBytes, resultBytes);
			})
			.expectComplete()
			.verify();
}
 

/**
 * Return the configured resource message writer.
 */
@Nullable
public ResourceHttpMessageWriter getResourceHttpMessageWriter() {
	return this.resourceHttpMessageWriter;
}
 

/**
 * Processes a resource request.
 * <p>Checks for the existence of the requested resource in the configured list of locations.
 * If the resource does not exist, a {@code 404} response will be returned to the client.
 * If the resource exists, the request will be checked for the presence of the
 * {@code Last-Modified} header, and its value will be compared against the last-modified
 * timestamp of the given resource, returning a {@code 304} status code if the
 * {@code Last-Modified} value  is greater. If the resource is newer than the
 * {@code Last-Modified} value, or the header is not present, the content resource
 * of the resource will be written to the response with caching headers
 * set to expire one year in the future.
 */
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
	return getResource(exchange)
			.switchIfEmpty(Mono.defer(() -> {
				logger.debug(exchange.getLogPrefix() + "Resource not found");
				return Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND));
			}))
			.flatMap(resource -> {
				try {
					if (HttpMethod.OPTIONS.matches(exchange.getRequest().getMethodValue())) {
						exchange.getResponse().getHeaders().add("Allow", "GET,HEAD,OPTIONS");
						return Mono.empty();
					}

					// Supported methods and required session
					HttpMethod httpMethod = exchange.getRequest().getMethod();
					if (!SUPPORTED_METHODS.contains(httpMethod)) {
						return Mono.error(new MethodNotAllowedException(
								exchange.getRequest().getMethodValue(), SUPPORTED_METHODS));
					}

					// Header phase
					if (exchange.checkNotModified(Instant.ofEpochMilli(resource.lastModified()))) {
						logger.trace(exchange.getLogPrefix() + "Resource not modified");
						return Mono.empty();
					}

					// Apply cache settings, if any
					CacheControl cacheControl = getCacheControl();
					if (cacheControl != null) {
						exchange.getResponse().getHeaders().setCacheControl(cacheControl);
					}

					// Check the media type for the resource
					MediaType mediaType = MediaTypeFactory.getMediaType(resource).orElse(null);

					// Content phase
					if (HttpMethod.HEAD.matches(exchange.getRequest().getMethodValue())) {
						setHeaders(exchange, resource, mediaType);
						exchange.getResponse().getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
						return Mono.empty();
					}

					setHeaders(exchange, resource, mediaType);
					ResourceHttpMessageWriter writer = getResourceHttpMessageWriter();
					Assert.state(writer != null, "No ResourceHttpMessageWriter");
					return writer.write(Mono.just(resource),
							null, ResolvableType.forClass(Resource.class), mediaType,
							exchange.getRequest(), exchange.getResponse(),
							Hints.from(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix()));
				}
				catch (IOException ex) {
					return Mono.error(ex);
				}
			});
}
 

@Test
public void ofResourceRange() throws IOException {
	final int rangeStart = 10;
	Resource body = new ClassPathResource("response.txt", getClass());
	BodyInserter<Resource, ReactiveHttpOutputMessage> inserter = BodyInserters.fromResource(body);

	MockServerHttpRequest request = MockServerHttpRequest.get("/foo")
			.range(HttpRange.createByteRange(rangeStart))
			.build();
	MockServerHttpResponse response = new MockServerHttpResponse();
	Mono<Void> result = inserter.insert(response, new BodyInserter.Context() {
		@Override
		public List<HttpMessageWriter<?>> messageWriters() {
			return Collections.singletonList(new ResourceHttpMessageWriter());
		}

		@Override
		public Optional<ServerHttpRequest> serverRequest() {
			return Optional.of(request);
		}

		@Override
		public Map<String, Object> hints() {
			return hints;
		}
	});
	StepVerifier.create(result).expectComplete().verify();

	byte[] allBytes = Files.readAllBytes(body.getFile().toPath());
	byte[] expectedBytes = new byte[allBytes.length - rangeStart];
	System.arraycopy(allBytes, rangeStart, expectedBytes, 0, expectedBytes.length);

	StepVerifier.create(response.getBody())
			.consumeNextWith(dataBuffer -> {
				byte[] resultBytes = new byte[dataBuffer.readableByteCount()];
				dataBuffer.read(resultBytes);
				DataBufferUtils.release(dataBuffer);
				assertArrayEquals(expectedBytes, resultBytes);
			})
			.expectComplete()
			.verify();
}
 

@Override
protected void register(GenericApplicationContext context, CodecConfigurer configurer) {
	configurer.customCodecs().writer(new ResourceHttpMessageWriter());
	configurer.customCodecs().decoder(new ResourceDecoder());
}
 

/**
 * Configure the {@link ResourceHttpMessageWriter} to use.
 * <p>By default a {@link ResourceHttpMessageWriter} will be configured.
 */
public void setResourceHttpMessageWriter(@Nullable ResourceHttpMessageWriter httpMessageWriter) {
	this.resourceHttpMessageWriter = httpMessageWriter;
}
 
 类所在包
 同包方法