Reputation: 2305
Edit: the root cause was a package structure + component scanning issue. I now have the main method class in package com.example
and the controller in package com.example.documents
and it is responding to HTTP requests.
...
I'm setting up a simple Spring Boot app that can POST and GET for a /documents endpoint. I'm puzzled why I keep getting 404s when I hit anything on the server. When I'm in Postman and hit localhost:8081/documents
or localhost:8081/hello
, I always get 404.
I have a feeling I've screwed up the mapping, but I'm not sure how to resolve it. I've tried running with Gradle's bootRun
as well as IntelliJ's built-in runner.
Console output doesn't show anything particularly interesting, just Spring components starting up.
<snip>
2021-01-25 17:01:35.067 INFO 13180 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path ''
2021-01-25 17:01:35.075 INFO 13180 --- [ main] j.Javaspringbootrestuploader2Application : Started Javaspringbootrestuploader2Application in 2.914 seconds (JVM running for 3.272)
our app is running...
Files:
Javaspringbootrestuploader2Application.java
package com.example.javaspringbootrestuploader2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Javaspringbootrestuploader2Application {
public static void main(String[] args) {
SpringApplication.run(Javaspringbootrestuploader2Application.class, args);
System.out.println("our app is running...");
}
}
DocumentController.java
package com.documents;
import java.util.List;
import org.springframework.web.bind.annotation.*;
@RestController
public class DocumentController {
private final DocumentRepository documentRepository;
DocumentController(DocumentRepository documentRepository) {
this.documentRepository = documentRepository;
}
// Aggregate root
// tag::get-aggregate-root[]
@GetMapping("/documents")
List<Document> all() {
return documentRepository.findAll();
}
// end::get-aggregate-root[]
@PostMapping("/documents")
Document newDocument(@RequestBody Document newDocument) {
return documentRepository.save(newDocument);
}
//one record
@GetMapping("documents/{id}")
Document one(@PathVariable Long id) {
return documentRepository.findById(id)
.orElseThrow(() -> new DocumentNotFoundException(id));
}
@RequestMapping("/hello")
public String sayHello() {
return "Hello, world!";
}
}
application.properties
server.port=8081
build.gradle
plugins {
id 'org.springframework.boot' version '2.4.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '15'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
(There's some other files like DocumentNotFoundException.java
but they're not very important to the question.)
What am I doing wrong? Thanks!
Upvotes: 1
Views: 1353
Reputation: 5460
Its looks like a component screener problem on your project.
Spring Scan all component and add it own Context path, for component screening its looking component on the Main class package and its subpackage.
What is defined in here group = 'com.example';
Your DocumentController component (Controller) is out of this package in this why Spring does not know about it and show 404.
Solution:
One: Bring the DocumentController in 'com.example' package or in sub-package of 'com.example' package.
Like this:
'com.example.documents';
Tow: Add an extra Component Screener Annotation on Main Class.
@ComponentScan({"com.documents"})
Like this:
@SpringBootApplication
@ComponentScan({"com.example", "com.documents"})
public class Javaspringbootrestuploader2Application {
public static void main(String[] args) {
SpringApplication.run(Javaspringbootrestuploader2Application.class, args);
System.out.println("our app is running...");
}
}
It will be work.
Upvotes: 3