SpringBoot Rest-Application funktioniert nicht - Keine Fehlermeldungen

tom.j85

Mitglied
Liebe Community,

ich brüte schon länger über folgendem Problem: Ich habe ein paar CRUD Methoden mithilfe von SpringBoot erstellt, aber bei Postman wird immer nur 404 not found angezeigt. Andere Programme in meinem Workspace mit der gleichen (zumindest meine ich das) Konfiguration funktionieren aber. Es geht um eine einfache Tode-Liste, die später in einem Frontend bearbeitet können werden soll. Die Dateien:

Java:
package todoEntities;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;


@Getter
@Setter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table
public class Todo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    @Max(20)
    private String name;
    
    @NotBlank
    private String details;
    
    private Boolean done;
    
    private Date date;
    

    
}

Das Repository:

Java:
package todoRepository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import todoEntities.Todo;



@Repository
public interface TodoRepository extends JpaRepository<Todo, Integer> {

}

Der Controller:

Java:
package todoController;

import java.util.List;
import java.util.Optional;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import todoEntities.Todo;
import todoRepository.TodoRepository;

@RestController
@RequestMapping("/todo/")
public class TodoController {

    @Autowired
    TodoRepository todorepository;

    @PostMapping
    public ResponseEntity<Todo> save(@Valid @RequestBody Todo todo) {
        todorepository.save(todo);
        return new ResponseEntity<Todo>(todo, HttpStatus.OK);

    }

    @PostMapping("saveall")
    public ResponseEntity<List<Todo>> saveAll(@Valid @RequestBody List<Todo> todos) {
        todorepository.saveAll(todos);
        return new ResponseEntity<List<Todo>>(todos, HttpStatus.OK);
    }

    @GetMapping("{id}")
    public ResponseEntity<Optional<Todo>> findById(@PathVariable Integer id) {
        if (!todorepository.existsById(id)) {
            return new ResponseEntity<Optional<Todo>>(HttpStatus.NOT_FOUND);
        } else {
            Optional<Todo> maybeTodo = todorepository.findById(id);
            return new ResponseEntity<Optional<Todo>>(maybeTodo, HttpStatus.OK);

        }

    }

    @GetMapping
    public ResponseEntity<List<Todo>> findAll() {

        List<Todo> maybeToDos = todorepository.findAll();
        return new ResponseEntity<List<Todo>>(maybeToDos, HttpStatus.OK);
    }

    @DeleteMapping("delete/{id}")
    public ResponseEntity<?> delete(@PathVariable Integer id) {

        if (!todorepository.existsById(id)) {
            return new ResponseEntity<Todo>(HttpStatus.NOT_FOUND);
        } else {
            todorepository.deleteById(id);
            return new ResponseEntity<Todo>(HttpStatus.OK);
        }

    }

    @PutMapping("update/{id}")
    public ResponseEntity<Todo> update(@PathVariable Integer id, @Valid @RequestBody Todo todo) {
        if (!todorepository.existsById(id)) {
            return new ResponseEntity<Todo>(HttpStatus.NOT_FOUND);
        } else {
            todo.setId(id);
            todorepository.save(todo);
            return new ResponseEntity<Todo>(HttpStatus.OK);
        }
    }

}

Die pom.xml:

XML:
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.todo3</groupId>
    <artifactId>todo3</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>todo3</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
                <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
            <version>1.4.199</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Und die applications.properties (obwohl ich mir nicht sicher bin ob die überhaupt irgendwas damit zu tun hat...)

Code:
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

und natürlich die Application mit der Main Methode:

Java:
package com.todo3.todo3;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Todo3Application {

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

}

Nach "run as SpringBoot Application" läuft letzere auch an. Keine Fehlermeldungen, alles scheint gut zu sein. Wenn ich dann aber bei Postman versuche die getMapping Methode "findAll" über localhost:8080/todo/ versuche abzurufen, bekomme ich eine einfache

JSON:
{
    "timestamp": "2020-04-21T13:47:46.400+0000",
    "status": 404,
    "error": "Not Found",
    "message": "No message available",
    "path": "/todo/"
}
...eigentlich erwarte ich aber eine leere Liste, oder? [ ]
gleiches gilt auch, wenn ich ein JSON Objekt über die PostMethod losschicke ..ich bin sehr ratlos und schon einige Stunden am suchen...wahrscheinlich ist es ein sehr einfacher und blöder Fehler, aber ich finde ihn nicht..vielen Dank für jede(n) Support, Tipp und Hilfe

LG
Tom
 
Hallo Thallius,
vielen Dank für die Antwort! Hm...ich glaube

Java:
@GetMapping
    public ResponseEntity<List<Todo>> findAll() {

        List<Todo> maybeToDos = todorepository.findAll();
        return new ResponseEntity<List<Todo>>(maybeToDos, HttpStatus.OK);
    }

