Back to: Spring Boot Tutorials
Spring Boot Service Components
In this article, I am going to discuss Spring Boot Service Components with Examples. Please read our previous article where we discussed Spring Boot File Handling.
What are Spring Boot Service Components?
Service components are class files that have the @Service annotation. These class files are used to write business logic. This is the logic that makes the connection between the end-user and the database.
How to Implement Service Components in Spring Boot?
For this project, we shall create two extra classes, one is the interface, which contains abstract functions. Another class implements this interface and adds logic to the functions. For this exercise, we shall be using the same fruit project we have used before.
In one of our previous exercises, we added some files, such as FruitExceptionController.java and FruitNotFoundException.java. These classes may remain, because they shall not interfere with the service components. The current file structure should be:
Until now, we have implemented our business logic in the REST controller class itself. However, this is not a correct modularised programming practice. Hence, we shall create a new class to handle the business logic and make calls from the REST controller class to this class.
Step 1: Create a new interface with the name FruitService.java in the src/main/java/com/dotnet/restful folder.
Step 2: Modify the newly created file as follows:
We have performed the following modifications:
- Imported the Collection package
- Changed the type of file from class to interface. When initializing the class, VS Code automatically sets the type of file to the class. It can be changed manually by replacing the class keyword with the interface keyword.
- Added four prototype functions: these functions are able to create, update and delete fruits from the application. Also, there is a function to retrieve the list of fruits.
Step 3: Create a file called FruitServiceImpl.java in the src/main/java/com/dotnet/restful directory.
Step 4: Import the following packages into the newly created class:
Step 5: Add the @Service annotation to the class.
Step 6: Modify the code as follows:
The following modifications are performed:
- Created a new repository of fruits and initialized it.
- Coded all of the prototype functions from the interface.
Step 7: Update the FruitServiceController.java class to use the newly created methods.
The class should look as follows as of now:
Change it to the following:
We have performed the following modifications:
- Created an autowired FruitService variable that will handle the business logic.
- Updated all functions to use the newly created functions.
- Removed the Map initialization in the ProductServiceController.java file.
- Removed packages that were no longer required.
Step 8: Save and compile the program. Ensure the compilation is successful.
Step 9: Open Postman and test the functions that we have implemented. Try a GET, PUT, POST, and DELETE request. All of them should work as before.
The GET request URL is http://localhost:8080/products. This must send the reply:
The PUT request URL is http://localhost:8080/products/<id>, where <id> must be populated with the id of the product which is to be updated. The body must contain the ID and new name of the fruit. The reply should be:
The POST request URL is http://localhost:8080/products. The body must contain the ID and name of the new fruit. The reply should be:
The DELETE request URL is http://localhost:8080/products/<id>. The body must be empty. The reply should be:
Congratulations! You have now learned how to implement service components in Spring Boot!
The Complete Example Code
FruitExceptionController.java
package com.dotnet.restful; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice public class FruitExceptionController { @ExceptionHandler(value = FruitNotFoundException.class) public ResponseEntity<Object> exception (FruitNotFoundException e) { return new ResponseEntity<>("Fruit not found!", HttpStatus.NOT_FOUND); } }
FruitNotFoundException.java
package com.dotnet.restful; public class FruitNotFoundException extends RuntimeException { }
Fruits.java
package com.dotnet.restful; public class Fruits { private String id; private String name; public String getId() {return id;} public void setId(String id) {this.id = id;} public String getName() {return name;} public void setName(String name) {this.name = name;} public Fruits (String nid, String nname) { id = nid; name = nname; } }
FruitService.java
package com.dotnet.restful; import java.util.Collection; public interface FruitService { public abstract void createFruit (Fruits fruits); public abstract void updateFruit (String id, Fruits fruits); public abstract void deleteFruit (String id); public abstract Collection<Fruits> getFruits(); }
FruitServiceController.java
package com.dotnet.restful; import org.springframework.beans.factory.annotation.Autowired; //Required web classes import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController public class FruitServiceController { @Autowired FruitService fruitService; @RequestMapping(value = "/products") public ResponseEntity<Object> getProduct() { return new ResponseEntity<>(fruitService.getFruits(), HttpStatus.OK); } @RequestMapping(value = "/products/{id}", method = RequestMethod.PUT) public ResponseEntity<Object> updateProduct(@PathVariable("id") String id, @RequestBody Fruits fruits) { fruitService.updateFruit(id, fruits); return new ResponseEntity<>("Fruit is updated!", HttpStatus.OK); } @RequestMapping(value = "/products/{id}", method = RequestMethod.DELETE) public ResponseEntity<Object> delete(@PathVariable("id") String id) { fruitService.deleteFruit(id); return new ResponseEntity<>("Fruit is deleted!", HttpStatus.OK); } @RequestMapping(value = "/products", method = RequestMethod.POST) public ResponseEntity<Object> createProduct(@RequestBody Fruits product) { fruitService.createFruit(product); return new ResponseEntity<>("Fruit is created!", HttpStatus.CREATED); } }
FruitServiceImpl.java
package com.dotnet.restful; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.springframework.stereotype.Service; @Service public class FruitServiceImpl implements FruitService { private static Map<String,Fruits> database = new HashMap<>(); static { Fruits apple = new Fruits("1","Apple"); database.put(apple.getId(), apple); Fruits banana = new Fruits("2","Banana"); database.put(banana.getId(), banana); Fruits chiku = new Fruits("3","Chiku"); database.put(chiku.getId(), chiku); Fruits dragon = new Fruits("4","Dragon Fruit"); database.put(dragon.getId(), dragon); } @Override public void createFruit(Fruits fruits) {database.put(fruits.getId(), fruits);} @Override public void deleteFruit(String id) {database.remove(id);} @Override public Collection<Fruits> getFruits() {return database.values();} @Override public void updateFruit(String id, Fruits fruits) { database.remove(id); fruits.setId(id); database.put(id, fruits); } }
FruitServiceInterceptor.java
package com.dotnet.restful; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @Component public class FruitServiceInterceptor implements HandlerInterceptor { @Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("In the preHandle() method: Before sending request to controller."); return true; } @Override public void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("In the postHandle() method: Before sending response to client."); } @Override public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception { System.out.println("In the afterCompletion() method: After sending response to client."); } }
FruitServiceInterceptorAppConfig.java
package com.dotnet.restful; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Component public class FruitServiceInterceptorAppConfig implements WebMvcConfigurer { @Autowired FruitServiceInterceptor fruitServiceInterceptor; @Override public void addInterceptors (InterceptorRegistry registry) { registry.addInterceptor(fruitServiceInterceptor); } }
RestfulApplication.java
package com.dotnet.restful; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication public class RestfulApplication { public static void main(String[] args) { SpringApplication.run(RestfulApplication.class, args); } @Bean public RestTemplate getRestTemplate () { return new RestTemplate(); } }
WebController.java
package com.dotnet.restful; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class WebController { @RequestMapping(value = "/view-products") public String viewProducts() {return "view-products";} @RequestMapping(value = "/add-products") public String addProducts() {return "add-products";} }
add-products.html
<!DOCTYPE html> <html> <head> <title>Add Products</title> <script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script> $(document).ready(function() { $("button").click(function() { var productmodel = { id : "5", name : "Fig" }; var requestJSON = JSON.stringify(productmodel); $.ajax({ type : "POST", url : "http://localhost:8080/products", headers : { "Content-Type" : "application/json" }, data : requestJSON, success : function(data) { alert(data); }, error : function(data) { } }); }); }); </script> </head> <body> <button>Click here to submit the form</button> </body> </html>
view-products.html
<!DOCTYPE html> <html> <head> <title>View Products</title> <script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script> $(document).ready(function(){ $.getJSON("http://localhost:8080/products", function(result){ $.each(result, function(key,value) { $("#productsJson").append(value.id+" "+value.name+" "); }); }); }); </script> </head> <body> <h1>Fruits: </h1> <div id = "productsJson"> </div> </body> </html>
In the next article, I am going to discuss Spring Boot Thymeleaf with Examples. Here, in this article, I try to explain Spring Boot Service Components with Examples. I hope you enjoy this Spring Boot Service Components article.