Java开发不得不知道的全局异常处理

关于异常处理逻辑,无论是在Controller层、Service层还是其他的什么位置我们需要做到的就是捕获异常并将其转化为自定义异常。捕获抛出异常在service文件夹下创建ExceptionService.javapackage com.javafamily.familydemo.service;import com.javafamily.familydemo.exception.PetsException;import com.javafamily.familydemo.exception.PetsExceptionType;import org.springframework.stereotype.Service;@Servicepublic class ExceptionService {    public void sError() {        try {            // 错误的驱动类            Class.forName("com.mysql.jdbc.xxxx.Driver");        } catch (ClassNotFoundException e) {            throw new PetsException(                    PetsExceptionType.SYSTEM_ERROR,                    "在XXX业务,sError()方法内,出现ClassNotFoundException,请告知管理员");        }    }    public void uError(int input) {        // 输入小于0,则抛出异常        if (input < 0) { //模拟业务校验失败逻辑            throw new PetsException(                    PetsExceptionType.USER_INPUT_ERROR,                    "数据输入错误,请确认后重新输入!");        }    }}1234567891011121314151617181920212223242526272829303132复制代码类型:[java]在任意一个controller文件中调用服务层if (id==1){    exceptionService.sError();}else {    exceptionService.uError(-1);}12345复制代码类型:[java]全局异常处理器@ControllerAdvice监听所有Controller与@ExceptionHandler注解相结合,当系统里面抛出的异常是自定义异常就交给下面的方法来处理。使用ExceptionResponse.error(e)包装为通用的接口数据结构返回给前端。package com.javafamily.familydemo.exception;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;@ControllerAdvicepublic class HandlerException {    // 处理主动转换的自定义异常    @ExceptionHandler(PetsException.class)    @ResponseBody    public ExceptionResponse petsException(PetsException e) {        if (e.getCode() == PetsExceptionType.SYSTEM_ERROR.getCode()) {            // 400异常不需要持久化,将异常信息告知用户        }        return ExceptionResponse.error(e);    }    // 处理在程序中未能捕获的异常    @ExceptionHandler(Exception.class)    @ResponseBody    public ExceptionResponse exception(Exception e) {        return ExceptionResponse.error(new PetsException(                PetsExceptionType.OTHER_ERROR));    }}123456789101112131415161718192021222324252627复制代码类型:[java]执行程序并在postman中进行访问。根据上面的截图可以看出我们给的状态码与真正的状态码是不相同的,说明我们只是利用了HTTP状态码去表达他的含义。所以我们要将两个状态码统一。在exception文件夹下创建GlobalResponseBodyAdvice实现ResponseBodyAdvice接口,在数据返回给前端之前做最后一步拦截处理。ResponseBodyAdvice的处理过程在全局异常处理的后面。package com.javafamily.familydemo.exception;import org.springframework.core.MethodParameter;import org.springframework.http.HttpStatus;import org.springframework.http.MediaType;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.stereotype.Component;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;@Component@ControllerAdvice// 在数据返回给前端之前做最后一步拦截处理public class GlobalResponseBodyAdvice implements ResponseBodyAdvice {    @Override    public boolean supports(MethodParameter returnType, Class converterType) {        //return returnType.hasMethodAnnotation(ResponseBody.class);        return true;    }    @Override    public Object beforeBodyWrite(Object body,                                  MethodParameter returnType,                                  MediaType selectedContentType,                                  Class selectedConverterType,                                  ServerHttpRequest request,                                  ServerHttpResponse response) {        // 如果响应结果是JSON数据类型        if (selectedContentType.equalsTypeAndSubtype(                MediaType.APPLICATION_JSON)) {            // 为HTTP响应结果设置状态码,状态码就是Response的code,二者达到统一            response.setStatusCode(                    HttpStatus.valueOf(((ExceptionResponse) body).getCode())            );            return body;        }        return body;    }}1234567891011121314151617181920212223242526272829303132333435363738394041复制代码类型:[java]执行程序,在postman中进行访问。优化我们有了GlobalResponseBodyAdvice作为在数据返回给前端之前做最后一步拦截处理就不再需要Controller层上封装ExceptionResponse封装类。可以在GlobalResponseBodyAdvice中进行统一的封装。完整代码:package com.javafamily.familydemo.exception;import org.springframework.core.MethodParameter;import org.springframework.http.HttpStatus;import org.springframework.http.MediaType;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.stereotype.Component;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;@Component@ControllerAdvicepublic class GlobalResponseBodyAdvice implements ResponseBodyAdvice {    @Override    public boolean supports(MethodParameter methodParameter, Class aClass) {        return true;    }    @Override    public Object beforeBodyWrite(Object body,                                  MethodParameter methodParameter,                                  MediaType mediaType,                                  Class aClass,                                  ServerHttpRequest serverHttpRequest,                                  ServerHttpResponse serverHttpResponse) {        // 如果响应结果是JSON数据类型        if (mediaType.equalsTypeAndSubtype(                MediaType.APPLICATION_JSON)) {            if (body instanceof ExceptionResponse) {                ExceptionResponse exceptionResponse = (ExceptionResponse) body;                if (exceptionResponse.getCode() != 999) {                    serverHttpResponse.setStatusCode(HttpStatus.valueOf(                            exceptionResponse.getCode()                    ));                }                return body;            } else {                serverHttpResponse.setStatusCode(HttpStatus.OK);                return ExceptionResponse.success(body);            }        }        return body;    }}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748复制代码类型:[java]Controller或全局异常处理响应的结果body是ExceptionResponse直接return给前端。Controller或全局异常处理响应的结果body不是ExceptionResponse,就将body封装为ExceptionResponse之后再return给前端。服务端数据校验的异常处理在上面我们已经讲了一个服务端数据校验的异常处理的代码,通过if判断,如果参数不合法就会抛出自定义的异常。但是这种写法有些麻烦,我们再介绍几种简单的方法。异常校验的规范及常用注解我们在model文件夹下的PetsVO.java的name字段添加@NotEmpty注解。public class PetsVO {    private long id;    // message是要返回给前端用户看的信息    @NotEmpty(message = "name不能为空")    private String name;    private String varieties;    private Date createTime;}12345678复制代码类型:[java]在controller层的savePets()中添加@Valid注解。除了@NotEmpty注解以外,还有很多常见的注解可以加在PetsVO的属性字段上,然后在参数校验的方法上加@Valid注解进行使用。注解用法@Null被注释的元素必须为 null@NotNull被注释的元素必须不为 null@AssertTrue被注释的元素必须为 true@AssertFalse被注释的元素必须为 false@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值@DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值@DecimalMax(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值@Size(max, min)被注释的元素的大小必须在指定的范围内@Digits (integer, fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内@Past被注释的元素必须是一个过去的日期@Future被注释的元素必须是一个将来的日期@Pattern(value)被注释的元素必须符合指定的正则表达式HibernateValidator附加的注解注解用法@Email被注释的元素必须是电子邮箱地址@Length被注释的字符串的大小必须在指定的范围内@NotEmpty被注释的字符串的必须非空@Range被注释的元素必须在合适的范围内执行代码,在postman中进行测试。将name空出来触发异常。用户输入异常的全局处理数据校验失败时会抛出异常BindException或MethodArgumentNotValidException。所以我们对这两种异常做全局处理,防止重复编码带来困扰,使其返回给前端的信息更精确。package com.javafamily.familydemo.exception;import org.springframework.validation.BindException;import org.springframework.validation.FieldError;import org.springframework.web.bind.MethodArgumentNotValidException;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;@ControllerAdvicepublic class HandlerException {    @ExceptionHandler(MethodArgumentNotValidException.class)    @ResponseBody    public ExceptionResponse handleBindException(MethodArgumentNotValidException ex) {        FieldError fieldError = ex.getBindingResult().getFieldError();        return ExceptionResponse.error(new PetsException(PetsExceptionType.USER_INPUT_ERROR,                fieldError.getDefaultMessage()));    }    @ExceptionHandler(BindException.class)    @ResponseBody    public ExceptionResponse handleBindException(BindException ex) {        FieldError fieldError = ex.getBindingResult().getFieldError();        return ExceptionResponse.error(new PetsException(PetsExceptionType.USER_INPUT_ERROR,                fieldError.getDefaultMessage()));    }    // 处理主动转换的自定义异常    @ExceptionHandler(PetsException.class)    @ResponseBody    public ExceptionResponse petsException(PetsException e) {        if (e.getCode() == PetsExceptionType.SYSTEM_ERROR.getCode()) {            // 400异常不需要持久化,将异常信息告知用户        }        return ExceptionResponse.error(e);    }    //处理程序员在程序中未能捕获(遗漏的)异常    @ExceptionHandler(Exception.class)    @ResponseBody    public ExceptionResponse exception(Exception e) {        return ExceptionResponse.error(new PetsException(                PetsExceptionType.OTHER_ERROR));    }}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748复制代码类型:[java]给出关于字段校验比较详细的提示信息。断言我们可以通过一下一行断言代码,来代替以上五行代码:Assert.isTrue(input<0,"数据输入错误,请确认后重新输入!");使用org.springframework.util.Assert断言,如果不满足条件就抛出IllegalArgumentException。可以使用下面的全局异常处理函数:

(0)

相关推荐

  • Spring 注解面面通 之 @RequestBody

      @RequestBody用于将完整请求正文映射到控制器处理方法的参数中,请求正文通过HttpMessageConverter进行转换.   注解解析   ① required:     请求正文是 ...

  • SpringBoot学习---SpringBoot打War包上传到tomcat

    一. pop.xml配置文件 二. 排除内置tomcat 三. 修改Springboot启动类 四. Maven打包工具package 五. Xftp上传到webapps目录下 六. 访问测试 一. ...

  • java使用POI实现excel文件的导入和导出(通用方法)

    说明: 1.文件导出功能: 通过反射获取实体类的属性名和属性值,写入文件是第一行为属性名,从第二行开始为属性值,调用时只需传入一个任意实体集合(List)即可. 2.文件导入功能 文件导入功能需要定义 ...

  • Springboot 全局统一处理异常

    import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind ...

  • 直播软件开发,你还有哪些不知道的直播开发难点

    直播软件开发的热度未曾退去,伴随直播行业的崛起,用户们也更乐意在直播软件上花费更多的时间,开发商开始把开发的重点放在直播软件开发上,随着入场者变多,开发的工作量也在不断增加,有不少想要自己购买源码搭建 ...

  • 揭秘|你所不知道的“一二级联动开发”!

    今天我们用案例的形式来讲讲土地"一二级联动开发",本故事纯属牧诗杜撰,如有雷同,请以本故事为准. 某本土龙头房企A公司与当地政府签订框架协议锁定了1000亩土地一级整理,政府缺钱, ...

  • 你所不知道的中国美色

    颜色它是一种语言,它是有自己的表达方式的.我们中国传统颜色,是几千年来积累下来的中国人看待世界的一个语言表达方式,而且这个语言,它跟我们日常使用的语言都不一样.我们日常使用的语言都是有逻辑性的,你要过 ...

  • 公共基础知识:你所不知道的人文常识汇总

    人文常识在中国传统文化中浩如烟海,博大精深,如何在浩如烟海的人文中把握准考点所在,是非常困难的,但是在我们历年事业单位考察中均有个别题目与当年的重大时政新闻紧密相关.小编根据2020年以来的时政帮各位 ...

  • 半手工壶,你所不知道的别样世界

    半手工壶,又称模具壶,一说起半手工壶,大家的第一反应是依靠模具制作,但就是这"依靠模具制作",也大有文章,不尽相同,主要在模具的运用上.而模具运用的不同,主要体现在身筒的制作上. ...

  • 飞机上您所不知道的25个真相

    现如今,飞机以舒适.方便与节省时间等原因成为出行首选的交通方式之一.可您是否知道,为何尽量不喝飞机上的冲泡茶饮,又为何在落地时必须关闭电子设备?飞机里潜藏着很多我们不知道的真相! [1]用来泡制咖啡和 ...

  • 把牙膏挤一点抹在脚趾上,看完你会感谢我的,不知道的人太多了!

    牙膏是我们每天都需要用到的清洁用品,它除了可以清洁我们的口腔和牙齿,你知道她还有什么妙用吗?今天给大家分享一些牙膏的妙用,每一个妙用都能对我们的生活起到很好的帮助,一起来看看吧! 妙用1:去除腥味  ...

  • 摄影爱好者不能不知道的50个技巧!

    摄影爱好者不能不知道的50个技巧!

  • 赚钱看客厅,存钱看卧室,不可不知道的招财秘法!

    如今社会竞争激烈,每一个人都在为了获取更多的财富,以改善生活而努力奔波.其实,这仅仅靠个人的努力,是远远不够的,有时还需要有风水的助力. 在新年即将来临之际,世德就来给大家讲一讲,如何通过风水来催旺财 ...