@Override public void afterPropertiesSet() throws Exception { super.afterPropertiesSet(); if (getConfiguration() == null) { FreeMarkerConfig config = autodetectConfiguration(); setConfiguration(config.getConfiguration()); } }
private Charset getCharset(@Nullable MediaType mediaType) { return Optional.ofNullable(mediaType).map(MimeType::getCharset).orElse(getDefaultCharset()); }
/** * Retrieve the FreeMarker template for the given locale, * to be rendering by this view. * <p>By default, the template specified by the "url" bean property * will be retrieved. * @param locale the current locale * @return the FreeMarker template to render */ protected Template getTemplate(Locale locale) throws IOException { return (getEncoding() != null ? obtainConfiguration().getTemplate(getUrl(), locale, getEncoding()) : obtainConfiguration().getTemplate(getUrl(), locale)); }
/** * Check that the FreeMarker template used for this view exists and is valid. * <p>Can be overridden to customize the behavior, for example in case of * multiple templates to be rendered into a single view. */ @Override public boolean checkResourceExists(Locale locale) throws Exception { try { // Check that we can get the template, even if we might subsequently get it again. getTemplate(locale); return true; } catch (FileNotFoundException ex) { // Allow for ViewResolver chaining... return false; } catch (ParseException ex) { throw new ApplicationContextException( "Failed to parse FreeMarker template for URL [" + getUrl() + "]", ex); } catch (IOException ex) { throw new ApplicationContextException( "Could not load FreeMarker template for URL [" + getUrl() + "]", ex); } }
@Override protected Mono<Void> renderInternal(Map<String, Object> renderAttributes, @Nullable MediaType contentType, ServerWebExchange exchange) { // Expose all standard FreeMarker hash models. SimpleHash freeMarkerModel = getTemplateModel(renderAttributes, exchange); if (logger.isDebugEnabled()) { logger.debug(exchange.getLogPrefix() + "Rendering [" + getUrl() + "]"); } Locale locale = LocaleContextHolder.getLocale(exchange.getLocaleContext()); DataBuffer dataBuffer = exchange.getResponse().bufferFactory().allocateBuffer(); try { Charset charset = getCharset(contentType); Writer writer = new OutputStreamWriter(dataBuffer.asOutputStream(), charset); getTemplate(locale).process(freeMarkerModel, writer); } catch (IOException ex) { DataBufferUtils.release(dataBuffer); String message = "Could not load FreeMarker template for URL [" + getUrl() + "]"; return Mono.error(new IllegalStateException(message, ex)); } catch (Throwable ex) { DataBufferUtils.release(dataBuffer); return Mono.error(ex); } return exchange.getResponse().writeWith(Flux.just(dataBuffer)); }
@Test public void checkResourceExists() throws Exception { FreeMarkerView view = new FreeMarkerView(); view.setConfiguration(this.freeMarkerConfig); view.setUrl("test.ftl"); assertTrue(view.checkResourceExists(Locale.US)); }
@Test public void render() throws Exception { FreeMarkerView view = new FreeMarkerView(); view.setConfiguration(this.freeMarkerConfig); view.setUrl("test.ftl"); ModelMap model = new ExtendedModelMap(); model.addAttribute("hello", "hi FreeMarker"); view.render(model, null, this.exchange).block(Duration.ofMillis(5000)); StepVerifier.create(this.exchange.getResponse().getBody()) .consumeNextWith(buf -> assertEquals("<html><body>hi FreeMarker</body></html>", asString(buf))) .expectComplete() .verify(); }
/** * Retrieve the FreeMarker template for the given locale, * to be rendering by this view. * <p>By default, the template specified by the "url" bean property * will be retrieved. * @param locale the current locale * @return the FreeMarker template to render */ protected Template getTemplate(Locale locale) throws IOException { return (getEncoding() != null ? getConfiguration().getTemplate(getUrl(), locale, getEncoding()) : getConfiguration().getTemplate(getUrl(), locale)); }
/** * Build a FreeMarker template model for the given model Map. * <p>The default implementation builds a {@link SimpleHash}. * @param model the model to use for rendering * @param exchange current exchange * @return the FreeMarker template model, as a {@link SimpleHash} or subclass thereof */ protected SimpleHash getTemplateModel(Map<String, Object> model, ServerWebExchange exchange) { SimpleHash fmModel = new SimpleHash(getObjectWrapper()); fmModel.putAll(model); return fmModel; }
/** * Obtain the FreeMarker configuration for actual use. * @return the FreeMarker configuration (never {@code null}) * @throws IllegalStateException in case of no Configuration object set * @since 5.0 */ protected Configuration obtainConfiguration() { Configuration configuration = getConfiguration(); Assert.state(configuration != null, "No Configuration set"); return configuration; }
@Override protected Mono<Void> renderInternal(Map<String, Object> renderAttributes, MediaType contentType, ServerWebExchange exchange) { // Expose all standard FreeMarker hash models. SimpleHash freeMarkerModel = getTemplateModel(renderAttributes, exchange); if (logger.isDebugEnabled()) { logger.debug("Rendering FreeMarker template [" + getUrl() + "]."); } Locale acceptLocale = exchange.getRequest().getHeaders().getAcceptLanguageAsLocale(); Locale locale = acceptLocale != null ? acceptLocale : Locale.getDefault(); DataBuffer dataBuffer = exchange.getResponse().bufferFactory().allocateBuffer(); try { Charset charset = getCharset(contentType).orElse(getDefaultCharset()); Writer writer = new OutputStreamWriter(dataBuffer.asOutputStream(), charset); getTemplate(locale).process(freeMarkerModel, writer); } catch (IOException ex) { String message = "Could not load FreeMarker template for URL [" + getUrl() + "]"; return Mono.error(new IllegalStateException(message, ex)); } catch (Throwable ex) { return Mono.error(ex); } return exchange.getResponse().writeWith(Flux.just(dataBuffer)); }
/** * Check that the FreeMarker template used for this view exists and is valid. * <p>Can be overridden to customize the behavior, for example in case of * multiple templates to be rendered into a single view. */ @Override public boolean checkResourceExists(Locale locale) throws Exception { try { // Check that we can get the template, even if we might subsequently get it again. getTemplate(locale); return true; } catch (FileNotFoundException ex) { if (logger.isDebugEnabled()) { logger.debug("No FreeMarker view found for URL: " + getUrl()); } return false; } catch (ParseException ex) { throw new ApplicationContextException( "Failed to parse FreeMarker template for URL [" + getUrl() + "]", ex); } catch (IOException ex) { throw new ApplicationContextException( "Could not load FreeMarker template for URL [" + getUrl() + "]", ex); } }
/** * Build a FreeMarker template model for the given model Map. * <p>The default implementation builds a {@link SimpleHash}. * @param model the model to use for rendering * @param exchange current exchange * @return the FreeMarker template model, as a {@link SimpleHash} or subclass thereof */ protected SimpleHash getTemplateModel(Map<String, Object> model, ServerWebExchange exchange) { SimpleHash fmModel = new SimpleHash(getObjectWrapper()); fmModel.putAll(model); return fmModel; }
/** * Return the configured FreeMarker {@link ObjectWrapper}, or the * {@link ObjectWrapper#DEFAULT_WRAPPER default wrapper} if none specified. * @see freemarker.template.Configuration#getObjectWrapper() */ protected ObjectWrapper getObjectWrapper() { ObjectWrapper ow = getConfiguration().getObjectWrapper(); Version version = Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS; return (ow != null ? ow : new DefaultObjectWrapperBuilder(version).build()); }
@Override public void afterPropertiesSet() throws Exception { super.afterPropertiesSet(); if (getConfiguration() == null) { FreeMarkerConfig config = autodetectConfiguration(); setConfiguration(config.getConfiguration()); } }