Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
d94ce0a1
S
spring-framework
项目概览
爱吃血肠
/
spring-framework
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
spring-framework
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
d94ce0a1
编写于
9月 20, 2016
作者:
J
Juergen Hoeller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Avoid package dependency cycles
上级
65e01eab
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
76 addition
and
51 deletion
+76
-51
spring-core/src/main/java/org/springframework/core/codec/ResourceRegionEncoder.java
...org/springframework/core/codec/ResourceRegionEncoder.java
+21
-1
spring-core/src/main/java/org/springframework/util/ResourceUtils.java
...src/main/java/org/springframework/util/ResourceUtils.java
+0
-24
spring-web-reactive/src/test/java/org/springframework/web/reactive/resource/ResourceWebHandlerTests.java
...mework/web/reactive/resource/ResourceWebHandlerTests.java
+1
-3
spring-web/src/main/java/org/springframework/http/codec/ResourceHttpMessageWriter.java
...springframework/http/codec/ResourceHttpMessageWriter.java
+27
-12
spring-web/src/main/java/org/springframework/http/codec/ResourceRegionHttpMessageWriter.java
...framework/http/codec/ResourceRegionHttpMessageWriter.java
+20
-1
spring-web/src/test/java/org/springframework/http/codec/ResourceHttpMessageWriterTests.java
...gframework/http/codec/ResourceHttpMessageWriterTests.java
+7
-10
未找到文件。
spring-core/src/main/java/org/springframework/core/codec/ResourceRegionEncoder.java
浏览文件 @
d94ce0a1
...
...
@@ -28,6 +28,8 @@ import reactor.core.publisher.Flux;
import
reactor.core.publisher.Mono
;
import
org.springframework.core.ResolvableType
;
import
org.springframework.core.io.InputStreamResource
;
import
org.springframework.core.io.Resource
;
import
org.springframework.core.io.buffer.DataBuffer
;
import
org.springframework.core.io.buffer.DataBufferFactory
;
import
org.springframework.core.io.buffer.DataBufferUtils
;
...
...
@@ -134,7 +136,7 @@ public class ResourceRegionEncoder extends AbstractEncoder<ResourceRegion> {
private
byte
[]
getContentRangeHeader
(
ResourceRegion
region
)
{
long
start
=
region
.
getPosition
();
long
end
=
start
+
region
.
getCount
()
-
1
;
OptionalLong
contentLength
=
ResourceUtils
.
contentLength
(
region
.
getResource
());
OptionalLong
contentLength
=
contentLength
(
region
.
getResource
());
if
(
contentLength
.
isPresent
())
{
return
getAsciiBytes
(
"Content-Range: bytes "
+
start
+
"-"
+
end
+
"/"
+
contentLength
.
getAsLong
()
+
"\r\n\r\n"
);
}
...
...
@@ -143,4 +145,22 @@ public class ResourceRegionEncoder extends AbstractEncoder<ResourceRegion> {
}
}
/**
* Determine, if possible, the contentLength of the given resource without reading it.
* @param resource the resource instance
* @return the contentLength of the resource
*/
private
OptionalLong
contentLength
(
Resource
resource
)
{
// Don't try to determine contentLength on InputStreamResource - cannot be read afterwards...
// Note: custom InputStreamResource subclasses could provide a pre-calculated content length!
if
(
InputStreamResource
.
class
!=
resource
.
getClass
())
{
try
{
return
OptionalLong
.
of
(
resource
.
contentLength
());
}
catch
(
IOException
ignored
)
{
}
}
return
OptionalLong
.
empty
();
}
}
spring-core/src/main/java/org/springframework/util/ResourceUtils.java
浏览文件 @
d94ce0a1
...
...
@@ -18,16 +18,11 @@ package org.springframework.util;
import
java.io.File
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
import
java.net.MalformedURLException
;
import
java.net.URI
;
import
java.net.URISyntaxException
;
import
java.net.URL
;
import
java.net.URLConnection
;
import
java.util.OptionalLong
;
import
org.springframework.core.io.InputStreamResource
;
import
org.springframework.core.io.Resource
;
/**
* Utility methods for resolving resource locations to files in the
...
...
@@ -389,23 +384,4 @@ public abstract class ResourceUtils {
con
.
setUseCaches
(
con
.
getClass
().
getSimpleName
().
startsWith
(
"JNLP"
));
}
/**
* Determine, if possible, the contentLength of the given resource
* without reading it.
* @param resource the resource instance
* @return the contentLength of the resource
*/
public
static
OptionalLong
contentLength
(
Resource
resource
)
{
// Don't try to determine contentLength on InputStreamResource - cannot be read afterwards...
// Note: custom InputStreamResource subclasses could provide a pre-calculated content length!
if
(
InputStreamResource
.
class
!=
resource
.
getClass
())
{
try
{
return
OptionalLong
.
of
(
resource
.
contentLength
());
}
catch
(
IOException
ignored
)
{
}
}
return
OptionalLong
.
empty
();
}
}
spring-web-reactive/src/test/java/org/springframework/web/reactive/resource/ResourceWebHandlerTests.java
浏览文件 @
d94ce0a1
...
...
@@ -527,9 +527,7 @@ public class ResourceWebHandlerTests {
TestSubscriber
.
subscribe
(
this
.
handler
.
handle
(
this
.
exchange
))
.
assertErrorWith
(
throwable
->
{
assertThat
(
throwable
,
instanceOf
(
ResponseStatusException
.
class
));
ResponseStatusException
exc
=
(
ResponseStatusException
)
throwable
;
assertThat
(
exc
.
getStatus
(),
is
(
HttpStatus
.
REQUESTED_RANGE_NOT_SATISFIABLE
));
assertThat
(
throwable
,
instanceOf
(
IllegalArgumentException
.
class
));
});
}
...
...
spring-web/src/main/java/org/springframework/http/codec/ResourceHttpMessageWriter.java
浏览文件 @
d94ce0a1
...
...
@@ -23,6 +23,7 @@ import java.util.HashMap;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Optional
;
import
java.util.OptionalLong
;
import
org.reactivestreams.Publisher
;
import
reactor.core.publisher.Flux
;
...
...
@@ -31,6 +32,7 @@ import reactor.core.publisher.Mono;
import
org.springframework.core.ResolvableType
;
import
org.springframework.core.codec.ResourceDecoder
;
import
org.springframework.core.codec.ResourceEncoder
;
import
org.springframework.core.io.InputStreamResource
;
import
org.springframework.core.io.Resource
;
import
org.springframework.core.io.support.ResourceRegion
;
import
org.springframework.http.HttpHeaders
;
...
...
@@ -43,8 +45,6 @@ import org.springframework.http.ZeroCopyHttpOutputMessage;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpResponse
;
import
org.springframework.util.MimeTypeUtils
;
import
org.springframework.util.ResourceUtils
;
import
org.springframework.web.server.ResponseStatusException
;
/**
* Implementation of {@link HttpMessageWriter} that can write
...
...
@@ -74,18 +74,14 @@ public class ResourceHttpMessageWriter extends AbstractServerHttpMessageWriter<R
this
.
resourceRegionHttpMessageWriter
=
new
ResourceRegionHttpMessageWriter
(
bufferSize
);
}
@Override
protected
Map
<
String
,
Object
>
resolveWriteHints
(
ResolvableType
streamType
,
ResolvableType
elementType
,
MediaType
mediaType
,
ServerHttpRequest
request
)
{
try
{
List
<
HttpRange
>
httpRanges
=
request
.
getHeaders
().
getRange
();
if
(!
httpRanges
.
isEmpty
())
{
return
Collections
.
singletonMap
(
ResourceHttpMessageWriter
.
HTTP_RANGE_REQUEST_HINT
,
httpRanges
);
}
}
catch
(
IllegalArgumentException
ex
)
{
throw
new
ResponseStatusException
(
HttpStatus
.
REQUESTED_RANGE_NOT_SATISFIABLE
,
"Could not parse Range request header"
,
ex
);
List
<
HttpRange
>
httpRanges
=
request
.
getHeaders
().
getRange
();
if
(!
httpRanges
.
isEmpty
())
{
return
Collections
.
singletonMap
(
ResourceHttpMessageWriter
.
HTTP_RANGE_REQUEST_HINT
,
httpRanges
);
}
return
Collections
.
emptyMap
();
}
...
...
@@ -139,12 +135,31 @@ public class ResourceHttpMessageWriter extends AbstractServerHttpMessageWriter<R
headers
.
setContentType
(
mediaType
);
}
if
(
headers
.
getContentLength
()
<
0
)
{
ResourceUtils
.
contentLength
(
resource
).
ifPresent
(
headers:
:
setContentLength
);
contentLength
(
resource
).
ifPresent
(
headers:
:
setContentLength
);
}
}
/**
* Determine, if possible, the contentLength of the given resource without reading it.
* @param resource the resource instance
* @return the contentLength of the resource
*/
private
OptionalLong
contentLength
(
Resource
resource
)
{
// Don't try to determine contentLength on InputStreamResource - cannot be read afterwards...
// Note: custom InputStreamResource subclasses could provide a pre-calculated content length!
if
(
InputStreamResource
.
class
!=
resource
.
getClass
())
{
try
{
return
OptionalLong
.
of
(
resource
.
contentLength
());
}
catch
(
IOException
ignored
)
{
}
}
return
OptionalLong
.
empty
();
}
private
Mono
<
Void
>
writeContent
(
Resource
resource
,
ResolvableType
type
,
ReactiveHttpOutputMessage
outputMessage
,
Map
<
String
,
Object
>
hints
)
{
if
(
outputMessage
instanceof
ZeroCopyHttpOutputMessage
)
{
Optional
<
File
>
file
=
getFile
(
resource
);
if
(
file
.
isPresent
())
{
...
...
spring-web/src/main/java/org/springframework/http/codec/ResourceRegionHttpMessageWriter.java
浏览文件 @
d94ce0a1
...
...
@@ -28,6 +28,7 @@ import reactor.core.publisher.Mono;
import
org.springframework.core.ResolvableType
;
import
org.springframework.core.codec.ResourceRegionEncoder
;
import
org.springframework.core.io.InputStreamResource
;
import
org.springframework.core.io.Resource
;
import
org.springframework.core.io.support.ResourceRegion
;
import
org.springframework.http.MediaType
;
...
...
@@ -80,7 +81,7 @@ class ResourceRegionHttpMessageWriter extends EncoderHttpMessageWriter<ResourceR
private
void
writeSingleResourceRegionHeaders
(
ResourceRegion
region
,
MediaType
contentType
,
ReactiveHttpOutputMessage
outputMessage
)
{
OptionalLong
resourceLength
=
ResourceUtils
.
contentLength
(
region
.
getResource
());
OptionalLong
resourceLength
=
contentLength
(
region
.
getResource
());
resourceLength
.
ifPresent
(
length
->
{
long
start
=
region
.
getPosition
();
long
end
=
start
+
region
.
getCount
()
-
1
;
...
...
@@ -91,6 +92,24 @@ class ResourceRegionHttpMessageWriter extends EncoderHttpMessageWriter<ResourceR
outputMessage
.
getHeaders
().
setContentType
(
contentType
);
}
/**
* Determine, if possible, the contentLength of the given resource without reading it.
* @param resource the resource instance
* @return the contentLength of the resource
*/
private
OptionalLong
contentLength
(
Resource
resource
)
{
// Don't try to determine contentLength on InputStreamResource - cannot be read afterwards...
// Note: custom InputStreamResource subclasses could provide a pre-calculated content length!
if
(
InputStreamResource
.
class
!=
resource
.
getClass
())
{
try
{
return
OptionalLong
.
of
(
resource
.
contentLength
());
}
catch
(
IOException
ignored
)
{
}
}
return
OptionalLong
.
empty
();
}
private
Mono
<
Void
>
writeResourceRegion
(
ResourceRegion
region
,
ResolvableType
type
,
ReactiveHttpOutputMessage
outputMessage
)
{
if
(
outputMessage
instanceof
ZeroCopyHttpOutputMessage
)
{
...
...
spring-web/src/test/java/org/springframework/http/codec/ResourceHttpMessageWriterTests.java
浏览文件 @
d94ce0a1
...
...
@@ -16,13 +16,9 @@
package
org.springframework.http.codec
;
import
static
org
.
hamcrest
.
Matchers
.*;
import
static
org
.
junit
.
Assert
.*;
import
java.nio.charset.StandardCharsets
;
import
java.util.Collections
;
import
org.hamcrest.Matchers
;
import
org.junit.Before
;
import
org.junit.Rule
;
import
org.junit.Test
;
...
...
@@ -40,16 +36,18 @@ import org.springframework.core.io.buffer.DataBufferUtils;
import
org.springframework.core.io.buffer.support.DataBufferTestUtils
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpRange
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.MediaType
;
import
org.springframework.mock.http.server.reactive.test.MockServerHttpRequest
;
import
org.springframework.mock.http.server.reactive.test.MockServerHttpResponse
;
import
org.springframework.tests.TestSubscriber
;
import
org.springframework.util.MimeTypeUtils
;
import
org.springframework.web.server.ResponseStatusException
;
import
static
org
.
hamcrest
.
Matchers
.*;
import
static
org
.
junit
.
Assert
.*;
/**
* Unit tests for {@link ResourceHttpMessageWriter}.
*
* @author Brian Clozel
*/
public
class
ResourceHttpMessageWriterTests
{
...
...
@@ -72,6 +70,7 @@ public class ResourceHttpMessageWriterTests {
this
.
resource
=
new
ByteArrayResource
(
content
.
getBytes
(
StandardCharsets
.
UTF_8
));
}
@Test
public
void
writableMediaTypes
()
throws
Exception
{
assertThat
(
this
.
writer
.
getWritableMediaTypes
(),
...
...
@@ -80,7 +79,6 @@ public class ResourceHttpMessageWriterTests {
@Test
public
void
shouldWriteResource
()
throws
Exception
{
TestSubscriber
.
subscribe
(
this
.
writer
.
write
(
Mono
.
just
(
resource
),
null
,
ResolvableType
.
forClass
(
Resource
.
class
),
MediaType
.
TEXT_PLAIN
,
this
.
request
,
this
.
response
,
Collections
.
emptyMap
())).
assertComplete
();
...
...
@@ -93,7 +91,6 @@ public class ResourceHttpMessageWriterTests {
@Test
public
void
shouldWriteResourceRange
()
throws
Exception
{
this
.
request
.
getHeaders
().
setRange
(
Collections
.
singletonList
(
HttpRange
.
createByteRange
(
0
,
5
)));
TestSubscriber
.
subscribe
(
this
.
writer
.
write
(
Mono
.
just
(
resource
),
null
,
ResolvableType
.
forClass
(
Resource
.
class
),
...
...
@@ -111,10 +108,9 @@ public class ResourceHttpMessageWriterTests {
public
void
shouldThrowErrorInvalidRange
()
throws
Exception
{
this
.
request
.
getHeaders
().
set
(
HttpHeaders
.
RANGE
,
"invalid"
);
this
.
expectedException
.
expect
(
ResponseStatus
Exception
.
class
);
this
.
expectedException
.
expect
(
IllegalArgument
Exception
.
class
);
TestSubscriber
.
subscribe
(
this
.
writer
.
write
(
Mono
.
just
(
resource
),
null
,
ResolvableType
.
forClass
(
Resource
.
class
),
MediaType
.
TEXT_PLAIN
,
this
.
request
,
this
.
response
,
Collections
.
emptyMap
()));
this
.
expectedException
.
expect
(
Matchers
.
hasProperty
(
"status"
,
is
(
HttpStatus
.
REQUESTED_RANGE_NOT_SATISFIABLE
)));
}
private
Mono
<
String
>
reduceToString
(
Publisher
<
DataBuffer
>
buffers
,
DataBufferFactory
bufferFactory
)
{
...
...
@@ -127,4 +123,5 @@ public class ResourceHttpMessageWriterTests {
})
.
map
(
buffer
->
DataBufferTestUtils
.
dumpString
(
buffer
,
StandardCharsets
.
UTF_8
));
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录