or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

annotation-controllers.mdconfiguration.mdcontent-negotiation.mdexception-handling.mdfunctional-routing.mdindex.mdresource-handling.mdview-rendering.mdwebclient.mdwebsocket.md
tile.json

view-rendering.mddocs/

View Rendering

Spring WebFlux provides view resolution and rendering capabilities for server-side template engines. This includes support for FreeMarker templates, script templates (JavaScript engines), and custom view implementations. The view rendering system integrates with the reactive programming model to render views asynchronously.

Capabilities

View Resolution

The ViewResolver interface resolves view names to View instances.

@FunctionalInterface
public interface ViewResolver {
    // Resolve view name to View instance
    Mono<View> resolveViewName(String viewName, Locale locale);
}

Usage:

import org.springframework.web.reactive.result.view.ViewResolver;
import reactor.core.publisher.Mono;
import java.util.Locale;

public class CustomViewResolver implements ViewResolver {

    @Override
    public Mono<View> resolveViewName(String viewName, Locale locale) {
        if (viewName.startsWith("custom:")) {
            return Mono.just(new CustomView(viewName));
        }
        return Mono.empty();
    }
}

View Interface

The View interface renders a model to the HTTP response.

public interface View {
    // Default content type
    default List<MediaType> getSupportedMediaTypes() {
        return Collections.emptyList();
    }

    // Check if view supports given media type
    default boolean isRedirectView() {
        return false;
    }

    // Render the view
    Mono<Void> render(Map<String, ?> model,
                     MediaType contentType,
                     ServerWebExchange exchange);
}

URL-Based View Resolver

The UrlBasedViewResolver resolves view names using a configured prefix and suffix.

public class UrlBasedViewResolver extends ViewResolverSupport implements ViewResolver, Ordered {
    public UrlBasedViewResolver() { ... }

    // Set view class
    public void setViewClass(Class<?> viewClass) { ... }

    // Get view class
    public Class<?> getViewClass() { ... }

    // Set prefix for view names
    public void setPrefix(String prefix) { ... }

    // Get prefix
    public String getPrefix() { ... }

    // Set suffix for view names
    public void setSuffix(String suffix) { ... }

    // Get suffix
    public String getSuffix() { ... }

    // Set view names this resolver can handle
    public void setViewNames(String... viewNames) { ... }

    // Get view names
    public String[] getViewNames() { ... }

    // Set whether to cache views
    public void setCache(boolean cache) { ... }

    // Check if caching enabled
    public boolean isCache() { ... }

    // Set cache limit
    public void setCacheLimit(int cacheLimit) { ... }

    // Get cache limit
    public int getCacheLimit() { ... }

    // Set order for resolver chain
    public void setOrder(int order) { ... }

    @Override
    public int getOrder() { ... }

    @Override
    public Mono<View> resolveViewName(String viewName, Locale locale) { ... }

    // Check if view name can be handled
    protected boolean canHandle(String viewName, Locale locale) { ... }

    // Create view instance
    protected Mono<View> createView(String viewName, Locale locale) { ... }

    // Load view
    protected Mono<View> loadView(String viewName, Locale locale) { ... }
}

Usage:

import org.springframework.web.reactive.result.view.UrlBasedViewResolver;
import org.springframework.web.reactive.result.view.freemarker.FreeMarkerView;

UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".ftl");
resolver.setViewClass(FreeMarkerView.class);
resolver.setViewNames("user*", "product*");
resolver.setCache(true);
resolver.setOrder(1);

// Resolves "userList" to "/WEB-INF/views/userList.ftl"

Rendering API

The Rendering interface provides a public API for view rendering with model and status.

public interface Rendering {
    // Get view name
    String view();

    // Get model attributes
    Map<String, Object> modelAttributes();

    // Get HTTP status
    HttpStatusCode status();

    // Get response headers
    HttpHeaders headers();

    // Create rendering with view name
    static Builder view(String viewName) { ... }

    // Create redirect rendering
    static Builder redirectTo(String url) { ... }
    static Builder redirectTo(URI url) { ... }

    interface Builder {
        // Set model attribute
        Builder modelAttribute(String name, Object value);

        // Set model attributes
        Builder modelAttributes(Object... attributes);
        Builder modelAttributes(Map<String, ?> attributes);

        // Set HTTP status
        Builder status(HttpStatusCode status);
        Builder status(int status);

        // Set header
        Builder header(String headerName, String... headerValues);

        // Set headers
        Builder headers(Consumer<HttpHeaders> headersConsumer);

