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

resource-handling.mddocs/

Resource Handling

Spring WebFlux provides comprehensive support for serving static resources (CSS, JavaScript, images, etc.) with features including caching, content negotiation, resource transformation, versioning strategies, and WebJars support. The resource handling chain allows for flexible processing of resources before they're served to clients.

Capabilities

Serve Static Resources

The ResourceWebHandler class handles requests for static resources.

public class ResourceWebHandler implements WebHandler, InitializingBean {
    // Set resource locations (file system paths or classpath locations)
    public void setLocations(List<Resource> locations) { ... }

    // Get resource locations
    public List<Resource> getLocations() { ... }

    // Set resource resolvers
    public void setResourceResolvers(List<ResourceResolver> resourceResolvers) { ... }

    // Get resource resolvers
    public List<ResourceResolver> getResourceResolvers() { ... }

    // Set resource transformers
    public void setResourceTransformers(List<ResourceTransformer> resourceTransformers) { ... }

    // Get resource transformers
    public List<ResourceTransformer> getResourceTransformers() { ... }

    // Set cache control
    public void setCacheControl(CacheControl cacheControl) { ... }

    // Get cache control
    public CacheControl getCacheControl() { ... }

    // Set whether to use last modified
    public void setUseLastModified(boolean useLastModified) { ... }

    // Check if using last modified
    public boolean isUseLastModified() { ... }

    // Set whether to optimize locations (check if locations exist at startup)
    public void setOptimizeLocations(boolean optimizeLocations) { ... }

    // Check if optimizing locations
    public boolean isOptimizeLocations() { ... }

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

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

    @Override
    public Mono<Void> handle(ServerWebExchange exchange) { ... }
}

Usage:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.CacheControl;
import org.springframework.web.reactive.resource.ResourceWebHandler;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Configuration
public class ResourceConfig {

    @Bean
    public ResourceWebHandler resourceWebHandler() {
        ResourceWebHandler handler = new ResourceWebHandler();
        handler.setLocations(List.of(
            new ClassPathResource("static/"),
            new ClassPathResource("public/")
        ));
        handler.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS));
        handler.setUseLastModified(true);
        handler.setOptimizeLocations(true);
        return handler;
    }
}

Resource Resolvers

Resource resolvers locate and resolve resources from configured locations.

public interface ResourceResolver {
    // Resolve resource for the given request
    Mono<Resource> resolveResource(ServerWebExchange exchange,
                                   String requestPath,
                                   List<? extends Resource> locations,
                                   ResourceResolverChain chain);

    // Resolve URL path for the given resource path
    Mono<String> resolveUrlPath(String resourcePath,
                                List<? extends Resource> locations,
                                ResourceResolverChain chain);
}
public interface ResourceResolverChain {
    // Resolve resource using remaining resolvers in the chain
    Mono<Resource> resolveResource(ServerWebExchange exchange,
                                   String requestPath,
                                   List<? extends Resource> locations);

    // Resolve URL path using remaining resolvers in the chain
    Mono<String> resolveUrlPath(String resourcePath,
                                List<? extends Resource> locations);
}

Path Resource Resolver

The PathResourceResolver resolves resources under configured locations.

public class PathResourceResolver extends AbstractResourceResolver {
    public PathResourceResolver() { ... }

    // Set allowed locations
    public void setAllowedLocations(Resource... allowedLocations) { ... }

    // Get allowed locations
    public Resource[] getAllowedLocations() { ... }

    // Set URL path helper
    public void setUrlPathHelper(UrlPathHelper urlPathHelper) { ... }

    // Get URL path helper
    public UrlPathHelper getUrlPathHelper() { ... }

    @Override
    protected Mono<Resource> resolveResourceInternal(ServerWebExchange exchange,
                                                     String requestPath,
                                                     List<? extends Resource> locations,
                                                     ResourceResolverChain chain) { ... }

    @Override
    protected Mono<String> resolveUrlPathInternal(String resourcePath,
                                                  List<? extends Resource> locations,
                                                  ResourceResolverChain chain) { ... }

    // Check if resource is accessible
    protected boolean isResourceUnderLocation(Resource resource, Resource location) { ... }

    // Get resource
    protected Mono<Resource> getResource(String resourcePath, Resource location) { ... }
}

Caching Resource Resolver

The CachingResourceResolver adds caching to resource resolution.

public class CachingResourceResolver extends AbstractResourceResolver {
    // Default cache name
    public static final String RESOLVED_RESOURCE_CACHE_KEY_PREFIX = "resolvedResource:";
    public static final String RESOLVED_URL_PATH_CACHE_KEY_PREFIX = "resolvedUrlPath:";

    public CachingResourceResolver(Cache cache) { ... }
    public CachingResourceResolver(org.springframework.cache.CacheManager cacheManager, String cacheName) { ... }

