Spring的请求映射与javax.ws.rs中的正则表达式类似。

huangapple go评论75阅读模式
英文:

Spring request mapping with regex like in javax.ws.rs

问题

我正尝试将此Google App Engine Maven服务器存储库重写为Spring。

我在URL映射方面遇到了问题。
Maven存储库服务器的标准URL如下:

  1. 以斜杠结尾的URL指向一个文件夹,例如:

     http://127.0.0.1/testDir/
     http://127.0.0.1/testDir/testDir2/
    
  2. 所有其他(结尾没有斜杠)的URL指向文件,例如:

     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
    

有关目录文件的原始应用映射。

之前使用了@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调度程序。

英文:

I'm trying rewrite this Google App Engine maven server repository to Spring.

I have problem with URL mapping.
Maven repo server standard looks like this:

  1. URL with slash at the end, points to a folder, example:

    http://127.0.0.1/testDir/
    http://127.0.0.1/testDir/testDir2/
    
  2. all others (without slash at the end) point to files, example:

    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
    

Original app mapping for directories and for files.

There were used annotations @javax.ws.rs.Path which supports regexy differently than Spring.

I tried bunch of combinations, for example something like this:

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

But I can't figure out how to do this in right way in Spring application.

I'd like to avoid writing a custom servlet dispatcher.

答案1

得分: 1

// 一个类似的问题曾经困扰过我,与一个使用Maven端点的Spring实现有关。

// 对于文件端点,你可以这样做
/**
 * 用于Jar文件的示例Maven端点
 */
@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) {
   // 与之前一样从requestUri中提取groupId
   ...
}
英文:

I had a similar problem once, also regarding a Spring implementation of a maven endpoint.

For the file endpoints, you could do something like this

/**
 * An example Maven endpoint for Jar files
 */
@GetMapping(&quot;/**/{artifactId}/{version}/{artifactId}-{version}.jar&quot;)
public ResponseEntity&lt;String&gt; getJar(@PathVariable(&quot;artifactId&quot;) String artifactId, @PathVariable(&quot;version&quot;) String version) {
   ...
}

This gives you the artifactId and the version, but for the groupId you would need to do some string parsing. You can get the current requestUri with the help of the ServletUriComponentsBuilder

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

For the folder endpoints, I'm not sure if this will work, but you can give it a try

@GetMapping(&quot;/**/{artifactId}/{version}&quot;)
public ResponseEntity&lt;String&gt; getJar(@PathVariable(&quot;artifactId&quot;) String artifactId, @PathVariable(&quot;version&quot;) String version) {
   // groupId extracted as before from the requestUri
   ...
}

答案2

得分: 0

不了解你的 Java 代码,但如果你逐个验证路径,只需检查字符串是否以 "/" 结尾,对于文件夹,字符串以 "/" 结尾,而对于文件,则不是。

\/{1}$

这个正则表达式只检查字符串是否以 "/" 结尾。如果匹配成功,表示是文件夹;如果匹配不成功,表示是文件。

英文:

Don't know about your java code, but if you are verifying one path at a time, you can just check if the string ends in "/" for a folder and the ones that don't are files

\/{1}$

this regular expression just checks that the string ends with "/" if there is a match, you have a folder, if there is not, you have a file

答案3

得分: 0

以下是翻译好的内容:

原始代码中,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", "你希望对文件执行的操作类型",
        "directory", "你希望对目录执行的操作类型"
);

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

然后根据你的业务逻辑继续进行如果有任何问题请随时告诉我

**注意** 根据你的需求简单地增强端点即可
英文:

Well there is no other specific standard in Spring then the way you have used it. However if you can customize URL then I have a special way to differentiate directory and files. That will increase the scalibility and readability of application and will reduce lot of code for you.

Your Code as of now

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

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

Change above code to as below in your controller class

private final Map&lt;String, String&gt; managedEntities=ImmutableMap.of(
        &quot;file&quot;,&quot;Type_Of_Operation_You_want_For_File&quot;,
        &quot;directory&quot;,&quot;Type_Of_Operation_You_want_For_Directory&quot;
        );

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

And proceed further the way you want to per your business logic. Let me know if you have any questions.

Note: Please simply enhance endpoint per your need.

答案4

得分: 0

Spring不允许匹配跨越多个路径段。路径段是路径分隔符(/)上的分隔值。因此,没有正则表达式组合可以实现此目的。虽然Spring 5允许仅在路径末尾使用**或{*foobar}来捕获foobar uri模板变量以在响应式堆栈中跨越多个路径段,但我认为这对您可能没有用。

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

另一个选择(虽然有些混乱)是拥有一个捕获所有(**)的端点,然后从请求中读取路径并确定它是文件路径还是目录路径,并执行相应的操作。

英文:

Spring doesn't allow matching to span multiple path segments. Path segments are delimited values of path on path separator (/). So no regex combination will get you there. Spring 5 although allows the span multiple path segments only at the end of path using ** or {*foobar} to capture in foobar uri template variable for reactive stack but I don't think that will be useful for you.

Your options are limited. I think the best option if possible is to use different delimiter than / and you can use regex.

Other option ( which is messy ) to have catch all (**) endpoint and read the path from the request and determine if it is file or directory path and perform actions.

答案5

得分: -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;
}

Results for URIs from the question:

test2 /testDir/
test2 /testDir/testDir2/

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

<details>
<summary>英文:</summary>

Try this solution:

```java
@GetMapping(&quot;**/{file:.+?\\..+}&quot;)
public String processFile(@PathVariable String file, HttpServletRequest request) {   
    return &quot;test1 &quot; + file;
}

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

Results for URIs from the question:

test2 /testDir/
test2 /testDir/testDir2/

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

huangapple
  • 本文由 发表于 2020年4月4日 02:00:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/61017815.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定