Сопоставление запросов Spring с регулярным выражением, как в javax.ws.rs - PullRequest
7 голосов
/ 03 апреля 2020

Я пытаюсь переписать этот репозиторий сервера Google App Engine maven в Spring.

У меня проблема с отображением URL. Стандарт сервера репозитория Maven выглядит следующим образом:

  1. URL с sla sh в конце указывает на папку, например:

    http://127.0.0.1/testDir/
    http://127.0.0.1/testDir/testDir2/
    
  2. все остальные (без sla * sh в конце) указывают на файлы, например:

    http://127.0.0.1/testFile.jar
    http://127.0.0.1/testFile.jar.sha1
    http://127.0.0.1/testDir/testFile2.pom
    http://127.0.0.1/testDir/testFile2.pom.md5
    

Исходное отображение приложений для каталогов и для files .

Были использованы аннотации @javax.ws.rs.Path, которые поддерживают регулярные выражения иначе, чем Spring.

Я пробовал несколько комбинаций, например что-то вроде этого:

@ResponseBody
@GetMapping("/{file: .*}")
public String test1(@PathVariable String file) {
    return "test1 " + file;
}

@ResponseBody
@GetMapping("{dir: .*[/]{1}$}")
public String test2(@PathVariable String dir) {
    return "test2 " + dir;
}

Но я не могу понять, как правильно сделать это в приложении Spring.

Я бы не хотел писать собственный диспетчер сервлетов.

Ответы [ 5 ]

1 голос
/ 13 апреля 2020

Spring не позволяет совпадению охватывать несколько сегментов пути. Сегменты пути - это разделенные значения пути на разделителе пути (/). Так что никакая комбинация регулярных выражений не приведет вас туда. Spring 5, хотя позволяет охватить несколько сегментов пути только в конце пути, используя ** или {* foobar}, чтобы захватить переменную шаблона uri foobar для реактивного стека, но я не думаю, что это будет полезно для вас.

Ваши возможности ограничены. Я думаю, что лучший вариант, если это возможно, это использовать другой разделитель, чем /, и вы можете использовать регулярное выражение.

Другой вариант (который является грязным), чтобы перехватить все (**) конечной точки и прочитать путь из запроса и определить, является ли это путь к файлу или каталогу и выполнить действия.

1 голос
/ 08 апреля 2020

Однажды у меня была похожая проблема, также касающаяся реализации Spring конечной точки maven.

Для конечных точек файла вы могли бы сделать что-то вроде этого

/**
 * An example Maven endpoint for Jar files
 */
@GetMapping("/**/{artifactId}/{version}/{artifactId}-{version}.jar")
public ResponseEntity<String> getJar(@PathVariable("artifactId") String artifactId, @PathVariable("version") String version) {
   ...
}

Это дает вам artifactId и version, но для groupId вам потребуется выполнить некоторый анализ строки. Вы можете получить текущий requestUri с помощью ServletUriComponentsBuilder

String requestUri = ServletUriComponentsBuilder.fromCurrentRequestUri().build().toUri().toString();
// requestUri = /api/v1/com/my/groupId/an/artifact/v1/an-artifact-v1.jar

Для конечных точек папки, я не уверен, будет ли это работать, но вы можете попробовать

@GetMapping("/**/{artifactId}/{version}")
public ResponseEntity<String> getJar(@PathVariable("artifactId") String artifactId, @PathVariable("version") String version) {
   // groupId extracted as before from the requestUri
   ...
}
0 голосов
/ 13 апреля 2020

Ну, в Spring нет другого специфического стандарта c, кроме того, как вы его использовали. Однако, если вы можете настроить URL, то у меня есть особый способ различать каталог и файлы. Это повысит масштабируемость и удобочитаемость приложения и уменьшит объем кода для вас.

Ваш код на данный момент

@ResponseBody
@GetMapping("/{file: .*}")
public String test1(@PathVariable String file) {
    return "test1 " + file;
}

@ResponseBody
@GetMapping("{dir: .*[/]{1}$}")
public String test2(@PathVariable String dir) {
    return "test2 " + dir;
}

Измените приведенный выше код на приведенный ниже в классе контроллера

private final Map<String, String> managedEntities=ImmutableMap.of(
        "file","Type_Of_Operation_You_want_For_File",
        "directory","Type_Of_Operation_You_want_For_Directory"
        );

@GetMapping(path = "/{type:file|directory}")
public String myFileOperationControl(@PathVariable String type){
        return "Test"+managedEntities.get(type));
        }

И продолжайте в том же духе, как хотите, согласно вашей бизнес логике c. Дайте знать, если у вас появятся вопросы.

Примечание: Пожалуйста, просто улучшите конечную точку в соответствии с вашими потребностями.

0 голосов
/ 08 апреля 2020

Не знаю о вашем java коде, но если вы проверяете один путь за раз, вы можете просто проверить, заканчивается ли строка на "/" для папки и для тех, которые не являются файлами

\/{1}$

это регулярное выражение просто проверяет, что строка заканчивается на "/", если есть совпадение, у вас есть папка, если нет, у вас есть файл

0 голосов
/ 07 апреля 2020

Попробуйте это решение:

@GetMapping("**/{dir:\\w+}")
public void processDirectory(@PathVariable String dir, HttpServletRequest request) {
    String path = request.getRequestURI();
    System.out.println("dir: " + dir + ", path: " + path);
}

@GetMapping("**/{file:.+?\\..+}")
public void processFile(@PathVariable String file, HttpServletRequest request) {
    String path = request.getRequestURI();
    System.out.println("file: " + file + ", path: " + path);
}

Вывод URL-адресов из описания после вызова по http:

dir: testDir, path: /testDir/
dir: testDir2, path: /testDir/testDir2/
file: testFile.jar, path: /testFile.jar
file: testFile.jar.sha1, path: /testFile.jar.sha1
file: testFile2.pom, path: /testDir/testFile2.pom
file: testFile2.pom.md5, path: /testDir/testFile2.pom.md5

Надеюсь, это поможет.

...