java开发中异常处理的几种手段

目录

一、枚举类定义错误码和错误描述

二、枚举类只定义错误码,错误描述放在配置文件中

三、使用@RestControllerAdvice

四、将错误码和错误描述放在配置中心


一、枚举类定义错误码和错误描述

package com.sumperman.resuratant.common;

public enum ErrorCodeEnum {
    /*
    * 重复提交数据库端异常
    * */
    REP_COMMIT_ERROR("ORDER001","重复提交"),
    /*
    * 数据库链接失败
    * */
    LINKED_DATABASE_FAIL("SYS001","系统错误"),

    /*
    * 数据库中没有相关的信息
    * */
    NO_QUERY_DATA("DATABASE001","没有查到相关信息")
    ;

    ErrorCodeEnum(String typeCode, String type) {
        this.typeCode = typeCode;
        this.type = type;
    }

    private String typeCode;
    private String type;

    public String getTypeCode() {
        return typeCode;
    }

    public void setTypeCode(String typeCode) {
        this.typeCode = typeCode;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

然后在异常的地方将错误码和错误描述返回:

@Service
public class BookService {

    @Autowired
    private BookMapper booM;

    //根据id查找数据的全部信息
    public HashMap<String,Object> findOneBookById(Long id) {
        HashMap<String,Object> map = new HashMap<>(1);
        Book book = booM.selectByPrimaryKey(id);
        if(book == null) {
            map.put(ErrorCodeEnum.NO_QUERY_DATA.getTypeCode(), ErrorCodeEnum.NO_QUERY_DATA.getType());
        }else {
            map.put(book.hashCode()+ "",book);
        }
        map.put(book.hashCode()+ "",book);
        return map;
    }
}

这是项目中经常使用的一种简单的手段,定义好枚举的错误码和错误描述直接返回给前端即可。优点:简单;缺点:增加或者修改均需要编译、打包、重新部署等。

二、枚举类只定义错误码,错误描述放在配置文件中

public enum ErrorCodeCenter {
    NO_DATA_IN_DATABASE("dining001")
    ;


    private String code = "0000";

    ErrorCodeCenter(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}

使用枚举的错误码

@Service
public class BookService {

    @Autowired
    private BookMapper booM;

    //根据id查找数据的全部信息
    public HashMap<String,Object> findOneBookById(Long id) {
        HashMap<String,Object> map = new HashMap<>(1);
        Book book = booM.selectByPrimaryKey(id);
        if(book == null) {
            map.put("failCode", ErrorCodeCenter.NO_DATA_IN_DATABASE.getCode());
        }else {
            map.put(book.hashCode()+ "",book);
        }

        map.put(book.hashCode()+ "",book);
        return map;
    }
}

 定义配置文件:errorCodeConfig.properties

dining001=查询的数据不存在

 读取配合文件的工具类:

public class PropertiesUtil {

    public static Properties parsePro(String filePath) {
        Properties prop = new Properties();
        //设置格式,否则解析的汉字是乱码
        InputStream in = PropertiesUtil.class.getResourceAsStream(filePath);
        try {
            prop.load(new InputStreamReader(in, "UTF-8"));
            //prop.load(in);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return prop;
    }

}

自定义返回值拦截器:

@ControllerAdvice
public class InterceptResponse implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }
    @Nullable
    @Override
    public Object beforeBodyWrite(@Nullable Object body, MethodParameter methodParameter, MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> aClass,
                                  ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        ServletServerHttpResponse responseTemp = (ServletServerHttpResponse) serverHttpResponse;
        HttpServletResponse resp = responseTemp.getServletResponse();
        ServletServerHttpRequest sshr = (ServletServerHttpRequest) serverHttpRequest;
        HttpServletRequest req = sshr.getServletRequest();
        //此处的 Result 对象是我自定义的返回值类型,具体根据自己需求修改即可
        HashMap<String,Object> ret = new HashMap<>(2);
        HashMap result = (HashMap) body;
        if(body instanceof HashMap && result.get("failCode")!=null) {
                String s = result.get("failCode").toString();
                /*!=null?result.get("failCode").toString():null;*/
                System.out.println("获取的错误码"+s);
                //替换failCode成用户描述
                Properties pro = PropertiesUtil.parsePro("/config/errorCodeConfig.properties");
                System.out.println("获取的pro"+pro);
                System.out.println("获取的结果" + s);
                ret.put("failCode",pro.getProperty(s));
            return ret;
        }
        System.out.println("返回的结果" +result);
        return result;
    }
}

 当发生异常时便可以将错误码转成错误描述返回给前端。该办法有一个好处是可以修改配置文件,然后重新启动程序就可以实现错误描述的修改,免去了编译代码和重新发版的麻烦。但是拦截器是基于切面的,底层是动态代理,性能上有所损失。如果不是经常需要修改错误码对应的描述,其实没多优势,就是看起来高大上,实际上比较鸡肋的一种设计。

三、使用@RestControllerAdvice

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.io.IOException;
import java.util.HashMap;

/**
 * @ControllerAdvice: 表示当前类是异常处理类,给Controller控制器类增强功能的
 *               位置: 在类的上面
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 定义处理异常的方法,当异常发生后,执行这个方法
     * 处理IOException异常
     *
     * @ExceptionHandler: 表示此方法处理相应的异常
     *               属性: value 表示异常的类型
     *               位置: 在方法的上面
     */
    @ExceptionHandler(value = IOException.class)
    public HashMap<String,Object> doNameException(Exception e) {
        System.out.println("doNameException===" + e);
        HashMap<String,Object> ret = new HashMap<>(2);
        ret.put("code","10001");
        ret.put("message","请求失败");
        return ret;
    }

    /**
     * 定义处理异常的方法,当异常发生后,执行这个方法
     * 处理RuntimeException异常
     *
     * @ExceptionHandler: 表示此方法处理相应的异常
     *               属性: value 表示异常的类型
     *               位置: 在方法的上面
     */
    @ExceptionHandler(value = RuntimeException.class)
    public HashMap<String,Object> doAgeException(Exception e) {
        System.out.println("doAgeException" + e);
        HashMap<String,Object> ret = new HashMap<>(2);
        ret.put("code","10002");
        ret.put("message","请求失败");
        return ret;
    }

    //处理其他异常  Error
    @ExceptionHandler
    public HashMap<String,Object> doOtherException(Exception e) {
        System.out.println("doOtherException" + e);
        HashMap<String,Object> ret = new HashMap<>(2);
        ret.put("code","10003");
        ret.put("message","请求失败");
        return ret;
    }
}

该办法是一种粗放式的处理方式,异常很难精细化。但是省去了维护错误和错误描述的麻烦,后台存好日志,也可以查找具体原因,前端展示给用户的是一些可接受的错误描述,适合做应急的处理,个人不推荐这种方式。

四、将错误码和错误描述放在配置中心

微服务框架可以考虑,将错误码和错误描述发布在配置中心,这样可以实现热更新。该方案需要另外搭建环境,暂时不实践。


版权声明:本文为weixin_41670928原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。