Data flow between different MVC layers - java

Below I present flow of data from a use form to persistence layer. But have doubts about which objects should be available in which layer of MVC and how data should be transfered between different layers of MVC. I am working with Spring so the code posted below is that of Spring framework.
Here we go, I have a DTO(Data transfer object) PatientForm, which holds form data entered by user.
public class Patient {
private int id;
private String name;
private String medicineOne;
private String medicineTwo;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMedicineOne() {
return medicineOne;
}
public void setMedicineOne(String medicineOne) {
this.medicineOne = medicineOne;
}
public String getMedicineTwo() {
return medicineTwo;
}
public void setMedicineTwo(String medicineTwo) {
this.medicineTwo = medicineTwo;
}
}
PatientForm is passed on to a controller PatientController, does not transfer data but passes the form to the service layer PatientService.
#PostMapping("/patient/addpatient")
public ModelAndView addPatient(#ModelAttribute("patientform") PatientForm patient){
patientService.addPatient(patient);
return new ModelAndView("redirect:/");
}
In service layer PatientService actual transfer of data from DTO to Pesistent Entity Patient takes place.
public void addPatient(com.hp.view.form.PatientForm patientForm){
String medicineOneName = patientForm.getMedicineOne();
Medicine medicineOne = medicineService.findByName(medicineOneName);
if(medicineOne == null){
medicineService.save(new Medicine(medicineOneName));
medicineOne = medicineService.findByName(medicineOneName);
}
String medicineTwoName = patientForm.getMedicineTwo();
Medicine medicineTwo = medicineService.findByName(medicineTwoName);
if(medicineTwo == null){
medicineService.save(new Medicine(medicineTwoName));
medicineTwo = medicineService.findByName(medicineTwoName);
}
List<Medicine> medicines = new ArrayList<>();
medicines.add(medicineOne);
medicines.add(medicineTwo);
Patient patient = new Patient();
patient.setName(patientForm.getName());
patient.setMedicine(medicines);
patientRepository.save(patient);
}
Here are my questions as per the flow above:
Should Controller layer or Service layer transfer data from DTO to Persistent Entity?
If data transfer is done in controller means model entity will be declared in controller layer. And if data transfer is done in service layer means DTO will be declared in service layer. Which of the two is prefered?
In my service layer I have instantiated instance of my entity object Patient. Will this create problem and I should let Spring contianer manage my entity beans?
Patient patient = new Patient();

(1) Should Controller layer or Service layer transfer data from DTO to
Persistent Entity?
FormBeans are client/channel/endpoint specific, so the Controller layer should do the client specific validations (like min length, max length, etc..) and then convert FormBean's data to Entity Bean which will be passed it to the Service layer.
In the 3 tier architecture, Service layer should be reusable (explained below) which should NOT be aware of FormBeans, therefore receives entity object and should be responsible for processing the business logic (performing business validations and core logic plus interacting with DAO/Repository classes).
(2) If data transfer is done in controller means model entity will be
declared in controller layer. And if data transfer is done in service
layer means DTO will be declared in service layer. Which of the two is
prefered?
A single service can be reused/exposed to connect with multiple end points like a Controller or a different web service and each end point might require different formbeans, so Controller (end point) layer is preferred to handle end point specific validations and then create/pass the correct entity object to the service.
(3) In my service layer I have instantiated instance of my entity
object Patient. Will this create problem and I should let Spring
container manage my entity beans?
No problem. As entity objects are NOT singletons, you can create them inside your service like how you did. But if you are allowing Spring to manage them, you need to ensure that they are created one instance per each input request. This is because Spring bean's default scope is singleton, which needs to be changed to request scope.

Actually, I would go with totally different approach. DTO's could be potentially bound for specific web application framework. That would decrease reusability of services. Instead, you can create something like "DTO to entity converter". A simple interface that could look like this:
public interface DtoToEntityConverter<T, R> {
R getEntity(T t);
}
And then you could define concrete class like (or even use lambdas in simpler cases):
#Component
public class PatientFormConverter implements DtoToEntityConverter<PatientForm, Patient> {
public Patient getEntity(PatientForm form) {
// Conversion rules and stuff...
}
}
Then, just inject that component to controller and invoke getEntity upon adding of patient:
addPatient(patientFormConverter.getEntity(patientForm));

