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 */ 027public interface JStachioModelView extends View { 028 029 @Override 030 default Mono<Void> render(Map<String, ?> model, MediaType contentType, ServerWebExchange exchange) { 031 if (contentType != null) { 032 exchange.getResponse().getHeaders().setContentType(contentType); 033 } 034 if (contentType != null) { 035 exchange.getResponse().getHeaders().setContentType(contentType); 036 } 037 038 View view = new AbstractView() { 039 040 @Override 041 protected Mono<Void> renderInternal(Map<String, Object> model, MediaType contentType, 042 ServerWebExchange exchange) { 043 return exchange.getResponse().writeWith(Mono.fromCallable(() -> { 044 try { 045 byte[] bytes = String.valueOf(jstachio().execute(model())).getBytes(StandardCharsets.UTF_8); 046 // just wrapping, no allocation 047 return exchange.getResponse().bufferFactory().wrap(bytes); 048 } 049 catch (Exception ex) { 050 throw new IllegalStateException("Failed to render script template", ex); 051 } 052 })); 053 } 054 055 }; 056 057 return view.render(model, contentType, exchange); 058 } 059 060 @Override 061 default List<MediaType> getSupportedMediaTypes() { 062 return List.of(MediaType.TEXT_HTML); 063 } 064 065 /** 066 * Returns the jstachio singleton by default. 067 * @return stachio singleton by default. 068 * @see JStachio#setStaticJStachio(java.util.function.Supplier) 069 */ 070 default JStachio jstachio() { 071 return JStachio.of(); 072 } 073 074 /** 075 * The model to be rendered by {@link #jstachio()}. 076 * @return model defaulting to <code>this</code> instance. 077 */ 078 default Object model() { 079 return this; 080 } 081 082 /** 083 * Creates a spring view from a model 084 * @param model an instance of a class annotated with {@link JStache}. 085 * @return view ready for rendering 086 */ 087 public static JStachioModelView of(Object model) { 088 return new JStachioModelView() { 089 @Override 090 public Object model() { 091 return model; 092 } 093 }; 094 } 095 096}