Open In App

Spring Boot – Service Class Example for Displaying Response Codes and Custom Error Codes

Sometimes the error or status messages in webpages would be different from the default error message thrown by Tomcat (or any other server). An important reason for this is websites want to look unique in their approach to their users. So, a customized page for displaying status codes is always better than the standard template. Spring Boot makes it easier in this case to handle several possibilities of wrong URLs entered by the user. To start with, Spring Boot is simple enough for basic configurations with Spring Initializr (https://start.spring.io/). The following steps need to be followed after going to the starter site:

  1. The site would already have default values for group, artifact, package name, etc which can be changed per the requirements.
  2. The latest stable version of Spring would have been selected in the starter by default but you can try the unstable SNAPSHOT and M3 versions if you prefer.
  3. There is also an option to add dependencies. For our tutorial we would be coding only RESTful web services, it would be sufficient to add Spring Web and Spring Boot DevTools dependency. Spring Boot DevTools provides features faster application restarts, LiveReload, and other configurations which ensures that the developer need not restart the application every time the code is changed.

After all the steps, the project can be downloaded as a zip file. After extracting the content in the zip files, it can be imported into the IDE by clicking:



  1. Import -> Maven -> Existing Maven Projects -> Next
  2. Click browse, go to the location where the project is downloaded, select the project folder and click select folder.

Now it’s time to mention the output expectations for this tutorial. The expected output is demonstrated with screenshots. The service class is expected to show output only for GET requests, other methods should display a 405 error code.

 

If the parameter values do not match the specified possible values or no parameter is present, a page not found error page should be displayed.



 

A request to GET /format=text should return a simple return message displaying the current time and status code as OK using HashMap as the response data format.

 

A request to GET /format=page should display the webpage. This is subjective in each case and in this case we are only going to display a sample webpage available in the public domain.

 

The above requirements can be coded in Controller classes annotated with the @RestController annotation as demonstrated in the example given below.

Controller.java File




package com.springboot.springbootdemo;
  
import java.lang.annotation.Repeatable;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.MethodNotAllowedException;
  
@RestController
public class Controller implements ErrorController {
  
    @GetMapping("/format=page")
    public ResponseEntity<Object> page()
    {
        return ResponseEntity.status(HttpStatus.FOUND)
            .location(URI.create(
            .build();
    }
  
    @GetMapping("/format=text")
    public HashMap<String, String> text()
    {
        HashMap<String, String> map
            = new HashMap<String, String>();
        SimpleDateFormat formatter = new SimpleDateFormat(
            "yyyy-MM-dd'T'HH:mm:ssZ");
        Date date = new Date(System.currentTimeMillis());
        String formattedString = formatter.format(date);
        map.put("currentTime", formattedString);
        map.put("status", "OK");
        return map;
    }
  
    @PostMapping("/**")
    public HashMap<String, String> all_except_get()
    {
        HashMap<String, String> map
            = new HashMap<String, String>();
        map.put("status", "401");
        return map;
    }
  
    @DeleteMapping("/**")
    public HashMap<String, String> all_delete()
    {
        HashMap<String, String> map = all_except_get();
        return map;
    }
  
    @PutMapping("/**")
    public HashMap<String, String> all_put()
    {
        HashMap<String, String> map = all_except_get();
        return map;
    }
  
    @PatchMapping("/**")
    public HashMap<String, String> all_patch()
    {
        HashMap<String, String> map = all_except_get();
        return map;
    }
  
    @RequestMapping("/error")
    public ResponseEntity<Object> handleError()
    {
        return ResponseEntity.status(HttpStatus.FOUND)
            .location(URI.create(
                "http://localhost:8002/LoginRegistration/404error.html"))
            .build();
    }
  
    public String getErrorPath() { return "/error"; }
}

An explainer of the code given above:

For example,




@PostMapping("/**")
public HashMap<String, String> all_except_get()
{
    HashMap<String, String> map
        = new HashMap<String, String>();
    map.put("status", "405");
    return map;
}

is the function to handle all POST requests. Similarly, the function given below handles all the DELETE requests:




@PutMapping("/**")
public HashMap<String, String> all_put() {
HashMap<String, String> map = all_except_get();
     return map;
}

As it is evident from the above code, a map with a status code need not be declared and returned each time. Since it has already been defined once, the function is invoked to get the map value into the variable which is then returned. The same procedure is followed for @DeleteMapping(“/**”) and @PatchMapping(“/**”) as well.

application.properties File

server.port=8075
server.error.whitelabel.enabled=false

Before coding the custom error handler methods, it is necessary to add the lines “server.error.whitelabel.enabled=false” in the application.properties file so that the default whitelabel error page can be overridden. 

Note: Spring Boot uses port 8080 by default to start Tomcat. If it is required to use a different port, the port number has to be mentioned in the application.properties file with the server.port=8075.

Now back to coding the error handler methods in the service class. The getErrorPath() method returns the path of the error page, which in this case returns the “/error” which is appended to the URL. Subsequently, there has to be a function to handle the error URL, which is given below:




@RequestMapping("/error")
public ResponseEntity<Object> handleError()
{
    return ResponseEntity.status(HttpStatus.FOUND)
        .location(URI.create(
        .build();
}

Similar to how it was demonstrated for the @GetMapping(“/format=page”), the return statement transfers the control to the error page. Some functions that can be coded using the service class, including the custom error function, are demonstrated and explained in the examples given above.


Article Tags :