In spring you let application context to manage your beans (i e. You don't initialize your class) and then you can autowire (include them in other classes) without explicitly initializing them.
1) Service layers are used as an intermediary between your controller and model. That is, you autowire your service into your rest controller.
2 and 3rd answer is explained above.
P.S.: here autowire means dependency injection - .http://www.javatpoint.com/dependency-injection-in-spring

Related

In Hexagonal architecture, can a service rely on another service, or is that tight coupling?

I am creating a banking application. Currently, there is one primary service, the transaction service. This service allows getting transactions by id, and creating transactions. In order to create a transaction, I first want to check if the transaction is valid, by checking the balance of the account it is trying to deduct from, and seeing if they have enough balance. Right now I am doing
TransactionController calls TransactionService. TransactionService creates Transaction, then checks if this is a valid transaction. At this point, I have created an AccountsService, that queries the AccountsRepository, returns an Account. I then do the comparison based on Account.balance > Transaction.amount.
I am conscious here that the TransactionService create method is relying on the AccountService get method. Additionally, AccountService is never directly called from a controller.
Is this an ok way to architect, or is there a more elegant way to do this?
In your case, I would say it is ok because I guess that if Account.balance < Transaction.amount you don't really want to go forward with the transaction. So you must at some point get the needed data from the AccountService, there is no way around that.
If you just wanted o trigger some side-effect task (like sending an email or something) you could rely on an event-based approach on which TransactionService would publish an event and a hypothetical NotificationsService would react to it at some point in time and do its thing.
Your logic seems fine. If you only need the Account Service from the Transaction service (or another Service), this is valid. No need to call an Account Service from a Controller just to do so if the logic makes no sense. In fact some Services that are invoked from a Controller may call many other services - such as an Email Service, a Text Message Service, and so on.
You can reference your AccountRepository directly in your TransactionService.
Sorry I don't speak Java but here is a C# example :
public class Transaction {
// implementation redacted
public Transaction(decimal amount, Account from, Account to) {
if(amount > from?.Balance) throw ... ;
// redacted
}
}
public class TransactionService {
private readonly AccountRepository accounts; // by injection
private readonly TransactionRepository transactions; // by injection
public void AddTransaction(decimal amount, int source, int destination) {
var from = accounts.Find(source); // throws if not found
var to = accounts.Find(destination); // throws if not found
var transaction = new Transaction(amount, from, to);
transactions.Insert(transaction);
transactions.Persist();
}
}
However, this solution is less ORM friendly because of the Transaction constructor. Another way around would be to use Account as your root aggregate, and place the business rule validation and entities relationship handling code there :
public class Account {
// implementation redacted
public void AddTransaction(decimal amount, Account to) {
if(amount > this.Balance) throw ... ;
// more redacted validations
this.Debitus.Add(new Transaction { Amount = amount, From = this, To = to });
}
}
public class TransactionService {
private readonly AccountRepository accounts; // by injection
public void AddTransaction(decimal amount, int source, int destination) {
var from = accounts.Find(source); // throws if not found
var to = accounts.Find(destination); // throws if not found
from.AddTransaction(amount, to);
accounts.Persist();
}
}
I wouldn't create an account service. I would call the account repo from the transaction service. Apart from that, i wouldnt create a transaction object before knowing if it is valid. I would check the conditions before creating the transaction.
Agree with #choquero70 I don't like to compose or couple Serivce's operations because that "getBalance" maybe is different for one purpose or another, I would implement on TransactionService invoking AccountRepository or whatever repo or client that you need. TransactionService is the "perspective" of the operation

how to write business logic in spring boot

