-2

Following problem: I'm studying for a test and I want to get this program working. Spring Boot (got the template with Spring Initializr) with REST web-services. The program is starting and "working", just not exactly the wayIi want it to. I want to use Postman to request my GetMapping and PostMapping (not in there yet), but all I get is:

I tried everything that went through my mind, but I can't figure it out. The "related posts" aren't working for me either. Postman gets the connection, but it doesn't see any data or it at least doesn't respond with any.

{
    "timestamp": "2022-09-04T18:47:39.690+00:00",
    "status": 404,
    "error": "Not Found",
    "message": "No message available",
    "path": "/api/donation/"
}

I obviously want to get the actual results. I've been trying to fix this for like two hours now and need some help.

Application.properties:

spring.datasource.url=jdbc:h2:mem:test
server.port=8080

Pom.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.7.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>template</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>template</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</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-validation</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>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.2.14</version>
        </dependency>
    </dependencies>

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

</project>

Application/Main:

package model;

import org.springframework.stereotype.Component;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

package main;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
    import org.springframework.context.annotation.ComponentScan;
    
    @SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
    public class TemplateApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(TemplateApplication.class, args);
        }
    
    }

Person entity:

@Entity
@Table(name="Person")
public class Person implements Serializable {

    @Id
    @Column(name="person_id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @NotNull
    @Column(name="person_firstName")
    private String firstName;

    @NotNull
    @Column(name="person_lastName")
    private String lastName;

    @OneToMany(mappedBy = "person")
    private List<Donation> donations = new ArrayList<>();

    public Person() {
    }

    public Person(String lastName, String firstName) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.donations = donations;
    }

    public Integer getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return Objects.equals(id, person.id) && Objects.equals(firstName, person.firstName) && Objects.equals(lastName, person.lastName) && Objects.equals(donations, person.donations);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, firstName, lastName, donations);
    }

    @Override
    public String toString() {
        return "Donation{" +
                "id=" + this.getId() +
                ", firstName='" + this.getFirstName() + '\'' +
                ", lastName='" + this.getLastName() + '\'' +
                '}';
    }
}

Donation entity:

package model;

import org.springframework.stereotype.Component;

import javax.persistence.*;
import javax.validation.constraints.Min;
import javax.validation.constraints.PastOrPresent;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.Objects;


@Entity
@Table(name="Donation")
public class Donation implements Serializable {

    @Id
    @Column(name="donation_id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @Min(value=5)
    @Column(name="donation_amount")
    private Integer amount;

    @Column(name="donation_date")
    private LocalDate date;

    @PastOrPresent
    @ManyToOne
    @JoinColumn(name="donation_person_id", nullable = false)
    private Person person;

    public Donation() {

    }

    public Donation(Person person,LocalDate date,Integer amount) {
        this.amount = amount;
        this.date = date;
        this.person = person;
    }

    public Integer getId() {
        return id;
    }

    public Integer getAmount() {
        return amount;
    }

    public LocalDate getDate() {
        return date;
    }


    public Person getPerson() {
        return person;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Donation donation = (Donation) o;
        return Objects.equals(id, donation.id) && Objects.equals(amount, donation.amount) && Objects.equals(date, donation.date) && Objects.equals(person, donation.person);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, amount, date, person);
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + this.getId() +
                ", amount=" + this.getAmount() +
                ", date=" + this.getDate() +
                '}';
    }
}

Donation repository:

package will.Repositories;

import will.model.Donation;
import will.model.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface DonationRepository extends JpaRepository<Donation,Integer> {

    @Query("SELECT SUM(d.amount) FROM Donation d WHERE d.person = :person")
    Integer sum (@Param("person") Person person);

}

Person repository:

package will.Repositories;

import will.model.Donation;
import will.model.Person;

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

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface PersonRepository extends JpaRepository<Person,Integer> {

    @Query("SELECT d FROM Donation d WHERE d.person = :person")
    List<Donation> personsDonations (@Param("person") Optional<Person> person);

}

Donation controller:

package will.Controller;

import java.util.*;    
import will.Repositories.DonationRepository;
import will.model.Donation;
import will.model.Person;
import will.Repositories.PersonRepository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "/api/donation")
public class DonationController {

    private final PersonRepository pRepository;
    private final DonationRepository dRepository;

    public DonationController(PersonRepository pRepository, DonationRepository dRepository) {
        this.pRepository = pRepository;
        this.dRepository = dRepository;
    }

    @GetMapping(path="")
    public List<Donation> findAllDonations(){
        return dRepository.findAll();
    }

    @GetMapping(value="{id}")
    public Donation findDonationById (@PathVariable(value="id") Integer id){
        Optional<Donation> donation = dRepository.findById(id);
        if(!donation.isPresent()){
//            throw new DonationNotFoundException("Eine Donation mit dieser id exisitiert nicht!");
        }
        return donation.get();

    }