        // Set cookie
        Builder cookie(ResponseCookie cookie);

        // Set cookies
        Builder cookies(Consumer<MultiValueMap<String, ResponseCookie>> cookiesConsumer);

        // Build rendering
        Rendering build();
    }
}

Usage:

import org.springframework.web.reactive.result.view.Rendering;
import org.springframework.http.HttpStatus;
import reactor.core.publisher.Mono;

@Controller
public class ViewController {

    @GetMapping("/users")
    public Mono<Rendering> listUsers() {
        return userService.findAll()
            .collectList()
            .map(users -> Rendering.view("userList")
                .modelAttribute("users", users)
                .modelAttribute("timestamp", Instant.now())
                .status(HttpStatus.OK)
                .build());
    }

    @GetMapping("/redirect")
    public Mono<Rendering> redirect() {
        return Mono.just(Rendering.redirectTo("/home").build());
    }
}

Fragments Rendering

The FragmentsRendering interface supports rendering multiple view fragments.

public interface FragmentsRendering extends Rendering {
    // Get fragments
    Collection<Fragment> fragments();

    // Create fragments rendering
    static Builder with(String viewName) { ... }
    static Builder with(String viewName, Object... modelAttributes) { ... }
    static Builder with(Fragment fragment) { ... }
    static Builder with(Collection<Fragment> fragments) { ... }

    interface Builder extends Rendering.Builder {
        // Add fragment
        Builder fragment(String viewName, Object... modelAttributes);
        Builder fragment(Fragment fragment);

        // Add fragments
        Builder fragments(Fragment... fragments);
        Builder fragments(Collection<Fragment> fragments);

        @Override
        FragmentsRendering build();
    }
}

Fragment Interface

The Fragment interface represents a view fragment with name and model.

public interface Fragment {
    // Get view name
    String viewName();

    // Get model attributes
    Map<String, Object> model();

    // Create fragment
    static Fragment create(String viewName) { ... }
    static Fragment create(String viewName, Map<String, Object> model) { ... }
    static Fragment create(String viewName, Object... modelAttributes) { ... }
}

Usage:

import org.springframework.web.reactive.result.view.FragmentsRendering;
import org.springframework.web.reactive.result.view.Fragment;

@Controller
public class FragmentController {

    @GetMapping("/dashboard")
    public Mono<FragmentsRendering> dashboard() {
        return Mono.just(
            FragmentsRendering
                .with("header", "title", "Dashboard")
                .fragment("sidebar", "activeMenu", "dashboard")
                .fragment("content", "data", getDashboardData())
                .fragment("footer")
                .build()
        );
    }

    @GetMapping("/page")
    public Mono<FragmentsRendering> pageWithFragments() {
        Fragment header = Fragment.create("header", "title", "My Page");
        Fragment content = Fragment.create("content", Map.of("items", getItems()));
        Fragment footer = Fragment.create("footer");

        return Mono.just(
            FragmentsRendering.with(List.of(header, content, footer))
                .status(HttpStatus.OK)
                .build()
        );
    }
}

View Resolution Result Handler

The ViewResolutionResultHandler handles return values that require view resolution.

public class ViewResolutionResultHandler extends HandlerResultHandlerSupport
        implements HandlerResultHandler, Ordered {

    public ViewResolutionResultHandler(List<ViewResolver> viewResolvers,
                                      RequestedContentTypeResolver contentTypeResolver) { ... }

    public ViewResolutionResultHandler(List<ViewResolver> viewResolvers,
                                      RequestedContentTypeResolver contentTypeResolver,
                                      ReactiveAdapterRegistry adapterRegistry) { ... }

    // Set default view names
    public void setDefaultViews(List<View> defaultViews) { ... }

    // Get default views
    public List<View> getDefaultViews() { ... }

    // Set default model attribute name
    public void setDefaultModelName(String defaultModelName) { ... }

    // Get default model attribute name
    public String getDefaultModelName() { ... }

    @Override
    public boolean supports(HandlerResult result) { ... }

    @Override
    public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) { ... }

    @Override
    public int getOrder() { ... }
}

Abstract View

Base class for View implementations.

public abstract class AbstractView implements View, BeanNameAware, ApplicationContextAware {
    // Default content type
    public static final MediaType DEFAULT_CONTENT_TYPE = MediaType.parseMediaType("text/html;charset=UTF-8");

    // Set supported media types
    public void setSupportedMediaTypes(List<MediaType> supportedMediaTypes) { ... }

