类org.springframework.http.HttpRange源码实例Demo

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

@Test
public void header() {
	HttpHeaders httpHeaders = new HttpHeaders();
	long contentLength = 42L;
	httpHeaders.setContentLength(contentLength);
	MediaType contentType = MediaType.TEXT_PLAIN;
	httpHeaders.setContentType(contentType);
	InetSocketAddress host = InetSocketAddress.createUnresolved("localhost", 80);
	httpHeaders.setHost(host);
	List<HttpRange> range = Collections.singletonList(HttpRange.createByteRange(0, 42));
	httpHeaders.setRange(range);

	given(mockResponse.getHeaders()).willReturn(httpHeaders);

	ClientResponse.Headers headers = defaultClientResponse.headers();
	assertEquals(OptionalLong.of(contentLength), headers.contentLength());
	assertEquals(Optional.of(contentType), headers.contentType());
	assertEquals(httpHeaders, headers.asHttpHeaders());
}
 
@Test // SPR-15041
public void applicationOctetStreamDefaultContentType() throws Exception {
	MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
	ClassPathResource body = Mockito.mock(ClassPathResource.class);
	BDDMockito.given(body.getFilename()).willReturn("spring.dat");
	BDDMockito.given(body.contentLength()).willReturn(12L);
	BDDMockito.given(body.getInputStream()).willReturn(new ByteArrayInputStream("Spring Framework".getBytes()));
	HttpRange range = HttpRange.createByteRange(0, 5);
	ResourceRegion resourceRegion = range.toResourceRegion(body);

	converter.write(Collections.singletonList(resourceRegion), null, outputMessage);

	assertThat(outputMessage.getHeaders().getContentType(), is(MediaType.APPLICATION_OCTET_STREAM));
	assertThat(outputMessage.getHeaders().getFirst(HttpHeaders.CONTENT_RANGE), is("bytes 0-5/12"));
	assertThat(outputMessage.getBodyAsString(StandardCharsets.UTF_8), is("Spring"));
}
 
@Test
public void header() {
	HttpHeaders httpHeaders = new HttpHeaders();
	long contentLength = 42L;
	httpHeaders.setContentLength(contentLength);
	MediaType contentType = MediaType.TEXT_PLAIN;
	httpHeaders.setContentType(contentType);
	InetSocketAddress host = InetSocketAddress.createUnresolved("localhost", 80);
	httpHeaders.setHost(host);
	List<HttpRange> range = Collections.singletonList(HttpRange.createByteRange(0, 42));
	httpHeaders.setRange(range);

	when(mockResponse.getHeaders()).thenReturn(httpHeaders);

	ClientResponse.Headers headers = defaultClientResponse.headers();
	assertEquals(OptionalLong.of(contentLength), headers.contentLength());
	assertEquals(Optional.of(contentType), headers.contentType());
	assertEquals(httpHeaders, headers.asHttpHeaders());
}
 
@Test // SPR-15041
public void applicationOctetStreamDefaultContentType() throws Exception {
	MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
	ClassPathResource body = Mockito.mock(ClassPathResource.class);
	BDDMockito.given(body.getFilename()).willReturn("spring.dat");
	BDDMockito.given(body.contentLength()).willReturn(12L);
	BDDMockito.given(body.getInputStream()).willReturn(new ByteArrayInputStream("Spring Framework".getBytes()));
	HttpRange range = HttpRange.createByteRange(0, 5);
	ResourceRegion resourceRegion = range.toResourceRegion(body);

	converter.write(Collections.singletonList(resourceRegion), null, outputMessage);

	assertThat(outputMessage.getHeaders().getContentType(), is(MediaType.APPLICATION_OCTET_STREAM));
	assertThat(outputMessage.getHeaders().getFirst(HttpHeaders.CONTENT_RANGE), is("bytes 0-5/12"));
	assertThat(outputMessage.getBodyAsString(StandardCharsets.UTF_8), is("Spring"));
}
 
