Java Spring boot: Repository & Service - java

please can you explain me shortly for what are responsible Repository class and Service class in Spring boot. As I know repo is for doing all the database operations and interacting with DB but somewhere I heard from videos that Service class talks to DB so I got confused and can't find any definition for them.
Thank you very much for your time.

#Service assigns Beans to handle logic
#Repository assigns Beans to take care of communicating with the DB

Service class is where you perform your business logic which you do not want the user to view and repository class is where you perform database operations on an entity.
There is one more class called controller which is used to interact with web requests which are then forwarded to service methods and if there is need for data from database they send it forward to repository class.
Hope this explains. It is usually a design pattern for building production level applications
Here is a short example
#Controller // Controller class
public class RequestController{
#Autowired
private ServiceClass service;
#RequestMapping("")
public string index(#Param("name") String name){
return service.getString();
}
#Service
public class ServiceClass{
#Autowired
private StuRepository repo;
public String getString(String name){
if(name.equals("Rahul")
return repo.findName();
else
throw new Error("business logic performed here");
}
#Repository
public interface StuRepository extends JpaRepository<Model,Integer>{
String findName();
}

Related

Using #Autowired and #Qualifier in the Controller to change datasource for the Service

I'm new to using Spring boot, and currently running into an issue.
I have an application with 3 layers, Controller, Service and Repository.
TL:DR, find a diagram of my setup here:
3Tier setup
So how do I make this work? Being able to switch around the repository in the controller class?
The controller calls the service, which then uses classes in the repository to return the correct data (after doing logic magic when needed). I am also using Hibernate and H2 inmemory to make SQL connections easier, however for testing purposes I would like to have hardcoded data and methods in another repository class. My controller uses the H2 inmem datasource via the service, and my test-class uses the hardcoded-datasource.
Using simple dependency injection I can add the required respository class to the service class-constructor, and depending on either using the test-class or controller class this works fine.
However, I would like to use the #Autowired annotation, and found out that you can use #Qualifier in the service class to switch between the repo classes that get autowired. However, I don't want to do this in the service class (have it hard coded there) but do it dynamically and let the datasource choice be injected by the controller or test class.
Is this even possible, and how should I do this?
You should use #service annotation on the top of ServiceImpl class
and then #autowired Service in Controller.
your package structure should be as follows:
entity
repository
service and service implements
controller
example for entities:
#Entity
#Table(name = "table_name")
public class NameEntiy implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private Long id;
#Column(name = "name_column_in_your_database")
private String data;
// constructors, getter, setter, hascode, equals and string methods
}
example for Repository:
#Repository("nameEntityRepositoryQualifier")
public interface INameEntityRepository extends JpaRepository<NameEntity, Long> {
}
example for service:
public interface INameEntityService {
public void save(NameEntity entity);
//yours methods
}
example for service implements:
#Service("nameEntityServiceQualifier")
public class NameEntityServiceImpl implements INameEntityService {
#Autowired
#Qualifier("nameEntityRepositoryQualifier")
INameEntityRepository nameEntityRepository ;
#Override
public void save(NameEntity entity) {
nameEntityRepository.save(entity);
}
}
example for controllers:
#Controller or #RestController
#RequestMapping("/pathController")
public class YourController {
#Autowired
#Qualifier("nameEntityServiceQualifier")
private INameEntityService nameEntityService;
//yours controller methods
}

Access to Spring Boot / MongoDB controller-classes from other classes

I'm making a REST API with Spring Boot and MongoDB in Java.
I've got, for instance, a Location class, with a corresponding LocationRepository and LocationController classes.
To access the Location-database (LocationRepository), I need to do it through the LocationController (as far as I know). I've got functions in this controller that run on POST/GET requests, and it's working just fine when sending requests from the front-end server (Nuxt.js w/ Axios) or just through Insomnia/Postman.
However, if I wan't to access the Location-database from the backend, and from another class in my program, I'm not sure how to do it.
I suppose I either need to send API-requests locally, or I need to get the actual instance of my LocationController to run functions on it.
Is sending API-requests locally like this bad practice?
Can I somehow get a hold of the instance of my LocationController? This is all managed through Spring, which I assume instanciates the controllers somewhere, but I have no idea where, or how to get a hold of them.
Here is an example of one of my controllers:
#RestController
#RequestMapping("api/locations")
public class LocationController {
#Autowired
private LocationRepository repository;
#RequestMapping(value = "/all", method = RequestMethod.GET)
public List<Location> getAllLocations(#RequestBody String body) {
return repository.findAll();
}
}
Appreciate any help!
EDIT: Using #Autowired LocationController locationController in any class that needs access to this seems to work.
You don't have to instantiate your controller, your repository is in charge of fetching data from database. You can do exctly the same that you're doing inside your controller :
public class MyGreatClass{
#Autowired
private LocationRepository repository;
public void myGreatMethod() {
List<Location> locations = repository.findAll();
// Do the stuff with location
}

When using Spring, call local method directly or use API

Just started learning how to use Spring! As a best practice if you are working on a spring method and you need to add/leverage a piece of functionality that you've already built out in another Spring Class which is accessible via the API, should you use the established API or call it directly?
Suppose you have a CustomerService component
#Service
public class CustomerService {
public Customer getCustomerById(CustomerId id) {
//your code here
}
}
Suppose now that you have an OrderService that needs to find the customer before placing an new order. You definitively would prefer to find the customer using your existing CustomerService API.
#Service
public class OrderService {
#Autowire private CustomerService customerService;
public void placeOrder(Order order, CustomerId custId) {
Customer customer = customerServive.getCustomerById(custId);
//your code here
}
}
That totally make sense.
Now suppose you have a controller to expose your CustomerService to your web clients.
#RestController
public CustomerController {
#Autowire private CustomerService customerService;
#GET("/customer/{custId}")
public Customer getCustomer(#Param CustomerId custId){
return customerService.getCustomerById(custId);
}
}
From you OrderServer you definitely don't need to/should not make an HTTP remote call to this HTTP service to get a customer. That would not make sense if they are both colocated in the JVM. It is a hell of a lot simpler and safer to just use your local service.
If however your CustomerService runs in a different process/JVM, one entirely different than the one it runs your OrderService than it would make sense to make a remote HTTP call to get your customer.
In a case like this, you probably would have a CustomerServiceGateway to make the remote call.
For example, in the orders api
interface CustomerService {
Order getCustomerById(CustomerId custId);
}
And then a gateway implementation:
#Service
public class CustomerServiceGateway implements CustomerService {
#Autowire private RestTemplate restTemplate;
Order getCustomerById(CustomerId custId) {
return restTemplate.getForObject("http://customer-api/customer/{custId}", custId);
}
}
This is an oversimplification, but even so you can see that is much harder to do and it only make sense if you try to invoke remote services.

#EJB workflowDao is null in service layer

I'm trying to figure out how to setup a Service/Dao layer in my application. I've found a few dozen resources all with different ways on how to do it and decided to follow the model found here: How should EntityManager be used in a nicely decoupled service layer and data access layer?
I can't figure out what I'm missing that's causing this NPE.
Usage:
#Path("/helloworld")
public class MyController {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String TestRequest() {
Workflow workflow = new Workflow();
workflow.setName("test");
WorkflowService workflowService = new WorkflowService();
workflowService.save(workflow);
return "Workflow ID:";
}
}
My Dao:
#Stateless
public class WorkflowDao {
#PersistenceContext(unitName = "unit")
private EntityManager entityManager;
public int save(Workflow workflow) {
entityManager.persist(workflow);
return workflow.getId();
}
}
My Service:
#Stateless
public class WorkflowService {
#EJB
WorkflowDao workflowDao;
public int save(Workflow workflow) {
int id = workflowDao.save(workflow); //throws NullPointerException because workflowDao is null
return id;
}
}
This is my first time setting up a Java project (only have worked on 1 before and it used Spring) so please keep that in mind if this looks horribly wrong.
WorkflowDao is not an EJB, it's a POJO with a#Stateless annotation. So naturally, injecting it with #EJB fails, creating a null workflowDao attribute and eventually producing a NullPointerException.
To make WorkflowDao into a full-fledged EJB, besides having a #Stateless or #Stateful annotation it needs to implement a local, remote or both interfaces, and those interfaces must be annotated respectively with #Local and #Remote. Please refer to the tutorial for details.
Also, quite possibly (this can be application server-dependent) you'll have to register the EJB in the application's xml descriptor files - for instance, in web.xml's <ejb-local-ref> element.
As a side note - it's not a good idea to use an EJB as a DAO, an EJB is typically used for implementing business logic (true, persist/merge operations can be called from here) but the actual persistence layer nowadays is implemented using JPA. In other words, WorkflowService should be the EJB service, there's no need to inject an EJB into it, and there's no need for a separate DAO layer - JPA entities fulfill this role.
If you instantiate your WorkflowService manually, the container wont perform any injection, since your WorkflowService is not managed by the Container.
I suggest you:
Annotate your Jax-RS Resource #Stateless
Inject your WorkfloService via #EJB as a member
Implementing a Local or Remote Interface is not necessary anymore
#Path("workflows")
#Stateless
public class WorkFlowResource{
#EJB
WorkflowService workflowService;
#GET
#Produces(MediaType.TEXT_PLAIN)
public String TestRequest() {
Workflow workflow = new Workflow();
workflow.setName("test");
workflowService.save(workflow);
return "Workflow ID:";
}
}

How can implement an Interface from a Remote stateless session bean?

im programming a project and im trying to apply multitier architecture.
Right now ive got 2 EJB, business and persistence and a shared jar. Due a funcional requirment, persistence must be replaceable. I made an Interface called IPersistence.
Then I crated a remote session bean called "persistence" inside the persistence EJB and put the remote interface in the shared library. Now, i need to call an IPersitence using injection from the business. How can i do that? Maybe the whole idea is wrong. I need some advice.
Thanks!
Here is a simple example where you have a car repository/DAO that abstracts the persistence from the business logic by not exposing if it is stored in a database, file, XML etc. The business class then injects an instance to be able to - in this case - save to an database. However you could have made other classes that implemented the CarRepository and provide other means for saving data in your application without touching other parts of your code.
Persistence layer
Interface for the repository/DAO
#Local
public interface CarRepository {
List<Car> findAllCars();
// Many other methods
}
Repository (Domain driven design) or Data Access Object
#Stateless
public class CarSqlRepository implements CarRepository {
#PersistenceContext(unitName = "MyUnit")
private EntityManager entityManager;
public List<Car> findAllCars() {
}
// Many other methods
}
Service/business layer
#Stateless
public class CarService {
#Inject
private CarRepository carRepository;
public List<Car> findAllCars() {
return carRepository.findAllCars();
}
// Many other methods
}

Categories