    // Get supported media types
    @Override
    public List<MediaType> getSupportedMediaTypes() { ... }

    // Set default charset
    public void setDefaultCharset(Charset defaultCharset) { ... }

    // Get default charset
    public Charset getDefaultCharset() { ... }

    // Set bean name
    @Override
    public void setBeanName(String beanName) { ... }

    // Get bean name
    public String getBeanName() { ... }

    // Set application context
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) { ... }

    // Get application context
    public ApplicationContext getApplicationContext() { ... }

    // Set request context attribute name
    public void setRequestContextAttribute(String requestContextAttribute) { ... }

    // Get request context attribute name
    public String getRequestContextAttribute() { ... }

    @Override
    public Mono<Void> render(Map<String, ?> model,
                            MediaType contentType,
                            ServerWebExchange exchange) { ... }

    // Render internal (abstract)
    protected abstract Mono<Void> renderInternal(Map<String, Object> renderAttributes,
                                                 MediaType contentType,
                                                 ServerWebExchange exchange);

    // Prepare model for rendering
    protected Mono<Map<String, Object>> getModelAttributes(Map<String, ?> model,
                                                           ServerWebExchange exchange) { ... }
}

Abstract URL-Based View

Base class for URL-based views.

public abstract class AbstractUrlBasedView extends AbstractView {
    // Set URL
    public void setUrl(String url) { ... }

    // Get URL
    public String getUrl() { ... }

    // Check if URL available
    public boolean checkResourceExists(Locale locale) throws Exception { ... }
}

Redirect View

The RedirectView handles HTTP redirects.

public class RedirectView extends AbstractUrlBasedView {
    public RedirectView() { ... }
    public RedirectView(String redirectUrl) { ... }

    // Set whether to use context-relative redirect
    public void setContextRelative(boolean contextRelative) { ... }

    // Check if context-relative
    public boolean isContextRelative() { ... }

    // Set whether to use HTTP 1.0 compatible redirect (302 instead of 303)
    public void setHttp10Compatible(boolean http10Compatible) { ... }

    // Check if HTTP 1.0 compatible
    public boolean isHttp10Compatible() { ... }

    // Set whether to propagate query properties
    public void setPropagateQuery(boolean propagateQuery) { ... }

    // Check if propagating query
    public boolean isPropagateQuery() { ... }

    // Set hosts that are allowed for redirects
    public void setHosts(String... hosts) { ... }

    // Get allowed hosts
    public String[] getHosts() { ... }

    @Override
    public boolean isRedirectView() { ... }

    @Override
    protected Mono<Void> renderInternal(Map<String, Object> model,
                                       MediaType contentType,
                                       ServerWebExchange exchange) { ... }

    // Create target URL
    protected String createTargetUrl(Map<String, Object> model, ServerWebExchange exchange) { ... }
}

Usage:

import org.springframework.web.reactive.result.view.RedirectView;
import org.springframework.http.HttpStatus;

@Configuration
public class ViewConfig {

    @Bean
    public RedirectView homeRedirect() {
        RedirectView view = new RedirectView("/home");
        view.setContextRelative(true);
        view.setHttp10Compatible(false);
        view.setPropagateQuery(true);
        return view;
    }
}

// In controller
@GetMapping("/old-path")
public RedirectView oldPath() {
    return new RedirectView("/new-path");
}

HTTP Message Writer View

The HttpMessageWriterView writes response using an HttpMessageWriter.

public class HttpMessageWriterView implements View {
    public HttpMessageWriterView(HttpMessageWriter<?> writer) { ... }
    public HttpMessageWriterView(HttpMessageWriter<?> writer, MediaType contentType) { ... }

    @Override
    public List<MediaType> getSupportedMediaTypes() { ... }

    @Override
    public Mono<Void> render(Map<String, ?> model,
                            MediaType contentType,
                            ServerWebExchange exchange) { ... }

    // Set model keys to extract value from
    public void setModelKeys(Set<String> modelKeys) { ... }
}

Request Context

The RequestContext holds request-specific state for view rendering.

public class RequestContext {
    public RequestContext(ServerWebExchange exchange,
                         Map<String, Object> model,
                         MessageSource messageSource) { ... }

    // Get server web exchange
    public ServerWebExchange getExchange() { ... }

    // Get model
    public Map<String, Object> getModel() { ... }

    // Get message source
    public MessageSource getMessageSource() { ... }