    // Get cache
    public Cache getCache() { ... }

    @Override
    protected Mono<Resource> resolveResourceInternal(ServerWebExchange exchange,
                                                     String requestPath,
                                                     List<? extends Resource> locations,
                                                     ResourceResolverChain chain) { ... }

    @Override
    protected Mono<String> resolveUrlPathInternal(String resourcePath,
                                                  List<? extends Resource> locations,
                                                  ResourceResolverChain chain) { ... }
}

Usage:

import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.web.reactive.resource.CachingResourceResolver;

CachingResourceResolver cachingResolver = new CachingResourceResolver(
    new ConcurrentMapCache("resourceCache")
);

Encoded Resource Resolver

The EncodedResourceResolver resolves pre-encoded variants of resources (gzip, brotli).

public class EncodedResourceResolver extends AbstractResourceResolver {
    // Default encodings
    public static final String[] DEFAULT_CODINGS = {"br", "gzip"};

    public EncodedResourceResolver() { ... }

    @Override
    protected Mono<Resource> resolveResourceInternal(ServerWebExchange exchange,
                                                     String requestPath,
                                                     List<? extends Resource> locations,
                                                     ResourceResolverChain chain) { ... }

    @Override
    protected Mono<String> resolveUrlPathInternal(String resourcePath,
                                                  List<? extends Resource> locations,
                                                  ResourceResolverChain chain) { ... }
}

Version Resource Resolver

The VersionResourceResolver resolves resources with version information in the URL.

public class VersionResourceResolver extends AbstractResourceResolver {
    public VersionResourceResolver() { ... }

    // Add content-based versioning for path patterns
    public VersionResourceResolver addContentVersionStrategy(String... pathPatterns) { ... }

    // Add fixed version strategy for path patterns
    public VersionResourceResolver addFixedVersionStrategy(String version, String... pathPatterns) { ... }

    // Add custom version strategy for path patterns
    public VersionResourceResolver addVersionStrategy(VersionStrategy strategy, String... pathPatterns) { ... }

    // Get strategy map
    public Map<String, VersionStrategy> getStrategyMap() { ... }

    @Override
    protected Mono<Resource> resolveResourceInternal(ServerWebExchange exchange,
                                                     String requestPath,
                                                     List<? extends Resource> locations,
                                                     ResourceResolverChain chain) { ... }

    @Override
    protected Mono<String> resolveUrlPathInternal(String resourcePath,
                                                  List<? extends Resource> locations,
                                                  ResourceResolverChain chain) { ... }
}

Usage:

import org.springframework.web.reactive.resource.VersionResourceResolver;

VersionResourceResolver versionResolver = new VersionResourceResolver()
    .addContentVersionStrategy("/**/*.js", "/**/*.css")
    .addFixedVersionStrategy("v1.0.0", "/**/*.png", "/**/*.jpg");

WebJars Resource Resolver

The LiteWebJarsResourceResolver resolves WebJars resources without version numbers in the path.

public class LiteWebJarsResourceResolver extends AbstractResourceResolver {
    public LiteWebJarsResourceResolver() { ... }

    @Override
    protected Mono<Resource> resolveResourceInternal(ServerWebExchange exchange,
                                                     String requestPath,
                                                     List<? extends Resource> locations,
                                                     ResourceResolverChain chain) { ... }

    @Override
    protected Mono<String> resolveUrlPathInternal(String resourcePath,
                                                  List<? extends Resource> locations,
                                                  ResourceResolverChain chain) { ... }
}

Resource Transformers

Resource transformers modify resource content before serving.

public interface ResourceTransformer {
    // Transform the given resource
    Mono<Resource> transform(ServerWebExchange exchange,
                            Resource resource,
                            ResourceTransformerChain chain);
}
public interface ResourceTransformerChain {
    // Transform using remaining transformers in the chain
    Mono<Resource> transform(ServerWebExchange exchange, Resource resource);
}

CSS Link Resource Transformer

The CssLinkResourceTransformer updates links in CSS files to versioned URLs.

public class CssLinkResourceTransformer extends ResourceTransformerSupport {
    public CssLinkResourceTransformer() { ... }

    @Override
    public Mono<Resource> transform(ServerWebExchange exchange,
                                    Resource resource,
                                    ResourceTransformerChain chain) { ... }
}

Usage:

import org.springframework.web.reactive.resource.CssLinkResourceTransformer;

CssLinkResourceTransformer cssTransformer = new CssLinkResourceTransformer();

// This transformer will rewrite URLs in CSS files like:
// background-image: url('/images/logo.png')
// to include version:
// background-image: url('/images/logo-abc123.png')

Caching Resource Transformer

The CachingResourceTransformer adds caching to resource transformation.

