springboot统一异常处理(返回json)并格式化异常

 更新时间:2023年07月10日 10:59:42   作者:卑微小钟  
这篇文章主要介绍了springboot统一异常处理(返回json)并格式化异常,对spring boot的默认异常处理方式进行修改,要统一返回数据格式,优雅的数据交互,优雅的开发应用,需要的朋友可以参考下

统一异常处理

当用spring boot开发后端时,我们常采用前后端分离的开发策略,这时候要求前端与后端需要进行数据交互,传统的一般采用json数据交互。

这时候我们要对spring boot的默认异常处理方式进行修改了,要统一返回数据格式,优雅的数据交互,优雅的开发应用。

首先我们要了解一般springboot的错误发生在什么地方。

一般发生在controller业务层filter中(如spring security)拦截器中、还有就是未知错误了。

下面我分享一下我的处理方式: @RestControllerAdvice+filter+重写BasicErrorController的处理方式。

@RestControllerAdvice

@RestControllerAdvice+@ExceptionHandler(Exception.class)可以处理经过controller的异常错误

@RestControllerAdvice
public class BaseExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(BaseExceptionHandler.class);
    /**
     * 未知异常
     * @param e 异常
     * @return 统一结果返回
     */
    @ExceptionHandler(Exception.class)
    public R exception(Exception e) {
        logger.error(e.getMessage(), e);
        return R.error().message(e.getMessage());
    }
    @ExceptionHandler(NoHandlerFoundException.class)
    public R noHandlerFoundException(){
        return R.error().message("当前页面不存在");
    }
}

filter捕获所有异常

当错误没有经过controller时,@RestControllerAdvice是不能捕获的,这时候就需要在filter进行处理。

public class ExceptionHandlerFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain){
        try {
            filterChain.doFilter(servletRequest, servletResponse);
        } catch (Exception e) {
            ResponseUtils.out((HttpServletResponse) servletResponse, R.error().message(e.getMessage()));
        }
    }
}

记得filter一定要注册到springboot才有作用,下面是我喜欢的一种方式

@Bean
FilterRegistrationBean<ExceptionHandlerFilter> exceptionFilterRegistrationBean() {
    FilterRegistrationBean<ExceptionHandlerFilter> bean = new FilterRegistrationBean<>();
    bean.setFilter(new ExceptionHandlerFilter());
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);//放在最前面
    return bean;
}

未知异常处理

当发生的异常不知道在哪时,springboot会进行默认异常处理,跳转到 /error

这时我们要统一数据返回就必须要从这下手了,创建一个新的Controller处理/error,继承BasicErrorController,并覆盖其中的方法

@RestController
public class MyErrorController extends BasicErrorController {
    @Autowired
    public MyErrorController(ErrorAttributes errorAttributes,
                             ServerProperties serverProperties,
                             List<ErrorViewResolver> errorViewResolvers) {
        super(errorAttributes, serverProperties.getError(), errorViewResolvers);
    }
    @Override
    public ModelAndView errorHtml(HttpServletRequest request,
                                  HttpServletResponse response) {
        HttpStatus status = getStatus(request);
        Map<String, Object> model = Collections
                .unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
//        return new ModelAndView("error", model, status);
        ResponseUtils.out(response, R.error().code(status.value()).message((String) model.get("error")));
        return null;
    }
    @Override
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
        //可以换成项目中自定义的通信json
        Map<String, Object> resultBody = new HashMap<>(16);
        resultBody.put("success", false);
        resultBody.put("code", body.get("status"));
        resultBody.put("message", body.get("error"));
        Map<String, Object> data = new HashMap<>();
        data.put("timestamp", body.get("timestamp"));
        data.put("path", body.get("path"));
        resultBody.put("data", data);
        return new ResponseEntity<>(resultBody, HttpStatus.OK);
    }
}

配置文件

spring:
  mvc:
    throw-exception-if-no-handler-found: true
  web:
    resources:
      add-mappings: false
server:
  error:
    include-exception: true
  servlet:
    encoding:
      charset: utf-8

统一结果返回的工具类

ResponseUtils

