Spring Boot: não é possível acessar o controlador REST no localhost (404)

104

Estou tentando adaptar o exemplo do controlador REST no site Spring Boot. Infelizmente, recebo o seguinte erro quando tento acessar o localhost:8080/itemURL.

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

Aplicação inicial:

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

Controlador 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...!";
   }

}

Estou construindo este projeto com Maven. Iniciei como jar (spring-boot: run) e também dentro do IDE (Eclipse).

Log do console:

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

O que tentei até agora:

  • Acessando o URL com o nome do aplicativo (InventoryApp)
  • Coloque outro @RequestMapping("/")no nível de classe doItemInventoryController

Pelo que entendi, não vou precisar de um contexto de aplicativo ao usar o Spring Boot. Estou certo?

O que mais posso fazer para acessar o método via URL?

mchlfchr
fonte
Como você está executando o aplicativo? Você pode talvez incluir alguns logs?
wjans
Tentei separadamente via Eclipse e com mvn spring-boot: run (como jar). Veja os registros (editados) acima
mchlfchr
A partir do log de inicialização, não parece que está encontrando seu controlador, em qual pacote está sua classe de controlador?
MattR
1
Está em um pacote separado. A classe inicial com o método principal está em "aplicativo", enquanto o controlador está no pacote "controlador". Eu vi exemplos (não os de spring.io), que também foram estruturados dessa forma.
mchlfchr
4
Por padrão, o spring-boot irá procurar componentes no mesmo pacote, ou pacotes "abaixo" (mesmo prefixo) que sua classe de aplicativo. Caso contrário, você precisa digitalizá-los explicitamente, por exemplo, usando @ComponentScan
MattR

Respostas:

197

Tente adicionar o seguinte à sua classe InventoryApp

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

spring-boot irá procurar por componentes nos pacotes abaixo com.nice.application, então se o seu controlador estiver instalado, com.nice.controllervocê precisa procurar explicitamente.

MattR
fonte
Eu tenho os mesmos problemas. Eu tento com a
varredura de
1
observe que @SpringBootApplicationinclui@Configuration
Krzakov
9
Parece mais fácil colocar o aplicativo no pacote "root", por exemplo, "org.whatever" e os controladores, serviços em subpacotes.
insan-e
7
Tenho o mesmo problema mas antes de chegar a esta solução encontrei ... Mais acabou. leve sua classe de aplicativo de boot de primavera (na qual o método principal é definido) um nível acima do pacote do controlador .. então os controladores estarão visíveis para isso e funcionarão
Tayab Hussain
1
Você também pode usar '@ComponentScan (basePackages = "com.nice.controller")'. A varredura padrão do componente começa no caminho, onde é a classe do aplicativo e também os pacotes subsidiários da varredura. Nesse caso, você não precisa usar a anotação @ComponentScan. Isso acontece automaticamente. Se você tiver mais de 1 controlador, é possível tê-los em pacotes diferentes também, você pode conectá-los em cadeia. Nesse caso, é importante evitar conflitos.
hariprasad
47

Somando-se a resposta de mattr:

Como indicado no aqui , @SpringBootApplicationinsere automaticamente as anotações necessárias: @Configuration, @EnableAutoConfiguratione também @ComponentScan; no entanto, o @ComponentScanprocurará apenas os componentes no mesmo pacote do App, neste caso o seu com.nice.application, enquanto o seu controlador reside em com.nice.controller. É por isso que você obtém 404 porque o aplicativo não encontrou o controlador no applicationpacote.

Cipley
fonte
5
Caso isso ainda não esteja completamente claro pela explicação acima, a classe com a anotação @SpringBootApplication deve estar ACIMA ou no mesmo nível em sua estrutura de diretório que as coisas que você gostaria que ela encontrasse. Por exemplo, eu tinha com.app.configuration e com.app.controllers. Por engano, coloquei minha classe Application em com.app.configuration e tudo o mais em com.app.configuration funcionou bem, mas nada em com.app.controllers estava sendo carregado. Mudei minha classe Application para com.app e os beans em outro lugar foram encontrados e as coisas começaram a funcionar. Erro de novato para mim.
glaukommatos
2
Adicionar @ComponentScan (basePackages = "com.base.package") resolveu no meu caso
Shamli
Isso realmente ajuda.
Madhu Tomy
12

Os desenvolvedores do SpringBoot recomendam localizar sua classe de aplicativo principal em um pacote raiz acima de outras classes. Usar um pacote raiz também permite que a anotação @ComponentScan seja usada sem a necessidade de especificar um atributo basePackage . Informações detalhadas Mas certifique-se de que o pacote raiz personalizado existe.

Torina
fonte
10

Mesma resposta 404 que obtive após o serviço executado com o código abaixo

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

}

Resposta:

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

após alterá-lo para o código abaixo, recebi a resposta adequada

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

}

Resposta:

{
"batchId": "DUE1529673844630",
"batchType": null,
"executionDate": null,
"status": "OPEN"
}
Mahender Ambala
fonte
1
Caso outros leitores não vejam, @Controller->@RestController
Janac Meena
7

