Reputation: 351
I built my Spring boot 2.x application using this demo:
https://spring.io/guides/gs/spring-boot/
The problem I'm having is that when there's an exception in Spring/Spring boot, it is printed to standard output. I don't want that. I want to capture them and do other processing such as logging them. I can capture the exceptions of my code but I can't capture the exceptions of Spring/Spring boot. Therefore, how do I capture all exceptions of Spring/Spring Boot 2.x so I can handle them? Is there an easy way to do this, like a generic exception catcher? Can someone show me some code?
My Code:
1. Example.java
package example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class Example extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(Example.class, args);
}
}
2. ExampleController.java
package example;
import org.springframework.stereotype.Controller;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class ExampleController {
@GetMapping ("/example")
public ModelAndView example()
{
MyData data= new MyData();
data.setName("Example");
data.setVersion("1.0");
ModelAndView model = new ModelAndView("page");
model.addObject("page", data);
return model;
}
}
3. GeneralExceptionHandler.java
package example;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
class GeneralExceptionHandler {
@ExceptionHandler(Exception.class)
public void handleException() {
System.out.println("Exception handler");
}
}
4. MyData.java
package example;
import lombok.Data;
@Data
public class MyData {
private String name;
private String version;
}
5. page.jsp
<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<form:form id="myForm" class="form-horizontal"
modelAttribute="page">
<form:label id="name" class="control-label" path="name" for="name">
${page.name}</form:label>
<!-- Error introduced on purpose to force exception. "version123" should be just "version" -->
<form:label id="version" class="control-label" path="version" for="version">
${page.version123}</form:label>
</form:form>
</html>
Upvotes: 3
Views: 13193
Reputation: 692
You can use AOP with pointcut on all public method in Controller. I use BaseController as base class for all my Controllers.
@RestController
@RequestMapping(value = "/api/application")
public class ApllicationController extends ApiController {
//class body with method
}
Then add AOP handling all exceptions throw from public methods in Controller.
@Aspect
@Configuration
public class AOP_ApiController {
@Pointcut("execution (public * *(..))")
private void anyPublicMethod() {}
@Pointcut("execution (* api.ApiController+.*(..))")//here package and class name as base class
private void methodOfApiController() {}
@AfterThrowing(value="methodOfApiController() && anyPublicMethod()", throwing="exception")
public void afterThrowingExceptionFromApiController(JoinPoint joinPoint, Exception exception) throws Exception {
ApiController controller = getController(joinPoint);
String methodName=getMethodName(joinPoint);
logException(exception, controller, methodName);
throw exception;
}
private ApiController getController(JoinPoint joinPoint) {
return (ApiController) joinPoint.getTarget();
}
private String getMethodName(JoinPoint joinPoint) {
return joinPoint.getSignature().getName();
}
private void logException(Exception ufeException, ApiController controller, String methodName) {
//log exception as you want
}
}
Upvotes: 1
Reputation: 2817
You can use @ExceptionHandler
annotation to catch a specific Exception, to do that you can simply annotate a method inside your controller with @ExceptionHandler
and provide it with a specific exception, example :
@ExceptionHandler(DataIntegrityViolationException.class)
public void handleException(){
// do some thing here
}
The limite of this way of doing is that it will handle only exceptions thrown by the @RequestMapping
where the @ExceptionHandler
is declared. To avoid this limitation you can use a Controller advice which allows you to use exactly the same exception handling techniques but apply them across the whole application, example using controller advice:
@ControllerAdvice
class GeneralExceptionHandler {
@ExceptionHandler(DataIntegrityViolationException.class)
public void handleException() {
// Do some thing here
}
}
hint : if you want to catch all checked exceptions you can use @ExceptionHandler(Exception.class)
Upvotes: 4