public class ResponseUtils {
    public static void out(HttpServletResponse response, R r) {
        ObjectMapper mapper = new ObjectMapper();
        response.setStatus(HttpStatus.OK.value());
        response.setContentType("application/json;charset=UTF-8");
        try {
            mapper.writeValue(response.getWriter(), r);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

R

@Data
public class R implements Serializable {
    private boolean success;
    private Integer code;
    private String message;
    private Map<String,Object> data;
    private R(){}
    public static R ok(){
        R r = new R();
        r.setSuccess(true);
        r.setCode(200);
        r.setMessage("成功");
        r.setData(new HashMap<>());
        return r;
    }
    public static R error() {
        R r = new R();
        r.setSuccess(false);
        r.setCode(500);
        r.setMessage("失败");
        r.setData(new HashMap<>());
        return r;
    }
    public R success(Boolean success){
        this.success = success;
        return this;
    }
    public R code(Integer code){
        this.code = code;
        return this;
    }
    public R message(String message){
        this.message = message;
        return this;
    }
    public R data(String key, Object value){
        this.data.put(key,value);
        return this;
    }
    public R data(Map<String,Object> map){
        this.setData(map);
        return this;
    }
}

到此这篇关于springboot统一异常处理(返回json)并格式化异常的文章就介绍到这了,更多相关springboot统一异常处理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一篇超详细的Spring Boot对jdbc支持的文章

    一篇超详细的Spring Boot对jdbc支持的文章

    JdbcTemplate 是在JDBC API基础上提供了更抽象的封装,并提供了基于方法注解的事务管理能力。 通过使用SpringBoot自动配置功能并代替我们自动配置beans,下面给大家介绍spring boot中使用JdbcTemplate相关知识,一起看看吧
    2021-07-07
  • 使用mybatis 实现量表关联并且统计数据量的步骤和代码

    使用mybatis 实现量表关联并且统计数据量的步骤和代码

    本文介绍了使用SpringBoot+MyBatis+EasyExcel技术栈实现数据库查询结果导出为Excel文件的步骤,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2025-10-10
  • springboot集成WebSockets广播消息(推荐)

    springboot集成WebSockets广播消息(推荐)

    这篇文章主要介绍了springboot-集成WebSockets广播消息,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-12-12
  • mybatis多个plugins的执行顺序解析

    mybatis多个plugins的执行顺序解析

    这篇文章主要介绍了mybatis多个plugins的执行顺序解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Java8函数式接口Predicate用法示例详解

    Java8函数式接口Predicate用法示例详解

    这篇文章主要为大家介绍了Java8函数式接口Predicate用法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • Java中的ArrayList、LinkedList、HashSet等容器详解

    Java中的ArrayList、LinkedList、HashSet等容器详解

    这篇文章主要介绍了Java中的ArrayList、LinkedList、HashSet等容器详解,集合表示一组对象,称为其元素,有些集合允许重复元素,而另一些则不允许,有些是有序的,有些是无序的,需要的朋友可以参考下
    2023-08-08
  • java后台实现js关闭本页面,父页面指定跳转或刷新操作

    java后台实现js关闭本页面,父页面指定跳转或刷新操作

    这篇文章主要介绍了java后台实现js关闭本页面,父页面指定跳转或刷新操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • mybatisPlus FieldStrategy 策略作用小结

    mybatisPlus FieldStrategy 策略作用小结

    MyBatis-Plus的FieldStrategy枚举用于控制实体字段在插入、更新和查询条件中的空值处理策略,下面就来详细的介绍一下mybatisPlus FieldStrategy 策略,感兴趣的可以了解一下
    2025-12-12
  • java中long和Long有什么区别详解

    java中long和Long有什么区别详解

    这篇文章主要介绍了Java中long和Long是基本数据类型和包装数据类型的区别,包括默认值、内存占用、使用场景、方法支持以及装箱和拆箱,包装数据类型如Integer提供了许多有用的方法,需要的朋友可以参考下
    2025-02-02
  • Java数据结构通关时间复杂度和空间复杂度

    Java数据结构通关时间复杂度和空间复杂度

    对于一个算法,其时间复杂度和空间复杂度往往是相互影响的,当追求一个较好的时间复杂度时,可能会使空间复杂度的性能变差,即可能导致占用较多的存储空间,这篇文章主要给大家介绍了关于Java时间复杂度、空间复杂度的相关资料,需要的朋友可以参考下
    2022-05-05

最新评论