Getting Started | Building an Application with Spring Boot
Build an application gyms with Spring boot and Angular use Jpa
Objective:
In this project we want to build an application shopping with spring boot and ionic. the project content Objects User, Shopping, Category, Product and Cart the Admin can add all information after login and the user can choose a product to add in his cart also he can save the product to his profile.
Used Skills in this project:
Java, SpringBoot, MicroServices, REST WebServices, JPA, Hibernate, OrikaBeanMapper, MySQL Database, Maven, Ionic, GitHub, SpringBoot Embedded Tomcat Server, STS-Eclipse IDE
Tools to be used
° Use any IDE to develop the Spring and Hibernate project. It may be STS/Eclipse/Netbeans. Here, we are using STS (Spring Tool Suite).
° Mysql for the database.
° Use any IDE to develop the Angular project. It may be Visual Studio Code/Sublime. Here, we are using Visual Studio Code.
° Server: Apache Tomcat/JBoss/Glassfish/Weblogic/Websphere.
Spring MVC
Spring MVC is the primary web framework built on the Servlet API. It is build on the popular MVC design pattern. MVC (Model-View-Controller) is a software architecture pattern, which separates application into three areas: model, view, and controller. The model represents a Java object carrying data. The view represents the visualization of the data that the model contains. The controller controls the data flow into model object and updates the view when the data changes. It separates the view and model.
Spring Boot Architecture
Spring Boot is a module of the Spring Framework. It is used to create stand-alone, production-grade Spring Based Applications with minimum efforts. It is developed on top of the core Spring Framework.
Introduction mysql to database
MySQL is a database management system that allows you to manage relational databases. It is open source software backed by Oracle. It means you can use MySQL without paying a dime. Also, if you want, you can change its source code to suit your needs. MySQL can run on various platforms UNIX, Linux, Windows, etc. You can install it on a server or even in a desktop. Besides, MySQL is reliable, scalable, and fast.
Introduction to the POM
POM A Project Object Model or POM is the fundamental unit of work in Maven. It is an XML file that contains information about the project and configuration details used by Maven to build the project. It contains default values for most projects. Examples for this is the build directory, which is target; the source directory, which is src/main/java; the test source directory, which is src/main/java; and so on. When executing a task or goal, Maven looks for the POM in the current directory. It reads the POM, gets the needed configuration information, then executes the goal.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0>/modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/>
</parent>
<groupId>com.shopping-app</groupId>
<artifactId>shopping-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>shopping-app</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Properties File
Properties files are used to keep ‘N’ number of properties in a single file to run the application in a different environment. In Spring Boot, properties are kept in the application.properties file under the classpath.
The application.properties file is located in the src/main/resources directory. The code for sample application.properties
We need to create database name it shopping-app
src/main/resources/application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/shopping-app?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.username=root
spring.activemq.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto=create-drop
server.port=8080
Class Diagram
Modals / Objects
We need to create five entities
- Cart
- Category
- Product
- Shopping
- User
Here, we are creating an Entity
Cart.java This object content id, name, count, price, total, added and relational @ManyToOne with User
src/main/java/com/shpping/model/Cart.java):
package com.shoppingapp.modal;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
public class Cart {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
private int count;
private double price;
private double total;
@Temporal(TemporalType.TIMESTAMP)
private Date added;
@ManyToOne
private User user;
public Cart() {
super();
}
public Cart(String name, int count, double price, double total, Date added, User user) {
super();
this.name = name;
this.count = count;
this.price = price;
this.total = total;
this.added = added;
this.user = user;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Date getAdded() {
return added;
}
public void setAdded(Date added) {
this.added = added;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Here, we are creating an Entity
Category.java This object content id, name, logo, expanded and relational @ManyToOne with Shopping and @OneToMany with Product We need to create a method addProductToCategory
src/main/java/com/shoppingapp/model/Category.java):
package com.shoppingapp.modal;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
@Entity
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
private String logo;
private boolean expanded;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "category")
private List<Product> products;
@ManyToOne
private Shopping shopping;
public Category() {
super();
}
public Category(String name, String logo, List<Product> products, Shopping shopping) {
super();
this.name = name;
this.logo = logo;
this.products = products;
this.shopping = shopping;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLogo() {
return logo;
}
public void setLogo(String logo) {
this.logo = logo;
}
public boolean isExpanded() {
return expanded;
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
public Shopping getShopping() {
return shopping;
}
public void setShopping(Shopping shopping) {
this.shopping = shopping;
}
public void addProductToCategory(Product product) {
if(getProducts() == null) {
this.products = new ArrayList<>();
}
getProducts().add(product);
product.setCategory(this);
}
}
Here, we are creating an Entity
Product.java This object content id, name, description, price, image, created and relational @ManyToOne with Category
src/main/java/com/shoppingapp/model/Product.java):
package com.shoppingapp.modal;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
private String description;
private double price;
private String image;
@Temporal(TemporalType.TIMESTAMP)
private Date created;
@ManyToOne
private Category category;
public Product() {
super();
}
public Product(String name, String description, double price, String image, Date created, Category category) {
super();
this.name = name;
this.description = description;
this.price = price;
this.image = image;
this.created = created;
this.category = category;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getImage() {
return image;
}
public voidsetImage(String image) {
this.image = image;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
}
Here, we are creating an Entity
Shopping.java This object content id, name, expanded and relational @ManyToOne with User and @OneToMany with Category We need to create a method addCategoryToShopping
src/main/java/com/shoppingapp/model/Shopping.java):
package com.shoppingapp.modal;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
@Entity
public class Shopping {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
private boolean expanded;
@ManyToOne
private User user;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "shopping")
private List<Category> categories;
public Shopping() {
super ();
}
public Shopping(String name, boolean expanded, User user, List<Category> categories) {
super();
this.name = name;
this.expanded = expanded;
this.user = user;
this.categories = categories;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isExpanded() {
return expanded;
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<Category> getCategories() {
return categories;
}
public void setCategories(List<Category> categories) {
this.categories = categories;
}
public void addCategoryToShopping(Category category) {
if(getCategories() == null) {
this.categories = new ArrayList<>();
}
getCategories().add(category);
category.setShopping(this);
}
}
Here, we are creating an Entity
User.java This object content id, username, password, admin and relational @OneToMany with Shopping and @OneToMany Cart We need to create two methods addCartToUser and addShoppingToUser
src/main/java/com/shoppingapp/model/User.java):
package com.shoppingapp.modal;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(unique = true)
private String username;
private String password;
private boolean admin;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private List<Shopping> shoppings;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private List<Cart> carts;
public User() {
super();
}
public User(String username, String password, boolean admin, List<Shopping> shoppings, List<Cart> carts) {
super();
this.username = username;
this.password = password;
this.admin = admin;
this.shoppings = shoppings;
this.carts = carts;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isAdmin() {
return admin;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
public List<Shopping> getShoppings() {
return shoppings;
}
public void setShoppings(List<Shopping> shoppings) {
this.shoppings = shoppings;
}
public List<Cart> getCarts() {
return carts;
}
public void setCarts(List<Cart> carts) {
this.carts = carts;
}
public void addCartToUser(Cart cart) {
if(getCarts() == null) {
this.carts = new ArrayList<>();
}
getCarts().add(cart);
cart.setUser(this);
}
public void addShoppingToUser(Shopping shopping) {
if (getShoppings()==null) {
this.shoppings = new ArrayList<>();
}
getShoppings().add(shopping);
shopping.setUser(this);
}
}
OrikaBeanMapper
Orika is a Java Bean mapping framework that recursively copies data from one object to another. It can be very useful when developing multi-layered applications. While moving data objects back and forth between these layers it is common to find that we need to convert objects from one instance into another to accommodate different APIs.
OrikaBeanMapper.java In this class Orika to convert entity => DTO / DTO => entity
src/main/java/com/gym/model/OrikaBeanMapper.java):
package com.shoppingapp.manager.service;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.ConfigurableMapper;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.impl.generator.JavassistCompilerStrategy;
import ma.glasnost.orika.metadata.ClassMapBuilder;
import ma.glasnost.orika.unenhance.HibernateUnenhanceStrategy;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component;
@Component
public class OrikaBeanMapper extends ConfigurableMapper {
private MapperFactory factory;
public OrikaBeanMapper() {
super(false);
init();
}
/**
* {@inheritDoc}
*/
@Override
protected void configure(MapperFactory factory) {
this.factory = factory;
}
private void registerClassMap(Class a, Class b) {
this.factory.classMap(a, b).mapNulls(true).mapNullsInReverse(true).byDefault().register();
}
/**
* Register class map with fields to exclude
*
* @param a
* @param b
* @param excludeFields
*/
private void registerClassMap(Class a, Class b, String... excludeFields) {
ClassMapBuilder builder = this.factory.classMap(a, b);
for (String excludeField : excludeFields) {
builder.exclude(excludeField);
}
builder.mapNulls(true).mapNullsInReverse(true).byDefault().register();
}
/**
* {@inheritDoc}
*/
@Override
protected void configureFactoryBuilder(final DefaultMapperFactory.Builder factoryBuilder) {
factoryBuilder.compilerStrategy(new JavassistCompilerStrategy());
factoryBuilder.unenhanceStrategy(new HibernateUnenhanceStrategy());
}
/**
* User Orika to convert entity => DTO / DTO => entity
*
* @param from
* @param toClass
* @param <T>
* @param <U> return
*/
public <T, U> T convertDTO(U from, Class<T> toClass) {
if (from == null) {
return null;
}
return map(from, toClass);
}
/**
* User Orika to convert entity => DTO / DTO => entity
*
* @param from
* @param toClass
* @param <T>
* @param <U>
* @return
*/
public <T, U> List<T> convertListDTO(Iterable<U> from, Class<T> toClass) {
if (from == null) {
return null;
}
return mapAsList(from, toClass);
}
public <T, U> Page<T> convertPageDTO(Page<U> from, Class<T> toClass) {
if (from == null) {
return null;
}
return from.map(entity -> factory.getMapperFacade().map(entity, toClass));
}
}
The DTO Classes
- CartDto- CategoryDto
- ProductDto
- ShoppingDto
- UserDto
What is a DTO?
DTO, which stands for Data Transfer Object, is a design pattern conceived to reduce the number of calls when working with remote interfaces. the main reason for using a Data Transfer Object is to batch up what would be multiple remote calls into a single one.
We'll handle the conversions that need to happen between the internal entities of a Spring application and the external DTOs (Data Transfer Objects) that are published back to the client.
Here, we are creating an Entity
CartDto.java This object content id, name, count, price, total
src/main/java/com/shpping/dto/CartDto.java):
package com.shoppingapp.dto;
import java.util.Date;
public class CartDto {
private long id;
private String name;
private int count;
private double price;
private double total;
private Date added;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Date getAdded() {
return added;
}
public void setAdded(Date added) {
this.added = added;
}
}
Here, we are creating an Entity
CategoryDto.java This object content id, name, logo, expanded and list of products form ProductDto
src/main/java/com/shoppingapp/dto/CategoryDto.java):
package com.shoppingapp.dto;
import java.util.List;
public class CategoryDto {
private long id;
private String name;
private String logo;
private boolean expanded;
private List<ProductDto> products;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLogo() {
return logo;
}
public void setLogo(String logo) {
this.logo = logo;
}
public boolean isExpanded() {
return expanded;
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
public List<ProductDto> getProducts() {
return products;
}
public void setProducts(List<ProductDto> products) {
this.products = products;
}
}
Here, we are creating an Entity
ProductDto.java This object content id, name, description, price, image and created
src/main/java/com/shoppingapp/dto/ProductDto.java):
package com.shoppingapp.dto;
import java.util.Date;
public class ProductDto {
private long id;
private String name;
private String description;
private double price;
private String image;
private Date created;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
}
Here, we are creating an Entity
ShoppingDto.java This object content id, name, expanded and relational and a list categories from CategoryDto
src/main/java/com/shoppingapp/dto/ShoppingDto.java):
package com.shoppingapp.modal;
import java.util.List;
public class ShoppingDto {
private long id;
private String name;
private boolean expanded;
private User user;
private List<Category> categories;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isExpanded() {
return expanded;
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
public List<CategoryDto> getCategories() {
return categories;
}
public void setCategories(List<CategoryDto> categories) {
this.categories = categories;
}
}
Here, we are creating an Entity
UserDto.java This object content id, username, password, admin and two lists from CartDo and ShoppingDto
src/main/java/com/shoppingapp/dto/UserDto.java):
package com.shoppingapp.dto;
import java.util.List;
public class User {
private long id;
private String username;
private String password;
private boolean admin;
private List<ShoppingDto> shoppings;
private List<CartDto> carts;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isAdmin() {
return admin;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
public List<ShoppingDto> getShoppings() {
return shoppings;
}
public void setShoppings(List<ShoppingDto> shoppings) {
this.shoppings = shoppings;
}
public List<CartDto> getCarts() {
return carts;
}
public void setCarts(List<CartDto> carts) {
this.carts = carts;
}
}
JPA Repositories
The JPA module of Spring Data contains a custom namespace that allows defining repository beans. It also contains certain features and element attributes that are special to JPA. Generally, the JPA repositories can be set up by using the repositories element, as shown in the following example:
Spring Repositories Spring has supported the concept of a repository for some time now. Repository is one of Spring's core stereotypes and you should plan on using them in your data access layer, regardless of your chosen data access layer API and framework.
Here, we are creating an interface CartDao
src/main/java/com/shoppingapp/dao/CartDao.java):
package com.shoppingapp.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.shoppingapp.modal.Cart;
public interface CartDao extends JpaRepository<Cart, Long> {
}
Here, we are creating an interface CategoryDao
src/main/java/com/shoppingapp/dao/CategoryDto.java):
package com.shoppingapp.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.shoppingapp.modal.Category;
public interface CategoryDao extends JpaRepository<Category, Long> {
}
Here, we are creating an interface ProductDao
src/main/java/com/shoppingapp/dao/ProductDao.java):
package com.shoppingapp.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.shoppingapp.modal.Product;
public interface ProductDao extends JpaRepository<Product, Long> {
}
Here, we are creating an interface ShoppingDao
src/main/java/com/shoppingapp/dao/ShoppingDao.java):
package com.shoppingapp.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.shoppingapp.modal.Shopping;
public interface ShoppingDao extends JpaRepository<Shopping, Long> {
}
Here, we are creating an interface UserDao
src/main/java/com/shoppingapp/dao/UserDao.java):
package com.shoppingapp.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.shoppingapp.modal.User;
public interface UserDao extends JpaRepository<User, Long> {
}
The services
Service Components are the class file which contains @Service annotation. These class files are used to write business logic in a different layer, separated from @RestController class file. The logic for creating a service component class file is shown here
We will create two interfaces in service package:
- ShoppingService.java- UserManService.java
What's the difference between @Component, @Repository and @Service
Can @Component, @Repository and @Service annotations be used interchangeably in Spring or do they provide any particular functionality besides acting as a notation device?
In other words, if I have a Service class and I change the annotation from @Service to @Component, will it still behave the same way?
Here, we are creating a service interface ShoppingService
ShoppingService.java This service interface content four methods
- addShoppingToUser
- addCategoryToShopping
- addCartToUser
- addProductToCategory
src/main/java/com/shoppingapp/service/ShoppingService.java):
package com.shoppingapp.service;
import org.springframework.stereotype.Service;
import com.shoppingapp.modal.Cart;
import com.shoppingapp.modal.Category;
import com.shoppingapp.modal.Product;
import com.shoppingapp.modal.Shopping;
import com.shoppingapp.modal.User;
@Service
public interface ShoppingService {
Shopping addShoppingToUser(Shopping shopping, User user);
Category addCategoryToShopping(Category category, Shopping shopping);
Cart addCartToUser(Cart cart, User user);
Product addProductToCategory(Product product, Category category);
}
Here, we are creating a service interface UserService
ShoppingService.java This service interface content two methods
- addUser
- editUser
UserService.java This interface content two methds addUser and editUser
src/main/java/com/shoppingapp/service/UserService.java):
package com.shoppingapp.service;
import org.springframework.stereotype.Service;
import com.shoppingapp.modal.User;
@Service
public interface UserService {
User addUser(User user);
User editUser(User user, User existsUser);
}
The Implements
Here we will use the implements for the Strategy pattern is a software design pattern commonly used for developing User interface that divides the related program logic into three interconnected elements.
The class that implements the Interface with @Component and @Transactional annotations is as shown −
- ShoppingServiceImpl.java
- UserManServiceImpl.java
Here, we are creating an implement class
ShoppingServiceImpl.java In this class we will implement ArbitrateService and @Override the methods addShoppingToUser, addCategoryToShopping, addCartToUser and addProductToCategory
src/main/java/com/shoppingapp/service/ShoppingServiceImpl.java):
package com.shoppingapp.service;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.shoppingapp.dao.CartDao;
import com.shoppingapp.dao.CategoryDao;
import com.shoppingapp.dao.ProductDao;
import com.shoppingapp.dao.ShpoppongDao;
import com.shoppingapp.modal.Cart;
import com.shoppingapp.modal.Category;
import com.shoppingapp.modal.Product;
import com.shoppingapp.modal.Shopping;
import com.shoppingapp.modal.User;
@Transactional
@Component
public class ShoppingServiceImpl implements ShoppingService {
@Autowired
private CartDao cartDao;
@Autowired
private CategoryDao categoryDao;
@Autowired
private ProductDao productDao;
@Autowired
private ShpoppongDao shoppingDao;
@Override
public Category addCategoryToShopping(Category category, Shopping shopping) {
if (shopping.getCategories().size()==0) {
category.setExpanded(true);
} else {
category.setExpanded(false);
}
shopping.addCategoryToShopping(category);
return categoryDao.save(category);
}
@Override
public Cart addCartToUser(Cart cart, User user) {
cart.setAdded(new Date());
user.addCartToUser(cart);
return cartDao.save(cart);
}
@Override
public Product addProductToCategory(Product product, Category category) {
product.setCreated(new Date());
category.addProductToCategory(product);
return productDao.save(product);
}
@Override
public Shopping addShoppingToUser(Shopping shopping, User user) {
if (user.getShoppings().size()==0) {
shopping.setExpanded(true);
} else {
shopping.setExpanded(false);
}
user.addShoppingToUser(shopping);
return shoppingDao.save(shopping);
}
}
Here, we are creating an implement class
UserServiceImpl.java In this class we will implement ArbitrateService and @Override the methods addUser and editUser
UserServiceImpl.java This object content id, name, and relational @ManyToOne with Sport and Gym
src/main/java/com/shoppingapp/service/UserServiceImpl.java):
package com.shoppingapp.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.shoppingapp.dao.UserDao;
import com.shoppingapp.modal.User;
@Transactional
@Component
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public User addUser(User user) {
if (user.getUsername().equals("admin") && user.getPassword().equals("admin") || user.getUsername().equals("drmas") && user.getPassword().equals("drmas")) {
user.setAdmin(true);
return userDao.save(user);
} else {
return userDao.save(user);
}
}
@Override
public User editUser(User user, User existsUser) {
existsUser.setUsername(user.getUsername());
existsUser.setPassword(user.getPassword());
existsUser.setAdmin(user.isAdmin());
return userDao.save(existsUser);
}
}
The manager services
It stands for Implementation. It's a Java convention. Often in java (particularly J2EE) you will get an object from some factory, and then use it. That object's type is often given to you as an interface, so that you don't need to know the actual class, just its methods.
We'll be developing the classes managers services. One possible reason for every service class to have an interface is that it makes interactions with sophisticated frameworks (Spring, JEE) much simpler. This is because Java can simply generate interceptor objects against interfaces.
We will create two interfaces in manager.service package:
- ShoppingManagerService- UserManagerService
Here, we are creating a service interface ShoppingManagerService
ShoppingManagerService.java This service interface content these methods
- addShoppingToUser
- addCategoryToShopping
- addCartToUser
- addProductToCategory
- findCategoriesToShopping
- findCategories
- findProductsToCategory
- findProducts
src/main/java/com/shoppingapp/manager/service/ShoppingManagerService.java):
package com.shoppingapp.manager.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.shoppingapp.dto.CartDto;
import com.shoppingapp.dto.CategoryDto;
import com.shoppingapp.dto.ProductDto;
import com.shoppingapp.dto.ShoppingDto;
@Service
public interface ShoppingManagerService {
CategoryDto addCategoryToShopping(CategoryDto categoryDto, long idUser);
CartDto addCartToUser(CartDto cartDto, long idUser);
ProductDto addProductToCategory(ProductDto productDto, long idCategory);
CategoryDto addShoppingToUser(ShoppingDto shoppingDto, long idUser);
List<CategoryDto> findCategoriesToShopping(long idShopping);
List<CategoryDto> findCategories();
List<ProductDto> findProductsToCategory(long idCategory);
List<ProductDto> findProducts();
}
Here, we are creating a service interface UserManagerService
UserManagerService.java This service interface content these methods
- addUser
- editUser
- deleteUser
- findCartsToUser
- findShoppingsToUser
- findUserById
- findUserByName
src/main/java/com/shoppingapp/model/UserManagerService.java):
package com.shoppingapp.manager.service;
import org.springframework.stereotype.Service;
import java.util.List;
import com.shoppingapp.dto.CartDto;
import com.shoppingapp.dto.ShoppingDto;
import com.shoppingapp.dto.UserDto;
@Service
public interface UserManagerService {
UserDto addUser(UserDto userDto);
UserDto editUser(UserDto userDto, long idUser);
void deleteUser(long idUser);
List<CartDto> findCartsToUser(long idUser);
List<ShoppingDto> findShoppingsToUser(long idUser);
UserDto findUserById(long idUser);
UserDto findUserByName(String username);
}
The managers classes implementation
An impl class is usually a class that implements the behaviour described by one of these interfaces. While the internal implementation class, With transactions configured, we can now annotation a bean with @Transactional and @Service either at the class or method level. Then conversion Entity to DTO. This is stands for Data Transfer Object and is a simple Plain Old Java Object which contains class properties and getters and settings methods for accessing those properties.
We will create seven interfaces in manager.service package:
Here, we are creating a class
ShoppingManagerServiceImpl.java In this class we will implement ShoppingManagerService and @Override the methods addUser, editUser, deleteUser, findCartsToUser, findShoppingsToUser, findUserById, findUserByName
src/main/java/com/shoppingapp/manager/service/ShoppingManagerServiceImpl.java):
package com.shoppingapp.manager.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.shoppingapp.dao.CategoryDao;
import com.shoppingapp.dao.ProductDao;
import com.shoppingapp.dao.ShpoppongDao;
import com.shoppingapp.dao.UserDao;
import com.shoppingapp.dto.CartDto;
import com.shoppingapp.dto.CategoryDto;
import com.shoppingapp.dto.ProductDto;
import com.shoppingapp.dto.ShoppingDto;
import com.shoppingapp.modal.Cart;
import com.shoppingapp.modal.Category;
import com.shoppingapp.modal.Product;
import com.shoppingapp.modal.Shopping;
import com.shoppingapp.modal.User;
import com.shoppingapp.service.ShoppingService;
@Service
@Transactional
public class ShoppingManagerServiceImpl implements ShoppingManagerService {
@Autowired
private OrikaBeanMapper orikaBeanMapper;
@Autowired
private ShoppingService shoppingService;
@Autowired
private UserDao userDao;
@Autowired
private CategoryDao categoryDao;
@Autowired
private ShpoppongDao shoppingDao;
@Autowired
private ProductDao productDao;
@Override
public CategoryDto addCategoryToShopping(CategoryDto categoryDto, long idShopping) {
Category category = orikaBeanMapper.map(categoryDto, Category.class);
Shopping shopping = shoppingDao.findById(idShopping).orElse(null);
return orikaBeanMapper.convertDTO(shoppingService.addCategoryToShopping(category, shopping), CategoryDto.class);
}
@Override
public CartDto addCartToUser(CartDto cartDto, long idUser) {
Cart cart = orikaBeanMapper.map(cartDto, Cart.class);
User user = userDao.findById(idUser).orElse(null);
return orikaBeanMapper.convertDTO(shoppingService.addCartToUser(cart, user), CartDto.class);
}
@Override
public ProductDto addProductToCategory(ProductDto productDto, long idCategory) {
Product product = orikaBeanMapper.map(productDto, Product.class);
Category category = categoryDao.findById(idCategory).orElse(null);
return orikaBeanMapper.convertDTO(shoppingService.addProductToCategory(product, category), ProductDto.class);
}
@Override
public CategoryDto addShoppingToUser(ShoppingDto shoppingDto, long idUser) {
Shopping shopping = orikaBeanMapper.map(shoppingDto, Shopping.class);
User user = userDao.findById(idUser).orElse(null);
return orikaBeanMapper.convertDTO(shoppingService.addShoppingToUser(shopping, user), CategoryDto.class);
}
@Override
public List<CategoryDto> findCategoriesToShopping(long idShopping) {
Shopping shopping = shoppingDao.findById(idShopping).orElse(null);
List<Category> categories = shopping.getCategories();
return orikaBeanMapper.convertListDTO(categories, CategoryDto.class);
}
@Override
public List<CategoryDto> findCategories() {
List<Category> shoppings = categoryDao.findAll();
return orikaBeanMapper.convertListDTO(shoppings, CategoryDto.class);
}
@Override
public List<ProductDto> findProductsToCategory(long idCategory) {
Category category = categoryDao.findById(idCategory).orElse(null);
List<Product> products = category.getProducts();
return orikaBeanMapper.convertListDTO(products, ProductDto.class);
}
@Override
public List<ProductDto> findProducts() {
List<Product> products = productDao.findAll();
return orikaBeanMapper.convertListDTO(products, ProductDto.class);
}
}
Here, we are creating an interface
UserManagerServiceImpl.java In this class we will implement UserManagerService and @Override the methods addUser, editUser, deleteUser, findCartsToUser, findShoppingsToUser, findUserById, findUserByName
src/main/java/com/shoppingapp/manager/service/UserManagerServiceImpl.java):
package com.shoppingapp.manager.service;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.shoppingapp.dao.UserDao;
import com.shoppingapp.dto.CartDto;
import com.shoppingapp.dto.ShoppingDto;
import com.shoppingapp.dto.UserDto;
import com.shoppingapp.modal.Cart;
import com.shoppingapp.modal.Shopping;
import com.shoppingapp.modal.User;
import com.shoppingapp.service.UserService;
@@Transactional
@Service
public class UserManagerServiceImpl implements UserManagerService {
@Autowired
private OrikaBeanMapper orikaBeanMapper;
@Autowired
private UserService userService;
@Autowired
private UserDao userDao;
@Override
public UserDto addUser(UserDto userDto) {
User user = orikaBeanMapper.map(userDto, User.class);
return orikaBeanMapper.convertDTO(userService.addUser(user), UserDto.class);
}
@Override
public UserDto editUser(UserDto userDto, long idUser) {
User user = orikaBeanMapper.map(userDto, User.class);
User existsUser = userDao.findById(idUser).orElse(null);
return orikaBeanMapper.convertDTO(userService.editUser(user, existsUser), UserDto.class);
}
@Override
public void deleteUser(long idUser) {
userDao.deleteById(idUser);
}
@Override
public List<CartDto> findCartsToUser(long idUser) {
User existsUser = userDao.findById(idUser).orElse(null);
List<Cart> carts = existsUser.getCarts();
return orikaBeanMapper.convertListDTO(carts, CartDto.class);
}
@Override
public UserDto findUserById(long idUser) {
return orikaBeanMapper.convertDTO(userDao.findById(idUser).orElse(null), UserDto.class);
}
@Override
public UserDto findUserByName(String username) {
Optional<User> user = userDao.findByUsername(username);
if (user.isPresent()) {
User user1 = user.get();
return orikaBeanMapper.convertDTO(user1, UserDto.class);
}
return null;
}
@Override
public List<ShoppingDto> findShoppingsToUser(long idUser) {
User existsUser = userDao.findById(idUser).orElse(null);
List<Shopping> shoppings = existsUser.getShoppings();
return orikaBeanMapper.convertListDTO(shoppings, ShoppingDto.class);
}
}
@RestController API
@RestController is a convenience annotation for creating Restful controllers. It is a specialization of @Component and is autodetected through classpath scanning. It adds the @Controller and @ResponseBody annotations. It converts the response to JSON or XML. It does not work with the view technology, so the methods cannot return ModelAndView. It is typically used in combination with annotated handler methods based on the @RequestMapping annotation.
We will create two classes in controller package:
- ShoppingController- UserController
Here, we are creating a controller class
ShoppingController.java We'll inject this bean into the ShoppingManagerService bean using @Autowired on the field definition: We need to add map requests with request mapping annotations e.g. @RequestMapping, @GetMapping, @PostMapping, @PutMapping, @DeleteMapping
src/main/java/com/shoppingapp/controller/ShoppingController.java):
package com.shoppingapp.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.shoppingapp.dto.CartDto;
import com.shoppingapp.dto.CategoryDto;
import com.shoppingapp.dto.ProductDto;
import com.shoppingapp.dto.ShoppingDto;
import com.shoppingapp.manager.service.ShoppingManagerService;
@RestController
@RequestMapping("api")
@CrossOrigin(origins = "*")
public class ShoppingController {
@Autowired
private ShoppingManagerService shoppingManagerService;
@PostMapping("/addShoppingToUser/{idUser}")
CategoryDto addShoppingToUser(@RequestBody ShoppingDto shoppingDto, @PathVariable long idUser) {
return shoppingManagerService.addShoppingToUser(shoppingDto, idUser);
}
@PostMapping("/addCategoryToShopping/{idShopping}")
CategoryDto addCategoryToShopping(@RequestBody CategoryDto categoryDto, @PathVariable long idShopping) {
return shoppingManagerService.addCategoryToShopping(categoryDto, idShopping);
}
@PostMapping("/addCartToUser/{idUser}")
CartDto addCartToUser(@RequestBody CartDto cartDto, @PathVariable long idUser) {
return shoppingManagerService.addCartToUser(cartDto, idUser);
}
@PostMapping("/addProductToCategory/{idCategory}")
ProductDto addProductToCategory(@RequestBody ProductDto productDto, @PathVariable long idCategory) {
return shoppingManagerService.addProductToCategory(productDto, idCategory);
}
@GetMapping("/findCategoriesToShopping/{idShopping}")
List<CategoryDto> findCategoriesToShopping(@PathVariable long idShopping) {
return shoppingManagerService.findCategoriesToShopping(idShopping);
}
@GetMapping("/findCategories")
List<CategoryDto> findCategories() {
return shoppingManagerService.findCategories();
}
@GetMapping("/findProductsToCategory/{idCategory}")
List<ProductDto> findProductsToCategory(@PathVariable long idCategory) {
return shoppingManagerService.findProductsToCategory(idCategory);
}
@GetMapping("/findProducts")
List<ProductDto> findProducts() {
return shoppingManagerService.findProducts();
}
}
Here, we are creating a controller class
UserController.java We'll inject this bean into the UserManagerService bean using @Autowired on the field definition: We need to add map requests with request mapping annotations e.g. @RequestMapping, @GetMapping, @PostMapping, @PutMapping, @DeleteMapping
src/main/java/com/shoppingapp/controller/UserController.java):
package com.shoppingapp.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.shoppingapp.dto.CartDto;
import com.shoppingapp.dto.ShoppingDto;
import com.shoppingapp.dto.UserDto;
import com.shoppingapp.manager.service.UserManagerService;
@RestController
@RequestMapping("api")
@CrossOrigin(origins = "*")
public class UserController {
@Autowired
private UserManagerService userManagerService;
@PostMapping("/addUser")
UserDto addUser(@RequestBody UserDto userDto) {
return userManagerService.addUser(userDto);
}
@PutMapping("/editUser/{idUSer}")
UserDto editUser(@RequestBody UserDto userDto, @PathVariable long idUser) {
return userManagerService.editUser(userDto, idUser);
}
@DeleteMapping("/deleteUser/{idUser}")
void deleteUser(@PathVariable long idUser) {
userManagerService.deleteUser(idUser);
}
@GetMapping("/findCartsToUser/{idUser}")
List<CartDto> findCartsToUser(@PathVariable long idUser) {
return userManagerService.findCartsToUser(idUser);
}
@GetMapping("/findUserById/{idUser}")
UserDto findUserById(@PathVariable long idUser) {
return userManagerService.findUserById(idUser);
}
@GetMapping("/findUserByUsername/{username}")
UserDto findUserByUsername(@PathVariable String username) {
return userManagerService.findUserByName(username);
}
@GetMapping("/findShoppingToUser/{idUser}")
List<ShoppingDto> findShoppingToUser(@PathVariable long idUser) {
return userManagerService.findShoppingsToUser(idUser);
}
}
ShoppingAppApplication
@SpringBootApplication and its use in a simple Spring Boot application. We use the @SpringBootApplication annotation in our Application or Main class to enable a host of features, e.g. Java-based Spring configuration, component scanning, and in particular for enabling Spring
src/main/java/com/shoppingapp/ShoppingAppApplication.java):
package com.shoppingapp;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@ComponentScan
@SpringBootApplication
public class ShoppingAppApplication {
public static void main(String[] args) {
SpringApplication.run(ShoppingAppApplication.class, args);
System.out.println("App started....");
}
}
Conclusion
Now we have an overview of Spring Boot CRUD example when building a CRUD App.
We also take a look at client-server architecture for REST API using Spring Web MVC & Spring Data JPA, as well, we are gooing to continue with Angular 10 project structure for building a front-end app to make HTTP requests and consume responses.