I am trying to create an application in Spring Boot. I am defining the methods updateBasket and removeItem but they seem to be having issues. When I ran the project, and in the form when I click let’s say “Update Quantity” it threw me a Whitelabel error, saying Bad request type, status 400. Tomcat server logs shows:
“Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter ‘itemId’ for method parameter type Long is present but converted to null]”
package com.example.test1.controller;
import com.example.test1.model.Beverage;
import com.example.test1.model.OrderItem;
import com.example.test1.model.Order;
import com.example.test1.service.BeverageService;
import com.example.test1.service.OrderItemService;
import com.example.test1.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import jakarta.servlet.http.HttpServletRequest;
// Import the HttpServletRequest
import java.text.DecimalFormat;
import jakarta.servlet.http.HttpSession;
import java.util.List;
import java.util.ArrayList;
@Controller
public class BasketController {
@Autowired
private BeverageService beverageService;
@Autowired
private OrderItemService orderItemService;
@Autowired
private OrderService orderService;
@GetMapping("/basket")
public String showBasket(HttpSession session, Model model) {
// Retrieve the basket from the session
List<OrderItem> basket = (List<OrderItem>) session.getAttribute("basket");
// If the basket is null (i.e., no items in the basket), initialize it
if (basket == null) {
basket = new ArrayList<>();
}
// Calculate the total price
double totalPrice = 0;
for (OrderItem item : basket) {
totalPrice += item.getPrice();
}
// Add the basket and the total price to the model so it can be accessed in the Thymeleaf template
model.addAttribute("items", basket);
model.addAttribute("totalPrice", totalPrice);
// Return the name of the Thymeleaf template to render
return "basket"; // This refers to the "basket.html" template
}
// Add beverage to basket
// BasketController.java
@PostMapping("/add-to-basket")
public String addToBasket(@RequestParam Long beverageId, HttpSession session) {
Beverage beverage = beverageService.getBeverageById(beverageId);
OrderItem orderItem = new OrderItem();
orderItem.setBeverage(beverage);
orderItem.setPrice(beverage.getPrice());
// Retrieve the current basket from the session or create a new one
List<OrderItem> basket = (List<OrderItem>) session.getAttribute("basket");
if (basket == null) {
basket = new ArrayList<>();
}
// Add the new OrderItem to the basket
basket.add(orderItem);
// Save the updated basket back into the session
session.setAttribute("basket", basket);
return "redirect:/basket"; // Redirect to the basket page to view the updated contents
}
@PostMapping("/submit-order")
public String submitOrder(HttpSession session, Model model) {
List<OrderItem> basket = (List<OrderItem>) session.getAttribute("basket");
if (basket != null && !basket.isEmpty()) {
// Create a new Order and set total price, etc.
Order order = new Order();
double totalPrice = 0;
for (OrderItem item : basket) {
totalPrice += item.getPrice(); // Calculate total price for the basket
}
order.setPrice(totalPrice); // Set the price of the order
// Save the order
orderService.saveOrder(order);
// Associate OrderItems with the Order
for (OrderItem item : basket) {
item.setOrder(order); // Link each item to the order
orderItemService.saveOrderItem(item); // Save the OrderItem
}
// Remove the basket from the session
session.removeAttribute("basket");
// Add order details to the model for the confirmation page
model.addAttribute("totalPrice", totalPrice); // Pass total price to the view
model.addAttribute("orderItems", basket); // Pass order items to the view
}
return "order-confirmation"; // Redirect to the order confirmation page
}
@PostMapping("/update-basket")
public String updateBasket(@RequestParam Long itemId, @RequestParam int quantity, HttpSession session, HttpServletRequest request) {
// Debugging: Print received itemId and quantity
System.out.println("Received itemId: " + itemId + ", quantity: " + quantity);
// Invalidate the current session and create a new one to avoid any session inconsistencies
session.invalidate(); // Clears the current session
session = request.getSession(true); // Creates a new session
// Retrieve the basket from session
List<OrderItem> basket = (List<OrderItem>) session.getAttribute("basket");
if (basket != null && !basket.isEmpty()) {
// Look for the OrderItem by id
for (OrderItem item : basket) {
System.out.println("Checking item with ID: " + item.getId());
if (item.getId() != null && item.getId().equals(itemId)) {
// Found the correct item, update its quantity and price
item.setQuantity(quantity);
item.setPrice(item.getBeverage().getPrice() * quantity);
// Debugging: print updated item details
System.out.println("Updated item: " + item.getId() + ", Quantity: " + item.getQuantity() + ", Price: " + item.getPrice());
break;
}
}
// Save the updated basket back into the session
session.setAttribute("basket", basket);
}
// Redirect back to the basket page to reflect the changes
return "redirect:/basket";
}
@PostMapping("/remove-item")
public String removeItem(@RequestParam Long itemId, HttpSession session) {
List<OrderItem> basket = (List<OrderItem>) session.getAttribute("basket");
if (basket != null) {
basket.removeIf(item -> item.getId().equals(itemId)); // Remove item by itemId
session.setAttribute("basket", basket); // Save updated basket in session
}
return "redirect:/basket"; // Redirect back to basket page
}
}
This is the BasketController.java file where I am defining the logic.
basket.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="UTF-8">
<title>Your Basket</title>
</head>
<body>
<h1>Your Basket</h1>
<!-- Empty Basket Check -->
<div th:if="${#lists.isEmpty(items)}">
<p>Your basket is empty. Add some beverages to your basket first.</p>
</div>
<!-- Display Items -->
<
<!-- Loop through each item in the basket -->
Basket.html Form
Ensure your form is correctly structured. Specifically, ensure that the input fields for itemId and quantity are correctly named and bound:
html
Copy code
<div th:each="item : ${items}">
<p th:text="'Beverage: ' + ${item.beverage.name}"></p>
<p th:text="'Price: €' + ${#numbers.formatDecimal(item.price, 2, 1)}"></p>
<p th:text="'Volume: ' + ${item.beverage.volume} + 'L'"></p>
<!-- Form to update quantity -->
<form action="/update-basket" method="post">
<input type="hidden" th:value="${item.id}" name="itemId" /> <!-- Ensure itemId is passed -->
<label for="quantity">Quantity</label>
<input type="number" id="quantity" name="quantity" th:value="${item.quantity}" min="1" />
<button type="submit">Update Quantity</button>
</form>
<!-- Form to remove item -->
<form action="/remove-item" method="post">
<input type="hidden" th:value="${item.id}" name="itemId" />
<button type="submit">Remove</button>
</form>
</div>
<!-- Display Total Price -->
<div>
<p th:text="'Total Price: €' + ${#numbers.formatDecimal(totalPrice, 2, 1)}"></p>
</div>
<!-- Submit Order Button -->
<form action="/submit-order" method="post">
<button type="submit">Place Order</button>
</form>
</body>
</html>
and the OrderItem.java model class:
package com.example.test1.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.JoinColumn;
@Entity
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String position;
private double price;
private int quantity = 1; // Default quantity
@ManyToOne
@JoinColumn(name = "beverage_id")
private Beverage beverage; // This is the reference to the Beverage entity
@ManyToOne
@JoinColumn(name = "order_id")
private Order order; // The order to which this item belongs
// Getters and Setters
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
public double getPrice() {
return price * quantity; // Return price based on quantity
}
public void setPrice(double price) {
this.price = price;
}
public Beverage getBeverage() {
return beverage;
}
public void setBeverage(Beverage beverage) {
this.beverage = beverage;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order; // Set the order for the order item
}
}
There are also some other model classes and controllers in my project but I think for understanding the problem these should be sufficient. Why the id is being returned as null?
Hamza Siddiqui is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
2