Spring-Boot @RequestMapping и @PathVariable с сопоставлением регулярных выражений

Я пытаюсь использовать WebJars-Locator с приложением Spring-Boot для сопоставления ресурсов JAR. На их веб-сайте я создал RequestMapping следующим образом:

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

Проблема в том, что переменная partialPath должна включать все, что находится после третьей косой черты. Однако в конечном итоге он ограничивает само отображение. Этот URI отображается правильно:

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

Но этот вообще не отображается на обработчик и просто возвращает 404:

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

Основное различие заключается в количестве компонентов в пути, которые должны обрабатываться регулярным выражением (". +"), Но не работают, если в этой части есть косая черта.

Если это помогает, это указывается в журналах:

2015-03-03 23: 03: 53.588 INFO 15324 --- [main] swsmmaRequestMappingHandlerMapping: Сопоставлено "{[/webjars-locator/{webjar}/{partialPath:.+} provided,methods=[GETpting,params= [], заголовки = [], потребляет = [], производит = [], custom = []} "в общедоступном org.springframework.http.ResponseEntity app.controllers.WebJarsLocatorController.locateWebjarAsset (java.lang.String, java.lang .String) 2

Есть ли какой-то тип скрытых настроек в Spring-Boot, чтобы включить сопоставление шаблонов регулярных выражений в RequestMappings?


person robross0606    schedule 04.03.2015    source источник
comment
Вы уверены, что это правильно? localhost / webjars-locator / angular-bootstrap / datetimepicker /   -  person minion    schedule 04.03.2015
comment
Я создал образец проекта, чтобы воспроизвести проблему. Этот URL не работает http://localhost:8080/webjars-locator/angular-bootstrap/datetimepicker/datetimepicker.js. Но http://localhost:8080/gradle-spring-mvc-web-project/webjars-locator/angular-bootstrap/datetimepicker.js работает нормально. @robross - Подтвердите то же самое.   -  person Mithun    schedule 04.03.2015
comment
Я абсолютно уверен, какие вопросы решаются правильно, а какие нет. Тем не менее, я заметил, что в примере у меня была опечатка, и исправил ее. Прости за это.   -  person robross0606    schedule 04.03.2015
comment
@Mithun, ваш проект несколько отличается от моего. Мне не нужно указывать путь к моему проекту в URL-адресе.   -  person robross0606    schedule 04.03.2015


Ответы (2)


Исходный код в документации не был подготовлен для дополнительных косых черт, извините за это!

Попробуйте вместо этого использовать этот код:

@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);
    }
}

Вскоре я также предоставлю обновление для документации по веб-журналу.

Обновлено 2015/08/05: добавлена ​​обработка If-Modified-Since

person philippn    schedule 04.03.2015
comment
Вы хотите добавить атрибут заголовка Last-Modified в ответ, чтобы избежать передачи ресурсов при каждой загрузке страницы. URLConnection conn = classPathResource.getURL().openConnection();, а затем используйте headers.setContentLength(conn.getContentLengthLong()); и headers.setLastModified(conn.getLastModified()); - person ciri-cuervo; 03.08.2015
comment
@ ciri-cuervo: Хороший момент! Я соответствующим образом обновил код. Спасибо за ваш отзыв! - person philippn; 05.08.2015
comment
Я не думаю, что это работает с return null, потому что Spring отправит статус ответа 200 OK, и сайт не загрузит ресурсы. Если вы установите атрибут Last-Modified в заголовках, Spring автоматически ответит 304 Not Modified (а не ресурс), когда найдет If-Modified-Since в запросе. Посмотрите на мой пример: WebJarsLocatorController.java - person ciri-cuervo; 06.08.2015
comment
Я тестировал его с Chrome, и, похоже, он отлично справляется. Из того, что я прочитал в документации, checkNotModified () прозрачно установит соответствующие заголовки ответа (включая статус). Источник: docs.spring.io/spring/docs/current/javadoc-api/org/ - person philippn; 06.08.2015

Похоже, у вас не может быть PathVariable, чтобы соответствовать "оставшейся части URL". Вы должны использовать шаблоны путей в стиле муравьев, то есть "**", как описано здесь:

Spring 3 RequestMapping: получить значение пути

Затем вы можете получить полный URL-адрес объекта запроса и извлечь «оставшуюся часть».

person ci_    schedule 04.03.2015
comment
comment
Я прочитал документы. Я знаю, что в нем явно не указано, что @PathVariable может применяться только к одному элементу в пути, но похоже, что это так. Нигде в документации я не смог найти пример регулярного выражения, которое соответствует нескольким элементам пути. - person ci_; 04.03.2015
comment
Регулярное выражение не соответствует нескольким переменным пути. Только один. Ссылка, которую я предоставил, приведет вас прямо к такому примеру. Подобные примеры можно найти по всему Интернету. Я подозреваю, что виноват Spring Boot. Тем не менее, я тестировал с одним элементом, и это тоже не сработало. - person robross0606; 04.03.2015
comment
Я не понимаю, у вас есть PathVariable с регулярным выражением, и вы хотите, чтобы он соответствовал интеграции / bootstrap / 3 / dataTables.bootstrap.css, что является более чем одним элементом пути. Предоставленная вами ссылка показывает, как она соответствует одному элементу пути. И да, в этом случае это работает. - person ci_; 04.03.2015
comment
Возможно, это можно выразить по-другому: ваше регулярное выражение не может соответствовать '/'. - person ci_; 04.03.2015
comment
Я думаю, что понял. Пример из веб-журналов неадекватен. Я воспользуюсь обходным путем, чтобы получить путь. - person robross0606; 04.03.2015