Getting 404 on simple Spring 4 REST service

2019-04-28 04:36发布

问题:

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

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 Jackson 2 on my classpath:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-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:

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

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

回答1:

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}"

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

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.

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

So the correct configuration is

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


回答2:

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

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.

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

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

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":

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

This should work just fine!

Hope this helps.



标签: spring rest