【问题标题】:RequestMapping with more than one path element具有多个路径元素的 RequestMapping
【发布时间】:2013-11-06 08:51:17
【问题描述】:

我正在尝试编写最简单的 Spring 应用程序,它在 @RequestMapping 中使用多个路径元素。例如,/appcontext/blog/hello-world.html 应该在请求映射中工作(显然 /appcontext 是我的应用程序的上下文)。

Spring 可以做这样的事情吗?当它只映射一件事时,我让它很容易工作。例如:

@RequestMapping("hello-world")

有效并且将匹配 /hello-world.do , /anything/hello-world.do ,但我的问题是,如果它在 /blog 路径中​​,我试图只匹配 hello-world ,并且每当我使用类似:

@RequestMapping("/blog/hello-world")

它永远不会触发。

以服务器日志为例:

INFO:   Mapped "{[/blog/hello],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo()

看起来它应该可以工作(这是我唯一的请求映射),但是:

WARNING:   No mapping found for HTTP request with URI [/context/blog/hello.html] in DispatcherServlet with name 'dispatcher'

Spring 可以做这样的事情吗?我不想把我所有的请求映射都放在 / 中,因为它会一团糟。

我得到的唯一映射是:

@RequestMapping("/**")

从那里,我可以直接查看 HttpServletRequest 对象,但这似乎破坏了使用 @RequestMapping 的全部意义。

这是我的控制器:

@Controller
public class BlogController {
    private static final Logger LOG = Logger.getLogger(BlogController.class.getName());

    @RequestMapping("/blog/hello")
    public String foo1() {
        LOG.info("foo1");
        return "nothing";
    }

    @RequestMapping("/blog/hello.html")
    public String foo2() {
        LOG.info("foo2");
        return "nothing";
    }
    @RequestMapping("/blog/hello.*")
    public String foo3() {
        LOG.info("foo3");
        return "nothing";
    }
    @RequestMapping("/blog/**")
    public String foo4() {
        LOG.info("foo4");
        return "nothing";
    }
    @RequestMapping("/blog/{path}")
    public String foo5(@PathVariable String path) {
        LOG.info("foo5 " + path);
        return "nothing";
    }
    // added this as a test - it's the only way that this controller works
    @RequestMapping("/**")
    public String foo6() {
        LOG.info("foo6");
        return "nothing";
    }
}

如果我没有 foo6 映射,那么无论我转到什么 URL,这都不起作用。

当我使用该控制器时,服务器日志中会显示以下内容:

INFO:   Mapped "{[/blog/hello],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo1()
INFO:   Mapped "{[/blog/hello.html],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo2()
INFO:   Mapped "{[/blog/hello.*],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo3()
INFO:   Mapped "{[/blog/**],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo4()
INFO:   Mapped "{[/blog/{path}],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo5(java.lang.String)
INFO:   Mapped "{[/**],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String mainweb.BlogController.foo6()

但是,如果我把它放进去,除了 foo6 之外什么都不会触发。

谢谢!

编辑:我创建了一个非常简单的项目,它只有一个类 Controller 和一个方法 RequestMapping。这个项目除了不工作之外什么都不做。除了使用通配符之外,根本没有办法让@RequestMapping 做任何事情。这似乎是 Spring 中的一个严重错误。所有文档都说@RequestMapping 不仅仅映射一个通配符。

【问题讨论】:

    标签: spring mapping


    【解决方案1】:

    在我看来,它没有映射到 /blog 路径的原因是您没有使用该路径来访问它。

    根据您在上述问题中发布的错误,您已定义/映射:

    /blog/hello
    

    而您正在尝试访问:

    /context/blog/hello.html
    

    即您在 URI 前面加上“/context”,并在后面加上“.html”。这就是它没有响应的原因。

    我建议尝试访问您已映射的 URI。但是,您可能还需要确保应用程序的根上下文是正确的。

    请注意,通过添加“.html”后缀,您并没有使用您定义的路径。如果您希望使用诸如此类的随机后缀,那么也可以在映射中使用通配符。即@RequestMapping(value = "/blog/hello**")

    但是,如果可以避免使用通配符,我通常建议不要使用它,因为当您向应用程序添加更多映射时,它们可能会引发一些意外。

    编辑 - 我也刚刚发现您的控制器更加混乱了这些映射。只需一起阅读以下映射: @RequestMapping("/blog/hello") @RequestMapping("/blog/hello.html") @RequestMapping("/blog/hello.*")

    您的映射相互冲突。该列表中的第一个映射是其他映射的子集,因此它将用于匹配任何这些映射的任何 URL。即第二个 2 是多余的。您可以通过将“裸”/blog/hello 放在其他 2 之后来潜在地解决此问题,以便首先获取更具体的映射,但是,依赖于编写方法的顺序似乎是在自找麻烦我。

    【讨论】:

    • 在服务器日志中,它显示了完整的 URI。 Web 应用程序根本不应该看到上下文元素。我无法想象我需要将上下文硬编码到我的 RequestMapping 中?如果我这样做,那是 Spring 的设计缺陷。如果可以避免的话,我绝对不想使用通配符。我真正想要的是使用 {path} 之类的东西将变量从路径中取出,但如果有另一个路径元素,它似乎不被支持。我的理想就像我的 foo5 方法,但是 Spring 支持吗?
    • Spring 中没有错误。这通常意味着您错误地配置了 Web 服务器。它是定义将传递给 Spring 的上下文的 Web 服务器。鉴于您的配置将“/context”作为上下文传递,我建议您在 Web 服务器配置中查找该文本。
    • 我相信这是Spring中的一个错误。我将应用程序更改为在根上下文中运行,并且行为没有变化。我的 foo1 到 foo5 方法在那里,我仍然得到“在 DispatcherServlet 中找不到带有 URI [/blog/hello.html] 的 HTTP 请求的映射”,即使它清楚地表明 /blog/hello.html、/blog/hello等,都在映射中。这都是 Spring 3.2.4。我会尝试把它放到一个最小的示例项目中并在上面提交一个错误。
    • 因此,您现在已经修复了上下文(现在是 /blog/hello.html 而不是 /context/blog/hello.html)。但是,如果您仍在使用上面的控制器,那么它将无法正常工作。那里到处都有冲突的映射。
    • 我删除了除我的 foo1 方法之外的所有方法,以消除任何冲突。此时我的整个应用程序是一个控制器和一个@RequestMapping,它不起作用。唯一有效的是通配符映射。我可以通过让一种方法检查 URI 然后将请求发送到其他方法来解决这个问题,但这似乎很笨拙。肯定有更好的方法吗?
    【解决方案2】:

    想通了。 servlet 映射切断了部分路径! servlet 映射基本上创建了一个迷你上下文。我不知道它会那样做,而且直观上并不明显,但这就是正在发生的事情。

    【讨论】:

      猜你喜欢
      • 2016-10-20
      • 1970-01-01
      • 2016-06-27
      • 1970-01-01
      • 1970-01-01
      • 2012-10-29
      • 2020-05-31
      • 2020-07-26
      • 2020-10-02
      相关资源
      最近更新 更多