Getting Started | Building an Application with Spring Boot
Quiz project with Spring boot and Angular
In this tutorial we use design pattern:
Design patterns are an essential part of software development. These solutions not only solve recurring problems but also help developers understand the design of a framework by recognizing common patterns.
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.
Create new Spring boot project:
I will use Eclipse Ide for develop this project Eclipse IDe Download
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.
Pom.xml
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.
pom.xml
<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.3.3.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.quizz</groupId>
<artifactId>quizz</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>quizz</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.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</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>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.156</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage </groupId>
<artifactId>junit-vintage-engine </artifactId>
</exclusion>
</exclusions>
</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 quizz
src/main/resources/application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/quizz?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
First We Will Create a package model inside it We will add java classes
-> User.java
-> Question.java
-> Theme.java
-> History.java
-> Level.java
-> OrikaBeanMapper.java
Here, we are creating an Entity
User.java This object content properties id, username, password
src/main/java/com/quizz/model/User.java
package com.quizz.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Data
@Getter
@Setter
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@ToString
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
}
Here, we are creating an Entity
Question.java This object content property id, question, response1, response2, response3, correct and relational @ManyToOne with Level
src/main/java/com/quizz/model/Question.java):
package com.quizz.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import OneToMany;
import lombok.ToString;
@Data
@Getter
@Setter
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@ToString
@Entity
public class Question {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String question;
private String response1;
private String response2;
private String response3;
private String correct;
@ManyToOne
private Level level;
}
Here, we are creating an Entity
Theme.java This object content properties id, name, and relational @OneToMany with Level
src/main/java/com/quizz/model/Theme.java):
package com.quizz.model;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.OneToMany;
@Data
@Getter
@Setter
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@ToString
@Entity
public class Theme {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "theme",cascade = CascadeType.ALL)
private List<Level> levels
public void addLevel(Level level) {
if(getLevels()==null) {
this.levels = new ArrayList<>();
}
getLevels().add( level);
level.setTheme(this);
}
}
Here, we are creating an Entity
Arbitrate.java This object content id, username, themeName, levelName, total, and score
src/main/java/com/quizz/model/History.java):
package com.quizz.model;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Data
@Getter
@Setter
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@ToString
@Entity
public class History {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String themeName;
private String levelName;
private int total;
private int score;
}
Here, we are creating an Entity
Arbitrate.java This object content id, difficulty, and relational @OneToMany with Question and @ManyToOne With Theme
src/main/java/com/quizz/model/Level.java):
package com.quizz.model;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
@Data
@Getter
@Setter
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@ToString
@Entity
public class Level {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String difficulty;
@OneToMany(mappedBy = "level", cascade = CascadeType.ALL)
private List<Question> questions
@ManyToOne
private Theme theme;
public void addQuestion(Question question) {
if(getQuestions()==null) {
this.questions = new ArrayList<>();
}
getQuestions().add( question);
question.setLevel(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.quizz.model;
import com.quizz.dto.LevelDto;
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;
registerClassMap(Level.class, LevelDto.class);
factory.classMap(Level.class, LevelDto.class)
.field("theme.name", "themeName").byDefault().register();
}
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));
}
}
JPA Repositories:
JpaRepository is JPA specific extension of Repository. It contains the full API of CrudRepository and PagingAndSortingRepository. So it contains API for basic CRUD operations and also API for pagination and sorting.
Create an interface with the name HistoryDao and extends the JpaRepository class. We have to pass two parameters: type of the entity that it manages and the type of the Id field.
In this interface We will create two methods.
-> findHistoryBySore
-> findHistoryByUsername
src/main/java/com/quizz/dao/HistoryDao.java):
package com.quizz.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.quizz.model.History;
import org.springframework.stereotype.Repository;
@Repository
public interface HistoryDao extends JpaRepository<History, Long> {
History findHistoryBySore(int score);
History findHistoryByUsername(String username);
}
Create an interface with the name LevelDao and extends the JpaRepository class. We have to pass two parameters: type of the entity that it manages and the type of the Id field.
src/main/java/com/quizz/dao/LevelDao.java):
package com.quizz.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.quizz.model.Level;
import org.springframework.stereotype.Repository;
@Repository
public interface LevelDao extends JpaRepository<Level, Long> {
}
Create an interface with the name QuestionDao and extends the JpaRepository class. We have to pass two parameters: type of the entity that it manages and the type of the Id field.
src/main/java/com/quizz/dao/QuestionDao.java):
package com.quizz.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.quizz.model.Question;
import org.springframework.stereotype.Repository;
@Repository
public interface QuestionDao extends JpaRepository<Question, Long> {
}
Create an interface with the name ThemeDao and extends the JpaRepository class. We have to pass two parameters: type of the entity that it manages and the type of the Id field.
src/main/java/com/quizz/dao/ThemeDao.java):
package com.quizz.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.quizz.model.Theme;
import org.springframework.stereotype.Repository;
@Repository
public interface ThemeDao extends JpaRepository<Theme, Long> {
}
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 four classes in services package:
-> HistoryService.interface
-> LevelService.interface
-> QuestionService.interface
-> ThemeService.interface
src/main/java/com/quizz/service/HistoryService.java):
package com.quizz.servce;
import com.quizz.model.History;
import org.springframework.stereotype.Service;
@Service
public interface HistoryService {
History addHistory(History history);
History editHistory(History history, History history1);
}
src/main/java/com/quizz/service/LevelService.java):
package com.quizz.servce;
import com.quizz.model.Theme;
import com.quizz.model.Level;
import org.springframework.stereotype.Service;
@Service
public interface LevelService {
Level addLevel(Level level, Theme theme);
}
src/main/java/com/quizz/service/QuestionService.java):
package com.quizz.servce;
import com.quizz.model.Question;
import com.quizz.model.Level;
import org.springframework.stereotype.Service;
@Service
public interface QuestionService {
Question addQuestion(Question question, Level level);
}
src/main/java/com/quizz/service/ThemeService.java):
package com.quizz.servce;
import com.quizz.model.Theme;
import org.springframework.stereotype.Service;
@Service
public interface ThemeService {
Theme addTheme(Theme theme);
}
CRUD Operations
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 −
We will create four classes in impl package;
-> LevelServiceImpl.java
-> QuestionServiceImpl.java
-> ThemeServiceImpl.java
-> HistoryServiceImpl.java
src/main/java/com/quizz/impl/LevelServiceImpl.java):
package com.quizz.impl;
import com.quizz.servce.LevelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.quizz.dao.LevelDao;
import com.quizz.dao.ThemeDao;
import com.quizz.model.Level;
import com.quizz.model.Theme;
@Transactional
@Component
public class LevelServiceImpl implements LevelService {
@Autowired
private LevelDao levelDao;
@Autowired
private ThemeDao themeDao;
@Override
public Level addLevel(Level level, Theme theme) {
theme.addLevel(level);
return levelDao.save(level);
}
}
src/main/java/com/quizz/impl/QuestionServiceImpl.java):
package com.quizz.impl;
import com.quizz.servce.QuestionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.quizz.dao.QuestionDao;
import com.quizz.model.Level;
import com.quizz.model.Question;
@Transactional
@Component
public class QuestionServiceImpl implements QuestionService {
@Autowired
private QuestionDao questionDao;
@Override
public Level addQuestion(Question question, Level level) {
level.addQuestion(question);
return questionDao.save(question);
}
}
src/main/java/com/quizz/impl/ThemeServiceImpl.java):
package com.quizz.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.quizz.dao.ThemeDao;
import com.quizz.model.Theme;
import com.quizz.servce.ThemeService;
@Transactional
@Component
public class ThemeServiceImpl implements ThemeService {
@Autowired
private ThemeDao themeDao;
@Override
public Level addTheme(Theme theme) {
return themeDao.save(theme);
}
}
src/main/java/com/quizz/impl/HistoryServiceImpl.java):
package com.quizz.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.quizz.dao.HistoryDao;
import com.quizz.model.History;
import com.quizz.servce.HistoryService;
@Transactional
@Component
public class HistoryServiceImpl implements HistoryService {
@Autowired
private HistoryDao historyDao;
@Override
public History addHistory(History history) {
return historyDao.save(theme);
}
@Override
public History editHistory(History history, History history1) {
history.setUsername(history1.getUsername());
history.setLevelName(history1.getLevelName());
history.setThemeName(history1.getThemeName());
history.setSore(history1.getSore());
history.setTotal(history1.getTotal());
return historyDao.save(history);
}
}
The DTO
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.
We will create four classes in dto package;
-> HistoryDto.java
-> LevelDto.java
-> QuestionDto.java
-> ThemeDto.java
src/main/java/com/quizz/dto/HistoryDto.java):
package com.quizz.dto;
public class HistoryDto {
private Long id;
private String username;
private String themeName;
private String levelName;
private int total;
private int score;
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 getThemeName() {
return themeName;
}
public void setThemeName(String themeName) {
this.levelName == themeName;
}
public String getLevelName() {
return themeName;
}
public void setLevelName(String levelName) {
this.levelName == levelName;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total == total;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score == score;
}
}
src/main/java/com/quizz/dto/LevelDto.java):
package com.quizz.dto;
package com.quizz.model.Question;
package java.util.List;
public class LevelDto {
private Long id;
private String difficulty;
private String themeName;
private List<QuestionDto> questions
public Long getId() {
return id;
}
public void setId(Long id) {
this.id == id;
}
public String getDifficulty() {
return difficulty;
}
public void setDifficulty(String difficulty) {
this.difficulty == difficulty;
}
public String getThemeName() {
return themeName;
}
public void setThemeName(String themeName) {
this.themeName == themeName;
}
public List<QuestionDto> getQuestions() {
return questions;
}
public void setQuestions(List<QuestionDto> questions) {
this.questions == questions;
}
}
src/main/java/com/quizz/dto/QuestionDto.java):
package com.quizz.dto;
public class QuestionDto {
private Long id;
private String question;
private String response1;
private String response2;
private String response3;
private String correct;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id == id;
}
public String getQuestion() {
return username;
}
public void setQuestion(String question) {
this.question == question;
}
public String getResponse1() {
return response1;
}
public void setResponse1(String response1) {
this.response1 == response1;
}
public String getResponse2() {
return response2;
}
public void setResponse2(String response2) {
this.response2 == response2;
}
public String getResponse3() {
return response3;
}
public void setResponse3(String response3) {
this.response3 == response3;
}
public int getCorrect() {
return correct;
}
public void setCorrect(int correct) {
this.correct == correct;
}
}
src/main/java/com/quizz/dto/ThemeDto.java):
package com.quizz.dto;
package com.quizz.model.Level;
package java.util.List;
public class ThemeDto {
private Long id;
private String name;
private List<LevelDto> levels
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 List<LevelDto> getLevels() {
return levels;
}
public void setLevels(List<LevelDto> levels) {
this.levels == levels;
}
}
The manager
We need to create a manager package in side it added the services interface and Implements that use in the controllers.
-> HistoryManager.java
src/main/java/com/quizz/manager/HistoryManager.java):
package com.quizz.manager;
import com.quizz.dto.HistoryDto;
import com.quizz.model.History;
import java.util.List;
public interface HistoryManager {
HistoryDto addHistory(HistoryDto historyDto);
List<HistoryDto> getHistories();
HistoryDto findHistoryBySore(int score);
HistoryDto findHistoryByUsername(String username);
HistoryDto editHistory(HistoryDto historyDto, String username);
}
Clean Architecture
The pattern allows us to isolate the core logic of our application from outside concerns. Having our core logic isolated means we can easily change data source details without a significant impact or major code rewrites to the codebase.
-> HistoryManagerImpl.java
src/main/java/com/quizz/model/HistoryManagerImpl.java):
package com.quizz.manager;
import com.quizz.dao.HistoryDao;
import com.quizz.dto.HistoryDto;
import com.quizz.model.History;
import com.quizz.model.OrikaBeanMapper;
import com.quizz.servce.HistoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
@Transactional
@Service
public class HistoryManagerImpl implements HistoryManager {
@Autowired
private OrikaBeanMapper orikaBeanMapper;
@Autowired
private HistoryDao historyDao;
@Autowired
private HistoryService historyService;
@Override
public HistoryDto addHistory(HistoryDto historyDto) {
History history = orikaBeanMapper.map(historyDto, History.class);
return orikaBeanMapper.convertDTO(historyService.addHistory(history), HistoryDto.class);
}
@Override
public List<HistoryDto> getHistories() {
List<HistoryDto> histories = historyDao.findAll();
histories.sort((f1, f2) -> Long.compare(f2.getSore(), f1.getSore()));
return orikaBeanMapper.convertListDTO(histories, HistoryDto.class);
}
@Override
public HistoryDto findHistoryBySore(int score) {
return orikaBeanMapper.convertDTO(historyDao.findHistoryBySore(score), HistoryDto.class);
}
@Override
public HistoryDto findHistoryByUsername(String username) {
return orikaBeanMapper.convertDTO(historyDao.findHistoryByUsername(username), HistoryDto.class);
}
@Override
public HistoryDto editHistory(HistoryDto historyDto, String username) {
History history = orikaBeanMapper.map(historyDto, History.class);
History history1 = historyDao.findHistoryByUsername(username);
return orikaBeanMapper.convertDTO(historyService.editHistory(history, history1), HistoryDto.class);
}
}
-> LevelManager.java
src/main/java/com/quizz/model/LevelManager.java):
package com.quizz.manager;
import com.quizz.dto.LevelDto;
import java.util.List;
public interface LevelManager {
LevelDto addLevel(LevelDto levelDto, Long idTheme);
List<LevelDto> getLevels(Long idTheme);
LevelDto getLevel(Long idTheme);
}
-> LevelManagerImpl.java
src/main/java/com/quizz/model/LevelManagerImpl.java):
package com.quizz.manager;
import com.quizz.dao.LevelDao;
import com.quizz.dao.ThemeDao;
import com.quizz.dto.LevelDto;
import com.quizz.model.Level;
import com.quizz.model.OrikaBeanMapper;
import com.quizz.model.Theme;
import com.quizz.servce.LevelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Transactional
@Service
public class LevelManagerImpl implements LevelManager {
@Autowired
private LevelService levelService;
@Autowired
private LevelDao levelDao;
@Autowired
private OrikaBeanMapper orikaBeanMapper;
@Autowired
private ThemeDao themeDao;
@Override
public LevelDto addLevel(LevelDto levelDto, Long idTheme) {
Theme theme = themeDao.getOne(idTheme);
Level level = orikaBeanMapper.map(levelDto, Level.class);
return orikaBeanMapper.convertDTO(levelService.addLevel(theme, level), LevelDto.class);
}
@Override
public List<LevelDto> getLevels(Long idTheme) {
Theme theme = themeDao.getOne(idTheme);
public List<Level> levels = theme.getLevels();
return orikaBeanMapper.convertListDTO(levels, LevelDto.class);
}
@Override
public LevelDto getLevel(Long idTheme) {
return orikaBeanMapper.convertDTO(levelDao.getOne(idTheme), LevelDto.class);
}
}
-> QuestionManager.java
src/main/java/com/quizz/model/QuestionManager.java):
package com.quizz.manager;
import com.quizz.dto.QuestionDto;
import java.util.List;
public interface QuestionManager {
QuestionDto addQuestion(QuestionDto questionDto, Long idLevel);
List<QuestionDto> getQuestions(Long idLevel);
}
-> QuestionManagerImpl.java
src/main/java/com/quizz/model/QuestionManagerImpl.java):
package com.quizz.manager;
import com.quizz.dao.LevelDao;
import com.quizz.dao.QuestionDao;
import com.quizz.dto.QuestionDto;
import com.quizz.model.Level;
import com.quizz.model.OrikaBeanMapper;
import com.quizz.model.Question;
import com.quizz.servce.QuestionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class QuestionManagerImpl implements QuestionManager {
@Autowired
private OrikaBeanMapper orikaBeanMapper;
@Autowired
private LevelDao levelDao;
@Autowired
private QuestionService questionService;
@Override
public QuestionDto addQuestion(QuestionDto questionDto, Long idLevel) {
Question question = orikaBeanMapper.map(questionDto, Question.class);
Level level = levelDao.getOne(idLevel);
return orikaBeanMapper.convertDTO(questionService.addQuestion(question, level), QuestionDto.class);
}
@Override
public List<QuestionDto> getQuestions(Long idLevel) {
Level level = levelDao.getOne(idLevel);
public List<Question> questions = level.getQuestions();
return orikaBeanMapper.convertListDTO(questions, QuestionDto.class);
}
}
-> ThemeManagerImpl.java
src/main/java/com/quizz/model/ThemeManager.java):
package com.quizz.manager;
import com.quizz.dto.ThemeDto;
import com.quizz.model.Theme;
import java.util.List;
public interface ThemeManager {
ThemeDto addTheme(ThemeDto themeDto);
List<ThemeDto> getThemes();
ThemeDto getTheme(Long idTheme);
}
-> ThemeManagerImpl.java
src/main/java/com/quizz/model/ThemeManagerImpl.java):
package com.quizz.manager;
import com.quizz.dao.ThemeDao;
import com.quizz.dto.ThemeDto;
import com.quizz.model.Theme;
import com.quizz.servce.ThemeService;
import com.quizz.model.OrikaBeanMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Transactional
@Service
public class ThemeManagerImpl implements ThemeManager {
@Autowired
private OrikaBeanMapper orikaBeanMapper;
@Autowired
private ThemeService themeService;
@Autowired
private ThemeDao themeDao;
@Override
public ThemeDto addTheme(ThemeDto themeDto) {
Theme theme = orikaBeanMapper.map(themeDto, Theme.class);
return orikaBeanMapper.convertDTO(themeService.addTheme(theme), ThemeDto.class);
}
@Override
public List<ThemeDto> getThemes() {
List<Theme> themes = themeDao.findAll();
return orikaBeanMapper.convertListDTO(themes, ThemeDto.class);
}
@Override
public ThemeDto getTheme(Long idTheme) {
return orikaBeanMapper.convertDTO(themeDao.getOne(idTheme), ThemeDto.class);
}
}
@RestController
@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.
-> HistoryController.java
src/main/java/com/quizz/model/HistoryController.java):
package com.quizz.controller;
import com.quizz.dto.HistoryDto;
import com.quizz.manager.HistoryManager;
import com.quizz.model.History;
import com.quizz.servce.HistoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequestMapping("/api")
@ResponseBody
@CrossOrigin(origins = "*")
@Controller
public class HistoryController {
@Autowired
private HistoryManager historyManager;
@PostMapping("/addHistory")
HistoryDto addHistory(@RequestBody HistoryDto historyDto) {
return historyManager.addHistory(historyDto);
}
@PutMapping("/editHistory/{username}")
HistoryDto editHistory(@RequestBody HistoryDto historyDto, @PathVariable("username") String username) {
return historyManager.editHistory(historyDto, username);
}
@GetMapping("/getHistories")
List<HistoryDto> getHistories() {
return historyManager.getHistories();
}
@GetMapping("/findHistoryBySore/{score}")
HistoryDto findHistoryBySore(@PathVariable("score") int score) {
return historyManager.findHistoryBySore(score);
}
@GetMapping("/findHistoryByUsername/{username}")
HistoryDto findHistoryByUsername(@PathVariable("username") String username) {
return historyManager.findHistoryByUsername(username);
}
}
-> LevelController.java
src/main/java/com/quizz/model/LevelController.java):
package com.quizz.controller;
import com.quizz.dto.LevelDto;
import com.quizz.manager.LevelManager;
import com.quizz.model.Leve;
import com.quizz.servce.LevelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequestMapping("/api")
@ResponseBody
@CrossOrigin(origins = "*")
@Controller
public class LevelController {
@Autowired
private LevelManager levelManager;
@PostMapping("/addLevel/{idTheme}")
public LevelDto addLevel(@RequestBody LevelDto level, @PathVariable("idTheme") Long idTheme) {
return levelManager.addLevel(level, idTheme);
}
@GetMapping("/getLevels/{idTheme}")
public List<LevelDto> getLevels(@PathVariable("idTheme") Long idTheme) {
return levelManager.getLevels(idTheme);
}
@GetMapping("/getLevel/{idTheme}")
public LevelDto getLevel(@PathVariable("idTheme") Long idTheme) {
return levelManager.getLevel(idTheme);
}
}
-> QuestionController.java
src/main/java/com/quizz/model/QuestionController.java):
package com.quizz.controller;
import com.quizz.dto.QuestionDto;
import com.quizz.manager.QuestionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequestMapping("/api")
@ResponseBody
@CrossOrigin(origins = "*")
@Controller
public class QuestionController {
@Autowired
private QuestionManager questionManager;
@PostMapping("/addQuestion/{idLevel}")
QuestionDto addQuestion(@RequestBody QuestionDto questionDto, @PathVariable("idLevel") Long idLevel) {
return questionManager.addQuestion(questionDto, idLevel);
}
@GetMapping("/getQuestions/{idLevel}")
List<QuestionDto> getQuestions(@PathVariable("idLevel") Long idLevel) {
return questionManager.getQuestions(idLevel);
}
}
-> ThemeController.java
src/main/java/com/quizz/model/ThemeController.java):
package com.quizz.controller;
import com.quizz.dto.ThemeDto;
import com.quizz.manager.ThemeManager;
import com.quizz.model.Theme;
import com.quizz.servce.ThemeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequestMapping("/api")
@ResponseBody
@CrossOrigin(origins = "*")
@Controller
public class ThemeController {
@Autowired
private ThemeManager themeManager;
@PostMapping("/addTheme")
public ThemeDto addTheme(@RequestBody ThemeDto theme) {
return themeManager.addTheme(theme);
}
@GetMapping("/getThemes")
public List<ThemeDto> getThemes() {
return themeManager.getThemes();
}
@GetMapping("/getTheme/{idTheme}")
public ThemeDto getTheme(@PathVariable("idTheme") Long idTheme) {
return themeManager.getTheme(idTheme);
}
}
Application.java
We need to run Application.run() because this method starts whole Spring Framework. Code below integrates your main() with Spring Boot.
src/main/java/com/quizz/Application.java):
package com.quizz;
import com.quizz.dao.ThemeDao;
import com.quizz.model.Theme;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class QuizzApplication {
public static void main(String[] args) {
SpringApplication.run(QuizzApplication.class, args);
System.out.println("App Started...");
}
}
Conclusion
We were building this application with functionality:
- Created a package model inside it We will add java classes- OrikaBeanMapper.java In this class Orika to convert entity => DTO / DTO => entity
- JPA Repositories:
- created four classes in services package:
- The class that implements the Interface with @Component and @Transactional annotations
- Data Transfer Objects DTO
- @RestController is a convenience annotation for creating Restful controllers.