/* * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.reactive.config; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.context.ApplicationContext; import org.springframework.util.Assert; import org.springframework.web.reactive.accept.CompositeContentTypeResolver; import org.springframework.web.reactive.handler.AbstractHandlerMapping; import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; import org.springframework.web.reactive.resource.ResourceWebHandler; import org.springframework.web.server.WebHandler; /** * Stores registrations of resource handlers for serving static resources such * as images, css files and others through Spring WebFlux including setting cache * headers optimized for efficient loading in a web browser. Resources can be * served out of locations under web application root, from the classpath, and * others. * * <p>To create a resource handler, use {@link #addResourceHandler(String...)} * providing the URL path patterns for which the handler should be invoked to * serve static resources (e.g. {@code "/resources/**"}). * * <p>Then use additional methods on the returned * {@link ResourceHandlerRegistration} to add one or more locations from which * to serve static content from (e.g. {{@code "/"}, * {@code "classpath:/META-INF/public-web-resources/"}}) or to specify a cache * period for served resources. * * @author Rossen Stoyanchev * @since 5.0 */ public class ResourceHandlerRegistry { private final ApplicationContext applicationContext; private final CompositeContentTypeResolver contentTypeResolver; private final List<ResourceHandlerRegistration> registrations = new ArrayList<>(); private int order = Integer.MAX_VALUE -1; /** * Create a new resource handler registry for the given application context. * @param applicationContext the Spring application context */ public ResourceHandlerRegistry(ApplicationContext applicationContext) { this(applicationContext, null); } /** * Create a new resource handler registry for the given application context. * @param applicationContext the Spring application context * @param contentTypeResolver the content type resolver to use */ public ResourceHandlerRegistry(ApplicationContext applicationContext, CompositeContentTypeResolver contentTypeResolver) { Assert.notNull(applicationContext, "ApplicationContext is required"); this.applicationContext = applicationContext; this.contentTypeResolver = contentTypeResolver; } /** * Add a resource handler for serving static resources based on the specified * URL path patterns. The handler will be invoked for every incoming request * that matches to one of the specified path patterns. * <p>Patterns like {@code "/static/**"} or {@code "/css/{filename:\\w+\\.css}"} * are allowed. See {@link org.springframework.web.util.pattern.ParsingPathMatcher} * for more details on the syntax. * @return A {@link ResourceHandlerRegistration} to use to further * configure the registered resource handler */ public ResourceHandlerRegistration addResourceHandler(String... patterns) { ResourceHandlerRegistration registration = new ResourceHandlerRegistration(this.applicationContext, patterns); this.registrations.add(registration); return registration; } /** * Whether a resource handler has already been registered for the given path pattern. */ public boolean hasMappingForPattern(String pathPattern) { for (ResourceHandlerRegistration registration : this.registrations) { if (Arrays.asList(registration.getPathPatterns()).contains(pathPattern)) { return true; } } return false; } /** * Specify the order to use for resource handling relative to other * {@code HandlerMapping}s configured in the Spring configuration. * <p>The default value used is {@code Integer.MAX_VALUE-1}. */ public ResourceHandlerRegistry setOrder(int order) { this.order = order; return this; } /** * Return a handler mapping with the mapped resource handlers; or {@code null} in case * of no registrations. */ protected AbstractHandlerMapping getHandlerMapping() { if (this.registrations.isEmpty()) { return null; } Map<String, WebHandler> urlMap = new LinkedHashMap<>(); for (ResourceHandlerRegistration registration : this.registrations) { for (String pathPattern : registration.getPathPatterns()) { ResourceWebHandler handler = registration.getRequestHandler(); handler.setContentTypeResolver(this.contentTypeResolver); try { handler.afterPropertiesSet(); handler.afterSingletonsInstantiated(); } catch (Exception ex) { throw new BeanInitializationException("Failed to init ResourceHttpRequestHandler", ex); } urlMap.put(pathPattern, handler); } } SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping(); handlerMapping.setOrder(this.order); handlerMapping.setUrlMap(urlMap); return handlerMapping; } }