(REST API using Spring Boot) Part-2 Adding Model, Service, Controller, and Dao Implementation

Aditi Mittal
Javarevisited
Published in
6 min readAug 17, 2019
User Flow

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.

--

--