简体   繁体   中英

spring boot registering rest controller doesn't work without class level requestmapping

boot application, however, even though my service component shows as registered bean in spring context its url is not getting registered. Basically, to register my component which has method level @RequestMapping annotation I need to define class level request mapping. And then it spring context is able to register the url handler.

my directory structure looks like;

├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── awesomecrypto
│   │   │           └── backend
│   │   │               ├── SpringBootApp.java
│   │   │               ├── entity
│   │   │               │   └── MarketData.java
│   │   │               ├── repository
│   │   │               │   └── MarketDataRepository.java
│   │   │               └── service
│   │   │                   └── MarketDataService.java
│   │   └── resources

SpringBootApp.java

package com.awesomecrypto.backend;

// import statements.

@SpringBootApplication
public class SpringBootApp {

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringBootApp.class, args);

        for (String name: applicationContext.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
}

MarketDataService

package com.awesomecrypto.backend.service;

// import statements here.

@Component
public class MarketDataService {

    @Autowired
    private MarketDataRepository marketDataRepository;

    @GetMapping("/marketData")
    @ResponseBody
    public String getMarketData() {
        return "foobar";
    }
}

Without having a @RequestMapping defined on MarketDataService class level there are no any url handlers registered for "/marketData" url.

2018-05-28 15:15:11.357  INFO 30618 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-05-28 15:15:11.357  INFO 30618 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1295 ms
2018-05-28 15:15:11.460  INFO 30618 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet dispatcherServlet mapped to [/]
2018-05-28 15:15:11.465  INFO 30618 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-05-28 15:15:11.465  INFO 30618 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-05-28 15:15:11.465  INFO 30618 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-05-28 15:15:11.465  INFO 30618 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2018-05-28 15:15:11.601  INFO 30618 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-05-28 15:15:11.813  INFO 30618 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6c65519: startup date [Mon May 28 15:15:10 PDT 2018]; root of context hierarchy
2018-05-28 15:15:11.915  INFO 30618 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-05-28 15:15:11.916  INFO 30618 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-05-28 15:15:11.939  INFO 30618 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-05-28 15:15:11.939  INFO 30618 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]

On the other hand, marketDataService is registered in spring context which doesn't makes sense. Here is the related getBeanDefinitionNames logs.

org.springframework.context.event.internalEventListenerFactory
springBootApp
org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory
marketDataRepository
marketDataService
org.springframework.boot.autoconfigure.AutoConfigurationPackages
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
org.springframework.boot.autoconfigure.condition.BeanTypeRegistry

Now if I add @RequestMapping("/test") on top of MarketDataService then spring registers a url handler.

2018-05-28 15:20:31.320  INFO 31536 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/test/marketData],methods=[GET]}" onto public java.lang.String com.awesomecrypto.backend.service.MarketDataService.getMarketData()

I am running application with;

mvn clean package

mvn spring-boot:run

All of the examples over the web doesn't mention about this and looks like it class level RequestMapping is not required but I couldn't make it. I appreciate for your help. Thanks!

Your @GetMapping annotation is being ignored because there is no annotation of type @Controller at the top of your MarketDataService class.

In your case, you should use the @RestController (which is itself annotated with @Controller and @ResponseBody ):

@RestController
public class MarketDataService {

    @Autowired
    private MarketDataRepository marketDataRepository;

    @GetMapping("/marketData")
    public String getMarketData() {
        return "foobar";
    }

}

The usage of @RequestMapping on a class is to pass down the given parameter as well as the given path parameter to children mappings in the same class.

For instance, adding @RequestMapping("/api") above the class MarketDataService would mean that the path in order to trigger the getMarketData() method would be /api/marketData instead of /marketData .

Likewise, if you added @RequestMapping(value = "/api", produces = "application/json") , it would pass down produces = "application/json" parameter to @GetMapping("/marketData") .

I see @RequestMapping being used on the class often when the controller is used to CRUD a given resource, eg:

@RestController
@RequestMapping("/marketData")
public class MarketDataService {

    @Autowired
    private MarketDataRepository marketDataRepository;

    @PostMapping("")
    public String createMarketData() {
        // ...
    }

    @GetMapping("")
    public String getAllMarketData() {
        // ...
    }

    @GetMapping("/{id}")
    public String getMarketDataById(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("")
    public String deleteAllMarketData() {
        // ...
    }

    @DeleteMapping("/{id}")
    public String deleteMarketDataById(@PathVariable Long id) {
        // ...
    }

    // ...

}

You don't need RequestMapping at the Class Level. Change your code to this and it will work for you.

 @RestController
 public class MarketDataService {

    @Autowired
    private MarketDataRepository marketDataRepository;

    @GetMapping("/marketData")
    public String getMarketData() {
     return "foobar";
    }
  }

I would encourage you to read more about Spring MVC architecture.

https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc

Also you can read the javaDocs for RequestMapping, RestController.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM