自定义系列 之 自定义异常

为什么自定义异常呢?主要有以下几个理由值得你去做:

1,统一异常,团队开发一定要有规则,不能自己想怎么抛异常就怎么抛,不仅仅是格式,可以对每种业务新建一个异常。

2,结合业务中断程序运行,有时候java代码本身不会有错误,但是不符合业务逻辑。例如用户想要发表评论,系统就会提示他要先登录,在这之前是没有java语法错误的,但是从业务逻辑上来说(或保证之后不会出错)这就需要抛错。

3,可以隐藏底层异常,只打印业务日志,不用输出堆栈信息。例如在查看商品详情这个操作中,可能包含查询商品基本信息,获取用户与商品关系,加入分享商品链接,载入商品评论,计算最近地铁站。。。多个步骤。如果在计算地铁站距离这一步出错了,那么可以直接打印汉字说明错误在这一步。便于排查。

自定义异常有几种方式:

1.新建异常类(继承自Exception或RuntimeException)

自定义父类异常

/**
 * @author uiao
 * @Title: 自定义父类异常
 * @date 2018/8/615:36
 */
public class BaseException extends Exception {
    public BaseException() {}

    public BaseException(String message) {
        super(message);
    }
}

按照业务来自定义各种异常

/**
 * @author uiao
 * @Title: 自定义Bean转换异常
 * @date 2018/8/615:42
 */
public class BeanConverterException extends BaseException {
    public BeanConverterException() {
    }

    public BeanConverterException(String message) {
        super(message);
    }
}
/**
 * @author uiao
 * @Title: 自定义账单异常
 * @date 2018/8/615:45
 */
public class BillException extends BaseException {
    public BillException() {
    }

    public BillException(String message) {
        super(message);
    }

    public String customException() {
        return "账单异常";
    }
}
/**
 * @author uiao
 * @Title: 自定义支付异常
 * @date 2018/8/615:40
 */
public class PayException extends BaseException {
    public PayException() {
        super("支付异常");
    }

    public PayException(String message) {
        super(message);
    }
}

异常的使用

扫描二维码关注公众号,回复: 2617761 查看本文章
/**
 * @author uiao
 * @Title: 自定义异常使用
 * @date 2018/8/615:58
 */
@Service
public class ExceptionDemoServiceImpl {

    public void payTest() throws PayException {
        if (true) {
            throw new PayException("支付金额和订单金额不相符,请核对金额");
        }
    }

    public void billTest() throws PayException, BillException {
        if (true) {
            throw new BillException("账单异常");
        }
        if (true) {
            throw new PayException();
        }
    }
}

测试类

/**
 * @author uiao
 * @Title: 自定义异常测试类
 * @date 2018/8/615:47
 */
@Controller
@RequestMapping(value = "exception", method = RequestMethod.GET)
public class ExceptionDemoController {

    org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(ExceptionDemoController.class);
    @Autowired
    private ExceptionDemoServiceImpl impl;

    @GetMapping("beanConverter")
    public void converter(HttpServletRequest request) {
        try {
            throw new BeanConverterException("bean 转换异常");
        } catch (BeanConverterException e) {
            logger.error(e.getMessage());
        }
    }

    @GetMapping("pay")
    public void pay(HttpServletRequest request) {
        try {
            impl.payTest();
        } catch (PayException e) {
            logger.error(e.getMessage());
        }
    }

    @GetMapping("bill")
    public void bill(HttpServletRequest request) {
        try {
            impl.billTest();
        } catch (BaseException e) {
            if (e instanceof BillException) {
                logger.error(((BillException) e).customException());
            } else if (e instanceof PayException) {
                logger.error(e.getMessage());
            }
        }
    }
}

2,重写HandlerExceptionResolver接口的resolveException方法做一个全局的异常处理(基于spring mvc)

    这种方法不同于第一种,上一个可以针对每一种业务定义异常,这种方法作用范围更大,在Controller层通过throws把异常抛出来,交给spring mvc来处理,重写的方法里判断异常类型(当然这些异常类型也可以是我们自定义的)进而做出处理。

全局处理异常类

public class ExceptionHandler implements HandlerExceptionResolver,Ordered {

    private static Logger logger = Logger.getLogger(ExceptionHandler.class);

    private static Integer order = Integer.MIN_VALUE;
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                                         Object handler, Exception e) {
        logger.error("异常请求URL:" + httpServletRequest.getRequestURL());
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            logger.warn("处理器的方法为:" + method.getName());
        }
        logger.error("异常栈 ==>> ");
        logger.error(ExceptionUtils.parseException(e));

        if (e instanceof NoHandlerFoundException){
            responseJson(httpServletResponse,"请求的页面不存在");
            return new ModelAndView((String) null);
        } else if(e instanceof ServletException){
            responseJson(httpServletResponse,e.getMessage());
            return new ModelAndView((String) null);
        }
        else if (e instanceof PermissionDefineException){
            responseJson(httpServletResponse, "您没有权限进行该操作");
            return new ModelAndView((String) null);
        }
        else if (e instanceof BaseException) {
            responseJson(httpServletResponse, "数据异常~ 请稍后再试");
            return new ModelAndView((String) null);
        }else {
            responseJson(httpServletResponse, "服务器异常~ 请稍后再试");
            return new ModelAndView((String) null);
        }
    }

    private void responseJson(HttpServletResponse response,String content){
        response.setHeader("Content-type", "text/html;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        ApiResponseBean respBean = ApiResponseBuilder.buildResponse(-1,content);
        PrintWriter out =null;
        try {
           out =  response.getWriter();
           out.write(JsonUtils.toJSONString(respBean));
           out.flush();
            out.close();
        } catch (IOException e) {
            logger.error(ExceptionUtils.parseException(e));
        }finally {
            if(out!=null){
                out.close();
            }
        }
    };


    @Override
    public int getOrder() {
        return order;
    }
}

加入xml文件

    <!--定义全局异常处理-->
    <bean class="com.uiao.web.exception.ExceptionHandler"/>

另外:spring boot也支持注解的异常处理,后续补上。

3,在web.xml里配置(基于spring mvc)

其实这个不能算是异常处理,因为不涉及异常的一些捕获抛出,所有流程都是正常执行的,只是对最后结果做一个再处理。

<error-page>
        <error-code>404</error-code>
        <location>/notFound</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/sysError</location>
    </error-page>

异常结果处理类

@Controller
public class ExceptionController {

    @RequestMapping("notFound")
    @ResponseBody
    public Map<String,Object> processNotFountException(){
        return Tools.getApiResponse(1,"页面未找到,请检查路径是否正确");
    }

    @RequestMapping("sysError")
    @ResponseBody
    public Map<String,Object> processException(){
        return Tools.getApiResponse(1,"数据异常,请稍后再试");
    }
}

这样可以给前端返回一些具体的提示。

猜你喜欢

转载自blog.csdn.net/fanxing1964/article/details/81456458