Wishlist Feature
Explore how to implement a wishlist feature in a full-stack e-commerce app backend using Java and Spring Boot. Learn to model wishlist entities, create repositories, services, and APIs with user authentication. Understand how to save and retrieve wishlist items for individual users, ensuring a personalized shopping experience.
We'll cover the following...
A wishlist is an e-commerce feature that allows shoppers to create personalized collections of products that they want to buy in the future and save in their user accounts.
Model
We’ll have one wishlist per user. So the Wishlist entity will have a one-to-one relationship with the user entity.
Each wishlist can have multiple products. So the Wishlist entity will have a many-to-one relationship with the product entity.
The Wishlist also have an auto-generated id field, as well as a created_date field. We can sort the items by the created_date field.
If we run the code and open the MySQL terminal, we’ll see that a wishlist table has been created.
Repository
Here, we’ll create a repository for the model.
The repository will have a method to find every product added to the wishlist, which will be sorted by date created.
Service
Here, we’ll create WishListService class in the service package. It will autowire WishListRepository.
It will have two simple methods to save a wishlist and read all the wishlist items for a user.
Controller
As we have our service, model, and repository ready, we’ll start building the APIs.
Create a class, WishListController, in the controllers package, which will autowire wishListService and AuthenticationService. We’ll use these to retrieve the user.
1
Add to wishlist API
We will have a request body, product, as well as a RequestParam token, which is the authentication token we generated and returned to the user during sign-in.
First, we’ll verify if the token is valid. Then, we’ll retrieve the user and save the item to the wishlist.
Test
Next, we’ll test if the saving feature of the wishlist API is working.
We’ll sign in and retrieve authenticationToken.
We’ll use this token to hit the /wishlist/add API with productDTO.
We’ll get a successful response with the following message: Added to Wishlist.
We can also verify in the database that we have added the product to the wishlist.
Get the wishlist API
Now, that we can save products in the Wishlist, it’s time to retrieve the Wishlist for the user.
Let’s hit the API in swagger and test it.
The final code
/*
* Copyright 2007-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}