@Test
public void header() {
	HttpHeaders httpHeaders = new HttpHeaders();
	List<MediaType> accept =
			Collections.singletonList(MediaType.APPLICATION_JSON);
	httpHeaders.setAccept(accept);
	List<Charset> acceptCharset = Collections.singletonList(UTF_8);
	httpHeaders.setAcceptCharset(acceptCharset);
	long contentLength = 42L;
	httpHeaders.setContentLength(contentLength);
	MediaType contentType = MediaType.TEXT_PLAIN;
	httpHeaders.setContentType(contentType);
	InetSocketAddress host = InetSocketAddress.createUnresolved("localhost", 80);
	httpHeaders.setHost(host);
	List<HttpRange> range = Collections.singletonList(HttpRange.createByteRange(0, 42));
	httpHeaders.setRange(range);

	MockHttpServletRequest servletRequest = new MockHttpServletRequest("GET", "/");
	httpHeaders.forEach(servletRequest::addHeader);
	servletRequest.setContentType(MediaType.TEXT_PLAIN_VALUE);

	DefaultServerRequest request = new DefaultServerRequest(servletRequest,
			this.messageConverters);

	ServerRequest.Headers headers = request.headers();
	assertEquals(accept, headers.accept());
	assertEquals(acceptCharset, headers.acceptCharset());
	assertEquals(OptionalLong.of(contentLength), headers.contentLength());
	assertEquals(Optional.of(contentType), headers.contentType());
	assertEquals(httpHeaders, headers.asHttpHeaders());
}
 
@Test
public void shouldWritePartialContentByteRange() throws Exception {
	MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
	Resource body = new ClassPathResource("byterangeresource.txt", getClass());
	ResourceRegion region = HttpRange.createByteRange(0, 5).toResourceRegion(body);
	converter.write(region, MediaType.TEXT_PLAIN, outputMessage);

	HttpHeaders headers = outputMessage.getHeaders();
	assertThat(headers.getContentType(), is(MediaType.TEXT_PLAIN));
	assertThat(headers.getContentLength(), is(6L));
	assertThat(headers.get(HttpHeaders.CONTENT_RANGE).size(), is(1));
	assertThat(headers.get(HttpHeaders.CONTENT_RANGE).get(0), is("bytes 0-5/39"));
	assertThat(outputMessage.getBodyAsString(StandardCharsets.UTF_8), is("Spring"));
}
 
@Test
public void shouldWritePartialContentByteRangeNoEnd() throws Exception {
	MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
	Resource body = new ClassPathResource("byterangeresource.txt", getClass());
	ResourceRegion region = HttpRange.createByteRange(7).toResourceRegion(body);
	converter.write(region, MediaType.TEXT_PLAIN, outputMessage);

	HttpHeaders headers = outputMessage.getHeaders();
	assertThat(headers.getContentType(), is(MediaType.TEXT_PLAIN));
	assertThat(headers.getContentLength(), is(32L));
	assertThat(headers.get(HttpHeaders.CONTENT_RANGE).size(), is(1));
	assertThat(headers.get(HttpHeaders.CONTENT_RANGE).get(0), is("bytes 7-38/39"));
	assertThat(outputMessage.getBodyAsString(StandardCharsets.UTF_8), is("Framework test resource content."));
}
 
@Test
public void partialContentMultipleByteRanges() throws Exception {
	MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
	Resource body = new ClassPathResource("byterangeresource.txt", getClass());
	List<HttpRange> rangeList = HttpRange.parseRanges("bytes=0-5,7-15,17-20,22-38");
	List<ResourceRegion> regions = new ArrayList<>();
	for(HttpRange range : rangeList) {
		regions.add(range.toResourceRegion(body));
	}

	converter.write(regions, MediaType.TEXT_PLAIN, outputMessage);

	HttpHeaders headers = outputMessage.getHeaders();
	assertThat(headers.getContentType().toString(), Matchers.startsWith("multipart/byteranges;boundary="));
	String boundary = "--" + headers.getContentType().toString().substring(30);
	String content = outputMessage.getBodyAsString(StandardCharsets.UTF_8);
	String[] ranges = StringUtils.tokenizeToStringArray(content, "\r\n", false, true);

	assertThat(ranges[0], is(boundary));
	assertThat(ranges[1], is("Content-Type: text/plain"));
	assertThat(ranges[2], is("Content-Range: bytes 0-5/39"));
	assertThat(ranges[3], is("Spring"));

	assertThat(ranges[4], is(boundary));
	assertThat(ranges[5], is("Content-Type: text/plain"));
	assertThat(ranges[6], is("Content-Range: bytes 7-15/39"));
	assertThat(ranges[7], is("Framework"));

	assertThat(ranges[8], is(boundary));
	assertThat(ranges[9], is("Content-Type: text/plain"));
	assertThat(ranges[10], is("Content-Range: bytes 17-20/39"));
	assertThat(ranges[11], is("test"));

	assertThat(ranges[12], is(boundary));
	assertThat(ranges[13], is("Content-Type: text/plain"));
	assertThat(ranges[14], is("Content-Range: bytes 22-38/39"));
	assertThat(ranges[15], is("resource content."));
}
 
