Microservices - Utility Payment Service Implementation
- Chinthaka Dinadasa
- 10 Nov, 2021
Hello readers, here is the latest article on Building Microservices With Spring Boot – Free Course With Practical Project which focuses on utility payment service implementation which enables users to process utility payments through internet banking solution microservices.
Here I’ll cover only limited functionality includes placing utility payments and reading placed utility payments from DB.
Developing Utility Payment Service
Just create another spring boot application using Spring Initializr with the following dependencies,
- Spring Web
- Lombok
- Spring Data JPA
- MySQL
- Eureka Discovery Client
Database Models
Here I’m going to store the utility payments summary with the status of a process in a single table.
package com.javatodev.finance.model;
public enum TransactionStatus {
PENDING, PROCESSING, SUCCESS, FAILED
}
package com.javatodev.finance.model.entity;
import com.javatodev.finance.model.TransactionStatus;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.math.BigDecimal;
@Getter
@Setter
@Entity
@Table(name = "utility_payment")
public class UtilityPaymentEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long providerId;
private BigDecimal amount;
private String referenceNumber;
private String account;
private String transactionId;
@Enumerated(EnumType.STRING)
private TransactionStatus status;
}
Repository Layer
package com.javatodev.finance.repository;
import com.javatodev.finance.model.dto.UtilityPayment;
import com.javatodev.finance.model.entity.UtilityPaymentEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UtilityPaymentRepository extends JpaRepository<UtilityPaymentEntity, UtilityPayment> {
}
DTO, Mapper, and REST Request and Responses
Here I’m going to use a separate DTO layer to bring data from this core service to the public over the API. Basically here I’ll not go to expose my entity layer, instead of that I’ll define the DTO layer to bring in and out data from this API.
package com.javatodev.finance.model.dto;
import com.javatodev.finance.model.TransactionStatus;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class UtilityPayment {
private Long providerId;
private BigDecimal amount;
private String referenceNumber;
private String account;
private TransactionStatus status;
}
Create utility payment request to bind incoming data from API,
package com.javatodev.finance.rest.request;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class UtilityPaymentRequest {
private Long providerId;
private BigDecimal amount;
private String referenceNumber;
private String account;
}
UtilityPaymentResponse to map response from API after processing utility payment.
package com.javatodev.finance.rest.response;
import lombok.Data;
@Data
public class UtilityPaymentResponse {
private String message;
private String transactionId;
}
Mapper class to map DTO -> Entity and vice versa,
package com.javatodev.finance.model.mapper;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public abstract class BaseMapper<E, D> {
public abstract E convertToEntity(D dto, Object... args);
public abstract D convertToDto(E entity, Object... args);
public Collection<E> convertToEntity(Collection<D> dto, Object... args) {
return dto.stream().map(d -> convertToEntity(d, args)).collect(Collectors.toList());
}
public Collection<D> convertToDto(Collection<E> entity, Object... args) {
return entity.stream().map(e -> convertToDto(e, args)).collect(Collectors.toList());
}
public List<E> convertToEntityList(Collection<D> dto, Object... args) {
return convertToEntity(dto, args).stream().collect(Collectors.toList());
}
public List<D> convertToDtoList(Collection<E> entity, Object... args) {
return convertToDto(entity, args).stream().collect(Collectors.toList());
}
public Set<E> convertToEntitySet(Collection<D> dto, Object... args) {
return convertToEntity(dto, args).stream().collect(Collectors.toSet());
}
public Set<D> convertToDtoSet(Collection<E> entity, Object... args) {
return convertToDto(entity, args).stream().collect(Collectors.toSet());
}
}
package com.javatodev.finance.model.mapper;
import com.javatodev.finance.model.dto.UtilityPayment;
import com.javatodev.finance.model.entity.UtilityPaymentEntity;
import org.springframework.beans.BeanUtils;
public class UtilityPaymentMapper extends BaseMapper<UtilityPaymentEntity, UtilityPayment> {
@Override
public UtilityPaymentEntity convertToEntity(UtilityPayment dto, Object... args) {
UtilityPaymentEntity entity = new UtilityPaymentEntity();
if (dto != null) {
BeanUtils.copyProperties(dto, entity);
}
return entity;
}
@Override
public UtilityPayment convertToDto(UtilityPaymentEntity entity, Object... args) {
UtilityPayment dto = new UtilityPayment();
if (entity != null) {
BeanUtils.copyProperties(entity, dto);
}
return dto;
}
}
Now we have all the components in order to place a utility payment in the database and read those when needed. Let’s focus on creating a utility payments service from here,
Utility Payments Service
In this service implementation, I’m going to explain how we could save all the utility payments requests in the local database. But here there is one more thing which should be present which is building communication with the core banking system, Which I’ll explain in the next article in this series.
package com.javatodev.finance.service;
import com.javatodev.finance.model.TransactionStatus;
import com.javatodev.finance.model.dto.UtilityPayment;
import com.javatodev.finance.model.entity.UtilityPaymentEntity;
import com.javatodev.finance.model.mapper.UtilityPaymentMapper;
import com.javatodev.finance.repository.UtilityPaymentRepository;
import com.javatodev.finance.rest.request.UtilityPaymentRequest;
import com.javatodev.finance.rest.response.UtilityPaymentResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.UUID;
@Slf4j
@Service
@RequiredArgsConstructor
public class UtilityPaymentService {
private final UtilityPaymentRepository utilityPaymentRepository;
private UtilityPaymentMapper utilityPaymentMapper = new UtilityPaymentMapper();
public UtilityPaymentResponse utilPayment(UtilityPaymentRequest paymentRequest) {
log.info("Utility payment processing {}", paymentRequest.toString());
UtilityPaymentEntity entity = new UtilityPaymentEntity();
BeanUtils.copyProperties(paymentRequest, entity);
entity.setStatus(TransactionStatus.PROCESSING);
UtilityPaymentEntity optUtilPayment = utilityPaymentRepository.save(entity);
String transactionId = UUID.randomUUID().toString();
optUtilPayment.setStatus(TransactionStatus.SUCCESS);
optUtilPayment.setTransactionId(transactionId);
utilityPaymentRepository.save(optUtilPayment);
return UtilityPaymentResponse.builder().message("Utility Payment Successfully Processed").transactionId(transactionId).build();
}
public List<UtilityPayment> readPayments(Pageable pageable) {
Page<UtilityPaymentEntity> allUtilPayments = utilityPaymentRepository.findAll(pageable);
return utilityPaymentMapper.convertToDtoList(allUtilPayments.getContent());
}
}
Controller Layer
Here we are exposing 2 endpoints in order to place utility payments and read all placed payments in the database.
package com.javatodev.finance.controller;
import com.javatodev.finance.rest.request.UtilityPaymentRequest;
import com.javatodev.finance.service.UtilityPaymentService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/api/v1/utility-payment")
public class UtilityPaymentController {
private final UtilityPaymentService utilityPaymentService;
@GetMapping
public ResponseEntity readPayments(Pageable pageable) {
return ResponseEntity.ok(utilityPaymentService.readPayments(pageable));
}
@PostMapping
public ResponseEntity processPayment(@RequestBody UtilityPaymentRequest paymentRequest) {
return ResponseEntity.ok(utilityPaymentService.utilPayment(paymentRequest));
}
}
All done for basic utility payments service and let’s configure application configurations as below,
server:
port: 8085
spring:
application:
name: internet-banking-utility-payment-service
datasource:
url: jdbc:mysql://localhost:3306/banking_core_utility_payment_service
username: root
password: password
jpa:
hibernate:
ddl-auto: update
eureka:
client:
service-url:
defaultZone: http://localhost:8081/eureka
info:
app:
name: ${spring.application.name}server:
port: 8085
spring:
application:
name: internet-banking-utility-payment-service
datasource:
url: jdbc:mysql://localhost:3306/banking_core_utility_payment_service
username: root
password: password
jpa:
hibernate:
ddl-auto: update
eureka:
client:
service-url:
defaultZone: http://localhost:8081/eureka
info:
app:
name: ${spring.application.name}
Then there is one more thing to do in the API gateway we developed earlier in Microservices – Setup API Gateway Using Spring Cloud Gateway, Just add the following route definition to the API gateway in order to access this utility payments service.
- id: internet-banking-utility-payment-service
uri: lb://internet-banking-utility-payment-service
predicates:
- Path=/utility-payment/**
filters:
- StripPrefix=1
Testing API With Postman
Just start all the components including service registry, API gateway, and internet banking utility payments service, and test API over a gateway to check the implementation.
Here are a few screenshots while testing the user service API using Postman, and you can access the same collection using the below link.
Conclusion
Thanks for reading our latest article on Utility Payments Service Implementation with practical usage.
This article only covers the basic implementation of utility payments service in an internet banking microservice project. I’ll explain the pending part which is building the communication layer between user service and core banking microservice with the next article.
If you are looking for spring boot practical application development tutorials, just check our article series.
You can get the source code for this tutorial from our GitHub repository.