    // Get message
    public String getMessage(String code) { ... }
    public String getMessage(String code, String defaultMessage) { ... }
    public String getMessage(String code, Object[] args) { ... }
    public String getMessage(String code, Object[] args, String defaultMessage) { ... }
    public String getMessage(MessageSourceResolvable resolvable) { ... }

    // Get locale
    public Locale getLocale() { ... }

    // Get context path
    public String getContextPath() { ... }

    // Get request URI
    public String getRequestUri() { ... }

    // Get query string
    public String getQueryString() { ... }

    // Get URL for path
    public String getContextUrl(String relativeUrl) { ... }
    public String getContextUrl(String relativeUrl, Map<String, ?> params) { ... }
}

Bind Status

The BindStatus holds status information for data binding in views.

public class BindStatus {
    public BindStatus(RequestContext requestContext,
                     String path,
                     boolean htmlEscape) { ... }

    // Get expression (path)
    public String getExpression() { ... }

    // Get value
    public Object getValue() { ... }

    // Get display value
    public String getDisplayValue() { ... }

    // Check if error
    public boolean isError() { ... }

    // Get error codes
    public String[] getErrorCodes() { ... }

    // Get error messages
    public String[] getErrorMessages() { ... }

    // Get error message
    public String getErrorMessage() { ... }

    // Get errors as single string
    public String getErrorMessagesAsString(String delimiter) { ... }
}

Request Data Value Processor

The RequestDataValueProcessor interface processes data values in forms and URLs.

public interface RequestDataValueProcessor {
    // Process action URL
    String processAction(ServerWebExchange exchange,
                        String action,
                        String httpMethod);

    // Process form field value
    String processFormFieldValue(ServerWebExchange exchange,
                                String name,
                                String value,
                                String type);

    // Get extra hidden fields
    Map<String, String> getExtraHiddenFields(ServerWebExchange exchange);

    // Process URL
    String processUrl(ServerWebExchange exchange, String url);
}

FreeMarker Support

FreeMarker Configuration

public interface FreeMarkerConfig {
    // Get FreeMarker configuration
    freemarker.template.Configuration getConfiguration();
}
public class FreeMarkerConfigurer implements FreeMarkerConfig, InitializingBean, ResourceLoaderAware {
    public FreeMarkerConfigurer() { ... }

    // Set template loader paths
    public void setTemplateLoaderPaths(String... templateLoaderPaths) { ... }

    // Set template loader path
    public void setTemplateLoaderPath(String templateLoaderPath) { ... }

    // Set prefer file system access
    public void setPreferFileSystemAccess(boolean preferFileSystemAccess) { ... }

    // Set default encoding
    public void setDefaultEncoding(String defaultEncoding) { ... }

    // Set configuration
    public void setConfiguration(freemarker.template.Configuration configuration) { ... }

    // Set FreeMarker settings
    public void setFreemarkerSettings(Properties settings) { ... }

    // Set FreeMarker variables
    public void setFreemarkerVariables(Map<String, Object> variables) { ... }

    @Override
    public freemarker.template.Configuration getConfiguration() { ... }
}

FreeMarker View

public class FreeMarkerView extends AbstractUrlBasedView {
    public FreeMarkerView() { ... }

    // Set encoding
    public void setEncoding(String encoding) { ... }

    // Get encoding
    public String getEncoding() { ... }

    // Check template exists
    @Override
    public boolean checkResourceExists(Locale locale) throws Exception { ... }

    @Override
    protected Mono<Void> renderInternal(Map<String, Object> renderAttributes,
                                       MediaType contentType,
                                       ServerWebExchange exchange) { ... }
}

FreeMarker View Resolver

public class FreeMarkerViewResolver extends UrlBasedViewResolver {
    public FreeMarkerViewResolver() { ... }
    public FreeMarkerViewResolver(String prefix, String suffix) { ... }

    // Set cache
    public void setCache(boolean cache) { ... }
}

Usage:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.reactive.result.view.freemarker.FreeMarkerViewResolver;

@Configuration
public class FreeMarkerConfig {

    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        configurer.setTemplateLoaderPath("classpath:/templates/");
        configurer.setDefaultEncoding("UTF-8");
        return configurer;
    }

    @Bean
    public FreeMarkerViewResolver freeMarkerViewResolver() {
        FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
        resolver.setPrefix("");
        resolver.setSuffix(".ftl");
        resolver.setCache(true);
        return resolver;
    }
}

Script Template Support

Script Template Configuration

public interface ScriptTemplateConfig {
    // Get script engine
    ScriptEngine getEngine();

