Spring Boot — REST with Custom Error Msg and Log | Code Factory
4 min readNov 2, 2020
Donate : Link
WordPress Blog : Link
Applications… : Link
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.10.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.codeFactory</groupId>
<artifactId>spring-boot-custom-err-response-and-logger</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-custom-err-response-and-logger</name>
<description>Rest endpoint with validation</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build></project>
SpringBootCustomErrResponseAndLogger.java
package com.codeFactory;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/**
* @author code.factory
*/
@SpringBootApplication
public class SpringBootCustomErrResponseAndLogger { public static void main(String[] args) {
SpringApplication.run(SpringBootCustomErrResponseAndLogger.class, args);
}}
WebMvcConfig.java
package com.codeFactory;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import com.codeFactory.utility.LogInterceptor;/**
* @author code.factory
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer { @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor());
}
}
EmployeeController.java
package com.codeFactory.controller;import javax.validation.Valid;import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;import com.codeFactory.model.Employee;/**
* @author code.factory
*/
@RestController
@Validated
public class EmployeeController { @PostMapping(value = "employee", consumes = "application/json", produces = "application/json")
public ResponseEntity<Employee> displayEmployee(@Valid @RequestBody Employee employee) {
return ResponseEntity.ok(employee);
}}
Employee.java
package com.codeFactory.model;import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;/**
* @author code.factory
*/
public class Employee { @Min(value = 1, message = "Id can't be less than 1 or bigger than 999999")
@Max(999999)
private int id; @Size(max = 15, message = "Name must be less than 15 characters")
@NotBlank
@Pattern(regexp = "^[A-Za-z ]*$", message = "Only characters allowed")
private String name; @NotBlank
@Pattern(regexp = "^[A-Za-z ]*$", message = "Only characters allowed")
private String designation; @NotBlank
private String address; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getDesignation() {
return designation;
} public void setDesignation(String designation) {
this.designation = designation;
} public String getAddress() {
return address;
} public void setAddress(String address) {
this.address = address;
}}
LogInterceptor.java
package com.codeFactory.utility;import java.util.UUID;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;/**
* @author code.factory
*/
public class LogInterceptor extends HandlerInterceptorAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(LogInterceptor.class); @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String requestId = UUID.randomUUID().toString();
log(request, response, requestId);
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
request.setAttribute("requestId", requestId);
return true;
} @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
super.afterCompletion(request, response, handler, ex);
long startTime = (Long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTime;
LOGGER.info("Request Id: {}, Handle: {} , Request take time: {}",
request.getAttribute("requestId"), handler, executeTime);
LOGGER.info("Response status: {}, Content type: {}",
response.getStatus(), response.getContentType());
} private void log(HttpServletRequest request, HttpServletResponse response, String requestId) {
LOGGER.info("Request Id: {}, Host {} HttpMethod: {}, URI: {}",
requestId, request.getHeader("host"), request.getMethod(), request.getRequestURI());
}
}
ValidationUtil.java
package com.codeFactory.utility;import java.util.ArrayList;
import java.util.List;import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.WebRequest;/**
* @author code.factory
*/
@ControllerAdvice
public class ValidationUtil { @ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
@ResponseBody
public Error handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
BindingResult result = ex.getBindingResult(); List<String> errorList = new ArrayList<>();
result.getFieldErrors().forEach((fieldError) -> {
errorList.add(fieldError.getObjectName() + "." + fieldError.getField() + " : "
+ fieldError.getDefaultMessage() + " : rejected value [" + fieldError.getRejectedValue() + "]");
});
result.getGlobalErrors().forEach((fieldError) -> {
errorList.add(fieldError.getObjectName() + " : " + fieldError.getDefaultMessage());
}); return new Error(HttpStatus.BAD_REQUEST, errorList);
} public static class Error {
private int errorCode;
private String error;
private List<String> fieldErrors = new ArrayList<>(); public Error(HttpStatus status, List<String> fieldErrors) {
this.errorCode = status.value();
this.error = status.name();
this.fieldErrors = fieldErrors;
} public int getErrorCode() {
return errorCode;
} public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
} public String getError() {
return error;
} public void setError(String error) {
this.error = error;
} public List<String> getFieldErrors() {
return fieldErrors;
} public void setFieldErrors(List<String> fieldErrors) {
this.fieldErrors = fieldErrors;
}
}
}
com.codeFactory.utility.LogInterceptor : Request Id: 1ae345fb-7d48-4f94-b507-d4e18dd29d36, Host localhost:8080 HttpMethod: POST, URI: /employee
com.codeFactory.utility.LogInterceptor : Request Id: 1ae345fb-7d48-4f94-b507-d4e18dd29d36, Handle: com.codeFactory.controller.EmployeeController#displayEmployee(Employee) , Request take time: 736
com.codeFactory.utility.LogInterceptor : Response status: 200, Content type: application/json
com.codeFactory.utility.LogInterceptor : Request Id: 210e19d3-11d5-415d-9a3b-e89f85c63667, Host localhost:8080 HttpMethod: POST, URI: /employee
com.codeFactory.utility.LogInterceptor : Request Id: 210e19d3-11d5-415d-9a3b-e89f85c63667, Handle: com.codeFactory.controller.EmployeeController#displayEmployee(Employee) , Request take time: 114
com.codeFactory.utility.LogInterceptor : Response status: 400, Content type: application/json