在Web应用开发中,异常处理是一个非常重要的环节。Spring Boot 提供了强大的异常处理机制,允许开发者通过全局异常处理来统一处理应用中的各种异常。本文将详细分析如何在Spring Boot中实现全局异常处理,并通过示例代码展示如何自定义错误页面。
Spring Boot 提供了多种异常处理方式,包括:
@ExceptionHandler
注解在Controller中处理特定异常。@ControllerAdvice
和@ExceptionHandler
注解实现全局异常处理。ErrorController
或使用ErrorAttributes
来自定义错误页面。本文将重点介绍全局异常处理和自定义错误页面的实现。
@ControllerAdvice
和 @ExceptionHandler
@ControllerAdvice
是一个全局异常处理类,它可以捕获所有Controller中抛出的异常。结合@ExceptionHandler
注解,可以针对不同类型的异常进行不同的处理。
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<String> handleException(Exception ex) { return new ResponseEntity<>("An error occurred: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<String> handleResourceNotFoundException(ResourceNotFoundException ex) { return new ResponseEntity<>("Resource not found: " + ex.getMessage(), HttpStatus.NOT_FOUND); } }
在这个示例中,GlobalExceptionHandler
类捕获了所有Exception
类型的异常,并返回一个包含错误信息的ResponseEntity
。对于ResourceNotFoundException
类型的异常,返回404状态码。
为了更好地管理异常,我们可以自定义异常类。例如,定义一个ResourceNotFoundException
类:
public class ResourceNotFoundException extends RuntimeException { public ResourceNotFoundException(String message) { super(message); } }
在Controller中抛出这个异常:
@RestController @RequestMapping("/api") public class MyController { @GetMapping("/resource/{id}") public String getResource(@PathVariable Long id) { if (id == null) { throw new ResourceNotFoundException("Resource not found with id " + id); } return "Resource found"; } }
除了处理所有异常,我们还可以针对特定的异常类型进行处理。例如,处理NullPointerException
:
@ExceptionHandler(NullPointerException.class) public ResponseEntity<String> handleNullPointerException(NullPointerException ex) { return new ResponseEntity<>("Null pointer exception: " + ex.getMessage(), HttpStatus.BAD_REQUEST); }
Spring Boot 默认提供了/error
路径来处理错误,并返回一个默认的错误页面。我们可以通过自定义ErrorController
或使用ErrorAttributes
来定制错误页面。
ErrorController
通过实现ErrorController
接口,我们可以自定义错误处理逻辑。
@Controller public class MyErrorController implements ErrorController { @RequestMapping("/error") public String handleError(HttpServletRequest request) { Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code"); Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception"); if (statusCode == HttpStatus.NOT_FOUND.value()) { return "error-404"; } else if (statusCode == HttpStatus.INTERNAL_SERVER_ERROR.value()) { return "error-500"; } else { return "error"; } } @Override public String getErrorPath() { return "/error"; } }
在这个示例中,MyErrorController
根据不同的HTTP状态码返回不同的错误页面。例如,404错误返回error-404.html
,500错误返回error-500.html
。
ErrorAttributes
ErrorAttributes
接口提供了获取错误信息的便捷方式。我们可以通过实现ErrorAttributes
接口来自定义错误信息的获取方式。
@Component public class MyErrorAttributes extends DefaultErrorAttributes { @Override public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) { Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, options); errorAttributes.put("customAttribute", "This is a custom attribute"); return errorAttributes; } }
在这个示例中,MyErrorAttributes
类继承了DefaultErrorAttributes
,并添加了一个自定义属性customAttribute
。
在src/main/resources/templates
目录下,我们可以创建自定义的错误页面模板。例如,error-404.html
和error-500.html
。
error-404.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>404 Not Found</title> </head> <body> <h1>404 Not Found</h1> <p>The requested resource was not found.</p> </body> </html>
error-500.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>500 Internal Server Error</title> </head> <body> <h1>500 Internal Server Error</h1> <p>An internal server error occurred.</p> </body> </html>
为了确保全局异常处理生效,我们需要在Spring Boot应用中进行一些配置。
@ControllerAdvice
确保GlobalExceptionHandler
类被Spring Boot扫描到。通常,Spring Boot会自动扫描@ControllerAdvice
注解的类。
ErrorController
确保MyErrorController
类被Spring Boot扫描到,并且/error
路径被正确映射。
ErrorAttributes
确保MyErrorAttributes
类被Spring Boot扫描到,并且自定义的错误属性能够被正确获取。
为了验证全局异常处理是否生效,我们可以编写一些测试用例。
ResourceNotFoundException
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class GlobalExceptionHandlerTest { @Autowired private TestRestTemplate restTemplate; @Test public void testResourceNotFoundException() { ResponseEntity<String> response = restTemplate.getForEntity("/api/resource/999", String.class); assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); assertEquals("Resource not found: Resource not found with id 999", response.getBody()); } }
NullPointerException
@Test public void testNullPointerException() { ResponseEntity<String> response = restTemplate.getForEntity("/api/resource/null", String.class); assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); assertEquals("Null pointer exception: null", response.getBody()); }
@Test public void testCustomErrorPage() { ResponseEntity<String> response = restTemplate.getForEntity("/nonexistent", String.class); assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); assertTrue(response.getBody().contains("404 Not Found")); }
通过本文的示例分析,我们了解了如何在Spring Boot中实现全局异常处理和自定义错误页面。全局异常处理可以帮助我们统一管理应用中的异常,提高代码的可维护性和可读性。自定义错误页面则可以提升用户体验,使错误信息更加友好和直观。
在实际开发中,我们可以根据具体需求选择合适的异常处理方式,并结合自定义错误页面来提供更好的用户体验。希望本文的内容能够帮助读者更好地理解和应用Spring Boot中的异常处理机制。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。