Spring-Boot @RequestMapping and @PathVariable with regular expression matching

robross0606 picture robross0606 · Mar 4, 2015 · Viewed 13.3k times · Source

I'm attempting to use WebJars-Locator with a Spring-Boot application to map JAR resources. As per their website, I created a RequestMapping like this:

@ResponseBody
@RequestMapping(method = RequestMethod.GET, value = "/webjars-locator/{webjar}/{partialPath:.+}")
public ResponseEntity<ClassPathResource> locateWebjarAsset(@PathVariable String webjar, @PathVariable String partialPath)
{

The problem with this is that the partialPath variable is supposed to include anything after the third slash. What it ends up doing, however, is limiting the mapping itself. This URI is mapped correctly:

http://localhost/webjars-locator/angular-bootstrap-datetimepicker/datetimepicker.js

But this one is not mapped to the handler at all and simply returns a 404:

http://localhost/webjars-locator/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.css

The fundamental difference is simply the number of components in the path which should be handled by the regular expression (".+") but does not appear to be working when that portion has slashes.

If it helps, this is provided in the logs:

2015-03-03 23:03:53.588 INFO 15324 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/webjars-locator/{webjar}/{partialPath:.+}],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity app.controllers.WebJarsLocatorController.locateWebjarAsset(java.lang.String,java.lang.String) 2

Is there some type of hidden setting in Spring-Boot to enable regular expression pattern matching on RequestMappings?

Answer

philippn picture philippn · Mar 4, 2015

The original code in the docs wasn't prepared for the extra slashes, sorry for that!

Please try this code instead:

@ResponseBody
@RequestMapping(value="/webjarslocator/{webjar}/**", method=RequestMethod.GET)
public ResponseEntity<Resource> locateWebjarAsset(@PathVariable String webjar, 
        WebRequest request) {
    try {
        String mvcPrefix = "/webjarslocator/" + webjar + "/";
        String mvcPath = (String) request.getAttribute(
                HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
        String fullPath = assetLocator.getFullPath(webjar, 
                mvcPath.substring(mvcPrefix.length()));
        ClassPathResource res = new ClassPathResource(fullPath);
        long lastModified = res.lastModified();
        if ((lastModified > 0) && request.checkNotModified(lastModified)) {
            return null;
        }
        return new ResponseEntity<Resource>(res, HttpStatus.OK);
    } catch (Exception e) {
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
}

I will also provide an update for webjar docs shortly.

Updated 2015/08/05: Added If-Modified-Since handling