使用正则表达式的 Spring 请求映射,如 javax.ws.rs

Posted

技术标签:

【中文标题】使用正则表达式的 Spring 请求映射,如 javax.ws.rs【英文标题】:Spring request mapping with regex like in javax.ws.rs 【发布时间】:2020-07-15 23:21:04 【问题描述】:

我正在尝试将this Google App Engine maven server repository 重写为 Spring。

我的网址映射有问题。 Maven repo 服务器标准如下所示:

    URL 以斜线结尾,指向一个文件夹,例如:

    http://127.0.0.1/testDir/
    http://127.0.0.1/testDir/testDir2/
    

    所有其他(末尾不带斜线)指向文件,例如:

    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
    

directories 和 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 应用程序中以正确的方式执行此操作。

我想避免编写自定义 servlet 调度程序。

【问题讨论】:

您没有在这两种模式中转义 / char。可能是你的问题。 【参考方案1】:

试试这个解决方案:

@GetMapping("**/file:.+?\\..+")
public String processFile(@PathVariable String file, HttpServletRequest request)    
    return "test1 " + file;


@GetMapping("**/dirName:\\w+")
public String processDirectory(@PathVariable String dirName, HttpServletRequest request) 
    String dirPath = request.getRequestURI();
    return "test2 " + dirPath;

问题中 URI 的结果:

test2 /testDir/
test2 /testDir/testDir2/

test1 testFile.jar
test1 testFile.jar.sha1
test1 testFile2.pom
test1 testFile2.pom.md5    

【讨论】:

【参考方案2】:

不知道你的java代码,但是如果你一次验证一个路径,你可以检查字符串是否以“/”结尾的文件夹和不是文件的字符串

\/1$

这个正则表达式只是检查字符串是否以“/”结尾,如果有匹配,你有一个文件夹,如果没有,你有一个文件

【讨论】:

【参考方案3】:

我曾经遇到过类似的问题,也是关于 Maven 端点的 Spring 实现。

对于文件端点,你可以这样做

/**
 * 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) 
   ...

这为您提供了artifactIdversion,但对于groupId,您需要进行一些字符串解析。您可以在ServletUriComponentsBuilder 的帮助下获取当前的requestUri

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
   ...

【讨论】:

【参考方案4】:

嗯,Spring 中没有其他特定标准,而不是您使用它的方式。但是,如果您可以自定义 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));
        

然后按照您想要的方式进一步处理您的业务逻辑。如果您有任何问题,请告诉我。

注意:请根据您的需要简单地增强端点。

【讨论】:

【参考方案5】:

Spring 不允许匹配跨越多个路径段。路径段是路径分隔符 (/) 上路径的分隔值。所以没有正则表达式组合会让你到达那里。 Spring 5 虽然只允许使用 ** 或 *foobar 在 foobar uri 模板变量中捕获反应堆栈的跨多个路径段,但我认为这对你没有用。

您的选择有限。如果可能的话,我认为最好的选择是使用与 / 不同的分隔符,您可以使用正则表达式。

其他选项(这是混乱的)捕获所有(**)端点并从请求中读取路径并确定它是文件还是目录路径并执行操作。

【讨论】:

以上是关于使用正则表达式的 Spring 请求映射,如 javax.ws.rs的主要内容,如果未能解决你的问题,请参考以下文章

spring mvc的几种使用方式1

spring mvc的几种使用方式1

Django的URLconf

SpringMVC常用注解

接口测试工具-Jmeter使用笔记(五:正则表达式提取器)

正则表达式