Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add reactive progressive rendering features to MustacheView #16829

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Switch naming convention in MustacheView to async prefix
  • Loading branch information
Dave Syer committed May 21, 2019
commit 1489bfe9a2012060c15bcd7bc8e7e3ce4432a74d
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public String layout(Model model) {
@RequestMapping(path = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public String sse(Model model) {
model.addAttribute("time", new Date());
model.addAttribute("flux.message",
model.addAttribute("async.message",
Flux.just("<span>Hello</span>", "<span>World</span>")
.delayElements(Duration.ofMillis(10)));
model.addAttribute("title", "Hello App");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{{#flux.message}}
{{#async.message}}
event: message
{{#ssedata}}
<h2>Title</h2>
{{{.}}}
{{/ssedata}}
{{/flux.message}}
{{/async.message}}
Original file line number Diff line number Diff line change
Expand Up @@ -3038,14 +3038,14 @@ There are some special features of the `MustacheView` that make it suitable for

===== Progressive Rendering

A model element of type `Publisher` will be left in the model (instead of expanding it before the view is rendered), if its name starts with "flux" or "mono" or "publisher". The `View` is then rendered and flushed to the HTTP response as soon as each element is published. Browsers are really good at rendering partially complete HTML, so the flux elements will most likely be visible to the user as soon as they are available. This is useful for rendering the "main" content of a page if it is a list or a table, for instance.
A model element of type `Publisher` will be left in the model (instead of expanding it before the view is rendered), if its name starts with "async." or "async:". The `View` is then rendered and flushed to the HTTP response as soon as each element is published. Browsers are really good at rendering partially complete HTML, so the flux elements will most likely be visible to the user as soon as they are available. This is useful for rendering the "main" content of a page if it is a list or a table, for instance.

===== Sserver Sent Event (SSE) Support

To render a `View` with content type `text/event-stream` you need a model element of type `Publisher`, and also a template that includes that element (probably starts and ends with it). There is a convenience Lambda (`ssedata`) added to the model for you that prepends every line with `data:` - you can use it if you wish to simplify the rendering of the data elements. Two new lines are added after each item in `{{#ssedata}}`. E.g. with an element called `flux.events` of type `Flux<Event>`:

```
{{#flux.events}}
{{#async.events}}
event: message
id: {{id}}
{{#ssedata}}
Expand All @@ -3054,7 +3054,7 @@ id: {{id}}
<span>Value: {{value}}<span>
</div>
{{/ssedata}}
{{/flux.events}}
{{/async.events}}
```

the output will be
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,7 @@ private Template compile(Resource resource) {
protected Mono<Void> resolveAsyncAttributes(Map<String, Object> model) {
Map<String, Object> result = new HashMap<>();
for (String key : model.keySet()) {
if (!key.startsWith("flux") && !key.startsWith("mono")
&& !key.startsWith("publisher")) {
if (!key.startsWith("async.") && !key.startsWith("async:")) {
result.put(key, model.get(key));
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public void viewResolvesPublisher() {
view.setUrl(this.templateUrl + "/flux.html");
view.setCharset(StandardCharsets.UTF_8.displayName());
view.setApplicationContext(this.context);
view.render(Collections.singletonMap("flux.value", Flux.just("World", "Spring")),
view.render(Collections.singletonMap("async:value", Flux.just("World", "Spring")),
MediaType.TEXT_HTML, this.exchange).block(Duration.ofSeconds(30));
assertThat(this.exchange.getResponse().getBodyAsString()
.block(Duration.ofSeconds(30))).isEqualTo("Hello\nWorld\nSpring\n");
Expand All @@ -90,7 +90,7 @@ public void viewResolvesSseManual() {
view.setUrl(this.templateUrl + "/sse.html");
view.setCharset(StandardCharsets.UTF_8.displayName());
view.setApplicationContext(this.context);
view.render(Collections.singletonMap("flux.value", Flux.just("World", "Spring")),
view.render(Collections.singletonMap("async.value", Flux.just("World", "Spring")),
MediaType.TEXT_EVENT_STREAM, this.exchange).block(Duration.ofSeconds(30));
assertThat(this.exchange.getResponse().getBodyAsString()
.block(Duration.ofSeconds(30))).isEqualTo(
Expand All @@ -106,7 +106,7 @@ public void viewResolvesSseData() {
view.setUrl(this.templateUrl + "/ssedata.html");
view.setCharset(StandardCharsets.UTF_8.displayName());
view.setApplicationContext(this.context);
view.render(Collections.singletonMap("flux.value", Flux.just("World", "Spring")),
view.render(Collections.singletonMap("async.value", Flux.just("World", "Spring")),
MediaType.TEXT_EVENT_STREAM, this.exchange)
.block(Duration.ofSeconds(300));
assertThat(this.exchange.getResponse().getBodyAsString()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Hello
{{#flux.value}}
{{#async:value}}
{{.}}
{{/flux.value}}
{{/async:value}}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{#flux.value}}
{{#async.value}}
event: message
data: {{.}}


{{/flux.value}}
{{/async.value}}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{#flux.value}}
{{#async.value}}
event: message
{{#ssedata}}
{{.}}
{{/ssedata}}
{{/flux.value}}
{{/async.value}}