001package io.jstach.opt.spring.webflux; 002 003import java.nio.charset.StandardCharsets; 004import java.util.List; 005import java.util.Map; 006 007import org.springframework.http.MediaType; 008import org.springframework.web.reactive.result.view.AbstractView; 009import org.springframework.web.reactive.result.view.View; 010import org.springframework.web.server.ServerWebExchange; 011 012import io.jstach.jstache.JStache; 013import io.jstach.jstachio.JStachio; 014import reactor.core.publisher.Mono; 015 016/** 017 * One way to use JStachio with Spring Webflux is to use this special View that will 018 * delegate to JStachio to render. 019 * <p> 020 * By default this view interface will use the static jstachio singleton which normally is 021 * the correct Spring wired version if configured correctly. 022 * 023 * @author agentgt 024 * @author dsyer 025 * 026 */ 027@SuppressWarnings("exports") 028public interface JStachioModelView extends View { 029 030 @Override 031 default Mono<Void> render(Map<String, ?> model, MediaType contentType, ServerWebExchange exchange) { 032 if (contentType != null) { 033 exchange.getResponse().getHeaders().setContentType(contentType); 034 } 035 if (contentType != null) { 036 exchange.getResponse().getHeaders().setContentType(contentType); 037 } 038 039 View view = new AbstractView() { 040 041 @Override 042 protected Mono<Void> renderInternal(Map<String, Object> model, MediaType contentType, 043 ServerWebExchange exchange) { 044 return exchange.getResponse().writeWith(Mono.fromCallable(() -> { 045 try { 046 byte[] bytes = String.valueOf(jstachio().execute(model())).getBytes(StandardCharsets.UTF_8); 047 // just wrapping, no allocation 048 return exchange.getResponse().bufferFactory().wrap(bytes); 049 } 050 catch (Exception ex) { 051 throw new IllegalStateException("Failed to render script template", ex); 052 } 053 })); 054 } 055 056 }; 057 058 return view.render(model, contentType, exchange); 059 } 060 061 @Override 062 default List<MediaType> getSupportedMediaTypes() { 063 return List.of(MediaType.TEXT_HTML); 064 } 065 066 /** 067 * Returns the jstachio singleton by default. 068 * @return stachio singleton by default. 069 * @see JStachio#setStatic(java.util.function.Supplier) 070 */ 071 default JStachio jstachio() { 072 return JStachio.of(); 073 } 074 075 /** 076 * The model to be rendered by {@link #jstachio()}. 077 * @return model defaulting to <code>this</code> instance. 078 */ 079 default Object model() { 080 return this; 081 } 082 083 /** 084 * Creates a spring view from a model 085 * @param model an instance of a class annotated with {@link JStache}. 086 * @return view ready for rendering 087 */ 088 public static JStachioModelView of(Object model) { 089 return new JStachioModelView() { 090 @Override 091 public Object model() { 092 return model; 093 } 094 }; 095 } 096 097}