müsste eigentlich reichen...dann wird die url aus @RequestMapping("/todo/") bedient, oder liege ich falsch? Ich habe aber auch die Vermutung dass irgendwas mit den Pfaden nicht stimmt..nur was...
 
Update:
----------------------

ich habe ein bisschen refactored (was aber nicht zur Lösung beigetragen hat, denke ich) und dann die Application mit der Main gezwungen diverse Pakete zu lesen:

Java:
package com.todoApplication;


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




//@EntityScan
//@ComponentScan(value= {"com.todoController","com.todoEntities","com.todoRepository"})
@SpringBootApplication(scanBasePackages = { "com.todoController","com.todoEntities","com.todoRepository"})
public class TodoApplication {

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

}

(das auskommentierte habe ich auch versucht, gleiches Ergebnis🙂

...immerhin bekomme ich jetzt eine Fehlermeldung...!


Code:
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-04-21 14:24:26.240 ERROR 14554 --- [  restartedMain] o.s.b.d.LoggingFailureAnalysisReporter   :

***************************
APPLICATION FAILED TO START
***************************

Description:

Field todoRepository in com.todoController.TodoController required a bean of type 'com.todoRepository.TodoRepository' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)
    - @org.springframework.beans.factory.annotation.Qualifier(value=todoRepository)


Action:

Consider defining a bean of type 'com.todoRepository.TodoRepository' in your configuration.

...das passiert mit Autowired, aber auch mit Konstruktorinjection, also

Java:
[...]

@RestController
@RequestMapping("/todo/")
public class TodoController {

//    private final TodoRepository todoRepository;   
    
private TodoRepository todoRepository;

        
    
      public TodoController(TodoRepository todoRepository){
      
            this.todoRepository = todoRepository;
        }
        
        [...]

Nur dann eben mit der Fehlermeldung

Code:
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-04-21 14:29:00.496 ERROR 14698 --- [  restartedMain] o.s.b.d.LoggingFailureAnalysisReporter   :

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.todoController.TodoController required a bean of type 'com.todoRepository.TodoRepository' that could not be found.


Action:

Consider defining a bean of type 'com.todoRepository.TodoRepository' in your configuration.

Das Internet sagt, wahrscheinlich erkennt die Application Datei nicht den Controller oder andere Komponenten...alerdings ist bei mir die Application Datei mit der Main von SpringBoot ganz oben im Folder src/main/java....und selbst wenn, dann hätte das doch der @ComponentScan, den ich dort mal reingeschrieben habe auffangen müssen...

Für jede Idee dankbar
und einen schönen Abend
Tom
 
Japp, sorry, das waren meine wilden und völlig verzweifelten Refactoring Versuche. Bei den Paketen steht jetzt überall com. usw dran...

eclipse.png
 
Kannst du zum Testen mal fie TodoApplication Klasse in das package com verschieben? Dann kannst du auch die scanBasePackages entfernen. Ich vermute den Fehler dort.
 
Hey, vielen Dank für den Input!
Bin mir nicht sicher was gemeint ist: Soll die todoApplication.java ganz aus den packages raus, sodass ein default package ganz oben entsteht? Das habe ich erfolglos versucht...
Das Projekt um das es geht ist ja ausschließlich todo3...in diesem Fall liegt die todoApplication ja schon ganz oben, nämlich im Paket com.todoApplication..oder meint ihr etwas anderes?
Besten Dank 🙂
 
Die TodoApplication ins „com“-package, sodass alle anderen Klassen in einem
Package unterhalb davon liegen 🙂
 
Ok, merci, ich habe umgeordnet und voilà! Es funktioniert! Und sogar Postman gibt die gewünschte leere Liste aus!

Lesson learned: Selbst wenn es keine Fehlermeldung in Eclipse / SpringBoot gibt, kann es sein die die dependency injection nicht funktioniert, weil die xyzApplication mit der Main Methode von Spring nicht im richtigen Ordner liegt!

Besten Dank an alle, die mitgeholfen haben!
 
Alternative wäre ansonsten noch, bei der SpringApplication auch noch @ComponentScan(...) mit anzugeben und da dann die packages angeben, die durchsucht werden sollen.

Also sowas in der Art:
Code:
@ComponentScan({"com.todoController","com.todoEntities","com.todoRepository"})

Denn nach meinem Vesrtändnis führt er einen Component Scan ab der @SpringAppliation aus. Da dies aber in einem package ist, in dem die ganzen Elemente nicht vorhanden sind, werden die Componenten nicht gefunden.
=> Lösungsvorschlag von @mrBrown: Lege die Application so, dass alle Komponenten im gleichen oder in einem Sub-Package sind.
=> Alternative, die ich hier erwähnen möchte: Gibt dem ComponentScan an, wo er überall suchen soll.
 

Zurück
Oben