Spring Boot: nie można uzyskać dostępu do kontrolera REST na hoście lokalnym (404)

105

Próbuję dostosować przykład kontrolera REST w witrynie Spring Boot. Niestety pojawia się następujący błąd, kiedy próbuję uzyskać dostęp do localhost:8080/itemadresu URL.

{
  "timestamp": 1436442596410,
  "status": 404,
  "error": "Not Found",
  "message": "No message available",
  "path": "/item"
}

POM:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>SpringBootTest</groupId>
   <artifactId>SpringBootTest</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <properties>
      <javaVersion>1.8</javaVersion>
      <mainClassPackage>com.nice.application</mainClassPackage>
      <mainClass>${mainClassPackage}.InventoryApp</mainClass>
   </properties>

   <build>
      <plugins>
         <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.3</version>
            <configuration>
               <source>${javaVersion}</source>
               <target>${javaVersion}</target>
            </configuration>
         </plugin>

         <!-- Makes the Spring Boot app executable for a jar file. The additional configuration is needed for the cmd: mvn spring-boot:repackage 
            OR mvn spring-boot:run -->
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>

            <configuration>
               <mainClass>${mainClass}</mainClass>
               <layout>ZIP</layout>
            </configuration>
            <executions>
               <execution>
                  <goals>
                     <goal>repackage</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>

         <!-- Create a jar with a manifest -->
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
               <archive>
                  <manifest>
                     <mainClass>${mainClass}</mainClass>
                  </manifest>
               </archive>
            </configuration>
         </plugin>
      </plugins>
   </build>

   <dependencyManagement>
      <dependencies>
         <dependency>
            <!-- Import dependency management from Spring Boot. This replaces the usage of the Spring Boot parent POM file. -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>1.2.5.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>

         <!-- more comfortable usage of several features when developing in an IDE. Developer tools are automatically disabled when 
            running a fully packaged application. If your application is launched using java -jar or if its started using a special classloader, 
            then it is considered a 'production application'. Applications that use spring-boot-devtools will automatically restart whenever files 
            on the classpath change. -->
         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
         </dependency>
      </dependencies>
   </dependencyManagement>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>

      <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
         <version>15.0</version>
      </dependency>
   </dependencies>
</project>

Aplikacja startowa:

package com.nice.application;
@SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan
public class InventoryApp {
   public static void main( String[] args ) {
      SpringApplication.run( InventoryApp.class, args );
   }
}

Kontroler REST:

package com.nice.controller; 
@RestController // shorthand for @Controller and @ResponseBody rolled together
public class ItemInventoryController {
   public ItemInventoryController() {
   }

   @RequestMapping( "/item" )
   public String getStockItem() {
      return "It's working...!";
   }

}

Buduję ten projekt z Mavenem. Uruchomiłem go jako jar (spring-boot: run), a także wewnątrz IDE (Eclipse).

Dziennik konsoli:

