(REST API using Spring Boot) Part-2 Adding Model, Service, Controller, and Dao Implementation
This article discusses the implementation of the model, service, data access object (DAO) and controller. It is in continuation of Part-1 that discussed the steps of setting up the Spring Boot project and writing a basic controller.
Controller is the interface that interacts with the outside world. It handles incoming HTTP requests and send response back to the caller. Based on the incoming request URL and HTTP verb (GET/POST/PUT/PATCH/DELETE), API decides which controller and action method to execute e.g. Get() method will handle HTTP GET request, Post() method will handle HTTP POST request, Put() method will handle HTTP PUT request and Delete() method will handle HTTP DELETE request for the above Web API. Service is the utility that defines the business logic of the application. DAO or Data Access Object is used to interact with the database directly.
Adding to application.properties
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/all_transactions
spring.datasource.username=****
spring.datasource.password=****
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
Writing Interfaces and Model Class
Model Class
Model Class in my case is for Transaction which will have id, type, email and date as it’s properties. Let’s declare these in the IntelliJ class.
‘@Table(name= “Transaction”)’ is used for creating a table with name Transaction in the MySQL database. ‘@GeneratedValue(strategy=GenerationType.AUTO)’ is used to generate id automatically whenever a new transaction is added. This means that whenever a transaction is created, id will automatically increment with 1. ‘@Column(name= “id”)’ is used to create a column with a particular name ‘id’ in the Transaction table in the database. Setters and getters methods are written for each of the attribute specified.
import javax.persistence.*;@Entity
@Table(name = "Transaction")
public class Transaction {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id")
private Integer id;
@Column(name="type")
private String type;
@Column(name="email")
private String email;
@Column(name="date")
private String date;
public Transaction(){
}
public Transaction(Integer id, String type, String email, String date) {
this.id=id;
this.type = type;
this.email = email;
this.date = date;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
Service Interface
Service will have the functionalities of saving the transaction, getting all the transactions, getting a transaction by id, screening a transaction and deleting a transaction. Saving the transaction function will be used in updating an existing transaction and creating a new transaction. We will create another package for service in which we will add the interface and implementation of the same.
Screening a transaction should return ‘REJECTED’ if the email id of transaction is in blacklist and transaction was made within last 30 days. In all other cases, it should return ‘ACCEPT’.
public interface TransactionService {
public List<Transaction> findAllTransactions();
public String screenTransactionById(int theId);
public Transaction findTransactionById(int theId);
public Transaction saveTransaction(Transaction theTransaction);
public int deleteTransactionById(int theId);
}
DAO Interface
DAO will have similar functions as of service i.e. getting all the transactions from DB, getting the transaction by id from DB, adding the transaction in DB and deleting the transaction in DB.
public interface TransactionDAO {
List<Transaction> getAllTransactions();
Transaction findTransactionById(int theId);
Transaction saveTransaction(Transaction theTransaction);
void deleteTransactionById(int theId);
}
DAO Implementation Class
DAO Implementation class will interact with the database. MySql is used as the database in this case. All the methods of DAO interface are overridden in this class.
If we annotate a class with @Autowired, Spring will automatically resolve the instance and inject it into the class that declared it. So we don’t need to obtain the singleton instance ourselves. If a class is a Singleton, there can only be one instance of that class throughout the application lifecycle.
Spring Repository is very close to DAO pattern where DAO classes are responsible for providing CRUD operations on database tables. ‘@Repository’ annotation is used to declare the class as a Repository object which is auto-detected by spring framework.
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import java.util.List;@Repository
public class TransactionDAOJpaImpl implements TransactionDAO {
private EntityManager entityManager;
@Autowired
public TransactionDAOJpaImpl(EntityManager entityManager){
this.entityManager = entityManager;
}
//get all the transactions from the database
@Override
public List<Transaction> getAllTransactions() {
Query theQuery= (Query) entityManager.createQuery("from Transaction");
List<Transaction> transactions = theQuery.getResultList();
return transactions;
}
//return the transaction by giving id as input
@Override
public Transaction findTransactionById(int theId) {
Transaction theTransaction = entityManager.find(Transaction.class,theId);
return theTransaction;
}
//add the transaction to the database
@Override
public Transaction saveTransaction(Transaction theTransaction) {
Transaction dbTransaction = entityManager.merge(theTransaction);
theTransaction.setId(dbTransaction.getId());
return theTransaction;
}
//delete the transaction from the database using transaction id
@Override
public void deleteTransactionById(int theId) {
Query theQuery = (Query) entityManager.createQuery("delete from Transaction where id=:transactionId");
theQuery.setParameter("transactionId", theId);
theQuery.executeUpdate();
}
}
Once the mappings are defined, entity manager can manage your entities. Entity Manager handles all interactions with the database.
Service Implementation Class
All the methods declared in service interface are overridden in this class.
The ‘@Transactional’ annotation itself defines the scope of a single database transaction. The database transaction happens inside the scope of a persistence context.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import static java.time.temporal.ChronoUnit.DAYS;@Service
public class TransactionServiceImpl implements TransactionService {
TransactionDAO transactionDAO;
private static final String[] blackListEmails = new String[] {"blacklist1@gmail.com","blacklist2@gmail.com","blacklist3@gmail.com","blacklist4@gmail.com"};
@Autowired
public TransactionServiceImpl(@Qualifier("transactionDAOJpaImpl") TransactionDAO theTransactionDao){
transactionDAO = theTransactionDao;
}
@Override
@Transactional
public List<Transaction> findAllTransactions() {
return transactionDAO.getAllTransactions();
}
@Override
@Transactional
public String screenTransactionById(int theId) {
Transaction theTransaction=transactionDAO.findTransactionById(theId);
String dateInString = theTransaction.getDate();
LocalDate localDate = LocalDate.parse(dateInString);
LocalDate today = LocalDate.now();
long difference=DAYS.between(localDate, today);
boolean isInBlackList = Arrays.asList(blackListEmails).contains(theTransaction.getEmail());
//return Reject if the email id is in blacklist and the transaction has been made in the last 30 days, otherwise return accept
if(isInBlackList && difference<30) {
return "REJECT";
}
else {
return "ACCEPT";
}
}
@Override
@Transactional
public Transaction findTransactionById(int theId) {
return transactionDAO.findTransactionById(theId);
}
@Override
@Transactional
public Transaction saveTransaction(Transaction theTransaction) {
return transactionDAO.saveTransaction(theTransaction);
}
@Override
@Transactional
public int deleteTransactionById(int theId) {
transactionDAO.deleteTransactionById(theId);
return theId;
}
}
Controller Class
Spring Boot annotations for handling different HTTP request types
- @RequestMapping — For handling any request type
- @GetMapping — GET request
- @PostMapping — POST request
- @PutMapping — PUT request
- @PatchMapping — PATCH request
- @DeleteMapping — DELETE request
Path variables are variables in the request URL and annotated with “@PathVariable”.
The POST, PUT and DELETE request can contain a payload known as “@RequestBody”. The payload contains the data that could be stored or updated. The payload is usually in JSON format
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;@RestController
@RequestMapping(path="/demo")
public class TransactionRestController {
private TransactionService transactionService;
@Autowired
public TransactionRestController(TransactionService thetransactionservice){
transactionService = thetransactionservice;
}
//For getting all the transactions
@RequestMapping(value = "/transactions", method= RequestMethod.GET)
public ResponseEntity<List<Transaction>> findAll(){
System.out.println(transactionService.findAllTransactions().size());
return new ResponseEntity<List<Transaction>>(transactionService.findAllTransactions(), HttpStatus.OK);
}
//For getting whether the transaction with a given id is rejected or accepted
@RequestMapping(value = "/transactions/{transactionId}", method = RequestMethod.GET)
public String screenTransaction(@PathVariable int transactionId) {
String theTransaction = transactionService.screenTransactionById(transactionId);
return theTransaction;
}
//For adding a transaction
@RequestMapping(value = "/transactions", method = RequestMethod.POST)
public Transaction addTransaction(@RequestBody Transaction theTransaction){
return (transactionService.saveTransaction(theTransaction));
}
//For updating a transaction
@RequestMapping(value = "/transactions", method = RequestMethod.PUT)
public Transaction updateTransaction(@RequestBody Transaction theTransaction){
Transaction transaction = transactionService.findTransactionById(theTransaction.getId());
if (transaction == null) {
throw new RuntimeException("Transaction to update doesn't exist");
}
return (transactionService.saveTransaction(theTransaction));
}
//For deleting a transaction
@RequestMapping(value = "/transactions/{transactionId}", method = RequestMethod.DELETE)
public String deleteTransaction(@PathVariable int transactionId){
Transaction tempTransaction = transactionService.findTransactionById(transactionId);
if(tempTransaction == null){
throw new RuntimeException("Transaction Id not found");
}
transactionService.deleteTransactionById(transactionId);
return "deleted transaction id " + transactionId;
}
}
Now you can get all the transactions by going to URL in Postman http://localhost:8080/demo/transactions , screen transaction in the URL http://localhost:8080/demo/transactions/{transactionId} and select GET. You can add transaction in the URL http://localhost:8080/demo/transactions and select POST and update transaction in the URL http://localhost:8080/demo/transactions and select PUT. You can also delete the transaction by going to http://localhost:8080/demo/transactions/{transactionId} and select DELETE.
If you want to learn more about Spring Boot, here are some of the useful resources e.g. books and courses for further reading:
- 5 Free Courses to Learn Spring and Spring Boot
- 10 Tips to become a better Java Developer
- 5 Spring Security Courses to Learn Online
- 3 Ways to Learn Spring Boot and Spring Cloud
- 5 Courses to Learn Spring Boot for Beginners
- Top 5 Courses to Learn Spring Framework in Depth
Stay tuned for Part 3 discussing writing the unit tests for the code written.