how can i write business logic in the service layer
Create a method in service class with argument cart object and returns response entity.
And then call the method from controller class. And move autowired loginRepository into service class.
public ResponseEntity method(Cart cart){
try {
String username = cart.getUserName();
String password = cart.getPassword();
String email = cart.getEmail();
String productname = cart.getProductName();
String price = cart.getPrice();
String discription = cart.getDiscription();
if (!(loginRepository.existsByUserNameAndPassword(username, password) && productname != null)) {
return new ResponseEntity<ApiError>(HttpStatus.NOT_FOUND);
}
if (!productRepository.existsByProductNameAndPriceAndDiscription(productname, price, discription)) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
Integer count = cartRepository.countByUserName(cart.getUserName());
System.out.println(count);
cartRepository.save(new Cart(cart.getUserName(), cart.getPassword(), cart.getEmail(),
cart.getProductName(), cart.getPrice(), cart.getDiscription(), count));
return new ResponseEntity<>(new MessageResponse("product Successfully added to cart"));
}
catch (Exception | ApiError e) {
return new ResponseEntity<ApiError>(HttpStatus.BAD_REQUEST);
}
}
Autowire service class in controller and call above method from controller like below.
service.method(cart);
This is a tricky questions to have a simple answer, there are multiple best practices available too refactor or restructure the code.
Design Patterns like MVC and DAO are helpful.
Spring 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.
Controllers help in having multi-action class that is able to serve multiple different requests.
Within controller we try to use the 'Single Responsibility Principle', it should delegate business processing to relevant business classes.
Keeping in mind this I would recommend that you move the entire business logic into a separate service class and keep only the transformation from the Request and Response in the controller.
Incase in future you would have to process headers and query parameters that would all be done in the controller and passed to the service layer for the actual business functionality.
I would also recommend that you use Spring's Exception Advice to handle exceptions.

Spring mvc - which layer should convert entities to dtos (and vice versa)

