Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
4ba3d073
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,发现更多精彩内容 >>
提交
4ba3d073
编写于
12月 09, 2015
作者:
R
Rossen Stoyanchev
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add HttpExceptionHandler
上级
448aac81
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
300 addition
and
38 deletion
+300
-38
spring-web-reactive/src/main/java/org/springframework/http/server/reactive/ErrorHandlingHttpHandler.java
...mework/http/server/reactive/ErrorHandlingHttpHandler.java
+73
-0
spring-web-reactive/src/main/java/org/springframework/http/server/reactive/HttpExceptionHandler.java
...gframework/http/server/reactive/HttpExceptionHandler.java
+43
-0
spring-web-reactive/src/test/java/org/springframework/http/server/reactive/ErrorHandlingHttpHandlerTests.java
...k/http/server/reactive/ErrorHandlingHttpHandlerTests.java
+168
-0
spring-web-reactive/src/test/java/org/springframework/web/reactive/method/InvocableHandlerMethodTests.java
...work/web/reactive/method/InvocableHandlerMethodTests.java
+16
-38
未找到文件。
spring-web-reactive/src/main/java/org/springframework/http/server/reactive/ErrorHandlingHttpHandler.java
0 → 100644
浏览文件 @
4ba3d073
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.springframework.http.server.reactive
;
import
java.util.Arrays
;
import
java.util.List
;
import
org.reactivestreams.Publisher
;
import
reactor.Publishers
;
import
reactor.core.publisher.convert.RxJava1Converter
;
import
rx.Observable
;
import
org.springframework.util.Assert
;
/**
* {@link HttpHandler} that delegates to a target {@link HttpHandler} and handles
* any errors from it by invoking one or more {@link HttpExceptionHandler}s
* sequentially until one of them completes successfully.
*
* @author Rossen Stoyanchev
*/
public
class
ErrorHandlingHttpHandler
extends
HttpHandlerDecorator
{
private
final
List
<
HttpExceptionHandler
>
exceptionHandlers
;
public
ErrorHandlingHttpHandler
(
HttpHandler
targetHandler
,
HttpExceptionHandler
...
exceptionHandlers
)
{
super
(
targetHandler
);
Assert
.
notEmpty
(
exceptionHandlers
,
"At least one exception handler is required"
);
this
.
exceptionHandlers
=
Arrays
.
asList
(
exceptionHandlers
);
}
@Override
public
Publisher
<
Void
>
handle
(
ServerHttpRequest
request
,
ServerHttpResponse
response
)
{
Publisher
<
Void
>
publisher
;
try
{
publisher
=
getDelegate
().
handle
(
request
,
response
);
}
catch
(
Throwable
ex
)
{
publisher
=
Publishers
.
error
(
ex
);
}
for
(
HttpExceptionHandler
handler
:
this
.
exceptionHandlers
)
{
publisher
=
applyExceptionHandler
(
publisher
,
handler
,
request
,
response
);
}
return
publisher
;
}
private
static
Publisher
<
Void
>
applyExceptionHandler
(
Publisher
<
Void
>
publisher
,
HttpExceptionHandler
handler
,
ServerHttpRequest
request
,
ServerHttpResponse
response
)
{
// see https://github.com/reactor/reactor/issues/580
Observable
<
Void
>
observable
=
RxJava1Converter
.
from
(
publisher
).
onErrorResumeNext
(
ex
->
{
return
RxJava1Converter
.
from
(
handler
.
handle
(
request
,
response
,
ex
));
});
return
RxJava1Converter
.
from
(
observable
);
}
}
spring-web-reactive/src/main/java/org/springframework/http/server/reactive/HttpExceptionHandler.java
0 → 100644
浏览文件 @
4ba3d073
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.springframework.http.server.reactive
;
import
org.reactivestreams.Publisher
;
/**
* A contract for resolving exceptions from HTTP request handling.
*
* <p>{@link ErrorHandlingHttpHandler} provides a way of applying a list
* {@link HttpExceptionHandler}s to a target {@link HttpHandler}.
*
* @author Rossen Stoyanchev
* @see ErrorHandlingHttpHandler
*/
public
interface
HttpExceptionHandler
{
/**
* Handle the given exception and return a completion Publisher to indicate
* when error handling is complete, or send an error signal if the exception
* was not handled.
*
* @param request the current request
* @param response the current response
* @param ex the exception to handle
* @return Publisher to indicate when exception handling is complete.
*/
Publisher
<
Void
>
handle
(
ServerHttpRequest
request
,
ServerHttpResponse
response
,
Throwable
ex
);
}
spring-web-reactive/src/test/java/org/springframework/http/server/reactive/ErrorHandlingHttpHandlerTests.java
0 → 100644
浏览文件 @
4ba3d073
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.springframework.http.server.reactive
;
import
java.net.URI
;
import
java.util.concurrent.TimeUnit
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.reactivestreams.Publisher
;
import
reactor.Publishers
;
import
reactor.rx.Streams
;
import
reactor.rx.action.Signal
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.http.HttpStatus
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertNull
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
/**
* @author Rossen Stoyanchev
*/
@SuppressWarnings
(
"ThrowableResultOfMethodCallIgnored"
)
public
class
ErrorHandlingHttpHandlerTests
{
private
MockServerHttpRequest
request
;
private
MockServerHttpResponse
response
;
@Before
public
void
setUp
()
throws
Exception
{
this
.
request
=
new
MockServerHttpRequest
(
HttpMethod
.
GET
,
new
URI
(
"http://localhost:8080"
));
this
.
response
=
new
MockServerHttpResponse
();
}
@Test
public
void
handleErrorSignal
()
throws
Exception
{
HttpExceptionHandler
exceptionHandler
=
new
UnresolvedExceptionHandler
();
HttpHandler
targetHandler
=
new
TestHttpHandler
(
new
IllegalStateException
(
"boo"
));
HttpHandler
handler
=
new
ErrorHandlingHttpHandler
(
targetHandler
,
exceptionHandler
);
Publisher
<
Void
>
publisher
=
handler
.
handle
(
this
.
request
,
this
.
response
);
Streams
.
wrap
(
publisher
).
toList
().
await
(
5
,
TimeUnit
.
SECONDS
);
assertEquals
(
HttpStatus
.
INTERNAL_SERVER_ERROR
,
this
.
response
.
getStatus
());
}
@Test
public
void
handleErrorSignalWithMultipleHttpErrorHandlers
()
throws
Exception
{
HttpExceptionHandler
[]
exceptionHandlers
=
new
HttpExceptionHandler
[]
{
new
UnresolvedExceptionHandler
(),
new
UnresolvedExceptionHandler
(),
new
HttpStatusExceptionHandler
(
HttpStatus
.
INTERNAL_SERVER_ERROR
),
new
UnresolvedExceptionHandler
()
};
HttpHandler
targetHandler
=
new
TestHttpHandler
(
new
IllegalStateException
(
"boo"
));
HttpHandler
httpHandler
=
new
ErrorHandlingHttpHandler
(
targetHandler
,
exceptionHandlers
);
Publisher
<
Void
>
publisher
=
httpHandler
.
handle
(
this
.
request
,
this
.
response
);
Streams
.
wrap
(
publisher
).
toList
().
await
(
5
,
TimeUnit
.
SECONDS
);
assertEquals
(
HttpStatus
.
INTERNAL_SERVER_ERROR
,
this
.
response
.
getStatus
());
}
@Test
public
void
unresolvedException
()
throws
Exception
{
HttpExceptionHandler
exceptionHandler
=
new
UnresolvedExceptionHandler
();
HttpHandler
targetHandler
=
new
TestHttpHandler
(
new
IllegalStateException
(
"boo"
));
HttpHandler
httpHandler
=
new
ErrorHandlingHttpHandler
(
targetHandler
,
exceptionHandler
);
Publisher
<
Void
>
publisher
=
httpHandler
.
handle
(
this
.
request
,
this
.
response
);
Throwable
ex
=
awaitErrorSignal
(
publisher
);
assertEquals
(
"boo"
,
ex
.
getMessage
());
assertNull
(
this
.
response
.
getStatus
());
}
@Test
public
void
thrownExceptionBecomesErrorSignal
()
throws
Exception
{
HttpExceptionHandler
exceptionHandler
=
new
HttpStatusExceptionHandler
(
HttpStatus
.
INTERNAL_SERVER_ERROR
);
HttpHandler
targetHandler
=
new
TestHttpHandler
(
new
IllegalStateException
(
"boo"
),
true
);
HttpHandler
handler
=
new
ErrorHandlingHttpHandler
(
targetHandler
,
exceptionHandler
);
Publisher
<
Void
>
publisher
=
handler
.
handle
(
this
.
request
,
this
.
response
);
Streams
.
wrap
(
publisher
).
toList
().
await
(
5
,
TimeUnit
.
SECONDS
);
assertEquals
(
HttpStatus
.
INTERNAL_SERVER_ERROR
,
this
.
response
.
getStatus
());
}
private
Throwable
awaitErrorSignal
(
Publisher
<?>
publisher
)
throws
Exception
{
Signal
<?>
signal
=
Streams
.
wrap
(
publisher
).
materialize
().
toList
().
await
(
5
,
TimeUnit
.
SECONDS
).
get
(
0
);
assertEquals
(
"Unexpected signal: "
+
signal
,
Signal
.
Type
.
ERROR
,
signal
.
getType
());
return
signal
.
getThrowable
();
}
private
static
class
TestHttpHandler
implements
HttpHandler
{
private
final
Throwable
exception
;
private
final
boolean
raise
;
public
TestHttpHandler
(
Throwable
exception
)
{
this
(
exception
,
false
);
}
public
TestHttpHandler
(
Throwable
exception
,
boolean
raise
)
{
this
.
exception
=
exception
;
this
.
raise
=
raise
;
assertTrue
(
exception
instanceof
RuntimeException
||
!
this
.
raise
);
}
@Override
public
Publisher
<
Void
>
handle
(
ServerHttpRequest
request
,
ServerHttpResponse
response
)
{
if
(
this
.
raise
)
{
throw
(
RuntimeException
)
exception
;
}
return
Publishers
.
error
(
this
.
exception
);
}
}
/** Leave the exception unresolved. */
private
static
class
UnresolvedExceptionHandler
implements
HttpExceptionHandler
{
@Override
public
Publisher
<
Void
>
handle
(
ServerHttpRequest
request
,
ServerHttpResponse
response
,
Throwable
ex
)
{
return
Publishers
.
error
(
ex
);
}
}
/** Set the response status to the given HttpStatus. */
private
static
class
HttpStatusExceptionHandler
implements
HttpExceptionHandler
{
private
final
HttpStatus
status
;
public
HttpStatusExceptionHandler
(
HttpStatus
status
)
{
this
.
status
=
status
;
}
@Override
public
Publisher
<
Void
>
handle
(
ServerHttpRequest
request
,
ServerHttpResponse
response
,
Throwable
ex
)
{
response
.
setStatusCode
(
this
.
status
);
return
Publishers
.
empty
();
}
}
}
spring-web-reactive/src/test/java/org/springframework/web/reactive/method/InvocableHandlerMethodTests.java
浏览文件 @
4ba3d073
...
@@ -23,8 +23,6 @@ import java.util.Collections;
...
@@ -23,8 +23,6 @@ import java.util.Collections;
import
java.util.List
;
import
java.util.List
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.TimeUnit
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.junit.Before
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.reactivestreams.Publisher
;
import
org.reactivestreams.Publisher
;
...
@@ -49,9 +47,6 @@ import static org.mockito.Mockito.when;
...
@@ -49,9 +47,6 @@ import static org.mockito.Mockito.when;
@SuppressWarnings
(
"ThrowableResultOfMethodCallIgnored"
)
@SuppressWarnings
(
"ThrowableResultOfMethodCallIgnored"
)
public
class
InvocableHandlerMethodTests
{
public
class
InvocableHandlerMethodTests
{
private
static
Log
logger
=
LogFactory
.
getLog
(
InvocableHandlerMethodTests
.
class
);
private
ServerHttpRequest
request
;
private
ServerHttpRequest
request
;
...
@@ -66,9 +61,10 @@ public class InvocableHandlerMethodTests {
...
@@ -66,9 +61,10 @@ public class InvocableHandlerMethodTests {
InvocableHandlerMethod
hm
=
createHandlerMethod
(
"noArgs"
);
InvocableHandlerMethod
hm
=
createHandlerMethod
(
"noArgs"
);
Publisher
<
HandlerResult
>
publisher
=
hm
.
invokeForRequest
(
this
.
request
);
Publisher
<
HandlerResult
>
publisher
=
hm
.
invokeForRequest
(
this
.
request
);
Object
value
=
awaitValue
(
publisher
);
List
<
HandlerResult
>
values
=
Streams
.
wrap
(
publisher
).
toList
().
await
(
5
,
TimeUnit
.
SECONDS
);
assertEquals
(
"success"
,
value
);
assertEquals
(
1
,
values
.
size
());
assertEquals
(
"success"
,
values
.
get
(
0
).
getValue
());
}
}
@Test
@Test
...
@@ -78,9 +74,10 @@ public class InvocableHandlerMethodTests {
...
@@ -78,9 +74,10 @@ public class InvocableHandlerMethodTests {
hm
.
setHandlerMethodArgumentResolvers
(
Collections
.
singletonList
(
new
RequestParamArgumentResolver
()));
hm
.
setHandlerMethodArgumentResolvers
(
Collections
.
singletonList
(
new
RequestParamArgumentResolver
()));
Publisher
<
HandlerResult
>
publisher
=
hm
.
invokeForRequest
(
this
.
request
);
Publisher
<
HandlerResult
>
publisher
=
hm
.
invokeForRequest
(
this
.
request
);
Object
value
=
awaitValue
(
publisher
);
List
<
HandlerResult
>
values
=
Streams
.
wrap
(
publisher
).
toList
().
await
(
5
,
TimeUnit
.
SECONDS
);
assertEquals
(
"success:null"
,
value
);
assertEquals
(
1
,
values
.
size
());
assertEquals
(
"success:null"
,
values
.
get
(
0
).
getValue
());
}
}
@Test
@Test
...
@@ -89,9 +86,10 @@ public class InvocableHandlerMethodTests {
...
@@ -89,9 +86,10 @@ public class InvocableHandlerMethodTests {
addResolver
(
hm
,
Publishers
.
just
(
"value1"
));
addResolver
(
hm
,
Publishers
.
just
(
"value1"
));
Publisher
<
HandlerResult
>
publisher
=
hm
.
invokeForRequest
(
this
.
request
);
Publisher
<
HandlerResult
>
publisher
=
hm
.
invokeForRequest
(
this
.
request
);
Object
value
=
awaitValue
(
publisher
);
List
<
HandlerResult
>
values
=
Streams
.
wrap
(
publisher
).
toList
().
await
(
5
,
TimeUnit
.
SECONDS
);
assertEquals
(
"success:value1"
,
value
);
assertEquals
(
1
,
values
.
size
());
assertEquals
(
"success:value1"
,
values
.
get
(
0
).
getValue
());
}
}
@Test
@Test
...
@@ -100,12 +98,10 @@ public class InvocableHandlerMethodTests {
...
@@ -100,12 +98,10 @@ public class InvocableHandlerMethodTests {
addResolver
(
hm
,
Publishers
.
from
(
Arrays
.
asList
(
"value1"
,
"value2"
,
"value3"
)));
addResolver
(
hm
,
Publishers
.
from
(
Arrays
.
asList
(
"value1"
,
"value2"
,
"value3"
)));
Publisher
<
HandlerResult
>
publisher
=
hm
.
invokeForRequest
(
this
.
request
);
Publisher
<
HandlerResult
>
publisher
=
hm
.
invokeForRequest
(
this
.
request
);
List
<
Signal
<
HandlerResult
>>
signals
=
awaitSignals
(
publisher
);
List
<
HandlerResult
>
values
=
Streams
.
wrap
(
publisher
).
toList
().
await
(
5
,
TimeUnit
.
SECONDS
);
assertEquals
(
"Expected only one value: "
+
signals
.
toString
(),
2
,
signals
.
size
());
assertEquals
(
1
,
values
.
size
());
assertEquals
(
Signal
.
Type
.
NEXT
,
signals
.
get
(
0
).
getType
());
assertEquals
(
"success:value1"
,
values
.
get
(
0
).
getValue
());
assertEquals
(
Signal
.
Type
.
COMPLETE
,
signals
.
get
(
1
).
getType
());
assertEquals
(
"success:value1"
,
signals
.
get
(
0
).
get
().
getValue
());
}
}
@Test
@Test
...
@@ -191,28 +187,10 @@ public class InvocableHandlerMethodTests {
...
@@ -191,28 +187,10 @@ public class InvocableHandlerMethodTests {
handlerMethod
.
setHandlerMethodArgumentResolvers
(
Collections
.
singletonList
(
resolver
));
handlerMethod
.
setHandlerMethodArgumentResolvers
(
Collections
.
singletonList
(
resolver
));
}
}
private
Object
awaitValue
(
Publisher
<
HandlerResult
>
publisher
)
throws
Exception
{
private
Throwable
awaitErrorSignal
(
Publisher
<?>
publisher
)
throws
Exception
{
Object
object
=
awaitSignal
(
publisher
,
Signal
.
Type
.
NEXT
).
get
();
Signal
<?>
signal
=
Streams
.
wrap
(
publisher
).
materialize
().
toList
().
await
(
5
,
TimeUnit
.
SECONDS
).
get
(
0
);
assertEquals
(
HandlerResult
.
class
,
object
.
getClass
());
assertEquals
(
"Unexpected signal: "
+
signal
,
Signal
.
Type
.
ERROR
,
signal
.
getType
());
return
((
HandlerResult
)
object
).
getValue
();
return
signal
.
getThrowable
();
}
private
Throwable
awaitErrorSignal
(
Publisher
<
HandlerResult
>
publisher
)
throws
Exception
{
return
awaitSignal
(
publisher
,
Signal
.
Type
.
ERROR
).
getThrowable
();
}
@SuppressWarnings
(
"unchecked"
)
private
Signal
<
HandlerResult
>
awaitSignal
(
Publisher
<
HandlerResult
>
publisher
,
Signal
.
Type
type
)
throws
Exception
{
Signal
<
HandlerResult
>
signal
=
awaitSignals
(
publisher
).
get
(
0
);
if
(!
type
.
equals
(
signal
.
getType
())
&&
signal
.
isOnError
())
{
logger
.
error
(
"Unexpected error: "
,
signal
.
getThrowable
());
}
assertEquals
(
"Unexpected signal: "
+
signal
,
type
,
signal
.
getType
());
return
signal
;
}
private
List
<
Signal
<
HandlerResult
>>
awaitSignals
(
Publisher
<
HandlerResult
>
publisher
)
throws
InterruptedException
{
return
Streams
.
wrap
(
publisher
).
materialize
().
toList
().
await
(
5
,
TimeUnit
.
SECONDS
);
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录