2
votes

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?

2
Are you sure this is resolving correctly? localhost/webjars-locator/angular-bootstrap/datetimepicker/… - minion
I created a sample project to reproduce the issue. This URL is not working http://localhost:8080/webjars-locator/angular-bootstrap/datetimepicker/datetimepicker.js. But, http://localhost:8080/gradle-spring-mvc-web-project/webjars-locator/angular-bootstrap/datetimepicker.js is working fine. @robross - Please confirm the same. - Mithun
I am absolutely positive which items are resolving correctly and which are not. However, I did note that I had a character typo in the example and fixed it. Sorry about that. - robross0606
@Mithun, your project appears to be somewhat different than mine. I do not need to put the path to my "project" in the URL. - robross0606

2 Answers

8
votes

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

1
votes

It appears that you cannot have a PathVariable to match "the remaining part of the url". You have to use ant-style path patterns, i.e. "**" as described here:

Spring 3 RequestMapping: Get path value

You can then get the entire URL of the request object and extract the "remaining part".