SpringBoot: Einfache RestAPI konsumieren gelingt nicht.

Zrebna

Bekanntes Mitglied
Hi!

Ich will innerhalb meiner SpringBoot-Application eine einfache externe API konsumieren, die öffentliche Feiertage anzeigt.
Zb. die von Deutschland 2023:
Ich habe dazu in einem dto-sub-package innerhalb meinem model-package eine entity-Klasse erstellt (jedoch nur mir den Attributen, die ich mir anzeigen will) :
Java:
public class Holiday {
    Date date;
    String localName;
    String name;
   
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public String getLocalName() {
        return localName;
    }
    public void setLocalName(String localName) {
        this.localName = localName;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

Danach habe ich innerhalb meiner index-view ein Suchfeld erstellt, das je nach Eingabe nach Feiertagen gem. Jahr und Ländercode suchen soll.
Die Strings in den views bitte ignorieren, die passe ich später noch an.
Eine gültige Sucheingabe wäre dann z.B.: 2023/DE

Relevante Stelle in index-View:
HTML:
    <div class="mt-4">
                <h4 th:text="#{search_reviews}"></h4>
                <form action="#" th:action="@{/search-reviews/{searchTerm}(searchTerm=${searchTerm})}" method="GET">
                    <div class="row my-2">
                        <input type="text" name="searchTerm" required
                            th:value="${searchTerm}" class="form-control"
                            th:placeholder="#{user_name}" />
                    </div>
                    <div class="row my-2">
                        <button type="submit" class="btn btn-primary" th:text="#{search}"></button>
                    </div>
                </form>
            </div>

Danach habe ich einen RestController erstellt:

Java:
@Controller

@RequestMapping("/api/holidays")

public class PublicHolidaysRestController {


    private final RestTemplate restTemplate;


    @Autowired

    public PublicHolidaysRestController(RestTemplateBuilder restTemplateBuilder) {

        this.restTemplate = restTemplateBuilder.build();

    }


    @GetMapping("/")

    public String consumePublicHolidaysByYearAndCountry(@PathVariable("searchTerm") String searchTerm, Model model) {


        ResponseEntity<Holiday[]> responseEntity = restTemplate

                .getForEntity("https://date.nager.at/api/v2/publicholidays/" + searchTerm, Holiday[].class);


        // extracting body into array of {@link Holiday}s

        Holiday[] holidays = responseEntity.getBody();


        ObjectMapper mapper = new ObjectMapper();


        mapper.registerModule(new JSR310Module());


        model.addAttribute("holidays", holidays);


        return "/holiday/holiday-list";


    }

}

Schließlich sollen in dieser view die einzelnen Feiertage angezeigt werden (Spaltenbenennungen noch nichts angepasst - bitte ignorieren) :
View -> holiday-list:
HTML:
DOCTYPE html>
<html layout:decorate="~{layouts/default-layout}">
<head>
<title></title>
</head>
<body>
    <div layout:fragment="content">
        <h4>Holidays</h4>
        <table class="border text-center table">
            <thead class="border table-dark">
                <tr>
                    <th class="border" scope="col" th:text="#{date}"></th>
                    <th class="border" scope="col" th:text="#{rating}"></th>
                    <th class="border" scope="col" th:text="#{review}"></th>
                    <th class="border" scope="col"></th>
                </tr>
            </thead>
            <tbody>
                <tr th:each="holiday : ${holidays}">
                    <td class="border" th:text="${holiday.name}"></td>
                    <td class="border" th:text="${holiday.localName}"></td>
                    <td class="border" th:text="${holiday.name}"></td>
                </tr>
            </tbody>
        </table>

    </div>
</body>
</html>


Beim Laufen des Codes komme ich nicht weit:
Code:
Resolved [org.springframework.web.bind.MissingPathVariableException: Required URI template variable 'searchTerm' for method parameter type String is not present]

Ich vermute, dass etnweder mein Versuch den searchTerm als Teil des Pfades in der index-View oder im RestController nicht korrekt ist.

Über Hilfe, wie ich doch noch diese einfache RestAPI konsumieren könnte, wäre ich dankbar.

Lg
Zrebna
 

KonradN

Super-Moderator
Mitarbeiter
Also dein Controller passt so doch nicht:
Java:
@GetMapping("/")
public String consumePublicHolidaysByYearAndCountry(@PathVariable("searchTerm") String searchTerm, Model model) {

Da meckert Spring Boot natürlich, denn Du willst die PathVariable aber im Mapping hast Du diese nicht!
Dein GetMapping müsste da z.B. so aussehen: @GetMapping("/{searchTerm}")

Siehe z.B. https://www.baeldung.com/spring-pathvariable
 

Zrebna

Bekanntes Mitglied
Tatsache, das habe ich verpeilt - nun sieht es so aus:

Java:
    @GetMapping("/{searchTerm}")
    public String consumePublicHolidaysByYearAndCountry(@PathVariable String searchTerm, Model model) {

        ResponseEntity<Holiday[]> responseEntity = restTemplate
                .getForEntity("https://date.nager.at/api/v2/publicholidays/" + searchTerm, Holiday[].class);

        // extracting body into array of {@link Holiday}s
        Holiday[] holidays = responseEntity.getBody();

        ObjectMapper mapper = new ObjectMapper();

        mapper.registerModule(new JSR310Module());

        model.addAttribute("holidays", holidays);

        return "/holiday/holiday-list";

    }

Aber bei Eingabe im entsprechendem Suchfeld gelangt das Programm weiterhin nicht in die obige Methode.
Eingabe im Suchfeld ist: 2023/DE

Der relevante Teil in der View, in der die Suche startet muss demnach fehlerhaft sein, aber ich finde den Fehler nicht.
Hier mal die view (Nicht wundern, Strings/Texte passe ich erst an, wenn funktionell alles klappt...)
HTML:
    <div class="mt-4">
                <h4 th:text="#{avg_score}"></h4>
                <form action="#" th:action="@{/api/holidays}" method="GET">
                    <div class="row my-2">
                        <input type="text" name="searchTerm" required
                            th:value="${searchTerm}" class="form-control"
                            th:placeholder="#{user_name}" />
                    </div>
                    <div class="row my-2">
                        <button type="submit" class="btn btn-primary" th:text="#{search}"></button>
                    </div>
                </form>
            </div>

Siehst du den Fehler?
 

KonradN

Super-Moderator
Mitarbeiter
Du baust ja auch eine URL auf, die nicht passt. Es wird erwartet, dass Du "/{value}" gibst, aber Du baust eine URL auf, die "/{value1}/{value2} aussieht.

Wenn Du da einen Wert in der URL mitgibst, dann muss dieser URL Encoded sein. Ein / hat in der URL eine spezielle Bedeutung und daher wird der als %2F codiert. Wenn Du also den String "2023/DE" übergeben willst in der URL "/{variable}", dann wäre dies die URL "/2023%2FDE"

Siehe dazu z.B.
 

KonradN

Super-Moderator
Mitarbeiter
Du hast da zumindest zwei angegeben. Wenn Du möchtest, dann kannst Du aber den Code so lassen. Nur eben beim Aufruf musst es URL Encoded sein. (Das muss generell jeder Parameter, den Du an der URL mitgibst!)

Wenn Du es ausprobierst und entsprechend den Aufruf umgestaltest, dann solltest Du in dem Mapping das Richtige bekommen.

Aber ich denke, ich sehe da noch ein Problem, denn Du baust da im Code eben nichts auf mit PathVariable.

Das Ergebnis Deines HTML Code dürfte eine URl sein /api/holidays?searchParam=2023%2FDE und eben kein /api/holidays/2023%2FDE
Sprich: Du hast es als normalen Parameter in der URL und nicht im Path!

Edit: Was Du da halt (im HTML Code) hast ist kein Aufruf einer REST Api sondern ein einfaches Submit einer Form.
 

Zrebna

Bekanntes Mitglied
Ja, stimmt - das ist mir auch schon aufgefallen - ich hab jetzt eh eine andere externe API ausgewählt und modelliere das gerade alles um.
Falls es nicht klappen sollte, dann melde ich mich nochmal - schon mal vielen Dank soweit!
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
ExceptionOfExpectation Persistierung in Hibernate(SpringBoot) Frameworks - Spring, Play, Blade, Vaadin & Co 2
ExceptionOfExpectation Desktop-Window in SpringBoot Frameworks - Spring, Play, Blade, Vaadin & Co 12
S java springboot HTML Produktstruktur Frameworks - Spring, Play, Blade, Vaadin & Co 1
G Java springboot Item mit ItemInstance verbinden Frameworks - Spring, Play, Blade, Vaadin & Co 2
ExceptionOfExpectation @Value() für application.properties [SpringBoot] Frameworks - Spring, Play, Blade, Vaadin & Co 9
Zrebna SpringBoot-Project: java.sql.SQLSyntaxErrorException: Access denied for user 'gap3'@'%' to database '3306/gap3' Frameworks - Spring, Play, Blade, Vaadin & Co 3
D SpringBoot Properties und Docker Frameworks - Spring, Play, Blade, Vaadin & Co 8
Dimax SpringBoot native Querry return ArrayList Frameworks - Spring, Play, Blade, Vaadin & Co 6
OnDemand SpringBoot Logrotation funktioniert nicht Frameworks - Spring, Play, Blade, Vaadin & Co 6
Robertop Springboot Server kann Jakarta Persistence Root nicht installieren? Frameworks - Spring, Play, Blade, Vaadin & Co 0
G SpringBoot MVC Frameworks - Spring, Play, Blade, Vaadin & Co 1
tom.j85 SpringBoot Rest-Application funktioniert nicht - Keine Fehlermeldungen Frameworks - Spring, Play, Blade, Vaadin & Co 13
V SpringBoot/Thymeleaf ein Attribut zum Controller schicken Frameworks - Spring, Play, Blade, Vaadin & Co 10
L OpenJFX, SpringBoot und Gradle Frameworks - Spring, Play, Blade, Vaadin & Co 12
L SpringBoot Web Application Frameworks - Spring, Play, Blade, Vaadin & Co 1
S SpringBoot MySQL not run Frameworks - Spring, Play, Blade, Vaadin & Co 5
B Springboot und LDAP - Authentifizieren gegen Gruppe Frameworks - Spring, Play, Blade, Vaadin & Co 3
R Authentifizieren mit SpringBoot Frameworks - Spring, Play, Blade, Vaadin & Co 4
M Günstigste oder kostenlose Variante SpringBoot Application laufen zu lassen Frameworks - Spring, Play, Blade, Vaadin & Co 7
Z Springboot - Hauptklasse nicht gefunden Frameworks - Spring, Play, Blade, Vaadin & Co 5
A SpringCloud | SpringBoot | Eureka Frameworks - Spring, Play, Blade, Vaadin & Co 0

Ähnliche Java Themen

Neue Themen


Oben