2015-07-09 14:21:52.132  INFO 1204 --- [           main] c.b.i.p.s.e.i.a.InventoryApp          : Starting InventoryApp on 101010002016M with PID 1204 (C:\eclipse_workspace\SpringBootTest\target\classes started by MFE in C:\eclipse_workspace\SpringBootTest)
2015-07-09 14:21:52.165  INFO 1204 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@7a3d45bd: startup date [Thu Jul 09 14:21:52 CEST 2015]; root of context hierarchy
2015-07-09 14:21:52.661  INFO 1204 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2015-07-09 14:21:53.430  INFO 1204 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2015-07-09 14:21:53.624  INFO 1204 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2015-07-09 14:21:53.625  INFO 1204 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.0.23
2015-07-09 14:21:53.731  INFO 1204 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2015-07-09 14:21:53.731  INFO 1204 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1569 ms
2015-07-09 14:21:54.281  INFO 1204 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2015-07-09 14:21:54.285  INFO 1204 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'characterEncodingFilter' to: [/*]
2015-07-09 14:21:54.285  INFO 1204 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2015-07-09 14:21:54.508  INFO 1204 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@7a3d45bd: startup date [Thu Jul 09 14:21:52 CEST 2015]; root of context hierarchy
2015-07-09 14:21:54.573  INFO 1204 --- [           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.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2015-07-09 14:21:54.573  INFO 1204 --- [           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.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2015-07-09 14:21:54.594  INFO 1204 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-07-09 14:21:54.594  INFO 1204 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-07-09 14:21:54.633  INFO 1204 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-07-09 14:21:54.710  INFO 1204 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2015-07-09 14:21:54.793  INFO 1204 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2015-07-09 14:21:54.795  INFO 1204 --- [           main] c.b.i.p.s.e.i.a.InventoryApp          : Started InventoryApp in 2.885 seconds (JVM running for 3.227)
2015-07-09 14:22:10.911  INFO 1204 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2015-07-09 14:22:10.911  INFO 1204 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2015-07-09 14:22:10.926  INFO 1204 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 15 ms

Czego próbowałem do tej pory:

  • Dostęp do adresu URL z nazwą aplikacji (InventoryApp)
  • Umieść kolejny @RequestMapping("/")na poziomie klasyItemInventoryController

O ile zrozumiałem, nie będę potrzebował kontekstu aplikacji podczas używania Spring Boot. Czy mam rację?

Co jeszcze mogę zrobić, aby uzyskać dostęp do metody za pośrednictwem adresu URL?

mchlfchr
źródło
Jak uruchamiasz aplikację? Czy możesz dołączyć jakieś dzienniki?
wjans,
Wypróbowałem to osobno przez Eclipse i za pomocą mvn spring-boot: run (as jar). Zobacz powyżej dzienniki (edytowane)
mchlfchr,
Z dziennika startowego nie wygląda na to, że szuka kontrolera, w jakim pakiecie znajduje się twoja klasa kontrolera?
MattR,
1
Jest w osobnym opakowaniu. Klasa startowa z metodą main znajduje się w „application”, podczas gdy kontroler znajduje się w pakiecie „controller”. Widziałem przykłady (nie te na spring.io), które również były tak skonstruowane.
mchlfchr
4
Domyślnie spring-boot skanuje w poszukiwaniu komponentów w tym samym pakiecie lub pakietów „poniżej” (ten sam prefiks) co klasa aplikacji. W przeciwnym razie musisz jawnie je przeskanować, np. Używając @ComponentScan
MattR

Odpowiedzi:

199

Spróbuj dodać poniższe elementy do swojej klasy InventoryApp

@SpringBootApplication
@ComponentScan(basePackageClasses = ItemInventoryController.class)
public class InventoryApp {
...

spring-boot przeskanuje poniżej komponenty w pakietach com.nice.application, więc jeśli twój kontroler jest w nim com.nice.controller, musisz go dokładnie przeskanować.

MattR
źródło
Mam te same problemy. Próbuję z komponentami, ale nic :-( Moje pytanie: stackoverflow.com/questions/33000931/ ...
emoleumassi
1
proszę zauważyć, że @SpringBootApplicationobejmuje@Configuration
krzakov
9
Najprościej wydaje się umieścić Aplikację w pakiecie „root”, np. „Org.cokolwiek”, a kontrolery, usługi w podpakietach.
insan-e
7
Mam ten sam problem, ale zanim doszedłem do tego rozwiązania, znalazłem go ... Więcej. weź swoją klasę aplikacji rozruchu sprężynowego (w której zdefiniowano główną metodę) o jeden poziom w górę do pakietu kontrolera .. wtedy kontrolery będą widoczne dla tego i będą działać
Tayab Hussain
1
Możesz także użyć „@ComponentScan (basePackages =" com.nice.controller ")”. Domyślne skanowanie składników rozpoczyna się na ścieżce, gdzie jest klasa aplikacji, a skanowanie obejmuje również pakiety zależne. W takim przypadku nie musisz używać adnotacji @ComponentScan. Działa automatycznie. Jeśli masz więcej niż 1 kontroler, możesz mieć je również w różnych pakietach, możesz je połączyć. W takim przypadku ważne jest, aby unikać konfliktów.
hariprasad
48

Dodając do odpowiedzi MattR za:

Zgodnie tutaj , @SpringBootApplicationautomatycznie wstawia potrzebne adnotacji: @Configuration, @EnableAutoConfiguration, a także @ComponentScan; jednak @ComponentScanbędzie szukać tylko komponentów w tym samym pakiecie co aplikacja, w tym przypadku w Twoim com.nice.application, podczas gdy Twój kontroler znajduje się w com.nice.controller. Dlatego otrzymujesz 404, ponieważ aplikacja nie znalazła kontrolera w applicationpakiecie.

Cipley
źródło
5
W przypadku, gdy nie jest to całkowicie jasne już z powyższego wyjaśnienia, klasa z adnotacją @SpringBootApplication musi znajdować się POWYŻEJ lub na tym samym poziomie w strukturze katalogów, co rzeczy, które chcesz, aby znalazła. Na przykład miałem com.app.configuration i com.app.controllers. Przez pomyłkę umieściłem klasę aplikacji w com.app.configuration, a wszystko inne w com.app.configuration działało dobrze, ale nic w com.app.controllers nie było ładowane. Przeniosłem moją klasę Application do com.app i znaleziono ziarna w innym miejscu i wszystko zaczęło działać. Błąd debiutanta dla mnie.
glaukommatos
2
Dodanie @ComponentScan (basePackages = "com.base.package") rozwiązało problem w moim przypadku
Shamli
To naprawdę pomaga.
Madhu Tomy
12

Deweloperzy SpringBoot zalecają zlokalizowanie głównej klasy aplikacji w pakiecie głównym ponad innymi klasami. Użycie pakietu głównego umożliwia również użycie adnotacji @ComponentScan bez konieczności określania atrybutu basePackage . Szczegółowe informacje Ale upewnij się, że istnieje niestandardowy pakiet główny.

torina
źródło
10

Ta sama odpowiedź 404, którą otrzymałem po wykonaniu usługi za pomocą poniższego kodu

@Controller
@RequestMapping("/duecreate/v1.0")
public class DueCreateController {

}

Odpowiedź:

{
"timestamp": 1529692263422,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/duecreate/v1.0/status"
}

po zmianie na poniższy kod otrzymałem poprawną odpowiedź

@RestController
@RequestMapping("/duecreate/v1.0")
public class DueCreateController {

}

Odpowiedź:

{
"batchId": "DUE1529673844630",
"batchType": null,
"executionDate": null,
"status": "OPEN"
}
Mahender Ambala
źródło
2
Oby inni czytelnicy tego nie widzieli, @Controller->@RestController
Janac Meena
8

Miałem ten problem i musisz naprawić swoje pakiety. Jeśli pobrałeś ten projekt z http://start.spring.io/ , masz swoją główną klasę w jakimś pakiecie. Na przykład, jeśli pakiet dla klasy głównej to: „com.example”, a kontroler musi znajdować się w pakiecie: „com.example.controller”. Mam nadzieję że to pomoże.

f.trajkovski
źródło
6

Istnieją dwie metody, aby temu zaradzić

  1. Umieść aplikację startową na początku struktury pakietu i umieść w niej cały kontroler.

    Przykład:

    pakiet com.spring.boot.app; - Uruchamiasz aplikację (tj. Main Method -SpringApplication.run (App.class, args);)

    Rest Controller ma taką samą strukturę pakietu Przykład: package com.spring.boot.app.rest;

  2. Jawnie zdefiniuj kontroler w pakiecie Bootup.

Metoda 1 jest bardziej przejrzysta.

Mohammed Sarfaraz
źródło
1
spring boot nienawidzi, że klasa aplikacji znajduje się pod jakimś pakietem innym niż pakiet podstawowy .. jeśli pakiet podstawowy to org.someapp i jeśli umieścimy go pod org.someapp.app, to bombarduje ..: - /
Priyank Thakkar
3

Musisz zmodyfikować klasę Starter-Application, jak pokazano poniżej.

@SpringBootApplication

@EnableAutoConfiguration

@ComponentScan(basePackages="com.nice.application")

@EnableJpaRepositories("com.spring.app.repository")

public class InventoryApp extends SpringBootServletInitializer {..........

Zaktualizuj strukturę pakietów kontrolera, usługi i repozytorium, jak wspomniałem poniżej.

Przykład: kontroler REST

package com.nice.controller; -> Musi zostać zmodyfikowany jako
package com.nice.application.controller;

Musisz przestrzegać właściwej struktury pakietów dla wszystkich pakietów, które są w przepływie Spring Boot MVC.

Tak więc, jeśli poprawnie zmodyfikujesz struktury pakietów projektu, aplikacja do rozruchu wiosennego będzie działać poprawnie.

Anjan
źródło
3
EnableAutoConfiguration jest zawarte w @SpringBootApplication, więc nie ma sensu go dodawać.
Sofiane
1

Wymień @RequestMapping( "/item" )się @GetMapping(value="/item", produces=MediaType.APPLICATION_JSON_VALUE).

Może to komuś pomoże.

Ihor Khomiak
źródło
1
pomogło mi to rozpoznać, że namezamiast valuew @GetMapping.
vortex.alex
0

Miałem dokładnie ten sam błąd, nie podawałem pakietu podstawowego. Podanie poprawnego pakietu podstawowego rozwiązało problem.

package com.ymc.backend.ymcbe;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages="com.ymc.backend")
public class YmcbeApplication {

    public static void main(String[] args) {
        SpringApplication.run(YmcbeApplication.class, args);
    }

}

Uwaga: bez .controller @ComponentScan (basePackages = "com.ymc.backend.controller"), ponieważ mam wiele innych klas komponentów, których mój projekt nie skanuje, jeśli podam .controller

Oto moja próbka kontrolera:

package com.ymc.backend.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@CrossOrigin
@RequestMapping(value = "/user")
public class UserController {

    @PostMapping("/sendOTP")
    public String sendOTP() {
        return "OTP sent";
    };


}
Nabin Kumar Khatiwada
źródło
0

Czasami wiosenny but zachowuje się dziwnie. Podałem poniżej w klasie aplikacji i działa:

@ComponentScan("com.seic.deliveryautomation.controller")
Uwielbiam Kumara
źródło
0

Mam problem 404 z powodu rozróżniania wielkości liter w adresach URL .

Na przykład @RequestMapping(value = "/api/getEmployeeData",method = RequestMethod.GET)należy uzyskać dostęp za pomocą http://www.example.com/api/getEmployeeData. Jeśli używamyhttp://www.example.com/api/getemployeedata , otrzymamy błąd 404.

Uwaga: http://www.example.comjest tylko w celach informacyjnych, o których wspomniałem powyżej. Powinna to być nazwa domeny, w której hostowałeś swoją aplikację.

Po wielu zmaganiach i zastosowaniu wszystkich innych odpowiedzi w tym poście zrozumiałem, że problem dotyczy tylko tego adresu URL. To może być głupi problem. Ale to kosztowało moje 2 godziny. Mam więc nadzieję, że to komuś pomoże.

Mahendran Sakkarai
źródło
0

dla mnie dodawałem spring-web zamiast spring-boot-starter-web do mojego pom.xml

kiedy zamieniam go z spring-web na spring-boot-starter-web, całe mapowanie jest pokazane w dzienniku konsoli.

sakirow
źródło
0

Działa również, jeśli użyjemy w następujący sposób:

@SpringBootApplication(scanBasePackages = { "<class ItemInventoryController package >.*" })
Muralidhar
źródło
0

Może się zdarzyć, że na porcie 8080 działa coś innego i tak naprawdę przez pomyłkę łączysz się z nim.

Zdecydowanie sprawdź to, zwłaszcza jeśli masz platformy dokujące, które wywołują inne usługi, nad którymi nie kontrolujesz, i przekazują te usługi.

Brad Parks
źródło
0

Problem dotyczy struktury Twojego pakietu. Aplikacja Spring Boot ma określoną strukturę pakietu, aby umożliwić kontekstowi sprężyny skanowanie i ładowanie różnych komponentów bean w jej kontekście.

W com.nice.application znajduje się Twoja klasa główna, aw com.nice.controller są to klasy kontrolera.

Przenieś pakiet com.nice.controller do com.nice.application, aby Spring mógł uzyskać dostęp do twoich fasoli.

Naresh Bhadke
źródło
-1

Możesz dodać wewnątrz POM.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <version>XXXXXXXXX</version>
</dependency>
cemahi
źródło
-2

Umieść swoją klasę springbootapplication w pakiecie głównym, na przykład jeśli twoja usługa, kontroler znajduje się w pakiecie springBoot.xyz to twoja główna klasa powinna znajdować się w pakiecie springBoot, w przeciwnym razie nie będzie skanować poniżej pakietów

ASG
źródło