@Test
public void shouldWritePartialContentByteRange() throws Exception {
	MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
	Resource body = new ClassPathResource("byterangeresource.txt", getClass());
	ResourceRegion region = HttpRange.createByteRange(0, 5).toResourceRegion(body);
	converter.write(region, MediaType.TEXT_PLAIN, outputMessage);

	HttpHeaders headers = outputMessage.getHeaders();
	assertThat(headers.getContentType(), is(MediaType.TEXT_PLAIN));
	assertThat(headers.getContentLength(), is(6L));
	assertThat(headers.get(HttpHeaders.CONTENT_RANGE).size(), is(1));
	assertThat(headers.get(HttpHeaders.CONTENT_RANGE).get(0), is("bytes 0-5/39"));
	assertThat(outputMessage.getBodyAsString(StandardCharsets.UTF_8), is("Spring"));
}
 
@Test
public void shouldWritePartialContentByteRangeNoEnd() throws Exception {
	MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
	Resource body = new ClassPathResource("byterangeresource.txt", getClass());
	ResourceRegion region = HttpRange.createByteRange(7).toResourceRegion(body);
	converter.write(region, MediaType.TEXT_PLAIN, outputMessage);

	HttpHeaders headers = outputMessage.getHeaders();
	assertThat(headers.getContentType(), is(MediaType.TEXT_PLAIN));
	assertThat(headers.getContentLength(), is(32L));
	assertThat(headers.get(HttpHeaders.CONTENT_RANGE).size(), is(1));
	assertThat(headers.get(HttpHeaders.CONTENT_RANGE).get(0), is("bytes 7-38/39"));
	assertThat(outputMessage.getBodyAsString(StandardCharsets.UTF_8), is("Framework test resource content."));
}
 
@Test
public void partialContentMultipleByteRanges() throws Exception {
	MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
	Resource body = new ClassPathResource("byterangeresource.txt", getClass());
	List<HttpRange> rangeList = HttpRange.parseRanges("bytes=0-5,7-15,17-20,22-38");
	List<ResourceRegion> regions = new ArrayList<>();
	for(HttpRange range : rangeList) {
		regions.add(range.toResourceRegion(body));
	}

	converter.write(regions, MediaType.TEXT_PLAIN, outputMessage);

	HttpHeaders headers = outputMessage.getHeaders();
	assertThat(headers.getContentType().toString(), Matchers.startsWith("multipart/byteranges;boundary="));
	String boundary = "--" + headers.getContentType().toString().substring(30);
	String content = outputMessage.getBodyAsString(StandardCharsets.UTF_8);
	String[] ranges = StringUtils.tokenizeToStringArray(content, "\r\n", false, true);

	assertThat(ranges[0], is(boundary));
	assertThat(ranges[1], is("Content-Type: text/plain"));
	assertThat(ranges[2], is("Content-Range: bytes 0-5/39"));
	assertThat(ranges[3], is("Spring"));

	assertThat(ranges[4], is(boundary));
	assertThat(ranges[5], is("Content-Type: text/plain"));
	assertThat(ranges[6], is("Content-Range: bytes 7-15/39"));
	assertThat(ranges[7], is("Framework"));

	assertThat(ranges[8], is(boundary));
	assertThat(ranges[9], is("Content-Type: text/plain"));
	assertThat(ranges[10], is("Content-Range: bytes 17-20/39"));
	assertThat(ranges[11], is("test"));

	assertThat(ranges[12], is(boundary));
	assertThat(ranges[13], is("Content-Type: text/plain"));
	assertThat(ranges[14], is("Content-Range: bytes 22-38/39"));
	assertThat(ranges[15], is("resource content."));
}
 
@Override
public List<HttpRange> range() {
	return delegate().getRange();
}
 
@Override
public List<HttpRange> range() {
	return this.headers.range();
}
 
源代码14 项目: spring-analysis-note   文件: MockServerRequest.java
@Override
public List<HttpRange> range() {
	return delegate().getRange();
}
 
源代码15 项目: spring-analysis-note   文件: BodyInsertersTests.java
@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();
}
 
