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
}
Related
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();
}
I have a RepositoryRestController that exposes resources for some persistent entities.
I have a method on my controller that takes a PersistentEntityResourceAssembler to help me generate the resources automatically.
#RepositoryRestController
#ExposesResourceFor(Customer.class)
#RequestMapping("/api/customers")
public class CustomerController {
#Autowired
private CustomerService service;
#RequestMapping(method = GET, value="current")
public ResponseEntity getCurrent(Principal principal Long id, PersistentEntityResourceAssembler assembler) {
return ResponseEntity.ok(assembler.toResource(service.getForPrincipal(principal)));
}
}
(Contrived example, but it saves going into too much detail about irrelevant details of my use-case)
I'd like to write a test for my controller (my real use-case is actually worth testing), and am planning on making use of #WebMvcTest.
So I have the following test class:
#RunWith(SpringRunner.class)
#WebMvcTest(CustomerController.class)
#AutoConfigureMockMvc(secure=false)
public class CustomerControllerTest {
#Autowired
private MockMvc client;
#MockBean
private CustomerService service;
#Test
public void testSomething() {
// test stuff in here
}
#Configuration
#Import(CustomerController.class)
static class Config {
}
}
But I get an exception saying java.lang.NoSuchMethodException: org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler.<init>()
Presumably something is not being configured correctly here because I'm missing the entire data layer. Is there some way of mocking out the PersistentEntityResourceAssembler? Or another approach I could use here?
I ended up for now with:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
The downsite of it is that the test would start the full Spring application context (but without the server).
I ended up doing a slightly hacky solution here:
I removed PersistentEntityResourceAssembler from the controller method.
I added an #Autowired RepositoryEntityLinks to the controller, on which I call linkToSingleResource to create the links as needed.
I added an #MockBean RepositoryEntityLinks to my test class, and configured the mocking to return something sensible:
given(repositoryEntityLinks.linkToSingleResource(any(Identifiable.class)))
.willAnswer(invocation -> {
final Identifiable identifiable = (Identifiable) invocation.getArguments()[0];
return new Link("/data/entity/" + identifiable.getId().toString());
});
It's far from ideal - I'd love to know if there's a way of getting just enough of the data layer up that I can depend on PersistentEntityResourceAssembler.
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.
I have some servlets and some websocket servlets in my java application.
I use latest stable spring framework.
what I know is that because the servlets are not called by a different bean so they are not injectable and I need to get the applicationContext and use getBean to get the required objects.
is it true?
or can I use #Autowired in servlets somehow ?
so I want to be able to do the following:
#ServerEndpoint(value="/ServConnect")
public class ServConnect {
#Autowired UserDb userDb;
Instead of
#ServerEndpoint(value="/ServConnect")
public class ServConnect {
UserDb userDb;
public void ServConnect() {
// get application context somehow
userDb = appCtx.getBean("userDb");
}
thank you
I have an existing Service layer of Java code that I'd like to use in some REST calls. The way I'd like to do this is to have a user pass in a service ID in the URL, and then on the backend lookup the service and method (in a DB or config file) and call it. For example:
http://foobar.com/rest/car
When this URL is called, I would take the serviceId of "car" and call the CarService. I imagine I'd have a simple configuration:
car=com.foobar.services.CarService
house=com.foobar.services.HouseService
etc..
Is there a way to do this using Spring? One concern I have is not calling the service, but figuring out which method to call. If I had a call to http://foobar.com/services/car/red - how would I pass in the method parameter of 'red' and decide which method to call?
Here's an example of what this would look like in Java:
#RequestMapping(value = "{serviceId}")
#ResponseBody
public Object getMarshalledObject(#PathVariable String serviceId) {
if ("car".equals(serviceId)) {
return getCar();
}
throw new ServiceNotFoundException("Service ID not found.");
}
I would make separate controllers for each service, and have each controller delegate to its corresponding service after it extracted the relevant information from the request.
Due to the nature of #RequestMapping on controllers and their methods, this should be pretty easy:
#RequestMapping("/car")
class CarController {
#Autowired
private CarService service;
#RequestMapping("/{color}")
public Object getCarsByColor(#PathVariable String carColor) {
return service.getCarsByColor(houseColor);
}
}
#RequestMapping("/house")
class HouseController {
#Autowired
private HouseService service;
#RequestMapping("/{houseId}")
public Object getHouseById(#PathVariable int houseId) {
return service.getHouseById(houseId);
}
}
What we have here is two different controllers, with different services, that are mapped by the #RequestMapping that is applied to the class. Further, the controller methods are called by the remaining path elements from the url.
Instead of a simple properties file where you have this...
car=com.foobar.services.CarService
house=com.foobar.services.HouseService
...configure Spring (in the appropriate dispatch configuration file) to manage those beans for you:
<bean id="car" class="com.foobar.services.CarService" />
<bean id="house" class="com.foobar.services.HouseService" />
Assuming your service classes implement a common interface (for example, com.foobar.services.BaseService), in your controller you can autowire them up like so:
#Autowired
#Qualifier("car")
private BaseService _carService;
#Autowired
#Qualifier("house")
private BaseService _houseService;