-
-
Save jonikarppinen/662c38fb57a23de61c8b to your computer and use it in GitHub Desktop.
package com.company.project.controllers; | |
import com.company.project.model.api.ErrorJson; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.boot.autoconfigure.web.ErrorAttributes; | |
import org.springframework.boot.autoconfigure.web.ErrorController; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import org.springframework.web.bind.annotation.RestController; | |
import org.springframework.web.context.request.RequestAttributes; | |
import org.springframework.web.context.request.ServletRequestAttributes; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
import java.util.Map; | |
/** | |
* Based on the helpful answer at http://stackoverflow.com/q/25356781/56285, | |
* with error details in response body added. | |
* | |
* @author Joni Karppinen | |
* @since 20.2.2015 | |
*/ | |
@RestController | |
public class CustomErrorController implements ErrorController { | |
private static final String PATH = "/error"; | |
@Value("${debug}") | |
private boolean debug; | |
@Autowired | |
private ErrorAttributes errorAttributes; | |
@RequestMapping(value = PATH) | |
ErrorJson error(HttpServletRequest request, HttpServletResponse response) { | |
// Appropriate HTTP response code (e.g. 404 or 500) is automatically set by Spring. | |
// Here we just define response body. | |
return new ErrorJson(response.getStatus(), getErrorAttributes(request, debug)); | |
} | |
@Override | |
public String getErrorPath() { | |
return PATH; | |
} | |
private Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) { | |
RequestAttributes requestAttributes = new ServletRequestAttributes(request); | |
return errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace); | |
} | |
} |
Hi,
Thanks! But I met a problem, maybe you know it. That is if request method is PUT, when throw exception e.g. valid param failure, it does not call error method in CustomErrorController, but if request method is POST, everything is OK. Do you know why?
should we need to provide a custom template page for this? How does this actually works?
this is a REST controller (see annotation at top of class). So the ErrorJson
instance is returned as the HTTP response body. No View or template is used.
How could one do the same with a template in thymeleaf. Can one add the error attributes to a model and pass it to thymeleaf (or jsp)?
You can also add path to the ErrorJson object, which shows in which URL the exception occurred. Like:
this.path = (String) errorAttributes.get("path");
(populated by spring boot as other variables)
I am getting this error :
2017-02-06 13:15:31.805 WARN 12584 --- [ost-startStop-1] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'mappingError' method
org.springframework.http.ResponseEntity<java.lang.String> com.cisco.eloqua.app.MappingError.error(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
to {[/error]}: There is already 'customErrorController' bean method
org.springframework.http.ResponseEntity<java.lang.String> com.cisco.eloqua.app.CustomErrorController.error(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) mapped.
2017-02-06 13:15:31.981 INFO 12584 --- [ost-startStop-1] utoConfigurationReportLoggingInitializer :
Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2017-02-06 13:15:32.002 ERROR 12584 --- [ost-startStop-1] o.s.boot.SpringApplication : Application startup failed
I modified little bit:
@RequestMapping(value = PATH)
ResponseEntity error(HttpServletRequest request, HttpServletResponse response) {
HttpHeaders responseHeaders = new HttpHeaders();
HttpStatus httpStatus = org.springframework.http.HttpStatus.valueOf(response.getStatus());
return new ResponseEntity("Cannot Process Your Request Right Now! Please Contact the Administrator for more detail.", responseHeaders,httpStatus);
}
package io.apptrade.spring.controller;
import io.apptrade.spring.model.ErrorJson;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.web.ErrorAttributes;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
@log
@RestController
@propertysource("classpath:application.properties") //custom-error-controller.debug place in file and set true/false
@configuration
public class CustomErrorController implements ErrorController{
private static final String PATH = "/error";
@Value("${custom-error-controller.debug}")
private boolean debug;
@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
@Autowired
private ErrorAttributes errorAttributes;
@RequestMapping(value = PATH)
ResponseEntity<ErrorJson> error(HttpServletRequest request, HttpServletResponse response){
return ResponseEntity.status(response.getStatus())
.body(
new ErrorJson(response.getStatus(), getErrorAttributes(request, debug)
)
);
}
@Override
public String getErrorPath(){
return PATH;
}
private Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
RequestAttributes requestAttributes = new ServletRequestAttributes(request);
return errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace);
}
}
package io.apptrade.spring.model;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.stereotype.Component;
import java.util.Map;
@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
@Getter(AccessLevel.PUBLIC)
@Setter(AccessLevel.PROTECTED)
@NoArgsConstructor
@component
public class ErrorJson{
private Integer status;
private String error;
@JsonIgnore
private String message;
private String timeStamp;
private String trace;
public ErrorJson(int status, Map<String, Object> errorAttributes) {
this.status = status;
this.error = (String) errorAttributes.get("error");
this.message = (String) errorAttributes.get("message");
this.timeStamp = errorAttributes.get("timestamp").toString();
this.trace = (String) errorAttributes.get("trace");
}
}
THIS Works!! and has been tested. Produces JSON
Thank you very much!
Hi
i get this error:
java: cannot access org.springframework.web.reactive.function.server.ServerRequest
class file for org.springframework.web.reactive.function.server.ServerRequest not found
Slightly change the class to use webrequest
`public class CustomErrorController implements ErrorController {
private static final String PATH = "/error";
@Value("${custom-error-controller.debug}")
private boolean debug;
@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
@Autowired
private ErrorAttributes errorAttributes;
@RequestMapping(value = PATH)
ResponseEntity<ErrorJson> error(WebRequest webRequest, HttpServletResponse response){
return ResponseEntity.status(response.getStatus())
.body(
new ErrorJson(response.getStatus(), getErrorAttributes(webRequest, debug)
)
);
}
@Override
public String getErrorPath(){
return PATH;
}
private Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
return errorAttributes.getErrorAttributes(webRequest, includeStackTrace);
}
}`
here is my implementation:
File: application.properties
server.error.whitelabel.enabled=false
File: OverrideErrorWhitePage.java
@Controller
public class OverrideErrorWhitePage implements ErrorController {
private static final String ERROR_PATH = "/error";
@ResponseBody
@ResponseStatus(HttpStatus.NOT_FOUND)
@RequestMapping(value = ERROR_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
public EcatalogGenericResponse handleError() {
return ResponseBodyBuilder.notFoundHandler();
}
@Override
public String getErrorPath() {
return ERROR_PATH;
}
}
File:App.java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
File: EcatalogGenericResponse.java
public class EcatalogGenericResponse<T> {
private String responseCode;
private String responseMessage;
private T data;
}
I want to know how to send error response to custom page in Latest Spring Boot. I tried below mention code but its converts message to JSON format.
@RestController
public class MyCustomErrorHandlerController implements ErrorController {
private static final String PATH = "/error";
@Value("${debug}")
private boolean debug;
@Autowired
private ErrorAttributes errorAttributes;
@RequestMapping(value = PATH)
ErrorJson error(HttpServletRequest request, HttpServletResponse response) {
// Appropriate HTTP response code (e.g. 404 or 500) is automatically set by Spring.
// Here we just define response body.
//return new Error(response.getStatus(), getErrorAttributes(request, debug));
return new ErrorJson(response.getStatus(), getErrorAttributes(request, debug));
}
@Override
public String getErrorPath() {
return PATH;
}
private Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
WebRequest webRequest = new ServletWebRequest(request);
return errorAttributes.getErrorAttributes(webRequest, includeStackTrace);
}
}
I am getting HTTP ERROR 406 code. Anyone has this problem before, at server side everything looks good, but client rejecting the request. I am thinking it is because, browser expecting html and from the server we are trying to send json response?
And the class for defining the error response body; something like this or whatever suits you:
If you're new to this: Spring implicitly converts objects (that controller methods return) into JSON, using the Jackson library.
Edit: For some needs, using
@ExceptionHandler
is arguably a handier approach than a customErrorController
. Here's an example of that: https://gist.github.com/jonikarppinen/6ade2554946df21db0a6.