ssm中项目异常处理

一、异常处理器 

 

 思考1:

 思考2:

 其实,spring已经早早就帮我们解决好处理异常的问题了,不用我们再写AOP代码了,但是我们要按照spring处理异常的格式进行书写

模拟一下前端发送访问资源请求后,收到的是异常信息(此时后端还没有做异常处理器):

 前端访问增加功能的资源路径后,收到的信息如下:(这时前端就懵逼了,我TM访问的是增加功能,这tm返回的是什么东西~)

异常处理器:

因此我们后端就需要做异常处理了(这里演示的就是其他异常,不需要向系统异常和业务异常一样还需要创建个类,用来封装提示用户信息到属性中):

后端处理完异常后客户端再次访问增加功能资源后,会接收到什么信息:

 因此客户端又事B了说,我什么数据都没有接收啊,我这是咋回事啊,

因此我们后端在处理完异常之后,可以返回一些数据给前端用户,那么用户就知道了,哦原来是后端出异常了啊~

 前端用户接收的信息如下所示:

二、项目中不同种类异常的处理方式

项目中出现的不同种类异常形式:

 那么如何处理上面三种类型的异常呢:

代码演示如下所示:

第一步:先把系统异常类、业务异常类写出来:(实际开发中业务中只出现系统异常的会,那么就写一个系统异常类就可以了,我这里是把三种情况(系统异常、业务异常、其他异常都写出来了),实际开发中出现哪个异常就写哪个异常类,然后通过异常处理器进行处理并且返回给用户提示信息就可以了)

系统异常类:

package com.itheima.exception;

/**
 *  业务异常类
 *
 *  注:继承RuntimeException运行时异常类的目的就是运行时出现异常的时候不再手动往上抛了,自动帮我们往上抛
 *
 */
public class SystemException extends RuntimeException{

    private Integer code;    // 加个code编号属性,来标注以后出现的是哪一种异常

    /**
     *  把构造方法最好都写出来
     */

    public SystemException(Integer code) {
        this.code = code;
    }

    public SystemException(String message, Integer code) {
        super(message);
        this.code = code;
    }

    public SystemException(String message, Throwable cause, Integer code) {
        super(message, cause);
        this.code = code;
    }

    public SystemException(Throwable cause, Integer code) {
        super(cause);
        this.code = code;
    }

    public SystemException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Integer code) {
        super(message, cause, enableSuppression, writableStackTrace);
        this.code = code;
    }

    /**
     *  getter and setter方法
     */
    public Integer getCode() {
        return code;
    }

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

业务异常类:

package com.itheima.exception;

/**
 *  系统异常类
 *
 *  注:继承RuntimeException运行时异常类的目的就是运行时出现异常的时候不再手动往上抛了,自动帮我们往上抛
 *
 */
public class BusinessException extends RuntimeException{

    private Integer code;    // 加个code编号属性,来用状态码标注以后出现的是哪一种异常

    /**
     *  把构造方法最好都写出来
     */


    public BusinessException(Integer code) {
        this.code = code;
    }

    public BusinessException(String message, Integer code) {
        super(message);
        this.code = code;
    }

    public BusinessException(String message, Throwable cause, Integer code) {
        super(message, cause);
        this.code = code;
    }

    public BusinessException(Throwable cause, Integer code) {
        super(cause);
        this.code = code;
    }

    public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Integer code) {
        super(message, cause, enableSuppression, writableStackTrace);
        this.code = code;
    }

    /**
     *  getter and setter方法
     */
    public Integer getCode() {
        return code;
    }

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

第二步:假设业务端通过id查询功能的时候出现了系统异常(比如说:服务器宕机了):

那么就把系统异常捕获到后,把想要返回给前端用户的信息封装到系统异常类的属性当中(通过构造方法),然后通过异常处理器返回给前端用户信息

注意1:假设系统异常和业务异常都出现在了业务层的某个功能中,那么先捕获到哪个种类的异常,异常处理器就会获取到该异常信息,并且把提示数据返回提示给用户(下面是先捕获的系统异常,因为系统异常排第一)

package com.itheima.service.impl;

import com.itheima.controller.Code;
import com.itheima.dao.BookDao;
import com.itheima.domain.Book;
import com.itheima.exception.BusinessException;
import com.itheima.exception.SystemException;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;