/**
 * 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 void handleRequest(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

	// For very general mappings (e.g. "/") we need to check 404 first
	Resource resource = getResource(request);
	if (resource == null) {
		logger.debug("Resource not found");
		response.sendError(HttpServletResponse.SC_NOT_FOUND);
		return;
	}

	if (HttpMethod.OPTIONS.matches(request.getMethod())) {
		response.setHeader("Allow", getAllowHeader());
		return;
	}

	// Supported methods and required session
	checkRequest(request);

	// Header phase
	if (new ServletWebRequest(request, response).checkNotModified(resource.lastModified())) {
		logger.trace("Resource not modified");
		return;
	}

	// Apply cache settings, if any
	prepareResponse(response);

	// Check the media type for the resource
	MediaType mediaType = getMediaType(request, resource);

	// Content phase
	if (METHOD_HEAD.equals(request.getMethod())) {
		setHeaders(response, resource, mediaType);
		return;
	}

	ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
	if (request.getHeader(HttpHeaders.RANGE) == null) {
		Assert.state(this.resourceHttpMessageConverter != null, "Not initialized");
		setHeaders(response, resource, mediaType);
		this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
	}
	else {
		Assert.state(this.resourceRegionHttpMessageConverter != null, "Not initialized");
		response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
		ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
		try {
			List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
			response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
			this.resourceRegionHttpMessageConverter.write(
					HttpRange.toResourceRegions(httpRanges, resource), mediaType, outputMessage);
		}
		catch (IllegalArgumentException ex) {
			response.setHeader("Content-Range", "bytes */" + resource.contentLength());
			response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
		}
	}
}
 
@Override
public List<HttpRange> range() {
	return this.delegate.getRange();
}
 
@Override
public Mono<Void> write(Publisher<? extends Resource> inputStream, @Nullable ResolvableType actualType,
		ResolvableType elementType, @Nullable MediaType mediaType, ServerHttpRequest request,
		ServerHttpResponse response, Map<String, Object> hints) {

	HttpHeaders headers = response.getHeaders();
	headers.set(HttpHeaders.ACCEPT_RANGES, "bytes");

	List<HttpRange> ranges;
	try {
		ranges = request.getHeaders().getRange();
	}
	catch (IllegalArgumentException ex) {
		response.setStatusCode(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE);
		return response.setComplete();
	}

	return Mono.from(inputStream).flatMap(resource -> {
		if (ranges.isEmpty()) {
			return writeResource(resource, elementType, mediaType, response, hints);
		}
		response.setStatusCode(HttpStatus.PARTIAL_CONTENT);
		List<ResourceRegion> regions = HttpRange.toResourceRegions(ranges, resource);
		MediaType resourceMediaType = getResourceMediaType(mediaType, resource, hints);
		if (regions.size() == 1){
			ResourceRegion region = regions.get(0);
			headers.setContentType(resourceMediaType);
			long contentLength = lengthOf(resource);
			if (contentLength != -1) {
				long start = region.getPosition();
				long end = start + region.getCount() - 1;
				end = Math.min(end, contentLength - 1);
				headers.add("Content-Range", "bytes " + start + '-' + end + '/' + contentLength);
				headers.setContentLength(end - start + 1);
			}
			return writeSingleRegion(region, response, hints);
		}
		else {
			String boundary = MimeTypeUtils.generateMultipartBoundaryString();
			MediaType multipartType = MediaType.parseMediaType("multipart/byteranges;boundary=" + boundary);
			headers.setContentType(multipartType);
			Map<String, Object> allHints = Hints.merge(hints, ResourceRegionEncoder.BOUNDARY_STRING_HINT, boundary);
			return encodeAndWriteRegions(Flux.fromIterable(regions), resourceMediaType, response, allHints);
		}
	});
}
 
@Override
public BodyBuilder range(HttpRange... ranges) {
	this.headers.setRange(Arrays.asList(ranges));
	return this;
}
 
private static HttpRange of(int first, int last) {
	return HttpRange.createByteRange(first, last);
}
 
源代码21 项目: spring-analysis-note   文件: MockServerRequest.java
@Override
public List<HttpRange> range() {
	return delegate().getRange();
}
 
@Override
public BodyBuilder range(HttpRange... ranges) {
	this.headers.setRange(Arrays.asList(ranges));
	return this;
}
 
