how to write business logic in spring boot - java

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.

Related

How to read a property from external api and set it to application context in springboot to make it available globally?

I have to invoke an external api in multiple places within my Springboot java application. The external api will just return a static constant String value at all times.
Please find below sample code to explain better my intentions and what I wish to achieve at the end of the day
My sample code invoking external api using RestTemplate to retrieve a String value.
ResponseEntity<String> result = new RestTemplate().exchange("http://localhost:7070/api/test/{id}",
HttpMethod.GET, entity, String.class, id);
JSONObject jsonResponse = new JSONObject(result.getBody());
String reqVal = jsonResponse.getString("reqKey");
Now, My intention is to make this String globally available within the application to avoid calling this api multiple times.
I am thinking of invoking this extenal api at application startup and set this String value in Springboot application context, so that it can be retrieved from anywhere with the application.
Can anyone suggest, how can I achieve my above requirement?
Or are there any other better options to think of?
Thanks in advance!
I would store it in memory in the Spring-managed Bean that calls the external API and then allow any other Spring-managed Bean to get it from this component.
#Service
public class ThirdPartyServiceClient implements ApplicationListener<ContextRefreshedEvent> {
private String reqKey = null;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
(...)
ResponseEntity<String> result = new RestTemplate()
.exchange("http://localhost:7070/api/test/{id}", HttpMethod.GET, entity, String.class, id);
JSONObject jsonResponse = new JSONObject(result.getBody());
this.reqKey = jsonResponse.getString("reqKey");
}
public String getKey() {
return reqKey;
}
}
Now you just need to inject ThirdPartyServiceClient Spring-managed bean in any other to be able to call getKey() method.

How to pass model attributes globally to avoid repeatable code in Spring controller?

I would like to ask you for some best practice to reduce the amount of repeatable code in my controller's methods - one of them is presented below.
I have quite a big and complex view with a lot of information and two forms. In every method of my controller (and there are quite a few) I have to pass the same attributes to my view (in post controllers even twice). I added a note SAME CODE in the code snippet below indicating identical pieces of code.
I wonder if there is any possibility to make a one global method in the controller gathering all attributes to be passed to the model and just reference it in any of particular methods?
I looked into ModelAndView or ModelMap, but cannot see those being suitable here.
Just want to avoid repeating this part:
Repeatable piece of code
model.addAttribute("hotels", hotelService.getAllHotels());
List<GetRoomDto> roomsDto = roomService.getAllRoomsByHotelId(hotelId);
model.addAttribute("rooms", roomsDto);
model.addAttribute("roomTypes", roomTypeService.findAllRoomTypeNames());
Full method with that piece of code appearing twice
#PostMapping("/hotels/{hotelId}/rooms")
public String createRoomForHotelById(#ModelAttribute("room") #Valid NewRoomDto roomDto,
BindingResult result,
#PathVariable("hotelId") Long hotelId,
Model model) {
if(result.hasErrors()) {
// SAME CODE
model.addAttribute("hotels", hotelService.getAllHotels());
List<GetRoomDto> roomsDto = roomService.getAllRoomsByHotelId(hotelId);
model.addAttribute("rooms", roomsDto);
model.addAttribute("roomTypes", roomTypeService.findAllRoomTypeNames());
//
model.addAttribute("hotel", new NewHotelDto());
LOG.info("Binding error: {}", result.toString());
return "admin/dashboard";
}
// SAME CODE
model.addAttribute("hotels", hotelService.getAllHotels());
List<GetRoomDto> roomsDto = roomService.getAllRoomsByHotelId(hotelId);
model.addAttribute("rooms", roomsDto);
model.addAttribute("roomTypes", roomTypeService.findAllRoomTypeNames());
//
LOG.info("AdminController: CreateRoomForHotelById: Created room: {}", roomDto.toString());
roomDto.setHotelId(hotelId);
roomService.createNewRoom(roomDto);
return "redirect:/auth/admin/hotels/{hotelId}/rooms";
}
You can also move the code from J Asgarov's answer into the same controller instead of another class annotated with #ControllerAdvice. That way that code will only be executed for #RequestMapping methods within that controller.
For multiple values you could also do something like this:
#ModelAttribute
public void foo(Model model, #PathVariable(required = false) Long hotelId) {
model.addAttribute("hotels", hotelService.getAllHotels());
if (hotelId != null) {
List<GetRoomDto> roomsDto = roomService.getAllRoomsByHotelId(hotelId);
model.addAttribute("rooms", roomsDto);
}
model.addAttribute("roomTypes", roomTypeService.findAllRoomTypeNames());
}
But seeing your code I would rather suggest you move the repeated code into a private method and call it whenever you need those inside your model.
Your method createRoomForHotelById for example causes a redirect, which basically discards everything you put in your model.
For global model attributes you can use #ControllerAdvice:
Create a class and annotate it with #ControllerAdvice.
Inside of that class pass the model attribute (which will now be available globally) like so:
#ModelAttribute("foo")
public Foo foo() {
return new Foo();
}

