Languages
[Edit]
EN

Spring Boot 2 - request mapping with wildcard parameter (/path/**)

6 points
Created by:
Alicia-Lambert
520

In this short article, we would like to show how to get wildcard request parameters (under stars parameter from /some/path/**) from URL in Spring Boot 2.

Quick solution:

package example.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.PathMatcher;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;

@Controller
public class ExampleController {

    @Autowired
    private PathMatcher pathMatcher;

    private String getWildcardParam(HttpServletRequest request) {
        String patternAttribute = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
        String mappingAttribute = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
        return this.pathMatcher.extractPathWithinPattern(patternAttribute, mappingAttribute);
    }

    @RequestMapping(
            method = RequestMethod.GET,
            value = "/items/{itemId}/**"
    )
    public ResponseEntity<String> getItem(HttpServletRequest request, @PathVariable String itemId) {
        String wildcardParam = this.getWildcardParam(request);  // <--- extracts all data located under **

        // Some logic here ...
    }
}

     

    Reusable @WildcardParam annotation

    This section contains an example source code, how to create and use simple @WildcardParam annotation.

    Simple steps:

    1. create wildcard annotation to simplify controller mappings usage,
    2. register wildcard annotation in application configuration,
    3. use wildcard parameters in @PathVariable way.

    ExampleController.java file:

    package example.controllers;
    
    import example.annotations.WildcardParam;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.servlet.HandlerMapping;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.Part;
    import java.io.IOException;
    import java.net.URISyntaxException;
    import java.util.Collection;
    import java.util.function.Function;
    
    @Controller
    public class ExampleController {
    
        @RequestMapping(
                method = RequestMethod.GET,
                value = "/items/{itemId}/**"
        )
        public ResponseEntity<String> getItem(
                @PathVariable String itemId,
                @WildcardParam String itemResource  // <--- contains all data located under **
        ) {
            // Some logic here ...
        }
    }

    WildcardParam.java file:

    package example.annotations;
    
    import org.springframework.core.MethodParameter;
    import org.springframework.util.PathMatcher;
    import org.springframework.web.bind.support.WebDataBinderFactory;
    import org.springframework.web.context.request.NativeWebRequest;
    import org.springframework.web.method.support.HandlerMethodArgumentResolver;
    import org.springframework.web.method.support.ModelAndViewContainer;
    import org.springframework.web.servlet.HandlerMapping;
    
    import javax.servlet.http.HttpServletRequest;
    import java.lang.annotation.*;
    
    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface WildcardParam {
    
        class Resolver implements HandlerMethodArgumentResolver {
    
            private PathMatcher pathMatcher;
    
            public Resolver(PathMatcher pathMatcher) {
                this.pathMatcher = pathMatcher;
            }
    
            @Override
            public boolean supportsParameter(MethodParameter methodParameter) {
                Annotation annotation = methodParameter.getParameterAnnotation(WildcardParam.class);
                return annotation != null;
            }
    
            @Override
            public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modeContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
                HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
                if (servletRequest == null) {
                    return null;
                }
                String patternAttribute = (String) servletRequest.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
                String mappingAttribute = (String) servletRequest.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
                return this.pathMatcher.extractPathWithinPattern(patternAttribute, mappingAttribute);
            }
        }
    }

    MVCConfig.java file:

    package example.config;
    
    import example.annotations.WildcardParam;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.util.PathMatcher;
    import org.springframework.web.method.support.HandlerMethodArgumentResolver;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    import java.util.List;
    
    @Configuration
    public class MVCConfig implements WebMvcConfigurer {
    
        @Autowired
        private PathMatcher pathMatcher;  // or replace it with bean creation function
    
        @Override
        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
            resolvers.add(new WildcardParam.Resolver(this.pathMatcher));
        }
    }

    See also

    1. Spring Boot 2 - request mapping with not decoded PathVariable (/path/{pathVariable})

    Alternative titles

    1. Spring Boot 2 - request mapping wildcard exceptions (/path/**)
    2. Spring Boot 2 - request mapping with wildcard variable (/path/**)
    Donate to Dirask
    Our content is created by volunteers - like Wikipedia. If you think, the things we do are good, donate us. Thanks!
    Join to our subscribers to be up to date with content, news and offers.
    Native Advertising
    🚀
    Get your tech brand or product in front of software developers.
    For more information Contact us
    Dirask - we help you to
    solve coding problems.
    Ask question.

    ❤️💻 🙂

    Join