SpringBoot自定错误返回数据

前一篇说到了怎么自定错误页面:链接地址

在一些的错误页面需要一些自定的数据,需要同时将这些数据提交到了错误页面展示,

在此之前要先说一下SpringBoot是怎么获取到的错误信息:

BasicErrorCOntroller类中errorHtml方法中有一段代码

Map<String, Object> model = Collections
                .unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));

在这里有getErrorAttributes方法获取的错误参数,进入这个方法,这个方法是在AbstractErrorController类中

protected Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
        WebRequest webRequest = new ServletWebRequest(request);
        return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace);
    }

发现这个返回的值是errorAttributes中的一个方法,这个errorAttributes对象是一个ErrorAttributes门面里的方法,而ErrorAttributes是一个接中,所以要找一个这个接口的实现类.那么这个实现类在哪里呢?

private final ErrorAttributes errorAttributes;

在上一篇文章《SpringBoot的错误页面解析原理》中说到过这么一段代码,在ErrorMvcAutoConfiguration自动配置错误的类中有如下这么一段代码,

public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver, Ordered {

这个DefaultErrorAttributes类就是ErrorAttributes接口的实现类

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

这个类会自已的创建放入IOC容器中,在第二个注解ConditionalOnMissingBean,这个注解是如果在容器中有一个ErrorAttributes的实现类就不会使用下面的代码来将DefaultErrorAttributes放到容器中.

@Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String, Object> errorAttributes = new LinkedHashMap<>();
        errorAttributes.put("timestamp", new Date());
        addStatus(errorAttributes, webRequest);
        addErrorDetails(errorAttributes, webRequest, includeStackTrace);
        addPath(errorAttributes, webRequest);
        return errorAttributes;
    }

在getErrorAttributes里面可以看到有一些关于添加数据的方法,这些方法我就不粘出来了,可能自已查看

所以在自定数据的时候,我只要重写DefaultErrorAttributes类中的getErrorAttributes方法即可.

实现自定数据-这个例子通过异常来举例

@Controller
public class UserController {

    @RequestMapping(path = {"hello/{username}"})
    public String hello(@PathVariable("username") String user) {
        if(user.equals("aaa")) {
            throw new UserNotFIndExceaption();
        }
        return "index";
    }
    
}

这段代码很容易看懂,就是一个控制器,通过hello/{username}来访问,当username是aaa出现异常

创建一个异常继承RuntimeException,这样可以抛出来

public class UserNotFIndExceaption extends RuntimeException{

    public UserNotFIndExceaption() {
        super("用户不存在");
    }    
}

创建一个全局的异常处理,当触发了UserNotFIndExceaption来执行下面的方法

@ControllerAdvice
public class MyExecaption{
    
    @ExceptionHandler(UserNotFIndExceaption.class)
    public String handleException(Exception e,HttpServletRequest request) {
        
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("code","user.notexist");
        map.put("message", e.getMessage());
        map.put("qwe","123");
        request.setAttribute("javax.servlet.error.status_code", 404);
        return "forward:/error";
    }
}

继承DefaultErrorAttributes类重写getErrorAttributes方法

import java.util.Map;

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

@Component
public class MyErrorAtt extends DefaultErrorAttributes{

    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
        map.put("com","123");
        return map;
    }
}

这样当在BasicErrorCOntroller中获取错误的数据的时候就会调用这个方法

这样几乎就实现了自定数据,为什么说是几乎是因为现在还没有办法拿到在MyExecaption类中定义的数据,

因为在里只是转发到了/error,并没有将MyExecaption里面定义的map数据携带过去,

这些数据可以能过request携带,因为放到request中有其它的放法中也可以得到,修改MyExecaption代码中的handleException.

@ExceptionHandler(UserNotFIndExceaption.class)
    public String handleException(Exception e,HttpServletRequest request) {
        
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("code","user.notexist");
        map.put("message", e.getMessage());
        map.put("sgc","123");
        request.setAttribute("javax.servlet.error.status_code", 404);
        request.setAttribute("ext", map);
        return "forward:/error";
    }

在自已创建的MyErrorAtt类中将数据得到就好了,在getErrorAttributes的参数中有一个WebRequest的对象,通过它就可以得到了,修改MyErrorAtt中的getErrorAttributes方法

@Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
        map.put("com","123");
        //通过webRequest得到放在reuqest中的方法
        map.put("ext",webRequest.getAttribute("ext",0));
        return map;
    }

这样就可以在前端得到自定的数据了

webRequest.getAttribute("ext",0)中有第二个参数这个是表示通过什么得到这个数据,在RequestAttributes有两个属性,在Rewqust中得到数据设置为0就好了

public interface RequestAttributes {

    /**
     * Constant that indicates request scope.
     */
    int SCOPE_REQUEST = 0;

    /**
     * Constant that indicates session scope.
     * <p>This preferably refers to a locally isolated session, if such
     * a distinction is available.
     * Else, it simply refers to the common session.
     */
    int SCOPE_SESSION = 1;

注:我使用的是SpringBoot的2.1.9的版本,这个里面有两个类的名字叫DefaultErrorAttributes需要使用的是

import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;

这个包名要看清楚,不要导错了包.

Last modification:October 15th, 2019 at 03:49 pm
如果觉得我的文章对你有用,请随意赞赏

Leave a Comment