From 7b98a75da1d69c2ba36104284d3f129f0675f9c7 Mon Sep 17 00:00:00 2001 From: Eric Bussieres Date: Sun, 17 May 2020 21:05:37 -0400 Subject: [PATCH] #512: Add beans access for reactive app (#513) * #512: Add beans access for reactive app * Add session object to reactive view --- docs/src/orchid/resources/changelog/v3_1_4.md | 3 +- .../PebbleServletWebConfiguration.java | 4 +-- .../pebble/boot/Controllers.java | 10 ++++++ .../com/mitchellbosecke/pebble/boot/Foo.java | 9 ++++++ .../boot/autoconfigure/ReactiveAppTest.java | 24 +++++++++++++- .../boot/autoconfigure/ServletAppTest.java | 15 +++++++++ .../src/test/resources/templates/beans.pebble | 1 + .../resources/templates/contextPath.pebble | 2 +- .../resources/templates/responseObject.pebble | 1 + .../spring/reactive/PebbleReactiveView.java | 32 +++++++++++++------ .../reactive/PebbleReactiveViewResolver.java | 5 --- .../spring/servlet/PebbleViewResolver.java | 12 ++----- .../pebble/spring/config/MVCConfig.java | 3 +- 13 files changed, 89 insertions(+), 32 deletions(-) create mode 100644 pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Foo.java create mode 100644 pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/beans.pebble create mode 100644 pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/responseObject.pebble diff --git a/docs/src/orchid/resources/changelog/v3_1_4.md b/docs/src/orchid/resources/changelog/v3_1_4.md index 4b6ba977a..4249b17ee 100644 --- a/docs/src/orchid/resources/changelog/v3_1_4.md +++ b/docs/src/orchid/resources/changelog/v3_1_4.md @@ -5,4 +5,5 @@ version: '3.1.4' - Slice filter: Use collection size when toIndex is greater than collection size (#504) - Adjust spring boot doc (#509) - Build with jdk14 (#508) -- Set proxyBeanMethods to false (#507) \ No newline at end of file +- Set proxyBeanMethods to false (#507) +- Add access to Spring Beans/request/session and response when using Pebble with WebFlux (#512) \ No newline at end of file diff --git a/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleServletWebConfiguration.java b/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleServletWebConfiguration.java index 9cf619577..122cdb680 100644 --- a/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleServletWebConfiguration.java +++ b/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleServletWebConfiguration.java @@ -17,10 +17,8 @@ class PebbleServletWebConfiguration extends AbstractPebbleConfiguration { @ConditionalOnMissingBean(name = "pebbleViewResolver") PebbleViewResolver pebbleViewResolver(PebbleProperties properties, PebbleEngine pebbleEngine) { - PebbleViewResolver pvr = new PebbleViewResolver(); + PebbleViewResolver pvr = new PebbleViewResolver(pebbleEngine); properties.applyToMvcViewResolver(pvr); - - pvr.setPebbleEngine(pebbleEngine); if (pebbleEngine.getLoader() instanceof ClasspathLoader) { // classpathloader doesn't like leading slashes in paths pvr.setPrefix(this.stripLeadingSlash(properties.getPrefix())); diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Controllers.java b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Controllers.java index 52eb0afa7..795b843de 100644 --- a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Controllers.java +++ b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Controllers.java @@ -26,4 +26,14 @@ public String extensions() { return "extensions"; } + @RequestMapping("/beans.action") + public String beans() { + return "beans"; + } + + @RequestMapping("/response.action") + public String response() { + return "responseObject"; + } + } \ No newline at end of file diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Foo.java b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Foo.java new file mode 100644 index 000000000..f45315082 --- /dev/null +++ b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Foo.java @@ -0,0 +1,9 @@ +package com.mitchellbosecke.pebble.boot; + +import org.springframework.stereotype.Component; + +@Component +public class Foo { + + public String value = "bar"; +} diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ReactiveAppTest.java b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ReactiveAppTest.java index 210b4624d..60d6a8b26 100644 --- a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ReactiveAppTest.java +++ b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ReactiveAppTest.java @@ -36,7 +36,7 @@ void testRequestAccess() throws Exception { .expectBody(String.class) .returnResult().getResponseBody(); - assertThat(result).isEqualTo("ctx path:"); + assertThat(result).isEqualTo("ctx path:/contextPath.action"); } @Test @@ -74,5 +74,27 @@ void testAdditionalExtensions() throws Exception { assertThat(result).isEqualTo("Hola Boot! Tested!"); } + + @Test + void testBeansAccess() throws Exception { + String result = this.client.get().uri("/beans.action").exchange() + .expectStatus().isOk() + .expectHeader().contentTypeCompatibleWith(MediaType.TEXT_HTML) + .expectBody(String.class) + .returnResult().getResponseBody(); + + assertThat(result).isEqualTo("beans:bar"); + } + + @Test + void testResponseAccess() throws Exception { + String result = this.client.get().uri("/response.action").exchange() + .expectStatus().isOk() + .expectHeader().contentTypeCompatibleWith(MediaType.TEXT_HTML) + .expectBody(String.class) + .returnResult().getResponseBody(); + + assertThat(result).isEqualTo("response:200 OK"); + } } diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ServletAppTest.java b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ServletAppTest.java index 431142b23..b4bdeb587 100644 --- a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ServletAppTest.java +++ b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ServletAppTest.java @@ -70,4 +70,19 @@ void testAdditionalExtensions() throws Exception { .andExpect(content().string("Hola Boot! Tested!")); } + @Test + void testBeansAccess() throws Exception { + this.mockMvc.perform(get("/beans.action")) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML)) + .andExpect(content().string("beans:bar")); + } + + @Test + void testResponseAccess() throws Exception { + this.mockMvc.perform(get("/response.action")) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML)) + .andExpect(content().string("response:200")); + } } diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/beans.pebble b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/beans.pebble new file mode 100644 index 000000000..c0a95852f --- /dev/null +++ b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/beans.pebble @@ -0,0 +1 @@ +beans:{{beans.foo.value}} \ No newline at end of file diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/contextPath.pebble b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/contextPath.pebble index 6b2af7875..bf5fc36c5 100644 --- a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/contextPath.pebble +++ b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/contextPath.pebble @@ -1 +1 @@ -ctx path:{{request.contextPath}} \ No newline at end of file +ctx path:{{request.contextPath}}{{request.path}} \ No newline at end of file diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/responseObject.pebble b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/responseObject.pebble new file mode 100644 index 000000000..1b11aa7d5 --- /dev/null +++ b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/responseObject.pebble @@ -0,0 +1 @@ +response:{{response.status}}{{response.statusCode}} \ No newline at end of file diff --git a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveView.java b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveView.java index c0809e716..48c2c51d8 100644 --- a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveView.java +++ b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveView.java @@ -1,9 +1,17 @@ package com.mitchellbosecke.pebble.spring.reactive; +import static java.util.Optional.ofNullable; + import com.mitchellbosecke.pebble.PebbleEngine; import com.mitchellbosecke.pebble.error.PebbleException; +import com.mitchellbosecke.pebble.spring.context.Beans; import com.mitchellbosecke.pebble.template.PebbleTemplate; - +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.Charset; +import java.util.Locale; +import java.util.Map; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferUtils; @@ -12,20 +20,16 @@ import org.springframework.util.MimeType; import org.springframework.web.reactive.result.view.AbstractUrlBasedView; import org.springframework.web.server.ServerWebExchange; - -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.nio.charset.Charset; -import java.util.Locale; -import java.util.Map; - -import static java.util.Optional.ofNullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; public class PebbleReactiveView extends AbstractUrlBasedView { + private static final String BEANS_VARIABLE_NAME = "beans"; + private static final String REQUEST_VARIABLE_NAME = "request"; + private static final String RESPONSE_VARIABLE_NAME = "response"; + private static final String SESSION_VARIABLE_NAME = "session"; + private PebbleEngine pebbleEngine; private String templateName; @@ -47,6 +51,7 @@ protected Mono renderInternal(Map renderAttributes, try { Charset charset = this.getCharset(contentType); Writer writer = new OutputStreamWriter(dataBuffer.asOutputStream(), charset); + this.addVariablesToModel(renderAttributes, exchange); this.evaluateTemplate(renderAttributes, locale, writer); } catch (Exception ex) { DataBufferUtils.release(dataBuffer); @@ -55,6 +60,13 @@ protected Mono renderInternal(Map renderAttributes, return exchange.getResponse().writeWith(Flux.just(dataBuffer)); } + private void addVariablesToModel(Map model, ServerWebExchange exchange) { + model.put(BEANS_VARIABLE_NAME, new Beans(this.getApplicationContext())); + model.put(REQUEST_VARIABLE_NAME, exchange.getRequest()); + model.put(RESPONSE_VARIABLE_NAME, exchange.getResponse()); + model.put(SESSION_VARIABLE_NAME, exchange.getSession()); + } + private Charset getCharset(@Nullable MediaType mediaType) { return ofNullable(mediaType) .map(MimeType::getCharset) diff --git a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveViewResolver.java b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveViewResolver.java index 138e7ae73..3f4a4734d 100644 --- a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveViewResolver.java +++ b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveViewResolver.java @@ -1,7 +1,6 @@ package com.mitchellbosecke.pebble.spring.reactive; import com.mitchellbosecke.pebble.PebbleEngine; - import org.springframework.web.reactive.result.view.AbstractUrlBasedView; import org.springframework.web.reactive.result.view.UrlBasedViewResolver; @@ -27,8 +26,4 @@ protected AbstractUrlBasedView createView(String viewName) { protected Class requiredViewClass() { return PebbleReactiveView.class; } - - public PebbleEngine getPebbleEngine() { - return this.pebbleEngine; - } } diff --git a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/servlet/PebbleViewResolver.java b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/servlet/PebbleViewResolver.java index 0b7a66f44..01271123d 100644 --- a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/servlet/PebbleViewResolver.java +++ b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/servlet/PebbleViewResolver.java @@ -8,18 +8,17 @@ import com.mitchellbosecke.pebble.PebbleEngine; import com.mitchellbosecke.pebble.loader.Loader; - import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Required; import org.springframework.web.servlet.view.AbstractTemplateViewResolver; import org.springframework.web.servlet.view.AbstractUrlBasedView; public class PebbleViewResolver extends AbstractTemplateViewResolver implements InitializingBean { private String characterEncoding = "UTF-8"; - private PebbleEngine pebbleEngine; + private final PebbleEngine pebbleEngine; - public PebbleViewResolver() { + public PebbleViewResolver(PebbleEngine pebbleEngine) { + this.pebbleEngine = pebbleEngine; this.setViewClass(this.requiredViewClass()); } @@ -34,11 +33,6 @@ public void setCharacterEncoding(String characterEncoding) { this.characterEncoding = characterEncoding; } - @Required - public void setPebbleEngine(PebbleEngine pebbleEngine) { - this.pebbleEngine = pebbleEngine; - } - @Override protected AbstractUrlBasedView buildView(String viewName) throws Exception { PebbleView view = (PebbleView) super.buildView(viewName); diff --git a/pebble-spring/pebble-spring5/src/test/java/com/mitchellbosecke/pebble/spring/config/MVCConfig.java b/pebble-spring/pebble-spring5/src/test/java/com/mitchellbosecke/pebble/spring/config/MVCConfig.java index 56d3a6615..10122412e 100644 --- a/pebble-spring/pebble-spring5/src/test/java/com/mitchellbosecke/pebble/spring/config/MVCConfig.java +++ b/pebble-spring/pebble-spring5/src/test/java/com/mitchellbosecke/pebble/spring/config/MVCConfig.java @@ -61,10 +61,9 @@ public Loader templateLoader() { @Bean public ViewResolver viewResolver(PebbleEngine pebbleEngine) { - PebbleViewResolver viewResolver = new PebbleViewResolver(); + PebbleViewResolver viewResolver = new PebbleViewResolver(pebbleEngine); viewResolver.setPrefix("com/mitchellbosecke/pebble/spring/template/"); viewResolver.setSuffix(".html"); - viewResolver.setPebbleEngine(pebbleEngine); viewResolver.setContentType("text/html"); return viewResolver; }