【问题标题】:Can we have more than one @Path annotation for same REST method [duplicate]我们可以为同一个 REST 方法提供多个 @Path 注释吗?
【发布时间】:2013-06-04 17:03:12
【问题描述】:

对于同一个 REST 方法,我们可以有多个 @Path 注释,即执行的方法是相同的,但它是在访问多个 URL 时执行的?

例如:我想在 http://a/b/chttp://a/b 上运行 searchNames() 方法。

【问题讨论】:

  • 您使用哪种编程语言和框架?
  • 我正在使用 Java 和 Jersey 框架。
  • 您能更详细地描述一下这个问题吗?因为从您的描述看来,您正在尝试解决一开始就不应该遇到的问题。

标签: java rest jersey jax-rs


【解决方案1】:

如果您使用的是 Spring,请尝试

@RequestMapping(value = {"/def", "/abc"}, method = RequestMethod.POST)

这将 work 用于 /abc 和 /def。

sSaroj 2017 年 11 月 17 日 10:13

【讨论】:

    【解决方案2】:

    您不能在单个方法上使用多个 @Path 注释。它会导致“重复注释”语法错误。

    但是,您可以通过多种方式有效地将两条路径映射到一个方法。

    @Path 注解中的正则表达式

    JAX-RS 中的@Path 注释接受参数,可以使用正则表达式限制其值。

    这个注释:

    @Path("a/{parameter: path1|path2}")

    将使/a/path1/a/path2 的请求都可以访问该方法。如果您需要使用子路径,请转义斜杠:{a:path1\\/subPath1|path2\\/subPath2}

    使用重定向状态代码提供响应

    或者,您可以设置重定向。这是在 Jersey(JAX-RS 的参考实现)中通过定义另一个子资源来实现的方法。这只是一个示例,如果您更喜欢处理重定向的不同方式,请随意使用它。

    @Path("basepath")
    public class YourBaseResource {
    
      //this gets injected after the class is instantiated by Jersey    
      @Context
      UriInfo uriInfo; 
    
      @Path("a/b")
      @GET
      public Responce method1(){
        return Response.ok("blah blah").build();
      }
    
      @Path("a/b/c")
      @GET
      public Response method2(){
        UriBuilder addressBuilder = uriInfo.getBaseUriBuilder();
        addressBuilder.path("a/b");
        return Response.seeOther(addressBuilder.build()).build();
      }
    
    }
    

    使用 servlet 过滤器重写 URL

    如果您经常需要这样的功能,我建议使用 servlet 过滤器拦截传入的请求并动态重写路径。这应该可以帮助您将所有重定向保存在一个地方。理想情况下,您可以使用现成的库。 UrlRewriteFilter 可以做到这一点,只要你对 BSD 许可证没问题(查看他们的谷歌代码网站了解详细信息)

    另一种选择是通过在您的 Java 应用程序前面设置的代理来处理此问题。您可以设置一个 Apache 服务器来提供基本的缓存和重写规则,而不会使您的 Java 代码复杂化。

    【讨论】:

    • 谢谢汤姆。 @Path 中的正则表达式不起作用,因为其中一个路径包含斜杠。重定向将发送状态 303,但我想要 200(两者相同)。将尝试 servlet 过滤器方法。
    • 您可以在@Path 正则表达式中使用斜杠
    • @Jonas 很高兴知道。正则表达式匹配的斜线是否优先于分隔路径段的斜线?就个人而言,我不会以这种方式实现它。这会使代码更难理解。
    • @Tom 您是否尝试过您在第二个解决方案中提供的示例?首先,Response.okResponse.seeOther 返回Response.ResponseBuilder 对象,你应该添加.build() 来返回Response。即使在我添加之后,这对我也不起作用。
    • @Cacheing 不是这个特定的 sn-p。你是对的,build() 电话不见了。添加后会发生什么? “对我不起作用”是什么意思?
    【解决方案3】:

    您的特定示例的另一种解决方案:

    假设:

    • /a 用于资源类
    • /b/c/b 是方法的路径

    因为完整路径看起来像:

    <protocol><host><port><app><url-pattern><resource-path><method-path>.

    使用可选参数

    @Path("/b{c : (/c)?}")
    public Response searchNames(@PathParam("c") String val) {
        ...
    }
    

    上面的示例适用于所有示例,例如:

    • /b
    • /b/
    • /b/c
    • /b/c/

    但是当提供c 时,val/c(它之前有一个/)。

    如果你想解决上面的问题(避免Java解析),你需要更复杂的东西:

    @Path("/b{slash : (/)?}{c:((?<=/).*)?}")
    

    对于第 3rd 个要点,它将仅返回 c(不是 /c),但对于第 4th 个要点,它将返回 c/必须用 Java 解析。

    但是对于你的情况(“执行的方法是一样的”),不用担心解析,因为你没有不同的动作。

    【讨论】:

      【解决方案4】:

      正如Tom's answer 中所述,您不能在单个方法上使用多个@Path 注释,因为您将在编译时遇到error: duplicate annotation

      我认为解决这个问题的最简单方法是使用方法重载:

      @Path("{foo}")
      public Response rest(@PathParam("foo") final String foo) {
          return this.rest(foo, "");
      }
      
      @Path("{foo}/{bar}")
      public Response rest(@PathParam("foo") final String foo,
                           @PathParam("bar") final String bar) {
          return Response.ok(foo + " " + bar).build();
      }
      

      如果您遇到多个重载方法具有签名的情况,您还可以使用更多不同的方法名称。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-12-12
        • 1970-01-01
        • 1970-01-01
        • 2018-12-08
        • 1970-01-01
        • 2019-01-04
        • 1970-01-01
        相关资源
        最近更新 更多