在简单的 Spring 4 REST 服务上获取 404

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21128275/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 06:27:40  来源:igfitidea点击:

Getting 404 on simple Spring 4 REST service

springrest

提问by badgerduke

I am trying to access a RESTful web service I have written:

我正在尝试访问我编写的 RESTful Web 服务:

http://localhost:8080/dukegen/ws/family/1

but getting a 404 using the address bar in the browser and do not know why. I am trying to return JSON. I have put Hymanson 2 on my classpath:

但是在浏览器中使用地址栏得到 404 并且不知道为什么。我正在尝试返回 JSON。我已将 Hymanson 2 放在我的类路径中:

<dependency>
    <groupId>com.fasterxml.Hymanson.core</groupId>
    <artifactId>Hymanson-databind</artifactId>
    <version>2.3.1</version>
</dependency>

Here is the server output:

这是服务器输出:

Jan 14, 2014 8:29:55 PM org.springframework.web.servlet.handler.AbstractUrlHandlerMapping registerHandler
INFO: Mapped URL path [/ws/family/{familyId}] onto handler 'familyResource'
Jan 14, 2014 8:29:55 PM org.springframework.web.servlet.handler.AbstractUrlHandlerMapping registerHandler
INFO: Mapped URL path [/ws/family/{familyId}.*] onto handler 'familyResource'
Jan 14, 2014 8:29:55 PM org.springframework.web.servlet.handler.AbstractUrlHandlerMapping registerHandler
INFO: Mapped URL path [/ws/family/{familyId}/] onto handler 'familyResource'
Jan 14, 2014 8:29:55 PM org.springframework.web.servlet.FrameworkServlet initServletBean
INFO: FrameworkServlet 'dispatcher': initialization completed in 360 ms
Jan 14, 2014 8:29:55 PM org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping found for HTTP request with URI [/dukegen/ws/family/1] in DispatcherServlet with name 'dispatcher'

Here is my Controller:

这是我的控制器:

@Controller
@RequestMapping("ws")
public class FamilyResource {

    @RequestMapping(value="family/{familyId}", method = RequestMethod.GET, produces="application/json")
    public @ResponseBody Family getFamily(@PathVariable long familyId) {
            .... builds Family object ....
             return family;
         }

}

Here is my dispatcher set up in web.xml:

这是我在 web.xml 中设置的调度程序:

 <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:/mvcContext.xml</param-value>
        </init-param>
  </servlet>

  <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/ws/*</url-pattern>
  </servlet-mapping>

My mvcContext.xml:

我的 mvcContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="ws.hamacher.dukegen.resource"/>

</beans>

Any help would appreciated.

任何帮助将不胜感激。

回答by Anoop

Couple of things are not correct here.

这里有几件事不正确。

First, in your request mapping, the mapping should be consistent. Your class should be mapped to "/ws"and your method which produces the result should be "/family/{familyId}"

首先,在你的请求映射中,映射应该是一致的。你的类应该被映射到 "/ws"你产生结果的方法应该是"/family/{familyId}"

In your web.xml you have configured the servlet to respond to /ws/*and your controller is Request Mapped to wsagain.This wont work.

在您的 web.xml 中,您已将 servlet 配置为响应,/ws/*并且您的控制器ws再次请求映射到。这行不通。

Once "/ws/*"is intercepted by your servlet, it should not be repeated in the Request Mappings. The Controller responds to only the URL pattern within its context. Whatever is after "/ws"in your URL is only in the context of the controller.

一旦"/ws/*"被您的 servlet 拦截,就不应该在请求映射中重复。控制器仅响应其上下文中的 URL 模式。无论是后"/ws"您的网址只在控制器的情况下。

I generally prefer the servlet to be mapped to "/"and all further resolutions coded within the controller. Just my preference, though.

我通常更喜欢将 servlet 映射到"/"控制器中并在控制器中编码所有进一步的分辨率。不过,这只是我的偏好。

So the correct configuration is

所以正确的配置是

web.xml

网页.xml

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:/mvcContext.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

and the controller

和控制器

   @Controller
   @RequestMapping("/ws")
   public class FamilyResource {
       @RequestMapping(value="/family/{familyId}", method = RequestMethod.GET, produces="application/json")
       public @ResponseBody Family getFamily(@PathVariable long familyId) {
          .... builds Family object ....
          return family;
       }
   }

回答by tinocoam

After searching in several posts in the stackoverflow, and not finding decisive answers, it follows what I verified:

在stackoverflow中搜索了几个帖子后,没有找到决定性的答案,它遵循我验证的内容:

1) If you set in the request mapping in this way: "/rest/*", in web.xml or in the "getServletMappings" method of the "AbstractAnnotationConfigDispatcherServletInitializer" class, DO NOT define the same context name in the RequestMapping of RestController.

1)如果在请求映射中这样设置:“/rest/*”,在web.xml或者“AbstractAnnotationConfigDispatcherServletInitializer”类的“getServletMappings”方法中,请勿在RestController的RequestMapping中定义相同的上下文名称.

MySpringMvcDispatcherServletInitializer.java

MySpringMvcDispatcherServletInitializer.java

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class MySpringMvcDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { DemoAppConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/rest/*" };
    }
}   

DemoRestController.java

DemoRestController.java

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value="/rest")
public class DemoRestController {

    // add code for the "/hello" endpoint

    @GetMapping(value="/hello")
    public String sayHello() {
        return "Hello World!";
    }   
}

If you repeat "/rest" in RequestMapping of the RestController class, it won′t work. You′ll receive a 404 error while trying to access the url: http://localhost:9091/your-context-app/rest/hello

如果在 RestController 类的 RequestMapping 中重复“/rest”,它将不起作用。尝试访问以下网址时,您将收到 404 错误:http://localhost:9091/your-context-app/rest/hello

2) When we define "/rest/*" in the request mapping, we are indicating to the Servlet Dispatcher that from this context "/rest" everything will be handled by it. So change the mapping of the RestController by removing "/rest". Enter another mapping, for example "/test":

2) 当我们在请求映射中定义“/rest/*”时,我们向 Servlet Dispatcher 指示从这个上下文“/rest”中的一切都将由它处理。因此,通过删除“/rest”来更改 RestController 的映射。输入另一个映射,例如“/test”:

DemoRestController.java

DemoRestController.java

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value="/test")
public class DemoRestController {

    // add code for the "/hello" endpoint

    @GetMapping(value="/hello")
    public String sayHello() {
        return "Hello World!";
    }   
}

3) Now, access the rest service with the URL: http://localhost:9091/your-context-app/rest/test/hello

3) 现在,使用 URL 访问 rest 服务:http://localhost:9091/your-context-app/rest/test/hello

This should work just fine!

这应该工作得很好!

Hope this helps.

希望这可以帮助。