How to convert one object into another without blocking

I need to rewrite some spring code to reactive-spring. So there's a reactive spring repository service which provides on type of object. But the return type of mapping method is another one type, which depends on locale. Now there's a blocking algorithm which calls get method from repository then split result, then take String locale and then make from them all one response object. How can I combine it into one non-blocking chain of reactive methods?
I see that the only thing I have to wait is Mongo Db service which is kind of reactive, but I want to write code properly to make Spring framework block Mono itself. Here is the example code:
#RestController
#RequestMapping
public class PhoneCheckController {
#Autowired
private MessageLocalization loc;
#Autowired
private PhoneCheckService service;
#GetMapping("/check")
public PhoneCheckResponse checkPhone(#Valid #ModelAttribute PhoneCheckRequest request, Locale locale) {
PhoneCheckResult result = service.checkPhoneNumber(DtoTransformer.toParams(request)).block();
return new PhoneCheckResponse(
result.getViolationLevel(),
loc.getMessage(result.getMessage(), locale)
);
}
}
I tried to make like this
public Mono<PhoneCheckResponse> checkPhone(#Valid #ModelAttribute PhoneCheckRequest request, Locale locale) {
PhoneCheckResult result = service.checkPhoneNumber(DtoTransformer.toParams(request));
return Mono.just(new PhoneCheckResponse(
result.getViolationLevel(), //reactive part I need put
loc.getMessage(result.getMessage(), locale) //reactive part
)
);
}

Designing custom workflow in JAVA and Spring

I am working on an spring 2.0.1.RELEASE application.
Brief of Application:
1. I have separate Transformer beans that transforms my DTO to Domain
and vice versa.
2. I have separate Validator beans that validate my domain object being passed.
3. I have Service classes that takes care of the applying rules and calling persistence layer.
Now, i want to build a Workflow in my application:
where i will just call the start of the workflow and below mentioned steps will be executed in order and exception handling will be done as per the step:
1.First-Transformtion - transformToDomain() method will be called for that object type.
2.Second-Validator - class valid() method will be called for that object.
3.Third-Service - class save() method will be called for that object.
4.Fourth- Transformation - transformToDTO() method will be called for that object type.
after this my workflow ends and i will return the DTO object as response of my REST API.
Exception handling part is the one, i also want to take care of, like if particular exception handler exist for that step then call it, else call global exception handler.
I designed some prototype of same, but looking for some expert advice and how this can be achieved with a better design in java.
Explanation with example considering above use case is highly appreciable.
I'm not so sure if what you are describing is a workflow system in its true sense, perhaps a Chain of Responsibility is more of what you are talking about?
Following what you described as a sequence of execution, here is a simplified example of how I would implement the chain:
Transformer.java
public interface Transformer<IN, OUT> {
OUT transformToDomain(IN dto);
IN transformToDTO(OUT domainObject);
}
Validator.java
public interface Validator<T> {
boolean isValid(T object);
}
Service.java
public interface Service {
void save(Object object);
}
And the implementation that binds everything:
ProcessChain.java
public class ProcessChain {
private Transformer transformer;
private Service service;
private Validator validator;
Object process(Object dto) throws MyValidationException {
Object domainObject = transformer.transformToDomain(dto);
boolean isValid = validator.isValid(domainObject);
if(!isValid){
throw new MyValidationException("Validation message here");
}
service.save(domainObject);
return transformer.transformToDTO(domainObject);
}
}
I haven't specified any Spring related things here because your question seems to be a design question rather than a technology questions.
Hope this helps
Brief of what i implemented in a way with not much hustle:
This is how I created flow of handlers:
Stream.<Supplier<RequestHandler>>of(
TransformToDomainRequestHandler::new,
ValidateRequestHandler::new,
PersistenceHandler::new,
TransformToDTORequestHandler::new)
.sequential()
.map(c -> c.get()) /* Create the handler instance */
.reduce((processed, unProcessed) -> { /* chains all handlers together */
RequestHandler previous = processed;
RequestHandler target = previous.getNextRequestHandler();
while (target != null && previous != null) {
previous = target;
target = target.getNextRequestHandler();
}
previous.setNextRequestHandler(unProcessed);
return processed;
}).get();
This is my Request Handler which all other handler extends

Data flow between different MVC layers

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

Categories

Resources