Skip to content

Commit 2b27382

Browse files
committed
update: SSE 适配 spring-boot 和 solon
1 parent e923e16 commit 2b27382

File tree

19 files changed

+458
-10
lines changed

19 files changed

+458
-10
lines changed

forest-core/src/main/java/com/dtflys/forest/http/ForestRequest.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4662,7 +4662,7 @@ public Object getAttachment(String name) {
46624662
}
46634663

46644664

4665-
/**
4665+
/**
46664666
* 根据名称获取该请求中的附件
46674667
* <p>Attachment 是和请求绑定的附件属性值,这些值不能通过网络请求传递到远端服务器。</p>
46684668
* <p>不同请求的附件相互独立,即使名称相同,也互不影响。</p>
@@ -4679,8 +4679,17 @@ public <R> R getAttachment(String name, Class<R> clazz) {
46794679
}
46804680
return clazz.cast(result);
46814681
}
4682-
4683-
4682+
4683+
/**
4684+
* 根据名称获取或添加该请求中的附件
4685+
* <p>当该请求中附件名所对应的附件值不存在时,会调用回调函数添加一个附件值</p>
4686+
*
4687+
* @param name 附件名
4688+
* @param supplier 附件值回调函数
4689+
* @return 附件值
4690+
* @param <R> 附件值类型
4691+
* @since 1.6.1
4692+
*/
46844693
public <R> R getOrAddAttachment(String name, Supplier<R> supplier) {
46854694
Object obj = getAttachment(name);
46864695
if (obj == null) {

forest-core/src/main/java/com/dtflys/forest/interceptor/SSEInterceptor.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
import com.dtflys.forest.http.ForestResponse;
55
import com.dtflys.forest.sse.EventSource;
66

7+
import java.io.InputStream;
8+
79
/**
810
* Forest SSE 拦截器
911
*
1012
* @since 1.6.1
1113
*/
12-
public interface SSEInterceptor extends Interceptor {
14+
public interface SSEInterceptor extends Interceptor<InputStream> {
1315

1416
/**
1517
* 监听打开回调函数:在开始 SSE 数据流监听的时候调用

forest-core/src/test/java/com/dtflys/forest/test/sse/MySSEInterceptor.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010
import com.dtflys.forest.sse.EventSource;
1111
import com.dtflys.forest.test.model.Contact;
1212

13-
public class MySSEInterceptor implements SSEInterceptor {
13+
import java.io.InputStream;
1414

15+
public class MySSEInterceptor implements SSEInterceptor {
1516

1617
@Override
17-
public void onSuccess(Object data, ForestRequest request, ForestResponse response) {
18+
public void onSuccess(InputStream data, ForestRequest request, ForestResponse response) {
1819
StringBuilder builder = (StringBuilder) request.getOrAddAttachment("text", StringBuilder::new);
1920
builder.append("MySSEInterceptor onSuccess\n");
2021
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.dtflys.forest.solon.test.sse;
2+
3+
import com.dtflys.forest.annotation.BaseRequest;
4+
import com.dtflys.forest.annotation.ForestClient;
5+
import com.dtflys.forest.annotation.Get;
6+
import com.dtflys.forest.http.ForestSSE;
7+
8+
@ForestClient
9+
@BaseRequest(baseURL = "http://localhost:{port}")
10+
public interface MySSEClient {
11+
12+
@Get("/sse")
13+
ForestSSE testSSE();
14+
15+
@Get(url = "/sse", interceptor = MySSEInterceptor.class)
16+
ForestSSE testSSE_withInterceptor();
17+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.dtflys.forest.solon.test.sse;
2+
3+
import com.dtflys.forest.annotation.SSEDataMessage;
4+
import com.dtflys.forest.annotation.SSEName;
5+
import com.dtflys.forest.annotation.SSEValue;
6+
import com.dtflys.forest.http.ForestRequest;
7+
import com.dtflys.forest.http.ForestResponse;
8+
import com.dtflys.forest.interceptor.SSEInterceptor;
9+
import org.noear.solon.annotation.Component;
10+
import org.noear.solon.annotation.Inject;
11+
12+
import java.io.InputStream;
13+
14+
@Component
15+
public class MySSEInterceptor implements SSEInterceptor {
16+
17+
@Inject
18+
private TestComp testComp;
19+
20+
@Override
21+
public void onSuccess(InputStream data, ForestRequest request, ForestResponse response) {
22+
StringBuilder builder = (StringBuilder) request.getOrAddAttachment("text", StringBuilder::new);
23+
builder.append("onSuccess\n");
24+
}
25+
26+
@Override
27+
public void afterExecute(ForestRequest request, ForestResponse response) {
28+
StringBuilder builder = (StringBuilder) request.getOrAddAttachment("text", StringBuilder::new);
29+
builder.append("afterExecute\n");
30+
}
31+
32+
@SSEDataMessage
33+
public void onData(ForestRequest request, @SSEName String name, @SSEValue String value) {
34+
StringBuilder builder = (StringBuilder) request.getOrAddAttachment("text", StringBuilder::new);
35+
builder.append("Receive name=" + name + "; value=" + value + "; comp=" + testComp.getValue() + "\n");
36+
}
37+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.dtflys.forest.solon.test.sse;
2+
3+
4+
import org.noear.solon.annotation.Component;
5+
6+
@Component
7+
public class TestComp {
8+
9+
public String getValue() {
10+
return "test";
11+
}
12+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.dtflys.forest.solon.test.sse;
2+
3+
import com.dtflys.forest.annotation.BindingVar;
4+
import com.dtflys.forest.http.ForestSSE;
5+
import okhttp3.mockwebserver.MockResponse;
6+
import okhttp3.mockwebserver.MockWebServer;
7+
import org.junit.Rule;
8+
import org.junit.Test;
9+
import org.junit.runner.RunWith;
10+
import org.noear.solon.annotation.Inject;
11+
import org.noear.solon.test.SolonJUnit4ClassRunner;
12+
import org.noear.solon.test.SolonTest;
13+
14+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
15+
16+
@RunWith(SolonJUnit4ClassRunner.class)
17+
@SolonTest(env = "sse")
18+
public class TestSSE {
19+
20+
@Rule
21+
public MockWebServer server = new MockWebServer();
22+
23+
@Inject
24+
private MySSEClient sseClient;
25+
26+
@BindingVar("port")
27+
public Integer getPort() {
28+
return server.getPort();
29+
}
30+
31+
@Test
32+
public void testSSE() {
33+
server.enqueue(new MockResponse().setResponseCode(200).setBody(
34+
"data:start\n" +
35+
"data:hello\n"
36+
));
37+
38+
StringBuilder builder = new StringBuilder();
39+
40+
sseClient.testSSE()
41+
.addOnData((eventSource, name, value) -> {
42+
builder.append("Receive ").append(name).append(": ").append(value).append("\n");
43+
})
44+
.listen();
45+
46+
assertThat(builder.toString()).isEqualTo(
47+
"Receive data: start\n" +
48+
"Receive data: hello\n"
49+
);
50+
}
51+
52+
53+
@Test
54+
public void testSSE_withInterceptor() {
55+
server.enqueue(new MockResponse().setResponseCode(200).setBody(
56+
"data:start\n" +
57+
"data:hello\n"
58+
));
59+
60+
ForestSSE sse = sseClient.testSSE_withInterceptor().listen();
61+
62+
assertThat(sse.getRequest().getAttachment("text").toString()).isEqualTo(
63+
"onSuccess\n" +
64+
"afterExecute\n" +
65+
"Receive name=data; value=start; comp=test\n" +
66+
"Receive name=data; value=hello; comp=test\n"
67+
);
68+
}
69+
70+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
forest:
3+
enabled: true
4+
max-connections: 300
5+
max-route-connections: 300
6+
connect-timeout: 3000
7+
max-retry-count: 0
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.dtflys.forest.springboot.test.sse;
2+
3+
import com.dtflys.forest.annotation.BaseRequest;
4+
import com.dtflys.forest.annotation.Get;
5+
import com.dtflys.forest.http.ForestSSE;
6+
7+
@BaseRequest(baseURL = "http://localhost:{port}")
8+
public interface MySSEClient {
9+
10+
@Get("/sse")
11+
ForestSSE testSSE();
12+
13+
@Get(url = "/sse", interceptor = MySSEInterceptor.class)
14+
ForestSSE testSSE_withInterceptor();
15+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.dtflys.forest.springboot.test.sse;
2+
3+
import com.dtflys.forest.annotation.SSEDataMessage;
4+
import com.dtflys.forest.annotation.SSEName;
5+
import com.dtflys.forest.annotation.SSEValue;
6+
import com.dtflys.forest.http.ForestRequest;
7+
import com.dtflys.forest.http.ForestResponse;
8+
import com.dtflys.forest.interceptor.SSEInterceptor;
9+
import org.springframework.stereotype.Component;
10+
11+
import javax.annotation.Resource;
12+
import java.io.InputStream;
13+
14+
@Component
15+
public class MySSEInterceptor implements SSEInterceptor {
16+
17+
@Resource
18+
private TestComp testComp;
19+
20+
@Override
21+
public void onSuccess(InputStream data, ForestRequest request, ForestResponse response) {
22+
StringBuilder builder = (StringBuilder) request.getOrAddAttachment("text", StringBuilder::new);
23+
builder.append("onSuccess\n");
24+
}
25+
26+
@Override
27+
public void afterExecute(ForestRequest request, ForestResponse response) {
28+
StringBuilder builder = (StringBuilder) request.getOrAddAttachment("text", StringBuilder::new);
29+
builder.append("afterExecute\n");
30+
}
31+
32+
@SSEDataMessage
33+
public void onData(ForestRequest request, @SSEName String name, @SSEValue String value) {
34+
StringBuilder builder = (StringBuilder) request.getOrAddAttachment("text", StringBuilder::new);
35+
builder.append("Receive name=" + name + "; value=" + value + "; comp=" + testComp.getValue() + "\n");
36+
}
37+
}

0 commit comments

Comments
 (0)