    // Get engine supplier
    Supplier<ScriptEngine> getEngineSupplier();

    // Get engine name
    String getEngineName();

    // Check if shared engine
    Boolean isSharedEngine();

    // Get scripts
    String[] getScripts();

    // Get render object
    String getRenderObject();

    // Get render function
    String getRenderFunction();

    // Get content type
    String getContentType();

    // Get charset
    Charset getCharset();

    // Get resource loader path
    String getResourceLoaderPath();
}
public class ScriptTemplateConfigurer implements ScriptTemplateConfig, InitializingBean {
    public ScriptTemplateConfigurer() { ... }
    public ScriptTemplateConfigurer(String engineName) { ... }

    // Set script engine
    public void setEngine(ScriptEngine engine) { ... }

    // Set engine supplier
    public void setEngineSupplier(Supplier<ScriptEngine> engineSupplier) { ... }

    // Set engine name
    public void setEngineName(String engineName) { ... }

    // Set whether to use shared engine
    public void setSharedEngine(Boolean sharedEngine) { ... }

    // Set scripts to load
    public void setScripts(String... scripts) { ... }

    // Set render object
    public void setRenderObject(String renderObject) { ... }

    // Set render function
    public void setRenderFunction(String renderFunction) { ... }

    // Set content type
    public void setContentType(String contentType) { ... }

    // Set charset
    public void setCharset(Charset charset) { ... }

    // Set resource loader path
    public void setResourceLoaderPath(String resourceLoaderPath) { ... }

    @Override
    public ScriptEngine getEngine() { ... }

    // Additional getters...
}

Script Template View

public class ScriptTemplateView extends AbstractUrlBasedView {
    public static final String DEFAULT_CONTENT_TYPE = "text/html";
    public static final String DEFAULT_RESOURCE_LOADER_PATH = "classpath:";

    public ScriptTemplateView() { ... }
    public ScriptTemplateView(String url) { ... }

    // Set engine
    public void setEngine(ScriptEngine engine) { ... }

    // Set engine supplier
    public void setEngineSupplier(Supplier<ScriptEngine> engineSupplier) { ... }

    // Set engine name
    public void setEngineName(String engineName) { ... }

    // Set shared engine
    public void setSharedEngine(Boolean sharedEngine) { ... }

    // Set scripts
    public void setScripts(String... scripts) { ... }

    // Set render object
    public void setRenderObject(String renderObject) { ... }

    // Set render function
    public void setRenderFunction(String renderFunction) { ... }

    // Set resource loader path
    public void setResourceLoaderPath(String resourceLoaderPath) { ... }

    @Override
    protected Mono<Void> renderInternal(Map<String, Object> model,
                                       MediaType contentType,
                                       ServerWebExchange exchange) { ... }
}

Script Template View Resolver

public class ScriptTemplateViewResolver extends UrlBasedViewResolver {
    public ScriptTemplateViewResolver() { ... }
    public ScriptTemplateViewResolver(String prefix, String suffix) { ... }
}

Usage:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.result.view.script.ScriptTemplateConfigurer;
import org.springframework.web.reactive.result.view.script.ScriptTemplateViewResolver;

@Configuration
public class ScriptTemplateConfig {

    @Bean
    public ScriptTemplateConfigurer scriptTemplateConfigurer() {
        ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
        configurer.setEngineName("nashorn");
        configurer.setScripts("scripts/polyfill.js", "scripts/render.js");
        configurer.setRenderFunction("render");
        configurer.setSharedEngine(false);
        return configurer;
    }

    @Bean
    public ScriptTemplateViewResolver scriptTemplateViewResolver() {
        ScriptTemplateViewResolver resolver = new ScriptTemplateViewResolver();
        resolver.setPrefix("templates/");
        resolver.setSuffix(".html");
        return resolver;
    }
}

Types

Rendering Context Interface

public interface RenderingContext {
    // Get application context
    ApplicationContext getApplicationContext();

    // Get locale
    Locale getLocale();

    // Get URL for path
    String getUrl(String path);
}

View Resolver Support

Base class for ViewResolver implementations.

public abstract class ViewResolverSupport {
    // Set default content type
    public void setDefaultContentType(MediaType contentType) { ... }

    // Get default content type
    public MediaType getDefaultContentType() { ... }

    // Set supported media types
    public void setSupportedMediaTypes(List<MediaType> supportedMediaTypes) { ... }

    // Get supported media types
    public List<MediaType> getSupportedMediaTypes() { ... }
}