public class CachingResourceTransformer extends ResourceTransformerSupport {
    public CachingResourceTransformer(Cache cache) { ... }
    public CachingResourceTransformer(org.springframework.cache.CacheManager cacheManager, String cacheName) { ... }

    // Get cache
    public Cache getCache() { ... }

    @Override
    public Mono<Resource> transform(ServerWebExchange exchange,
                                    Resource resource,
                                    ResourceTransformerChain chain) { ... }
}

Version Strategies

Version strategies determine how version information is extracted and embedded in resource URLs.

public interface VersionStrategy {
    // Get the resource version
    String getResourceVersion(Resource resource);

    // Extract version from request path
    String extractVersion(String requestPath);

    // Remove version from request path
    String removeVersion(String requestPath, String version);

    // Add version to request path
    String addVersion(String requestPath, String version);
}

Content Version Strategy

The ContentVersionStrategy uses MD5 hash of resource content as version.

public class ContentVersionStrategy extends AbstractFileNameVersionStrategy {
    public ContentVersionStrategy() { ... }

    @Override
    public String getResourceVersion(Resource resource) { ... }
}

Usage:

import org.springframework.web.reactive.resource.ContentVersionStrategy;

ContentVersionStrategy strategy = new ContentVersionStrategy();

// For a file like "app.js", this generates:
// app-abc123def456.js
// where "abc123def456" is the MD5 hash of the content

Fixed Version Strategy

The FixedVersionStrategy uses a fixed version string.

public class FixedVersionStrategy extends AbstractPrefixVersionStrategy {
    public FixedVersionStrategy(String version) { ... }

    @Override
    public String getResourceVersion(Resource resource) { ... }
}

Usage:

import org.springframework.web.reactive.resource.FixedVersionStrategy;

FixedVersionStrategy strategy = new FixedVersionStrategy("v1.0.0");

// For a file like "app.js", this generates:
// v1.0.0/app.js

Transformed Resource

The TransformedResource represents a transformed resource with modified content.

public class TransformedResource implements HttpResource {
    public TransformedResource(Resource original, byte[] transformedContent) { ... }

    // Get original resource
    public Resource getOriginal() { ... }

    @Override
    public InputStream getInputStream() throws IOException { ... }

    @Override
    public long contentLength() throws IOException { ... }

    @Override
    public long lastModified() throws IOException { ... }

    @Override
    public Resource createRelative(String relativePath) throws IOException { ... }

    @Override
    public String getFilename() { ... }

    @Override
    public URL getURL() throws IOException { ... }

    @Override
    public URI getURI() throws IOException { ... }

    @Override
    public File getFile() throws IOException { ... }

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

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

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

    @Override
    public String getDescription() { ... }

    @Override
    public HttpHeaders getResponseHeaders() { ... }
}

HTTP Resource

The HttpResource interface extends Resource with HTTP-specific metadata.

public interface HttpResource extends Resource {
    // Get HTTP response headers for this resource
    HttpHeaders getResponseHeaders();
}

Resource URL Provider

The ResourceUrlProvider generates public URLs for static resources.

public class ResourceUrlProvider implements ApplicationContextAware {
    // Set resource handler registry
    public void setResourceHandlers(Map<String, ResourceWebHandler> resourceHandlers) { ... }

    // Get resource handlers
    public Map<String, ResourceWebHandler> getResourceHandlers() { ... }

    // Get resource URL for path
    public Mono<String> getForUriString(String uriString, ServerWebExchange exchange) { ... }

    // Get resource URL for lookup path
    public Mono<String> getForLookupPath(String lookupPath, ServerWebExchange exchange) { ... }
}

Usage:

import org.springframework.web.reactive.resource.ResourceUrlProvider;

@RestController
public class ResourceController {

    private final ResourceUrlProvider resourceUrlProvider;

    public ResourceController(ResourceUrlProvider resourceUrlProvider) {
        this.resourceUrlProvider = resourceUrlProvider;
    }

    @GetMapping("/page")
    public Mono<String> getPage(ServerWebExchange exchange) {
        // Get versioned URL for a resource
        return resourceUrlProvider.getForLookupPath("/css/main.css", exchange)
            .map(versionedUrl -> {
                // Returns something like: /css/main-abc123.css
                return buildHtmlPage(versionedUrl);
            });
    }
}

Resource Handler Utils

Utility methods for resource handling.

public class ResourceHandlerUtils {
    // Check if request is a resource request
    public static boolean isResourceRequest(ServerWebExchange exchange) { ... }

    // Get media type for resource
    public static MediaType getMediaType(Resource resource) { ... }

    // Set headers for resource
    public static void setHeaders(ServerWebExchange exchange,
                                  Resource resource,
                                  MediaType mediaType) { ... }
}

Types

Abstract Resource Resolver