@Override
public List<HttpRange> range() {
	return delegate().getRange();
}
 
@Override
public List<HttpRange> range() {
	return this.headers.range();
}
 
源代码25 项目: java-technology-stack   文件: MockServerRequest.java
@Override
public List<HttpRange> range() {
	return delegate().getRange();
}
 
源代码26 项目: java-technology-stack   文件: BodyInsertersTests.java
@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();
}
 
/**
 * 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 void handleRequest(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

	// For very general mappings (e.g. "/") we need to check 404 first
	Resource resource = getResource(request);
	if (resource == null) {
		logger.debug("Resource not found");
		response.sendError(HttpServletResponse.SC_NOT_FOUND);
		return;
	}

	if (HttpMethod.OPTIONS.matches(request.getMethod())) {
		response.setHeader("Allow", getAllowHeader());
		return;
	}

	// Supported methods and required session
	checkRequest(request);

	// Header phase
	if (new ServletWebRequest(request, response).checkNotModified(resource.lastModified())) {
		logger.trace("Resource not modified");
		return;
	}

	// Apply cache settings, if any
	prepareResponse(response);

	// Check the media type for the resource
	MediaType mediaType = getMediaType(request, resource);

	// Content phase
	if (METHOD_HEAD.equals(request.getMethod())) {
		setHeaders(response, resource, mediaType);
		return;
	}

	ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
	if (request.getHeader(HttpHeaders.RANGE) == null) {
		Assert.state(this.resourceHttpMessageConverter != null, "Not initialized");
		setHeaders(response, resource, mediaType);
		this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
	}
	else {
		Assert.state(this.resourceRegionHttpMessageConverter != null, "Not initialized");
		response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
		ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
		try {
			List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
			response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
			this.resourceRegionHttpMessageConverter.write(
					HttpRange.toResourceRegions(httpRanges, resource), mediaType, outputMessage);
		}
		catch (IllegalArgumentException ex) {
			response.setHeader("Content-Range", "bytes */" + resource.contentLength());
			response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
		}
	}
}
 
@Override
@SuppressWarnings("unchecked")
public Mono<Void> write(Publisher<? extends Resource> inputStream, @Nullable ResolvableType actualType,
		ResolvableType elementType, @Nullable MediaType mediaType, ServerHttpRequest request,
		ServerHttpResponse response, Map<String, Object> hints) {

	HttpHeaders headers = response.getHeaders();
	headers.set(HttpHeaders.ACCEPT_RANGES, "bytes");

	List<HttpRange> ranges;
	try {
		ranges = request.getHeaders().getRange();
	}
	catch (IllegalArgumentException ex) {
		response.setStatusCode(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE);
		return response.setComplete();
	}

	return Mono.from(inputStream).flatMap(resource -> {

		if (ranges.isEmpty()) {
			return writeResource(resource, elementType, mediaType, response, hints);
		}

		response.setStatusCode(HttpStatus.PARTIAL_CONTENT);
		List<ResourceRegion> regions = HttpRange.toResourceRegions(ranges, resource);
		MediaType resourceMediaType = getResourceMediaType(mediaType, resource, hints);

		if (regions.size() == 1){
			ResourceRegion region = regions.get(0);
			headers.setContentType(resourceMediaType);
			long contentLength = lengthOf(resource);
			if (contentLength != -1) {
				long start = region.getPosition();
				long end = start + region.getCount() - 1;
				end = Math.min(end, contentLength - 1);
				headers.add("Content-Range", "bytes " + start + '-' + end + '/' + contentLength);
				headers.setContentLength(end - start + 1);
			}
			return writeSingleRegion(region, response, hints);
		}
		else {
			String boundary = MimeTypeUtils.generateMultipartBoundaryString();
			MediaType multipartType = MediaType.parseMediaType("multipart/byteranges;boundary=" + boundary);
			headers.setContentType(multipartType);
			Map<String, Object> allHints = Hints.merge(hints, ResourceRegionEncoder.BOUNDARY_STRING_HINT, boundary);
			return encodeAndWriteRegions(Flux.fromIterable(regions), resourceMediaType, response, allHints);
		}
	});
}
 
@Override
public BodyBuilder range(HttpRange... ranges) {
	this.headers.setRange(Arrays.asList(ranges));
	return this;
}
 
private static HttpRange of(int first, int last) {
	return HttpRange.createByteRange(first, last);
}
 
 类所在包
 类方法
 同包方法