Skip to content

Allow adding registration directly in ResourceHandlerRegistry #34967

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,19 @@ protected String[] getPathPatterns() {
return this.pathPatterns;
}

/**
* Create the resource handler.
* Return a {@link ResourceHttpRequestHandler} instance.
*/
protected ResourceHttpRequestHandler createRequestHandler() {
return new ResourceHttpRequestHandler();
}

/**
* Return a {@link ResourceHttpRequestHandler} instance.
*/
protected ResourceHttpRequestHandler getRequestHandler() {
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
ResourceHttpRequestHandler handler = createRequestHandler();
if (this.resourceChainRegistration != null) {
handler.setResourceResolvers(this.resourceChainRegistration.getResourceResolvers());
handler.setResourceTransformers(this.resourceChainRegistration.getResourceTransformers());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,22 @@ public ResourceHandlerRegistration addResourceHandler(String... pathPatterns) {
return registration;
}

/**
* Add a resource handler to serve static resources. The handler is invoked
* for requests that match one of the specified URL path patterns.
* <p>Patterns such as {@code "/static/**"} or {@code "/css/{filename:\\w+\\.css}"}
* are supported. This method allows users to register a subclass of {@link ResourceHandlerRegistration}.
* <p>For pattern syntax see {@link PathPattern} when parsed patterns
* are {@link PathMatchConfigurer#setPatternParser enabled} or
* {@link AntPathMatcher} otherwise. The syntax is largely the same with
* {@link PathPattern} more tailored for web usage and more efficient.
*/
public ResourceHandlerRegistration addResourceHandler(ResourceHandlerRegistration registration) {
Assert.notNull(registration, "ResourceHandlerRegistration must not be null");
this.registrations.add(registration);
return registration;
}

/**
* Whether a resource handler has already been registered for the given path pattern.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@
import java.nio.charset.StandardCharsets;
import java.util.List;

import jakarta.servlet.http.HttpServletRequest;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.core.io.Resource;
import org.springframework.http.CacheControl;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.HandlerMapping;
Expand Down Expand Up @@ -71,6 +76,8 @@ void setup() {

this.registration = this.registry.addResourceHandler("/resources/**");
this.registration.addResourceLocations("classpath:org/springframework/web/servlet/config/annotation/");
this.registry.addResourceHandler(new NoExtensionAsHtmlResourceHttpHandlerRegistration("/noext/**"))
.addResourceLocations("classpath:org/springframework/web/servlet/config/annotation/noext/");
this.response = new MockHttpServletResponse();
}

Expand Down Expand Up @@ -224,4 +231,45 @@ void lastModifiedDisabled() {
assertThat(handler.isUseLastModified()).isFalse();
}

@Test
void noExtensionResource() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/noExtResource");

ResourceHttpRequestHandler handler = getHandler("/noext/**");
handler.handleRequest(request, this.response);

assertThat(this.response.getContentType()).isEqualTo("text/html");
}


static class NoExtensionAsHtmlResourceHttpHandlerRegistration extends ResourceHandlerRegistration {

public NoExtensionAsHtmlResourceHttpHandlerRegistration(String... pathPatterns) {
super(pathPatterns);
}

@Override
protected ResourceHttpRequestHandler createRequestHandler() {
return new NoExtensionAsHtmlResourceHttpHandler();
}
}

static class NoExtensionAsHtmlResourceHttpHandler extends ResourceHttpRequestHandler {

@Override
protected @Nullable MediaType getMediaType(HttpServletRequest request, Resource resource) {
String filename = resource.getFilename();
String ext = StringUtils.getFilenameExtension(filename);
if (!StringUtils.hasText(ext)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion:
Currently, the custom handler assumes that resources without a file extension are of type text/html. However may not work well for different context type. To make it more flexible, maybe allowing the user to configure the type gives more control/flexibility and can support many use cases.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Currently, the custom handler assumes that resources without a file extension are of type text/html. However may not work well for different context type. To make it more flexible, maybe allowing the user to configure the type gives more control/flexibility and can support many use cases.

This is just an example to illustrate its use case.

return MediaType.TEXT_HTML;
}
else {
return super.getMediaType(request, resource);
}
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
no ext