SpringBoot 源码分析 -- 定制错误响应以及定制错误的json数据

  • 使用工具Postman-win64-5.5.2-Setup.exe 模拟除浏览器外的其他客户端的错误处理机制
  • 自定义一个异常类
public class UserNotExitException extends RuntimeException {
    public UserNotExitException() {
        super("用户不存在!");
    }
}
  • 自定义错误的Json数据

1.自定义异常处理&定制返回的json数据格式:

  • 使用 @ControllerAdvice 实现全局异常处理,只需要定义类,添加该注解即可
@ControllerAdvice
public class MyExceptionHandler {
    @ExceptionHandler(UserNotExitException.class)
    //不能在参数中声明Map,否则springmvc异常处理不起作用
    //需要返回json格式给客户端显示
    @ResponseBody
    public ModelAndView handleExceptin(Exception e) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("code", "user.notExist");
        mv.addObject("message", e.getMessage());
        return mv;
    }
}

解释:

(1)@ControllerAdvice ,很多可能没有用过这个注解,这是一个增强的 Controller,是SpringMVC的功能,可以实现全局异常处理。

(2)@ExceptionHandler 注解用来指明异常的处理类型,表明处理

UserNotExitException.class

即如果这里指定为 NullpointerException,就只处理空指针的异常类,数组越界等异常就不会进到这个方法中来。

当然,也可以指明为Exception.class,处理所有异常。

  • 存在问题抛出:上面的Controller层代码经过测试,页面并不能显示我们自定义的异常信息,而是之前定义的版本:

原因:出在ModelAndView的使用上, 我们没有跳转页面,所有ModelAndView没有起作用。因此换成Map

@ControllerAdvice
public class MyExceptionHandler {
    //不能在参数中声明Map,否则springmvc异常处理不起作用
    //需要返回json格式给客户端显示
    @ExceptionHandler(UserNotExitException.class)
    @ResponseBody
    public Map<String,Object> handleExceptin(Exception e) {
        Map<String,Object> map = new HashMap<>();
        map.put("code", "user.notExist");
        map.put("message", e.getMessage());
        return map;
    }
}

 

页面效果:

(1)浏览器

(2)模拟其他客户端访问:

  • 存在问题:我们发现浏览器和客户端返回的都是json,没有自适应效果

  • SpringBoot源码剖析:
  • ErrorMvcAutoConfiguration.java中

 

BasicErrorController类:是一个自适应的类,会进行自适应处理

@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes,
      ObjectProvider<ErrorViewResolver> errorViewResolvers) {
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {

表现在:浏览器访问返回“text/html”,客户端访问返回json

@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
		HttpStatus status = getStatus(request);
		Map<String, Object> model = Collections
				.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
		response.setStatus(status.value());
		ModelAndView modelAndView = resolveErrorView(request, response, status, model);
		return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
	}

	@RequestMapping
	public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
		HttpStatus status = getStatus(request);
		if (status == HttpStatus.NO_CONTENT) {
			return new ResponseEntity<>(status);
		}
		Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
		return new ResponseEntity<>(body, status);
	}

因此,自适应解决方法:转发到/error进行自适应响应效果处理

"forward:/error"

@ExceptionHandler(UserNotExitException.class)
    public String handleExceptin(Exception e) {
        Map<String,Object> map = new HashMap<>();
        map.put("code", "user.notExist");
        map.put("message", e.getMessage());
        return "forward:/error";
    }
效果展示:

(1)浏览器

(2)客户端

  • 来到这一步,我们发现,自适应有了,不过浏览器页面状态码 status=200,显然不对。

  • 源码一顿分析,如下:

  •  查看源码给我们提供了解决方法:传入我们自己的错误状态码  4xx 5xx,否则就不会进入定制错误页面的解析流程

    传入自己的错误状态码 如:4xx,5xx
  • @ExceptionHandler(UserNotExitException.class)
        public String handleExceptin(Exception e, HttpServletRequest request) {
            Map<String,Object> map = new HashMap<>();
            //传入自己的错误状态码 如:4xx,5xx
            //Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
            request.setAttribute("javax.servlet.error.status_code", 500);
            map.put("code", "user.notExist");
            map.put("message", e.getMessage());
            return "forward:/error";
        }
  • 效果展示:

(1)浏览器:

(2)客户端

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值