@Service
public class BookServiceImpl implements BookService {

    /**
     *  注入dao数据层依赖 : private BookDao bookDao;
     *      然后等会spring容器拿到管理的业务层BookServiceImpl对象后,又因为业务层和数据层有依赖关系
     *      通过依赖关系就可以调用数据层的增删改查功能了
     */

    @Autowired // 自动装配(处理依赖关系)注解
    private BookDao bookDao;

    // 增
    public boolean save(Book book) {

        // 调用数据层的增加功能
        bookDao.save(book);
        return true;
    }

    // 删
    public boolean delete(Integer id) {

        // 调用数据层的删除功能
        bookDao.delete(id);
        return true;
    }

    // 改
    public boolean update(Book book) {

        // 调用数据层的修改功能
        bookDao.update(book);
        return true;
    }

    // 通过id查询
    public Book getById(Integer id) {

        /**
         *  模拟假定这个地方出现了 系统异常(比如说:程序运行到这里后服务器宕机了)
         *
         *      我们用 1/0来模拟:服务器宕机
         *
         */
        try {
            int i =1/0; // 模拟系统异常
        } catch (Exception e){    // 捕获到系统异常后,把想要返回给前端的信息封装到
                                   // 系统异常类的属性中(通过构造方法)
            throw new SystemException("服务器访问超时~",e, Code.SYSTEM_ERR);
            // 把想返回给前端的信息封装到SystemException对象的属性当中
            // Code.SYSTEM_ERR :系统异常状态码标识 50001
        }
        
        /**
         *  这里模拟假设出现了 业务异常
         */

        if (id==2){
            throw new BusinessException("请不要用你的技术挑战我的耐性~",Code.BUSINESS_ERR);
            // Code.BUSINESS_ERR : 业务异常状态码标识 60001
        }

        // 调用数据层的通过id查询功能
        Book books = bookDao.getById(id);
        return books;
    }

    // 查询所有
    public List<Book> getAll() {

        // 调用数据层的查询所有功能
        List<Book> list = bookDao.getAll();
        return list;
    }
}

第三步:通过异常处理器进行系统或者业务或者其他异常处理并且把刚才封装到系统异常类/业务异常类属性中返回给客户的数据,返回给用户:

细节:真正开发中,我们其实可以直接把这三种异常处理器写出来,然后项目中如果出现的是系统异常,那么就直接被系统异常处理器处理并且返回给用户信息即可了,如果是其他两种,也可以直接被其他两种异常处理器捕获到然后进行处理异常

package com.itheima.controller;

import com.itheima.exception.BusinessException;
import com.itheima.exception.SystemException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 *  spring处理异常 (异常处理器类)
 */

// @ControllerAdvice // 这是普通风格处理异常的注解 (只要访问路径用的不是REST风格就用这个注解)
@RestControllerAdvice   // 这是REST风格的处理异常的注解 (告诉spring这是一个处理异常的类的注解)
// 注1:这个@RestControllerAdvice注解需要被SpringMvcConfig类的@ComponentScan({"com.itheima.controller"})注解
// 扫描到,(SpringMvcConfig类的扫描注解刚好扫到controller包下,所以能扫到,因此如果换成其他的包,记得扫一下)

public class ProjectExceptionAdvice {

    /**
     *  注: 系统异常处理器
     *
     * @return: 返回给前端信息
     */

    @ExceptionHandler(SystemException.class)    // 该注解作用: 拦截是否是系统异常,是的话就调用下面的方法进行处理异常
    public Result doSystemException(SystemException sy){
            // (SystemException sy):把SystemException对象传递过来(因为刚才业务层模拟系统异常的时候,把返回给前端的信息封装到sy对象属性中了)
        /**
         *  拿到系统异常之后需要做以下几步骤:
         *  1、记录日志
         *  2、发送给运维,开发人员
         *  3、安抚一下客户(客户访问资源的时候出现异常了,咱们肯定要说一些好听的给用户)
         */

        return new Result(null,sy.getCode(), sy.getMessage());
        // 把封装到sy系统异常类属性中的系统异常状态码信息返回给用户
    }

    /**
     *  注: 业务异常处理器  (和系统异常处理器方式是一样的)
     *
     * @return: 返回给前端信息
     */