Eu tive esse problema e o que você precisa fazer é consertar seus pacotes. Se você baixou este projeto de http://start.spring.io/, então você tem sua classe principal em algum pacote. Por exemplo, se o pacote para a classe principal é: "com.example" então e seu controlador deve estar no pacote: "com.example.controller". Espero que isto ajude.

f.trajkovski
fonte
6

Existem 2 métodos para superar isso

  1. Coloque o aplicativo de inicialização no início da estrutura do pacote e coloque todo o controlador dentro dele.

    Exemplo:

    package com.spring.boot.app; - Você inicializa o aplicativo (ou seja, Método Principal -SpringApplication.run (App.class, args);)

    Você Rest Controller com a mesma estrutura de pacote Exemplo: package com.spring.boot.app.rest;

  2. Defina explicitamente o controlador no pacote de inicialização.

O Método 1 é mais limpo.

Mohammed Sarfaraz
fonte
1
spring boot odeia a classe de aplicativo estar em algum pacote diferente do pacote básico ... se o pacote básico for org.someapp e se colocá-lo em org.someapp.app, ele bombardeia ...: - /
Priyank Thakkar
3

Você precisa modificar a classe Starter-Application conforme mostrado abaixo.

@SpringBootApplication

@EnableAutoConfiguration

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

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

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

E atualize a estrutura de pacotes do controlador, serviço e repositório como mencionei abaixo.

Exemplo: REST-Controller

package com.nice.controller; -> Tem que ser modificado como
package com.nice.application.controller;

Você precisa seguir a estrutura de pacote adequada para todos os pacotes que estão no fluxo Spring Boot MVC.

Portanto, se você modificar as estruturas do pacote do pacote do projeto corretamente, seu aplicativo de inicialização rápida funcionará corretamente.

Anjan
fonte
3
EnableAutoConfiguration está incluído em @SpringBootApplication, portanto, é inútil adicioná-lo.
Sofiane
1

Substitua @RequestMapping( "/item" )por @GetMapping(value="/item", produces=MediaType.APPLICATION_JSON_VALUE).

Talvez ajude alguém.

Ihor Khomiak
fonte
1
ajudou-me a reconhecer que havia escrito em namevez de valueno @GetMapping.
vortex.alex
0

Eu tive exatamente o mesmo erro, não estava dando pacote básico. Dando o pacote básico correto, resolvido.

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

}

Nota: não incluindo .controller @ComponentScan (basePackages = "com.ymc.backend.controller") porque tenho muitas outras classes de componentes que meu projeto não verifica se eu apenas fornecer .controller

Aqui está meu exemplo de controlador:

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
fonte
0

Às vezes, a bota de mola se comporta de forma estranha. Especifiquei abaixo na classe do aplicativo e funciona:

@ComponentScan("com.seic.deliveryautomation.controller")
Amo Kumar
fonte
0

Eu tenho o problema 404, por causa da sensibilidade a maiúsculas e minúsculas de URL .

Por exemplo, @RequestMapping(value = "/api/getEmployeeData",method = RequestMethod.GET)deve ser acessado usando http://www.example.com/api/getEmployeeData. Se estivermos usandohttp://www.example.com/api/getemployeedata , obteremos o erro 404.

Nota: http://www.example.com é apenas para referência que mencionei acima. Deve ser o seu nome de domínio onde você hospedou seu aplicativo.

Depois de muita luta e aplicação de todas as outras respostas deste post, descobri que o problema é apenas com aquele url. Pode ser um problema bobo. Mas custou minhas 2 horas. Espero que ajude alguém.

Mahendran Sakkarai
fonte
0

para mim, eu estava adicionando spring-web em vez de spring-boot-starter-web em meu pom.xml

quando eu o substituo de spring-web para spring-boot-starter-web, todo o mapeamento é mostrado no log do console.

Sakirow
fonte
0

Também funciona se usarmos o seguinte:

@SpringBootApplication(scanBasePackages = { "<class ItemInventoryController package >.*" })
Muralidhar
fonte
0

Pode ser que algo mais esteja sendo executado na porta 8080 e você esteja realmente se conectando a ele por engano.

Definitivamente verifique isso, especialmente se você tiver dockers que ativam outros serviços que você não controla e estão encaminhando portas para esses serviços.

Brad Parks
fonte
0

O problema está na estrutura do pacote. O Spring Boot Application tem uma estrutura de pacote específica para permitir que o contexto do spring faça a varredura e carregue vários beans em seu contexto.

Em com.nice.application é onde está sua classe principal e em com.nice.controller, você tem suas classes de controlador.

Mova seu pacote com.nice.controller para com.nice.application para que o Spring possa acessar seus beans.

Naresh Bhadke
fonte
-1

Você pode adicionar dentro do POM.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <version>XXXXXXXXX</version>
</dependency>
Cemahi
fonte
-2

Coloque sua classe springbootapplication no pacote raiz, por exemplo, se o seu serviço, controlador estiver no pacote springBoot.xyz, sua classe principal deve estar no pacote springBoot, caso contrário, não irá verificar os pacotes abaixo

ASG
fonte