This post continues from the last one. I will try to complete the lead microservice in this post. I will be focusing primarily on the CRUD operation. In CRM applications, that is the primary set of operations.
I will start by creating the exception class. Later I would show how to use this exception class and Spring Rest exception handling and build a robust error handling around the API calls.
Listing 1 - BusinessException.java
Next step would be to introduce the service class. Since this is CRUD most of the functionality can be encapsulated in an abstract parent service class. Any specific feature like convert lead to opportunity can be implemented in the LeadService class.
Listing 2 - AbstractBaseBusinessDelegate.java
And then finally the LeadService implementation class is shown in Listing 3.
Listing 3 - LeadBusinessDelegate.java
Note that this code will not compile. In order to get this to compile, you will need to add 2 new dependencies for the Jodd libraries. Jodd is a popular micro framework which provides very useful utilities and lightweight framework to develop Java applications.
Listing 4 - build.gradle snippet
Now I am going to add the Spring Rest controller. This class is responsible for handling all microservices call. It then delegates to the business delegate to complete the business operation. As you must have already noted, the business delegate then calls repository to retrieve any data from the backing data store. In this series, I am using JPA store or my code is interacting with a relational database. Later I intend to add NoSQL store also and show if and how they can reside together.
Just like the business delegate most of the functionality is encapsulated in the base controller class as shown in Listing 5.
Listing 5 - AbstractBaseController.java
And finally here is the LeadController implementation class in Listing 6.
Listing 6 - LeadController.java
Thats all for now. The source code is available on Github repository
https://github.com/kdhrubo/playground.git
I will start by creating the exception class. Later I would show how to use this exception class and Spring Rest exception handling and build a robust error handling around the API calls.
Listing 1 - BusinessException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.effectiv.crm.exception; | |
import org.springframework.core.NestedRuntimeException; | |
public class BusinessException extends NestedRuntimeException { | |
private static final long serialVersionUID = 1L; | |
public BusinessException(String msg) { | |
super(msg); | |
} | |
} |
Next step would be to introduce the service class. Since this is CRUD most of the functionality can be encapsulated in an abstract parent service class. Any specific feature like convert lead to opportunity can be implemented in the LeadService class.
Listing 2 - AbstractBaseBusinessDelegate.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.effectiv.crm.business; | |
import java.io.Serializable; | |
import org.springframework.data.domain.Page; | |
import org.springframework.data.domain.Pageable; | |
import org.springframework.data.jpa.repository.JpaRepository; | |
import org.springframework.transaction.annotation.Transactional; | |
import com.effectiv.crm.domain.BaseEntity; | |
import com.effectiv.crm.exception.BusinessException; | |
import jodd.bean.BeanUtil; | |
import lombok.Getter; | |
import lombok.extern.slf4j.Slf4j; | |
@Slf4j | |
public abstract class AbstractBaseBusinessDelegate<T extends BaseEntity, Id extends Serializable> { | |
@Getter | |
private JpaRepository<T, Id> repository; | |
public AbstractBaseBusinessDelegate(JpaRepository<T, Id> repository) { | |
this.repository = repository; | |
} | |
@Transactional(readOnly = true) | |
public T findOne(Id id) { | |
return repository.findOne(id); | |
} | |
@Transactional(readOnly = true) | |
public Page<T> findAll(Pageable pageable) { | |
return repository.findAll(pageable); | |
} | |
@Transactional | |
public T save(T t) { | |
//log.info("saving ---> " + t); | |
return repository.save(t); | |
} | |
@Transactional | |
public void delete(Id id) { | |
T t = findOne(id); | |
if (t == null) { | |
throw new BusinessException( | |
"Record with id = " + id + " not found. May be it is already deleted or purged. "); | |
} | |
try { | |
BeanUtil.silent.setProperty(t, "deleted", true); | |
} catch (Exception e) { | |
log.error("Error while setting deleted property in restore - {}", e); | |
throw new BusinessException("Entity cannot be deleted (soft delete) - " + e.getLocalizedMessage() | |
+ ". Check if deleted field is present."); | |
} | |
repository.save(t); | |
} | |
} |
Listing 3 - LeadBusinessDelegate.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.effectiv.crm.business; | |
import org.springframework.stereotype.Component; | |
import com.effectiv.crm.domain.Lead; | |
import com.effectiv.crm.repository.LeadRepository; | |
@Component | |
public class LeadBusinessDelegate extends AbstractBaseBusinessDelegate<Lead, String>{ | |
public LeadBusinessDelegate(LeadRepository repository) { | |
super(repository); | |
} | |
} |
Listing 4 - build.gradle snippet
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
compile group: 'org.jodd', name: 'jodd-core', version: '3.8.5' | |
compile group: 'org.jodd', name: 'jodd-bean', version: '3.8.5' |
Now I am going to add the Spring Rest controller. This class is responsible for handling all microservices call. It then delegates to the business delegate to complete the business operation. As you must have already noted, the business delegate then calls repository to retrieve any data from the backing data store. In this series, I am using JPA store or my code is interacting with a relational database. Later I intend to add NoSQL store also and show if and how they can reside together.
Just like the business delegate most of the functionality is encapsulated in the base controller class as shown in Listing 5.
Listing 5 - AbstractBaseController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.effectiv.crm.controller; | |
import org.springframework.data.domain.Page; | |
import org.springframework.data.domain.Pageable; | |
import org.springframework.http.HttpStatus; | |
import org.springframework.web.bind.annotation.*; | |
import com.effectiv.crm.business.AbstractBaseBusinessDelegate; | |
import com.effectiv.crm.domain.BaseEntity; | |
import lombok.Getter; | |
import lombok.extern.slf4j.Slf4j; | |
import java.io.Serializable; | |
import javax.validation.Valid; | |
@Slf4j | |
public abstract class AbstractBaseController<T extends BaseEntity, Id extends Serializable> { | |
@Getter | |
protected AbstractBaseBusinessDelegate<T, Id> service; | |
public AbstractBaseController(AbstractBaseBusinessDelegate<T, Id> service) { | |
this.service = service; | |
} | |
@PostMapping | |
@ResponseStatus(value = HttpStatus.CREATED) | |
@ResponseBody | |
public T create(@RequestBody @Valid T t) { | |
return service.save(t); | |
} | |
@GetMapping() | |
@ResponseStatus(value = HttpStatus.FOUND) | |
@ResponseBody | |
public Page<T> findAll(Pageable pageable) { | |
log.info("pageable.pageNumber -> {}" , pageable.getPageNumber()); | |
log.info("pageable.pageSize -> {}" , pageable.getPageSize()); | |
log.info("pageable.sort -> {}" , pageable.getSort()); | |
return service.findAll(pageable); | |
} | |
@GetMapping("/{id}") | |
@ResponseStatus(value = HttpStatus.FOUND) | |
@ResponseBody | |
public T findOne(@PathVariable("id") Id id) { | |
return service.findOne(id); | |
} | |
@DeleteMapping("/{id}") | |
@ResponseStatus(value = HttpStatus.OK) | |
public void delete(@PathVariable("id") Id id) { | |
service.delete(id); | |
} | |
} |
And finally here is the LeadController implementation class in Listing 6.
Listing 6 - LeadController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.effectiv.crm.controller; | |
import com.effectiv.crm.business.LeadBusinessDelegate; | |
import com.effectiv.crm.domain.Lead; | |
import org.springframework.web.bind.annotation.*; | |
@RestController | |
@RequestMapping("/leads") | |
public class LeadController extends AbstractBaseController<Lead, String>{ | |
public LeadController(LeadBusinessDelegate service) { | |
super(service); | |
} | |
} |
Thats all for now. The source code is available on Github repository
https://github.com/kdhrubo/playground.git
Comments
Post a Comment