Spring Boot — REST with Custom Error Msg and Log | Code Factory

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

--

--