    @GetMapping(value="?min={min}")
    public List<Person> findMinSum (@PathVariable(value="min") Integer id){
        List<Person> minSumPersonen;

        List<Person> people = pRepository.findAll();
        List<Person> richPeople= new ArrayList<>();
//
        for(Person p : people){
            if(dRepository.sum(p)>=id){
                richPeople.add(p);
            }
        }

        return richPeople;
//
//
//
//        Map<Person,Integer> donationsSummen = new HashMap<>() {
//        };
//
//        for(Donation i : donations){
//            if(donationsSummen.containsKey(i.getPerson())){
//                donationsSummen.put(i.getPerson(),donationsSummen.get(i.getPerson())+i.getAmount());
//            }
//            else{
//                donationsSummen.put(i.getPerson(),i.getAmount());
//            }
//        }

    }
}

Person controller:

package will.Controller;

import will.Repositories.DonationRepository;
import will.model.Donation;
import will.model.Person;
import will.Repositories.PersonRepository;

import java.net.URI;
import java.util.List;
import java.util.Optional;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import javax.validation.Valid;

@RestController
@RequestMapping("/api/person")
public class PersonController {

    private PersonRepository pRepository;
    private DonationRepository dRepository;

    public PersonController(PersonRepository pRepository, DonationRepository dRepository) {
        this.pRepository = pRepository;
        this.dRepository = dRepository;
    }

    @GetMapping(value = "/{id}/donations")
    List<Donation> personsDonations(@PathVariable(value = "id") Integer id) {

        return pRepository.personsDonations(pRepository.findById(id));

    }


    @PostMapping(path = "/{personid}/donations")
    public ResponseEntity<Donation> createDonation(@PathVariable Integer personid, @Valid
    @RequestBody Donation donation) {
        Optional<Person> person = pRepository.findById(personid);
//        if (!emp.isPresent()) {
//            throw new EmployeeNotFoundException("Employee not found: " + empid);
//        }
//
//        if (wh.getWhId() != null) {
//            throw new WorkingHoursHasIdException("WH has id: " + wh.getWhId());
//        }

        donation.setPerson(person.get());

        Donation savedDonation = dRepository.save(donation);

        String path = "/{personid}/donations";
        URI uri = ServletUriComponentsBuilder.fromCurrentRequest().replacePath(path).build(savedDonation.getId());

        return ResponseEntity.created(uri).body(savedDonation);
    }
}

Finally, the data.sql that initializes the database at the start:

INSERT INTO Person (person_lastName, person_firstName) VALUES('Bauer', 'Barbara');
INSERT INTO Person (person_lastName, person_firstName) VALUES('Bauer', 'Christoph');
INSERT INTO Person (person_lastName, person_firstName) VALUES('Denk', 'Christian');
INSERT INTO Person (person_lastName, person_firstName) VALUES('Hamberger', 'Claudia');
INSERT INTO Person (person_lastName, person_firstName) VALUES('Hofer', 'Barbara');
INSERT INTO Person (person_lastName, person_firstName) VALUES('Imbacher', 'Gustav');
INSERT INTO Person (person_lastName, person_firstName) VALUES('Hofer', 'Andreas');
INSERT INTO Person (person_lastName, person_firstName) VALUES('Langberger', 'Armin');
INSERT INTO Person (person_lastName, person_firstName) VALUES('Maurer', 'Daniel');
INSERT INTO Person (person_lastName, person_firstName) VALUES('Strasser', 'Julia');
INSERT INTO Person (person_lastName, person_firstName) VALUES('Tomanek', 'Florian');
INSERT INTO Person (person_lastName, person_firstName) VALUES('Schuster', 'Elisabeth');

INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(1, '2019-09-04', 25);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(2, '2019-09-04', 25);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(3, '2019-09-04', 25);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(4, '2019-09-04', 5);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(5, '2019-09-04', 35);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(6, '2019-09-04', 5);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(7, '2019-09-05', 22);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(8, '2019-09-04', 25);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(9, '2019-09-06', 25);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(10, '2019-09-11', 20);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(11, '2019-09-04', 25);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(12, '2019-09-04', 100);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(1, '2019-10-06', 15);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(5, '2019-10-07', 15);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(6, '2019-10-07', 15);
INSERT INTO Donation (donation_person_id, donation_date, donation_amount) VALUES(7, '2019-10-07', 15);

This is a lot, but I really need some help here. Probably a really stupid mistake I just can't seem to find it.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • Your application class is in package main, but your controller is in package controller so won't be scanned. Try moving the controller to main or a subpackage of main – johnnyutts Sep 04 '22 at 19:49

1 Answers1

0

I have the practice that I always use the / character even when the controller is default, I would advise to elaborate that action and try it out

@RequestMapping("/")

Another thing that you can change is the default context in Spring you need to change the property

server.servlet.context-path=/api

in this case you need to call /api/donation

  • you could also check the default port of your application and see if it matches the one you are calling.
  • sometimes I have some issues with the use of methods GET, POST you need to call the same method in your Spring Boot annotation in your call to the API.

Another thins is this lines of code:

@RestController
@Component
@RequestMapping("/person")

you don't need to add all this annotations the annotation @RestControlle create a Bean in Spring Boot application too, the annotation @Component is not necessary.

I hope you find the solution to the problem I would start with verifying the API call and then the properties.