    @ExceptionHandler(BusinessException.class)   //  拦截是否是业务异常,是的话就调用下面的方法进行处理异常
    public Result doBusinessException(BusinessException bs){


        return new Result(null,bs.getCode(),bs.getMessage());
    }

    /**
     *  注: 其他异常处理器 (可以理解为除了业务异常和系统异常之外的所有异常)
     */

    @ExceptionHandler(Exception.class)    //  拦截是否是其他异常,是的话就调用下面的方法进行处理异常
    public Result doException(){

        return new Result(null,0,"出现异常了铁子~");
    }
}

假设客户端进行访问有系统异常的通过id查询的功能时候:

补:Code类:专门用来储存成功/失败标识符号的

package com.itheima.controller;


/**
 *      分析该类的作用:
 *           标记状态码(比如1:表示成功,2:表示失败)的类,( Result里面的 )
 *
 *           注意:这些状态码不是固定的,是实际开发中前端程序员和后端程序员商量好规定的一种状态信息,
 *           通过这些商量的状态码,就可以知道拿没拿到数据了
 *
 */
public class Code {

    /**
     *  调用增删改查功能成功的状态码标记
     *
     *  注:因为是static静态修饰的,所以可以直接用类名Code调用属性名
     *  public修饰:代表公共的(也就是说,任何包下的只要通过类名. 的方式都可以调取到Code类下的属性值)
     *
     */
    public static final Integer SAVE_OK = 20011;
    public static final Integer DELETE_OK = 20021;
    public static final Integer UPDATE_OK = 20031;
    public static final Integer SELECT_OK = 20041;

    /**
     *  调用增删改查功能失败的状态码标记
     */
    public static final Integer SAVE_ERR = 20010;
    public static final Integer DELETE_ERR = 20020;
    public static final Integer UPDATE_ERR = 20030;
    public static final Integer SELECT_ERR = 20040;


    /**
     *  系统异常 & 业务异常成功/失败状态码标记
     */
    public static final Integer SYSTEM_ERR =50001; // 出现系统异常状态码
    public static final Integer BUSINESS_ERR =60001;   // 出现业务异常状态码


}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
[ 2021年,将Spring全家桶的课程进行Review,确保不再有顺序错乱等问题导致学员看不懂内容,进入2022年,将Spring的课程进行整理,整理为案例精讲的系列课程,并开始逐步增加高阶的Spring Security等内容,课件将逐步进行上传,敬请期待! ]本课程是Spring全家桶案例精讲课程的第二部分Spring MVC,Spring案例精讲课程以真实场景、项目实战为导向,循序渐进,深入浅出的讲解Java网络编程,助力您在技术工作更进一步。 本课程聚焦Java Spring的Web知识点,主要是关于Spring MVC的应用,包含:表单的增删改查、国际化、过滤器、拦截器、日志Log4j2及slf4j的使用、主题更改网站皮肤及样式、文件上传等的案例讲解,并且最后以一个SSM(Spring+Spring MVC+Mybatis)贯穿前后台的案例作为Spring MVC课程的终奖, 从而使大家快速掌握Spring的基础核心知识,快速上手,为面试、工作等做好充足准备。 由于本课程聚焦于案例,即直接上手操作,对于Spring的原理等不会做过多介绍,希望了解原理等内容的需要通过其他视频或者书籍去了解,建议按照该案例课程一步步做下来,之后再去进一步回顾原理,这样能够促进大家对原理有更好的理解。 【通过Spring全家桶,我们保证你能收获到以下几点】 1、掌握Spring全家桶主要部分的开发、实现2、可以使用Spring MVC、Spring Boot、Spring Cloud及Spring Data进行大部分的Spring开发3、初步了解使用微服务、了解使用Spring进行微服务的设计实现4、奠定扎实的Spring技术,具备了一定的独立开发的能力  【实力讲师】 毕业于清华大学软件学院软件工程专业,曾在Accenture、IBM等知名外企任管理及架构职位,近15年的JavaEE经验,近8年的Spring经验,一直致力于架构、设计、开发及管理工作,在电商、零售、制造业等有丰富的项目实施经验 【本课程适用人群】如果你是一定不要错过!  适合于有JavaEE基础的,如:JSP、JSTL、Java基础等的学习者没有基础的学习者跟着课程可以学习,但是需要补充相关基础知识后,才能很好的参与到相关的工作。 【Spring全家桶课程共包含如下几门】 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值