Base class for resource resolver implementations.

public abstract class AbstractResourceResolver implements ResourceResolver {
    protected final Log logger = LogFactory.getLog(getClass());

    @Override
    public Mono<Resource> resolveResource(ServerWebExchange exchange,
                                         String requestPath,
                                         List<? extends Resource> locations,
                                         ResourceResolverChain chain) { ... }

    @Override
    public Mono<String> resolveUrlPath(String resourcePath,
                                      List<? extends Resource> locations,
                                      ResourceResolverChain chain) { ... }

    protected abstract Mono<Resource> resolveResourceInternal(ServerWebExchange exchange,
                                                              String requestPath,
                                                              List<? extends Resource> locations,
                                                              ResourceResolverChain chain);

    protected abstract Mono<String> resolveUrlPathInternal(String resourcePath,
                                                          List<? extends Resource> locations,
                                                          ResourceResolverChain chain);
}

Resource Transformer Support

Base class for resource transformer implementations.

public abstract class ResourceTransformerSupport implements ResourceTransformer {
    protected final Log logger = LogFactory.getLog(getClass());

    // Set resource URL provider
    public void setResourceUrlProvider(ResourceUrlProvider resourceUrlProvider) { ... }

    // Get resource URL provider
    public ResourceUrlProvider getResourceUrlProvider() { ... }

    // Resolve URL path
    protected Mono<String> resolveUrlPath(String resourcePath,
                                         ServerWebExchange exchange,
                                         Resource resource,
                                         ResourceTransformerChain chain) { ... }

    // Convert to public resource URL
    protected Mono<String> toAbsolutePath(String path, ServerWebExchange exchange) { ... }
}

Abstract File Name Version Strategy

Base class for version strategies that add version to file name.

public abstract class AbstractFileNameVersionStrategy implements VersionStrategy {
    protected final Log logger = LogFactory.getLog(getClass());

    @Override
    public String extractVersion(String requestPath) { ... }

    @Override
    public String removeVersion(String requestPath, String version) { ... }

    @Override
    public String addVersion(String requestPath, String version) { ... }

    // File name pattern: name-version.extension
    protected String extractVersionFromFilename(String filename) { ... }
}

Abstract Prefix Version Strategy

Base class for version strategies that add version as URL prefix.

public abstract class AbstractPrefixVersionStrategy implements VersionStrategy {
    protected final Log logger = LogFactory.getLog(getClass());

    @Override
    public String extractVersion(String requestPath) { ... }

    @Override
    public String removeVersion(String requestPath, String version) { ... }

    @Override
    public String addVersion(String requestPath, String version) { ... }

    // Path pattern: version/path/to/resource
}

No Resource Found Exception

Exception thrown when a resource cannot be found.

public class NoResourceFoundException extends ResponseStatusException {
    public NoResourceFoundException(String resourcePath) { ... }
    public NoResourceFoundException(HttpMethod method, String resourcePath) { ... }

    public String getResourcePath() { ... }
}

Usage:

public Mono<Resource> findResource(String path) {
    return resourceService.find(path)
        .switchIfEmpty(Mono.error(new NoResourceFoundException(path)));
}

Complete Configuration Example

import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.CacheControl;
import org.springframework.web.reactive.resource.*;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;

@Configuration
public class ResourceHandlingConfig {

    @Bean
    public ResourceWebHandler resourceWebHandler() {
        ResourceWebHandler handler = new ResourceWebHandler();

        // Configure locations
        handler.setLocations(Arrays.asList(
            new ClassPathResource("static/"),
            new ClassPathResource("public/")
        ));

        // Configure cache control
        handler.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS).cachePublic());
        handler.setUseLastModified(true);
        handler.setOptimizeLocations(true);

        // Configure resource resolvers
        VersionResourceResolver versionResolver = new VersionResourceResolver()
            .addContentVersionStrategy("/**/*.js", "/**/*.css")
            .addFixedVersionStrategy("v1.0", "/**/*.png", "/**/*.jpg");

        EncodedResourceResolver encodedResolver = new EncodedResourceResolver();
        CachingResourceResolver cachingResolver = new CachingResourceResolver(
            new ConcurrentMapCache("resourceCache")
        );
        PathResourceResolver pathResolver = new PathResourceResolver();

        handler.setResourceResolvers(Arrays.asList(
            cachingResolver,
            encodedResolver,
            versionResolver,
            pathResolver
        ));

        // Configure resource transformers
        CssLinkResourceTransformer cssTransformer = new CssLinkResourceTransformer();
        CachingResourceTransformer cachingTransformer = new CachingResourceTransformer(
            new ConcurrentMapCache("transformerCache")
        );

        handler.setResourceTransformers(Arrays.asList(
            cachingTransformer,
            cssTransformer
        ));

        return handler;
    }
}