Abstruct

The three methods of exception handling in SpringBoot are described below.

  • How to handle exceptions for each Controller
  • How to handle exceptions across all Controllers
  • How to handle exceptions by implementing ErrorController

1. How to handle exceptions for each Controller

The Point is @ExceptionHandler(Pattern1Exception.class).

1.1. Pattern1Exception

1
2
3
4
5
public class Pattern1Exception extends Exception{
    public Pattern1Exception(String msg){
        super(msg);
    }
}

1.2. Pattern1RestController

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class Pattern1RestController {
    @RequestMapping("/pattern1")
    public String test() throws Pattern1Exception {
        throwExceptionMethod();
        return "ok";
    }

    private void throwExceptionMethod() throws Pattern1Exception {
        throw new Pattern1Exception("pattern1");
    }

    @ExceptionHandler(Pattern1Exception.class)
    public String pattern1ExceptionHandle(Pattern1Exception e) {
        log.error("pattern1 exception handle : ", e);

        return "ng";
    }
}

2. How to handle exceptions across all Controllers

The Point is @RestControllerAdvice and @ExceptionHandler(Pattern2Exception.class).

2.1. Pattern2ControllerAdvice

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
@Slf4j
public class Pattern2ControllerAdvice {
    @ExceptionHandler(Pattern2Exception.class)
    public String pattern2ExceptionHandle(Pattern2Exception e) {
        log.error("pattern2 exception handle : ", e);
        return "ng";
    }
}

2.2. Pattern2Exception

1
2
3
4
5
public class Pattern2Exception extends Exception{
    public Pattern2Exception(String msg){
        super(msg);
    }
}

2.3. Pattern2RestController1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class Pattern2RestController1 {
    @RequestMapping("/pattern2-1")
    public String test() throws Pattern2Exception {
        throwExceptionMethod();
        return "ok";
    }

    private void throwExceptionMethod() throws Pattern2Exception {
        throw new Pattern2Exception("pattern2-1");
    }
}

2.4. Pattern2RestController2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class Pattern2RestController2 {
    @RequestMapping("/pattern2-2")
    public String test() throws Pattern2Exception {
        throwExceptionMethod();
        return "ok";
    }

    private void throwExceptionMethod() throws Pattern2Exception {
        throw new Pattern2Exception("pattern2-2");
    }
}

3. How to handle exceptions by implementing ErrorController

BasicErrorController.java was used as a reference.

The points are as follows.

  • implements ErrorController
  • public ResponseEntity<String> error(HttpServletRequest request)
    • for http request (@RestController)
  • public ModelAndView errorHtml(HttpServletRequest req, ModelAndView mav)
    • for http page (@Controller)

3.1. MyBasicErrorController

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class MyBasicErrorController implements ErrorController {

    @RequestMapping
    public ResponseEntity<String> error(HttpServletRequest request) {
        var returnData = "my basic error controller";
        return new ResponseEntity<>(returnData, HttpStatus.BAD_REQUEST);
    }

    @RequestMapping
    public ModelAndView errorHtml(HttpServletRequest req, ModelAndView mav) {

        log.error("MyErrorController : RequestURL = {}", req.getRequestURL());

        mav.setStatus(HttpStatus.NOT_FOUND);

        // Thymeleaf template src/main/resources/templates/error.html
        mav.setViewName("error");

        return mav;
    }

    @Override
    public String getErrorPath() {
        return "/error";
    }
}

3.2. Pattern3Exception

1
2
3
4
5
public class Pattern3Exception extends Exception{
    public Pattern3Exception(String msg){
        super(msg);
    }
}

3.3. Pattern3RestController

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class Pattern3RestController {
    @RequestMapping("/pattern3")
    public String test() throws Pattern3Exception {
        throwExceptionMethod();
        return "ok";
    }

    private void throwExceptionMethod() throws Pattern3Exception {
        throw new Pattern3Exception("pattern3");
    }
}

4. build.gradle

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
plugins {
	id 'org.springframework.boot' version '2.4.1'
	id 'io.spring.dependency-management' version '1.0.10.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'

	// for thymeleaf
	compile "org.springframework.boot:spring-boot-starter-thymeleaf"
}

test {
	useJUnitPlatform()
}

5. Reference