In which layer should DTO/Entity conversion take place.
Having following structure in a Spring Mvc application:
Controller
Service
Repository
The approach I'm using now, where service layer is #Transactional.
#RestController
public class ExampleController {
#Autowired
private ExampleService exampleService;
#Autowired
private ExampleMapper exampleMapper;
#GetMapping("/examples")
public ResponseEntity<List<ExamleDto>> getAll() {
var examples = exampleService.getAll();
return ResponseEntity.ok(exampleMapper.examplesToExampleDtos(examples));
}
#PostMapping("/examples")
public ResponseEntity<Void> create(#RequestBody #Valid ExampleCreateDto createDto) {
var example = exampleService.create(createDto)
return ResponseEntity.created(URI.create("examples/" + example.getId()).build();
}
// PUT, DELETE, ...
}
#Service
#Transactional
public class ExampleService {
#Autowired
private ExampleRepository exampleRepository;
#Autowired
private ExampleMapper exampleMapper;
public List<Examle> getAll() {
var examples = exampleRepository.findAll();
return examples;
}
public void create(ExampleDto exampleDto) {
var example = exampleMapper.asExample(exampleDto);
return exampleRepository.save(example);
}
}
public interface ExampleRepository extends JpaRepository<Example, Long> {
Why I choose this aproach:
The service layer is transactional, so whenever we get back to the controller, all changes will be flushed (version field for example) will all be set.
It makes you think about your entitygraph, lets say you have a Person entity which has a list of Deparments. Lets say the PersonDto contains also the list of DeparmentDtos, it forces you to fetch all deparments before hand or you will run into a LazyInitializationException in the controller layer.
Which in my opinion is a good thing, because if you would perform the mapping in the service you would be doing N + 1 queries (N being the number of deparments) without realizing it.
Services who need each other to perform there business tasks, work on the entity model instead of the DTO model, which might have some validation (#NotNull, #Size, ...) which only supposed to be valided when it comes from the outside, but internally not all validations should be applied.
Business rules will still be checked in the service layer as part of the service method.
The only thing here is that for update/creates service still communicate by passing dtos iso of entities.
I googled this topic a lot, but couldn't find a definitive answer.

Responsibilities and use of Service and DAO Layers

I am currently developing a web application using Struts2 with Spring plugin and hibernate and while I was looking at online examples I saw the use of Service and DAO layers now it came to me what are the real use of Service and data access object layers? If The Service layer is just calling the methods of DAO layers to perform CRUD operations. wouldn't be sensible to just call the DAO layers methods directly?
Let's say this example of Dao and Service Layer
PeopleService
#Transactional
public class PeopleService {
private PeopleDao pDao;
public PeopleDao getPDao() { return pDao; }
public void setPDao(PeopleDao peopleDao) { this.pDao = peopleDao; }
public void createPerson(String name){
pDao.createPerson(name);
}
public List<Person> getPeople(){
return pDao.getPeople();
}
}
PeopleDao
public class PeopleDao {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session sess() {
return sessionFactory.getCurrentSession();
}
public Person getPersonById(long id) {
return (Person) sess().load(Person.class, id);
}
public void deletePersonById(long id) {
sess().delete(getPersonById(id));
}
public void createPerson(String name) {
Person p = new Person();
p.setName(name);
sess().save(p);
}
#SuppressWarnings("unchecked")
public List<Person> getPeople() {
return sess().createQuery("from Person").list();
}
}
My question is what is the real use of Service layers if they are only being injected by their representative DAO and then calling its method?
It is a good idea to have those two layers when your business logic is more complex than your data logic. The service layer implements the business logic. In most cases, this layer has to perform more operations than just calling a method from a DAO object. And if you're thinking of making your application bigger, this is probably the best solution.
Imagine you want to include a City entity and create a relationship between People and City. Here is an example:
#Transactional
public class PeopleService {
....
private PeopleDAO pDAO;
private CityDAO cDAO;
...
public void createPerson(String name, String city)
throws PeopleServiceException {
Person p = new Person();
p.setName(name);
City c = cDAO.getCityByName(city);
if (c == null) throw new ServiceException(city + " doesn't exist!");
if (c.isFull()) throw new ServiceException(city + " is full!");
c.addPeople(p);
sess().save(p);
sess().save(c);
}
...
}
In this example, you can implement more complex validations, like checking the consistency of the data. And PersonDAO has not been modified.
Another example:
DAO and Service layers with Spring
Definition of Service layer pattern
If your application will grow with new and changing requirements you are very well served with having distinct layers for those TWO DISTINCT ASPECTS (persistence->DAO, business use case -> services) of your software.
One aspect is your persistence model with its relations, validations, transactions and many access patterns.
The services are driven by the business use cases which have a very different granularity. In the beginning you may have very simple services which don't do much more than calling DAOs to hand over data they received from, let's say, a web page. But this is likely to change over time and services will grow into small networks of collaborating objects that do a lot more to serve the business use case. If you don't use DAOs then
your services will contain code that deals with querying objects, transaction handling, validation, all of which has nothing to do with real business requirements
service code will look messy and it will be difficult to find out what parts of the code are actually business related
if you then change the persistence model you might end up changing many services
Also you can not easily unit test your persistence model but write tests only on the service layer. Do not forget that decoupling and encapsulation are important techniques to minimize the impact of change.
When done right, having a DAO layer will not introduce much implementation overhead so there is not much extra cost in having it. It will soon pay off and you will be very glad to have this dedicated layer.
Check out this article: http://codeblock.engio.net/?p=180. It also comes with a full implementation hosted on github

Organization of services in service layer?

I have a Java server application with a ton of different entities. So far, each entity top level entity has its own CRUD service. By top level, I mean the root of a tree of entities that can stand alone.
Now I am getting into the heart of my Flex client and find I am needing/writing many different queries. But where best to put these queries?
Say for example, I have a query to find all "foos" based on their associate with a certain "bar". Currently that query is on the "foo" service (findAllByBar), but I am finding that it would be very convenient to have it (also?) in the "bar" service (findFoos). On the other hand, I could also create a query service and lump all the queries in there.
Whats a good practice to do here?
Try to layer your application in these perspectives:
Domain: design your class as entities like "Customer", value objects like "Address" or "Color", and aggregate roots (like "Order" which includes a list of "LineItem")
Repositories: these are the data access for the entities, create a repository for each aggregat root (CustomerRepository, OrderRepository, ...)
Services: create a coarse grained services spitted by logical business abstractions or bounded context not by entities, it is not logical to create a service for order and a service for items and a service for customers when all these entities are representing one atomic business value of order processing, then your service will use all required repositories to handle the data access.
example:
public class OrderRepository {
public Foo getById(int id) {
//
}
public Foo getByCustomer(Customer customer) {
//
}
}
public class CustomerRepository {
public Foo getById(int id) {
//
}
public Foo getByUserName(string userName) {
//
}
}
public class TradingService {
private OrderRepository _orderRepository;
private CustomerRepository _customerRepository;
public TradingService(OrderRepositoryInterface orderRep, CustomerRepositoryInterface cusRep) {
_orderRepository = orderRep;
_customerRepository = custRep;
}
public void placeOrder(string customerUserName, Order order) {
Customer customer = _customerRepository.getByUserName(customerUserName);
order.setCustomer(customer);
_orderRepository.add(order);
// ....
}
}
I would put queries in their respective classes instead of creating one (bloatable)query service

Categories

Resources