SpringBoot2.1.6定制错误数据时无法获取并显示异常

定制错误数据有status,timeStamp,exception,message,ext,其中status,timeStamp,exception是从容器中获取的,但是异常确没有显示,如下:

在这里插入图片描述
首先,前端页面是不可能出现获取数据的代码写错的情况,因为下面几个一模一样的获取方法,人家都出来了,就它没出来,所以应该是后端的问题:
在这里插入图片描述

下面为处理请求的controller

/**
 * @Classname HelloController
 * @Description TODO
 * @Date 19-7-24 上午9:02
 * @Created by xns
 */
@Controller
public class HelloController {
    @ResponseBody
    @RequestMapping("/hello")
    public String hello(@RequestParam("user") String user){
    //如果用户是aaa,则抛出UserNotExistException这个异常
        if(user.equals("aaa")){
            throw new UserNotExistException();
        }
        return "Hello World";
    }
}

自定义的异常类:

/**
 * @Classname UserNotExistException
 * @Description TODO
 * @Date 19-7-27 上午11:49
 * @Created by xns
 */
public class UserNotExistException extends RuntimeException {
    public UserNotExistException() {
        super("用户不存在!!!");
    }
}

下面是为controller定制异常处理器的类:

import com.xns.springboot.exception.UserNotExistException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * @Classname MyExceptionHandler
 * @Description TODO
 * @Date 19-7-27 上午11:58
 * @Created by xns
 */

//异常指示器
@ControllerAdvice //定义全局异常处理类
public class MyExceptionHandler {
    @ExceptionHandler(UserNotExistException.class) //handleException就会处理所有 Controller层抛出的UserNotExistException及其子类的异常
    public String handleException(Exception e, HttpServletRequest request){
        Map<String,Object> map = new HashMap<>();
        //传入我们自己的错误状态码 4xx,5xx等
        request.setAttribute("javax.servlet.error.status_code",500);
        map.put("code","user.notexist");
        map.put("message","用户出错了");
        request.setAttribute("ext",map);
        //转发到/error让BasicErrorController进行自适应页面
        return "forward:/error";
    }
}

下面的代码来给容器中加入我自己定义的ErrorAttributes

import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;

import java.util.Map;

/**
 * @Classname MyErrorAttributes
 * @Description TODO
 * @Date 19-7-27 下午3:17
 * @Created by xns
 */
//给容器中加入我们自己定义的ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {

    //看这里,重点
    public MyErrorAttributes(ServerProperties serverProperties) {
        super(serverProperties.getError().isIncludeException());
    }

    //返回值的map就是页面和json能获取的所有字段
    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String,Object> map = super.getErrorAttributes(webRequest,includeStackTrace);
        map.put("company","xns");

        //我们异常处理器携带的数据
        Map<String,Object> ext = (Map<String,Object>)webRequest.getAttribute("ext",0);
        map.put("ext",ext);
        return map;
    }
}

解决办法:写一个构造器,这样,就可以正常获取异常信息了
第一步:
resources/application.properties下,即配置文件里,写上:

server.error.include-exception=true

第二步:
在自己定义的ErrorAttributes里添加如下代码

 public MyErrorAttributes(ServerProperties serverProperties) {
        super(serverProperties.getError().isIncludeException());
 }

添加完成后,这个类的完整代码如下:

import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;

import java.util.Map;

/**
 * @Classname MyErrorAttributes
 * @Description TODO
 * @Date 19-7-27 下午3:17
 * @Created by xns
 */
//给容器中加入我们自己定义的ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {

    public MyErrorAttributes(ServerProperties serverProperties) {
        super(serverProperties.getError().isIncludeException());
    }

    //返回值的map就是页面和json能获取的所有字段
    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String,Object> map = super.getErrorAttributes(webRequest,includeStackTrace);
        map.put("company","xns");

        //我们异常处理器携带的数据
        Map<String,Object> ext = (Map<String,Object>)webRequest.getAttribute("ext",0);
        map.put("ext",ext);
        return map;
    }
}

正常显示:
在这里插入图片描述
原因:下面是相关源码ErrorMvcAutoConfiguration,一个自动配置类

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
// Load before the main WebMvcAutoConfiguration so that the error View is available
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class, WebMvcProperties.class })
public class ErrorMvcAutoConfiguration {

	private final ServerProperties serverProperties;

	private final DispatcherServletPath dispatcherServletPath;

	private final List<ErrorViewResolver> errorViewResolvers;

	public ErrorMvcAutoConfiguration(ServerProperties serverProperties, DispatcherServletPath dispatcherServletPath,
			ObjectProvider<ErrorViewResolver> errorViewResolvers) {
		this.serverProperties = serverProperties;
		this.dispatcherServletPath = dispatcherServletPath;
		this.errorViewResolvers = errorViewResolvers.orderedStream().collect(Collectors.toList());
	}
	
	@Bean
	@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
	public DefaultErrorAttributes errorAttributes() {
		return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());
	}

看这段代码:

@Bean
	@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
	public DefaultErrorAttributes errorAttributes() {
		return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());
	}

点进DefaultErrorAttributes发现这段代码:

/**
	 * Create a new {@link DefaultErrorAttributes} instance.
	 * @param includeException whether to include the "exception" attribute
	 */
	public DefaultErrorAttributes(boolean includeException) {
		this.includeException = includeException;
	}

看注释,它说,参数includeException说明是否包含exception,所以这里应该传入的是true
看上一段代码,所以this.serverProperties.getError().isIncludeException()的值应该为true,点进getError(),来到了ServerProperties类看到:

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {

和方法

public ErrorProperties getError() {
		return this.error;
	}

它返回了一个ErrorProperties类型的值,然后我们再点进isIncludeException(),来到了ErrorProperties类,看到:

public boolean isIncludeException() {
		return this.includeException;
	}

所以这里的数值应该返回true
又因为在ErrorMvcAutoConfiguration这个类中有这样一个注解:

@EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class, WebMvcProperties.class })

它开启了自动配置,并且将ServerProperties.class, ResourceProperties.class, WebMvcProperties.class这几个类和我们的application.properties进行了绑定
所以我们通过application.properties来设置includeException的值为true(即server.error.include-exception=true)
添加完成这个,还是不能出现,(下面为我自己的推断,如有错误,请指正)

    @Bean
	@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
	public DefaultErrorAttributes errorAttributes() {
		return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());
}

看这段代码,注解@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)的意思是当ErrorAttributes类型的Bean不存在于BeanFactory中时才创建这个Bean ,但是上面,我已经将自己定义的ErrorAttributes加入了容器,所以这个组件不会被注册.所以我就想着自己实现一个,new一个DefaultErrorAttributes所以,就添加了下面的代码:

public MyErrorAttributes(ServerProperties serverProperties) {
        super(serverProperties.getError().isIncludeException());
    }

这里的serverProperties直接从容器中获取值,因为由SpringBoot自动配置原理,可以知道,它已经被加入到容器中,用到的时候可直接获取.
初学SpringBoot,若有问题,请指正,谢谢!

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值