SpringMVC异常处理

本文详细阐述了Spring MVC中的异常解析器如何统一处理控制器抛出的异常,包括ExceptionHandler注解的使用,以及ResponseStatus用于自定义异常响应的实践。通过实例展示了如何配置全局和特定异常处理器,以及如何定制HTTP状态码和错误消息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异常解析器

doDispatch:执行请求的分发

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    ...
    try{
        //SpringMVC执行流程
        ...
        // 这里执行控制器
		mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
		...
	}
	catch (Exception ex) {
		dispatchException = ex;  //当控制器中抛出异常时,会跳转到这里
	}
	catch (Throwable err) {
		...
	}
	//这里进行结果的处理
	processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	...
}			

processDispatchResult:执行控制器返回结果的处理

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
		@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
		@Nullable Exception exception) throws Exception {
	boolean errorView = false;
	
    //如果控制器发生异常
	if (exception != null) {
		if (exception instanceof ModelAndViewDefiningException) {
			logger.debug("ModelAndViewDefiningException encountered", exception);
			mv = ((ModelAndViewDefiningException) exception).getModelAndView();
		}
		else {
		    //获取处理器
			Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
			//processHandlerException方法用于处理异常
			mv = processHandlerException(request, response, handler, exception);
			errorView = (mv != null);
		}
	}
	...
}

processHandlerException:处理异常

@Nullable
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
		@Nullable Object handler, Exception ex) throws Exception {

	// Success and error responses may use different content types
	request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);

	// Check registered HandlerExceptionResolvers...
	ModelAndView exMv = null;
	if (this.handlerExceptionResolvers != null) {
	    //对handlerExceptionResolvers进行遍历,当执行第二个元素时,进行异常的处理
		for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
			exMv = resolver.resolveException(request, response, handler, ex);
			if (exMv != null) {
				break;
			}
		}
	}
	...
	throw ex;
}

HandlerExceptionResolverComposite类的resolveException:对异常解析器进行遍历,每个解析器依次对异常进行处理

@Override
@Nullable
public ModelAndView resolveException(
		HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {

	if (this.resolvers != null) {
	    //对异常解析器进行遍历,每个解析器依次对异常进行处理
		for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) {
			ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
			if (mav != null) {
				return mav;
			}
		}
	}
	return null;
}

在这里插入图片描述
三个异常解析器:
ExceptionHandlerExceptionResolver:解析@ExceptionHandler
ResponseStatusExceptionResolver:解析@ResponseStatus
DefaultHandlerExceptionResolver:如果Spring自带的异常没被以上两个解析器处理,则使用默认处异常解析器处理

@ExceptionHandler

该注解标注的方法用于处理该控制器中抛出的指定异常

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("/getUserList")
    public List<User> getUserList(){
        int i = 1/0;  //这里抛出异常
        List<User> users = userService.list(null);
        return users;
    }
    //@ExceptionHandler标注的方法用于处理该控制器中抛出的指定异常
    @ExceptionHandler(value = {ArithmeticException.class})
    public void handleException(Exception e){
        System.out.println(e.getMessage());
    };
}
=====output:
http://localhost:8080/user/getUserList请求后,控制台打印:
/ by zero
# 相当于handleException处理(try-catch)了这个控制器中抛出的异常

统一处理异常

  • @ControllerAdvice默认对所有Controller的抛出异常进行处理。basePackages可以指定要拦截的Controller
  • @RestControllerAdvice = @ControllerAdvice + @ResponseBody
  • 该注解本质也是个Component,被标注的类会加入ioc容器
/**
 * 统一异常处理  
 */
@RestControllerAdvice  
public class GlobalExceptionHandler {
    /**
     *  @ExceptionHandler指定出现什么异常时执行这个方法。
     * 全局异常处理:@ExceptionHandler中写Exception.class,表示只要出现异常,就会执行该方法
     * @param e
     * @return  CommonResponseVo是自定义的同一返回格式
     */
    @ExceptionHandler(Exception.class)
    public CommonResponseVo error(Exception e){  
        System.out.println("全局异常处理...");
        return CommonResponseVo.onfailed(e.getMessage());
    }

    /**
     * 特定异常处理
     * 当异常发生时,先找特定异常,如果没有,则向上找父类,一直找到Exception.class的全局异常处理方法
     * @param e
     * @return
     */
    @ExceptionHandler(ArithmeticException.class)
    public CommonResponseVo error(ArithmeticException e){
        System.out.println("特定异常ArithmeticException处理...");
        return CommonResponseVo.onfailed(e.getMessage());
    }

    /**
     * 自定义异常处理  需要在异常处try-catch,然后抛出自定义异常
     * @param e
     * @return
     */
    @ExceptionHandler(GuliException.class)
    public CommonResponseVo error(GuliException e){
        System.out.println("自定义异常GuliException处理...");
        return CommonResponseVo.onfailed(e);
    }
}

@ResponseStatus

带有@ResponseStatus注解的异常类会被ResponseStatusExceptionResolver 解析。
一般标注在自定义的异常类上,并且抛出该异常时可以显示@ResponseStatus中定义的属性值

1. 自定义异常

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value = HttpStatus.NOT_FOUND,reason = "用户未找到!")
public class UserNotFoundException extends RuntimeException {
}

2. Controller抛出自定义异常

@GetMapping("/login/{username}/{password}")
public String login(@PathVariable String username,@PathVariable String password){
    //抛出异常
    if(!"admin".equals(username)){
        throw  new UserNotFoundException();
    }
    return "success";
}

显示的错误信息会根据@ResponseStatus的value变化,reason属性的值没显示,不知道为啥
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值