Suggest a customer's recently used addresses
Java · Spring Boot · beginner · modification
Adds an `AddressController` exposing `/recent` under `/api/customers/me/addresses`, so the checkout page can offer the address a customer used last. `AddressService.recentlyUsed` asks the repository for the customer's addresses, sorted by `lastUsedAt` and capped at the five most recent with a `PageRequest`, and maps them to `AddressView`. The repository gains a derived `findByCustomerId(Long, Pageable)` finder; paging and ordering are pushed down to the database rather than done in memory.
Shop backend on Spring Boot 3.3 (Java 21), Spring Data JPA (Hibernate 6) on PostgreSQL, Spring Security. Every `/api/**` request needs a signed-in session; at login the principal is a `ShopUser(Long customerId, String email)` record that `@AuthenticationPrincipal` resolves, and `customerId` is never null. Existing and unchanged: the `Address` entity (`id`, `customerId`, `line1`, `lastUsedAt`, a non-null `Instant`) and the `AddressView` record with `AddressView.from(address)`. `AddressRepository extends JpaRepository<Address, Long>`; a `List`-returning derived finder with a `Pageable` applies that page's sort and limit in the query and issues no count query. A customer has at most a few dozen addresses.
Requirements
- `GET /api/customers/me/addresses/recent` returns the signed-in customer's saved addresses ordered by `lastUsedAt`, most recently used first, so the checkout page can preselect the address they are most likely to want. Each element is an `AddressView` (id, line1, lastUsedAt); the response is a JSON array.
- Return at most the 5 most recently used of the customer's addresses. A customer with 5 or fewer gets all of them (still most-recent-first); a customer with none gets an empty array. Addresses that tie on `lastUsedAt` may come back in any order relative to each other.
- Only the signed-in customer's own addresses appear; another customer's addresses are never included. `lastUsedAt` is a non-null instant on every address (it is set when the address is created and updated on each use).
Files touched
- src/main/java/com/acme/shop/addresses/AddressRepository.java
- src/main/java/com/acme/shop/addresses/AddressController.java
- src/main/java/com/acme/shop/addresses/AddressService.java
--- src/main/java/com/acme/shop/addresses/AddressRepository.java
package com.acme.shop.addresses;
+import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
+import java.util.List;
public interface AddressRepository extends JpaRepository<Address, Long> {
+
+ List<Address> findByCustomerId(Long customerId, Pageable pageable);
}
--- src/main/java/com/acme/shop/addresses/AddressController.java
+package com.acme.shop.addresses;
+
+import com.acme.shop.security.ShopUser;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/customers/me/addresses")
+public class AddressController {
+
+ private final AddressService addressService;
+
+ AddressController(AddressService addressService) {
+ this.addressService = addressService;