From 5ec82918afdf23a432c96f9125722e129aa9c38a Mon Sep 17 00:00:00 2001 From: Scott Murphy Heiberg Date: Wed, 20 Nov 2024 20:15:01 -0800 Subject: [PATCH 1/3] Move WebMvcConfigurer to auto configuration --- .../ControllersAutoConfiguration.java | 65 +++++++++++++++++++ .../ControllersGrailsPlugin.groovy | 60 ----------------- 2 files changed, 65 insertions(+), 60 deletions(-) diff --git a/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersAutoConfiguration.java b/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersAutoConfiguration.java index 85b916322e0..641e4aad8fe 100644 --- a/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersAutoConfiguration.java +++ b/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersAutoConfiguration.java @@ -17,6 +17,8 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.web.filter.CharacterEncodingFilter; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.EnumSet; @@ -30,6 +32,15 @@ public class ControllersAutoConfiguration { @Value("${" + Settings.FILTER_FORCE_ENCODING + ":false}") private boolean filtersForceEncoding; + @Value("${" + Settings.RESOURCES_CACHE_PERIOD + ":0}") + int resourcesCachePeriod; + + @Value("${" + Settings.RESOURCES_ENABLED + ":true}") + boolean resourcesEnabled; + + @Value("${" + Settings.RESOURCES_PATTERN + ":"+Settings.DEFAULT_RESOURCE_PATTERN+"}") + String resourcesPattern; + @Bean @ConditionalOnMissingBean(CharacterEncodingFilter.class) public CharacterEncodingFilter characterEncodingFilter() { @@ -67,4 +78,58 @@ public FilterRegistrationBean grailsWebRequestFilter(ApplicationContext registrationBean.setOrder(GrailsFilters.GRAILS_WEB_REQUEST_FILTER.getOrder()); return registrationBean; } + + @Bean + GrailsWebMvcConfigurer webMvcConfig() { + return new GrailsWebMvcConfigurer(resourcesCachePeriod, resourcesEnabled, resourcesPattern); + } + + static class GrailsWebMvcConfigurer implements WebMvcConfigurer { + + private static final String[] SERVLET_RESOURCE_LOCATIONS = new String[] { "/" }; + + private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[] { + "classpath:/META-INF/resources/", "classpath:/resources/", + "classpath:/static/", "classpath:/public/" + }; + + private static final String[] RESOURCE_LOCATIONS; + + static { + RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length + + SERVLET_RESOURCE_LOCATIONS.length]; + System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, 0, + SERVLET_RESOURCE_LOCATIONS.length); + System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, + SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length); + } + + boolean addMappings; + Integer cachePeriod; + String resourcesPattern; + + GrailsWebMvcConfigurer(Integer cachePeriod, Boolean addMappings, String resourcesPattern) { + this.addMappings = addMappings; + this.cachePeriod = cachePeriod; + this.resourcesPattern = resourcesPattern; + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + if (!addMappings) { + return; + } + + if (!registry.hasMappingForPattern("/webjars/**")) { + registry.addResourceHandler("/webjars/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/") + .setCachePeriod(cachePeriod); + } + if (!registry.hasMappingForPattern(resourcesPattern)) { + registry.addResourceHandler(resourcesPattern) + .addResourceLocations(RESOURCE_LOCATIONS) + .setCachePeriod(cachePeriod); + } + } + } } diff --git a/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersGrailsPlugin.groovy b/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersGrailsPlugin.groovy index 2995ed8add1..ac96cb64a42 100644 --- a/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersGrailsPlugin.groovy +++ b/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersGrailsPlugin.groovy @@ -19,7 +19,6 @@ import grails.config.Settings import grails.core.GrailsControllerClass import grails.plugins.Plugin import grails.util.GrailsUtil -import groovy.transform.CompileStatic import groovy.util.logging.Slf4j import org.grails.core.artefact.ControllerArtefactHandler import org.grails.plugins.web.servlet.context.BootStrapClassRunner @@ -31,9 +30,6 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean import org.springframework.context.ApplicationContext import org.springframework.util.ClassUtils -import org.springframework.web.multipart.support.StandardServletMultipartResolver -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping import jakarta.servlet.MultipartConfigElement @@ -67,9 +63,6 @@ class ControllersGrailsPlugin extends Plugin { int fileSizeThreashold = config.getProperty(Settings.CONTROLLERS_UPLOAD_FILE_SIZE_THRESHOLD, Integer, 0) boolean isTomcat = ClassUtils.isPresent("org.apache.catalina.startup.Tomcat", application.classLoader) String grailsServletPath = config.getProperty(Settings.WEB_SERVLET_PATH, isTomcat ? Settings.DEFAULT_TOMCAT_SERVLET_PATH : Settings.DEFAULT_WEB_SERVLET_PATH) - int resourcesCachePeriod = config.getProperty(Settings.RESOURCES_CACHE_PERIOD, Integer, 0) - boolean resourcesEnabled = config.getProperty(Settings.RESOURCES_ENABLED, Boolean, true) - String resourcesPattern = config.getProperty(Settings.RESOURCES_PATTERN, String, Settings.DEFAULT_RESOURCE_PATTERN) if (!Boolean.parseBoolean(System.getProperty(Settings.SETTING_SKIP_BOOTSTRAP))) { bootStrapClassRunner(BootStrapClassRunner) @@ -93,9 +86,6 @@ class ControllersGrailsPlugin extends Plugin { annotationHandlerMapping(RequestMappingHandlerMapping, interceptorsClosure) annotationHandlerAdapter(RequestMappingHandlerAdapter) - // add Grails webmvc config - webMvcConfig(GrailsWebMvcConfigurer, resourcesCachePeriod, resourcesEnabled, resourcesPattern) - // add the dispatcher servlet dispatcherServlet(GrailsDispatcherServlet) dispatcherServletRegistration(DispatcherServletRegistrationBean, ref("dispatcherServlet"), grailsServletPath) { @@ -128,55 +118,6 @@ class ControllersGrailsPlugin extends Plugin { } } } - - @CompileStatic - static class GrailsWebMvcConfigurer implements WebMvcConfigurer { - - private static final String[] SERVLET_RESOURCE_LOCATIONS = [ "/" ] - - private static final String[] CLASSPATH_RESOURCE_LOCATIONS = [ - "classpath:/META-INF/resources/", "classpath:/resources/", - "classpath:/static/", "classpath:/public/" ] - - private static final String[] RESOURCE_LOCATIONS - static { - RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length - + SERVLET_RESOURCE_LOCATIONS.length] - System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, 0, - SERVLET_RESOURCE_LOCATIONS.length) - System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, - SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length); - } - - boolean addMappings = true - Integer cachePeriod - String resourcesPattern - - GrailsWebMvcConfigurer(Integer cachePeriod, boolean addMappings = true, String resourcesPattern = '/static/**') { - this.addMappings = addMappings - this.cachePeriod = cachePeriod - this.resourcesPattern = resourcesPattern - } - - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { - if (!addMappings) { - return - } - - if (!registry.hasMappingForPattern("/webjars/**")) { - registry.addResourceHandler("/webjars/**") - .addResourceLocations("classpath:/META-INF/resources/webjars/") - .setCachePeriod(cachePeriod) - } - if (!registry.hasMappingForPattern(resourcesPattern)) { - registry.addResourceHandler(resourcesPattern) - .addResourceLocations(RESOURCE_LOCATIONS) - .setCachePeriod(cachePeriod) - } - } - } - @Override void onChange( Map event) { if (!(event.source instanceof Class)) { @@ -205,5 +146,4 @@ class ControllersGrailsPlugin extends Plugin { } } } - } From 79ca9e56cbe1108334a5d2f4209570a118b2a645 Mon Sep 17 00:00:00 2001 From: Scott Murphy Heiberg Date: Wed, 20 Nov 2024 21:29:28 -0800 Subject: [PATCH 2/3] move multipartConfig to auto configuration --- .../ControllersAutoConfiguration.java | 31 ++++++++++++++++--- .../ControllersGrailsPlugin.groovy | 8 +---- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersAutoConfiguration.java b/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersAutoConfiguration.java index 641e4aad8fe..8e6519111c9 100644 --- a/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersAutoConfiguration.java +++ b/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersAutoConfiguration.java @@ -3,6 +3,7 @@ import grails.config.Settings; import jakarta.servlet.DispatcherType; import jakarta.servlet.Filter; +import jakarta.servlet.MultipartConfigElement; import org.grails.web.config.http.GrailsFilters; import org.grails.web.filters.HiddenHttpMethodFilter; import org.grails.web.servlet.mvc.GrailsWebRequestFilter; @@ -33,13 +34,25 @@ public class ControllersAutoConfiguration { private boolean filtersForceEncoding; @Value("${" + Settings.RESOURCES_CACHE_PERIOD + ":0}") - int resourcesCachePeriod; + private int resourcesCachePeriod; @Value("${" + Settings.RESOURCES_ENABLED + ":true}") - boolean resourcesEnabled; + private boolean resourcesEnabled; - @Value("${" + Settings.RESOURCES_PATTERN + ":"+Settings.DEFAULT_RESOURCE_PATTERN+"}") - String resourcesPattern; + @Value("${" + Settings.RESOURCES_PATTERN + ":" + Settings.DEFAULT_RESOURCE_PATTERN + "}") + private String resourcesPattern; + + @Value("${" + Settings.CONTROLLERS_UPLOAD_LOCATION + ":#{null}}") + private String uploadTmpDir; + + @Value("${" + Settings.CONTROLLERS_UPLOAD_MAX_FILE_SIZE + ":128000}") + private long maxFileSize; + + @Value("${" + Settings.CONTROLLERS_UPLOAD_MAX_REQUEST_SIZE + ":128000}") + private long maxRequestSize; + + @Value("${" + Settings.CONTROLLERS_UPLOAD_FILE_SIZE_THRESHOLD + ":0}") + private int fileSizeThreshold; @Bean @ConditionalOnMissingBean(CharacterEncodingFilter.class) @@ -80,7 +93,15 @@ public FilterRegistrationBean grailsWebRequestFilter(ApplicationContext } @Bean - GrailsWebMvcConfigurer webMvcConfig() { + public MultipartConfigElement multipartConfigElement() { + if (uploadTmpDir == null) { + uploadTmpDir = System.getProperty("java.io.tmpdir"); + } + return new MultipartConfigElement(uploadTmpDir, maxFileSize, maxRequestSize, fileSizeThreshold); + } + + @Bean + public GrailsWebMvcConfigurer webMvcConfig() { return new GrailsWebMvcConfigurer(resourcesCachePeriod, resourcesEnabled, resourcesPattern); } diff --git a/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersGrailsPlugin.groovy b/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersGrailsPlugin.groovy index ac96cb64a42..e73928df14d 100644 --- a/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersGrailsPlugin.groovy +++ b/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersGrailsPlugin.groovy @@ -57,10 +57,6 @@ class ControllersGrailsPlugin extends Plugin { def config = application.config boolean useJsessionId = config.getProperty(Settings.GRAILS_VIEWS_ENABLE_JSESSIONID, Boolean, false) - String uploadTmpDir = config.getProperty(Settings.CONTROLLERS_UPLOAD_LOCATION, System.getProperty("java.io.tmpdir")) - long maxFileSize = config.getProperty(Settings.CONTROLLERS_UPLOAD_MAX_FILE_SIZE, Long, 128000L) - long maxRequestSize = config.getProperty(Settings.CONTROLLERS_UPLOAD_MAX_REQUEST_SIZE, Long, 128000L) - int fileSizeThreashold = config.getProperty(Settings.CONTROLLERS_UPLOAD_FILE_SIZE_THRESHOLD, Integer, 0) boolean isTomcat = ClassUtils.isPresent("org.apache.catalina.startup.Tomcat", application.classLoader) String grailsServletPath = config.getProperty(Settings.WEB_SERVLET_PATH, isTomcat ? Settings.DEFAULT_TOMCAT_SERVLET_PATH : Settings.DEFAULT_WEB_SERVLET_PATH) @@ -76,8 +72,6 @@ class ControllersGrailsPlugin extends Plugin { "${CompositeViewResolver.BEAN_NAME}"(CompositeViewResolver) - multipartConfigElement(MultipartConfigElement, uploadTmpDir, maxFileSize, maxRequestSize, fileSizeThreashold) - def handlerInterceptors = springConfig.containsBean("localeChangeInterceptor") ? [ref("localeChangeInterceptor")] : [] def interceptorsClosure = { interceptors = handlerInterceptors @@ -91,7 +85,7 @@ class ControllersGrailsPlugin extends Plugin { dispatcherServletRegistration(DispatcherServletRegistrationBean, ref("dispatcherServlet"), grailsServletPath) { loadOnStartup = 2 asyncSupported = true - multipartConfig = multipartConfigElement + multipartConfig = ref('multipartConfigElement') } for (controller in application.getArtefacts(ControllerArtefactHandler.TYPE)) { From 4634e09062563fb003290581b1109467fae1d05c Mon Sep 17 00:00:00 2001 From: Scott Murphy Heiberg Date: Wed, 20 Nov 2024 22:04:38 -0800 Subject: [PATCH 3/3] Move DispatcherServlet to ControllersAutoConfiguration --- .../ControllersAutoConfiguration.java | 26 +++++++++++++++++++ .../ControllersGrailsPlugin.groovy | 14 ---------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersAutoConfiguration.java b/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersAutoConfiguration.java index 8e6519111c9..9a1ffe3abf1 100644 --- a/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersAutoConfiguration.java +++ b/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersAutoConfiguration.java @@ -1,23 +1,28 @@ package org.grails.plugins.web.controllers; import grails.config.Settings; +import grails.core.GrailsApplication; import jakarta.servlet.DispatcherType; import jakarta.servlet.Filter; import jakarta.servlet.MultipartConfigElement; import org.grails.web.config.http.GrailsFilters; import org.grails.web.filters.HiddenHttpMethodFilter; +import org.grails.web.servlet.mvc.GrailsDispatcherServlet; import org.grails.web.servlet.mvc.GrailsWebRequestFilter; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean; import org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; +import org.springframework.util.ClassUtils; import org.springframework.web.filter.CharacterEncodingFilter; +import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -54,6 +59,9 @@ public class ControllersAutoConfiguration { @Value("${" + Settings.CONTROLLERS_UPLOAD_FILE_SIZE_THRESHOLD + ":0}") private int fileSizeThreshold; + @Value("${" + Settings.WEB_SERVLET_PATH + ":#{null}}") + String grailsServletPath; + @Bean @ConditionalOnMissingBean(CharacterEncodingFilter.class) public CharacterEncodingFilter characterEncodingFilter() { @@ -100,6 +108,24 @@ public MultipartConfigElement multipartConfigElement() { return new MultipartConfigElement(uploadTmpDir, maxFileSize, maxRequestSize, fileSizeThreshold); } + @Bean + public DispatcherServlet dispatcherServlet() { + return new GrailsDispatcherServlet(); + } + + @Bean + public DispatcherServletRegistrationBean dispatcherServletRegistration(GrailsApplication application, DispatcherServlet dispatcherServlet, MultipartConfigElement multipartConfigElement) { + if (grailsServletPath == null) { + boolean isTomcat = ClassUtils.isPresent("org.apache.catalina.startup.Tomcat", application.getClassLoader()); + grailsServletPath = isTomcat ? Settings.DEFAULT_TOMCAT_SERVLET_PATH : Settings.DEFAULT_WEB_SERVLET_PATH; + } + DispatcherServletRegistrationBean dispatcherServletRegistration = new DispatcherServletRegistrationBean(dispatcherServlet, grailsServletPath); + dispatcherServletRegistration.setLoadOnStartup(2); + dispatcherServletRegistration.setAsyncSupported(true); + dispatcherServletRegistration.setMultipartConfig(multipartConfigElement); + return dispatcherServletRegistration; + } + @Bean public GrailsWebMvcConfigurer webMvcConfig() { return new GrailsWebMvcConfigurer(resourcesCachePeriod, resourcesEnabled, resourcesPattern); diff --git a/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersGrailsPlugin.groovy b/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersGrailsPlugin.groovy index e73928df14d..75bb581b33a 100644 --- a/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersGrailsPlugin.groovy +++ b/grails-plugin-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersGrailsPlugin.groovy @@ -23,16 +23,12 @@ import groovy.util.logging.Slf4j import org.grails.core.artefact.ControllerArtefactHandler import org.grails.plugins.web.servlet.context.BootStrapClassRunner import org.grails.web.errors.GrailsExceptionResolver -import org.grails.web.servlet.mvc.GrailsDispatcherServlet import org.grails.web.servlet.mvc.TokenResponseActionResultTransformer import org.grails.web.servlet.view.CompositeViewResolver import org.springframework.beans.factory.support.AbstractBeanDefinition -import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean import org.springframework.context.ApplicationContext -import org.springframework.util.ClassUtils import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping -import jakarta.servlet.MultipartConfigElement /** * Handles the configuration of controllers for Grails. @@ -57,8 +53,6 @@ class ControllersGrailsPlugin extends Plugin { def config = application.config boolean useJsessionId = config.getProperty(Settings.GRAILS_VIEWS_ENABLE_JSESSIONID, Boolean, false) - boolean isTomcat = ClassUtils.isPresent("org.apache.catalina.startup.Tomcat", application.classLoader) - String grailsServletPath = config.getProperty(Settings.WEB_SERVLET_PATH, isTomcat ? Settings.DEFAULT_TOMCAT_SERVLET_PATH : Settings.DEFAULT_WEB_SERVLET_PATH) if (!Boolean.parseBoolean(System.getProperty(Settings.SETTING_SKIP_BOOTSTRAP))) { bootStrapClassRunner(BootStrapClassRunner) @@ -80,14 +74,6 @@ class ControllersGrailsPlugin extends Plugin { annotationHandlerMapping(RequestMappingHandlerMapping, interceptorsClosure) annotationHandlerAdapter(RequestMappingHandlerAdapter) - // add the dispatcher servlet - dispatcherServlet(GrailsDispatcherServlet) - dispatcherServletRegistration(DispatcherServletRegistrationBean, ref("dispatcherServlet"), grailsServletPath) { - loadOnStartup = 2 - asyncSupported = true - multipartConfig = ref('multipartConfigElement') - } - for (controller in application.getArtefacts(ControllerArtefactHandler.TYPE)) { log.debug "Configuring controller $controller.fullName" if (controller.available) {