Search code examples
javahtmlspringformsthymeleaf

Path variable read as a String rather than as a number Spring error


http://localhost:8080/basket/delete/%7BbasketId%7D?basketId=7&bookTitle=Ritle2&author=Rauther2&publisher=Publisher&quantity=1&price=5.0

The above URL is what is searched for upon clicking on a 'Delete item from basket' button in my Spring app. The controller is supposed to take in this Basket Id (in this case = 7) and delete it from the basket. However I am getting the below error as it seems to be reading in "{basketId}" rather than the Id itself:

[org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; nested exception is java.lang.NumberFormatException: For input string: "{basketId}"]

Why is this happening and how do I ensure it takes in the value of the basketId instead?

HTML:

 <tr th:each="basketItem : ${basket}">
        <form action="/basket/delete/{basketId}" method="delete">
        <td> <input name="basketId"  th:value="${basketItem.basketId}"  readonly> </td>
        <td> <input name="bookTitle" th:value="${basketItem.bookTitle}"  readonly> </td>
        <td> <input name="author"    th:value="${basketItem.author}"   readonly> </td>
        <td> <input name="publisher" th:value="${basketItem.publisher}"readonly> </td>
        <td> <input name="quantity"  th:value="${basketItem.quantity}"   readonly> </td>
        <td> <input name="price"     th:value="${basketItem.price}"     readonly> </td>
            <td>  <button > Delete from basket</button></td>
        </form>
    </tr>

Basket Controller:

@DeleteMapping("/basket/delete/{basketId}")
 String deleteBook(@PathVariable  Long basketId, Model model) {
    System.out.println("Delte mapping : " + basketId);
    if (basketRepository.existsById(basketId)){
        basketRepository.deleteById(basketId);
    }
    else {
        System.out.println("Item does not exist!");
    };
    //basketRepository.save(basket);
    model.addAttribute("basket", basketRepository.findAll());
    return "basket/list";
}

@GetMapping("/basket/delete/{basketId}")
public String deleteItem(@PathVariable Long basketId,Model model) {
    System.out.println("Get mapping : " + basketId);
    Basket basketItem = basketRepository.findById(basketId)
            .orElseThrow();
    basketRepository.delete(basketItem);

    model.addAttribute("basket", basketRepository.findAll());

    return "basket/list";
}

Basket:

package springLibrary.domain;

import javax.persistence.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

@Entity
public class Basket {

 
    private @Id
    @GeneratedValue
    Long basketId;
    private String bookTitle;
    private String author;
    private String publisher;
    private int quantity;
    private double price;


    public Basket() {
    }

    public Basket(String bookTitle, String author, String publisher, int quantity, double price) {

        this.bookTitle = bookTitle;
        this.author = author;
        this.publisher = publisher;
        this.quantity = quantity;
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Basket basket = (Basket) o;
        return Objects.equals(bookTitle, basket.bookTitle);
    }

    @Override
    public int hashCode() {
        return Objects.hash(bookTitle);
    }

    @Override
    public String toString() {
        return "Basket{" +
                "basketId=" + basketId +
                ", bookTitle='" + bookTitle + '\'' +
                ", author='" + author + '\'' +
                ", publisher='" + publisher + '\'' +
                ", quantity=" + quantity +
                ", price=" + price +
                '}';
    }

    public Long getBasketId() {
        return basketId;
    }

    public void setBasketId(Long basketId) {
        this.basketId = basketId;
    }

    public String getBookTitle() {
        return bookTitle;
    }

    public void setBookTitle(String bookTitle) {
        this.bookTitle = bookTitle;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getPublisher() {
        return publisher;
    }

    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

Solution

  • Thank you to @M. Deinum for this - the reason it was being read as a String was due to the formatting of the action itself.

    In Thymeleaf, it should be structured as so:

    <form th:action="@{/basket/delete/{basketId}(basketId=${basketItem.basketId})}" method="delete">