如何抓住该死的异常

全局异常处理

  全局异常的作用:可以捕捉系统内部产生的错误,不管是参数错误,还是程序错误,还是突然代码发神经导致的错误。但是这些错误我们都可以拿到,并且输出对应我们想要前台看到的信息。让前台更优雅的看到这些错误,不至于看到都是系统提示的英文鸟语。

全局异常扫描注解

  在application启动类中,需要配置全局异常扫描:@EnableAutoConfiguration

//启动类09
@SpringBootApplication  //扫描所有包
@MapperScan(basePackages = "com.wt.mapper")
@ComponentScan(basePackages = {"com.wt"})
@EnableAutoConfiguration
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

包的结构

处理代码

1、返回的处理结果类型JsonData,Commonreturntype类

package com.wt.response;

//通用返回格式
public class CommonReturnType {
            //摆明对应的请求的返回处理结果  success或fail
    private String status;
    //status= success 则data返回json数据
    //status= fail   返回的错误码格式

    private Object data;

    public static CommonReturnType create(Object result, String status) {
        CommonReturnType type = new CommonReturnType();
        type.setStatus(status);
        type.setData(result);
        return type;
    }

    //定义一个通用的创建方法
    public static CommonReturnType create(Object result) {
        return CommonReturnType.create(result, "success");
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

2、错误接口类的定义:CommonError

package com.wt.error;

public interface CommonError {
    //获取错误信息码
    public int getErrCode();
    //获取错误信息
    public String getErrMsg();
    //获取共同的错误
    public CommonError setErrMsg(String errMsg);

}

3、EmBusinessError定义枚举错误信息,这里存储了我们自己觉得需要抛出的异常文字定义,总之我们想要抛出啥错误信息,就需要在这里定义更多的枚举变量

package com.wt.error;

import javax.xml.stream.events.Comment;

public enum EmBusinessError implements CommonError {

//枚举变量要放在最开始
    //通用错误类型  10001
    PARAMETER_VALIDATION_ERROR(10001, "参数不合法"),
        UNKNOWN_ERROR(10002, "未知错误");
    EmBusinessError(int errCode, String errMsg) {
        this.errCode = errCode;
        this.errMsg = errMsg;

    }
    //成员变量可以靠后放置
    private int errCode;
    private String errMsg;

    @Override
    public int getErrCode() {
        return this.errCode;
    }

    @Override
    public String getErrMsg() {
        return this.errMsg;
    }

    @Override
    public CommonError setErrMsg(String errMsg) {
        this.errMsg = errMsg;
        return this;
    }
    public void setErrCode(int errCode) {
        this.errCode = errCode;
    }
}

4、BusinessException包装类业务异常类实现,这个又是另一种错误抛出的信息提示

package com.wt.error;
//业务错误处理
public class BusinessException extends RuntimeException implements CommonError{
    private CommonError commonError;
    //直接接收EmbusinessError 的传参用于构造业务异常
    public BusinessException(CommonError commonError){
        super();
        this.commonError = commonError;
    }

    //接收自定义的errMsg的方式构造业务异常
    public BusinessException(CommonError commonError, String errMsg) {
        super();
        this.commonError= commonError;
        this.commonError.setErrMsg(errMsg);
    }

    @Override
    public int getErrCode() {
        return this.commonError.getErrCode();
    }

    @Override
    public String getErrMsg() {
        return this.commonError.getErrMsg();
    }

    @Override
    public CommonError setErrMsg(String errMsg) {
        this.commonError.setErrMsg(errMsg);
        return this;
    }
    public CommonError getCommonError() {
        return commonError;
    }
}

5、GlobalExceptionHandler最后定义全局异常捕获类,这就相当于一个接口,一个监视器一样,我们程序出现错误就会有这样一个监管的人来逮住你

package com.wt.errorhandler;

import com.wt.error.BusinessException;
import com.wt.error.EmBusinessError;
import com.wt.response.CommonReturnType;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

//全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
    //日志监测
    public static final  org.slf4j.Logger logger=LoggerFactory.getLogger(GlobalExceptionHandler.class);

    //错误处理
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public CommonReturnType doError(HttpServletRequest httpServletReques, HttpServletResponse
                                    httpServletResponse, Exception ex) {
        ex.printStackTrace();
        //map存储异常响应的数据
        Map<String, Object> responseData = new HashMap<>();
        //如果是业务异常类型
        if (ex instanceof BusinessException) {
            System.out.println("===这里错误了进来了么哟===");
            BusinessException businessException = (BusinessException) ex;
            //map中就放置  错误码和信息
            responseData.put("errCode", businessException.getErrCode());
            responseData.put("errMsg", businessException.getErrMsg());
            //
        } else if (ex instanceof ServletRequestBindingException) {
            responseData.put("errCode", EmBusinessError.UNKNOWN_ERROR.getErrCode());
            //拦截到对应错误信息 输出对应的异常信息
            responseData.put("errMsg", "url绑定路由问题");
        } else if (ex instanceof NoHandlerFoundException) {
            responseData.put("errCode", EmBusinessError.UNKNOWN_ERROR.getErrCode());
            responseData.put("errMsg", "没有找到对应的访问路径");
        } else {
            /*这里错误了没*/
            responseData.put("errCode", EmBusinessError.UNKNOWN_ERROR.getErrCode());
            responseData.put("errMsg", EmBusinessError.UNKNOWN_ERROR.getErrMsg());
        }
        //错误日志输出
        logger.error(responseData.toString());
        System.out.println("================这个是错误集合"+responseData.toString());
        //回写错误集合
        return CommonReturnType.create(responseData,"fail");
    }
}

测试

  测试还是老规矩:在controller中进行测试,controller在api模块中,别搞忘了

    //异常错误
    @GetMapping("/exceptiontest")
    public CommonReturnType exceptionTest() {
        //这里传递一个参数  有个为空 代表参数错误
        int i=1/0;
       return CommonReturnType.create(null, "fail");
    }

  访问路径:http://localhost:8088/exceptiontest

全局异常检测下的验证器

项目结构图

引入依赖

        <!--校验相关 -->
        <!--apache工具包,方便常规操作 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
        <!--hibernate校验工具 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.1.4.Final</version>
        </dependency>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.4</version>
        </dependency>
        <!--hutool工具 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.7</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-parent</artifactId>
            <version>5.3.7</version>
            <type>pom</type>
        </dependency>

校验器

1、校验结果的判断ValidationResult

package com.wt.validator;


import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;
import java.util.Map;

//校验结果
//检验结果的正确与否
public class ValidationResult {
    //检验结果是否有错
    private boolean hasErrors = false ;
    //存放错误信息 的map
    private Map<String, String> errorMsgMap = new HashMap<>();

    public boolean isHasErrors() {
        return hasErrors;
    }

    public void setHasErrors(boolean hasErrors) {
        this.hasErrors = hasErrors;
    }

    public Map<String, String> getErrorMsgMap() {
        return errorMsgMap;
    }

    public void setErrorMsgMap(Map<String, String> errorMsgMap) {
        this.errorMsgMap = errorMsgMap;
    }

    //实现通用的通过格式化字符串信息获取错误结果的msg方法
    public String getErrMsg() {
        return StringUtils.join(errorMsgMap.values().toArray(), ",");
    }
}

2、校验器的实现类ValidatorImpl,这里会和全局异常配合使用,当校验的结果和规定的不符合,就会捕捉到错误的信息进行处理,并且返回规定的错误提示信息。vo类是页面向后台传递数据的对象,将页面数据封装与后台进行查询交互,这样一个对象可以很好的规范用户在页面的操作。免得搞一些小动作。

package com.wt.validator;

import cn.hutool.core.map.MapUtil;
import com.wt.error.BusinessException;
import com.wt.error.EmBusinessError;
import org.apache.ibatis.io.ResolverUtil;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Set;


@Component
public class ValidatorImpl implements InitializingBean {
    private Validator validator;

    public void check(Object bean) throws BusinessException{
        ValidationResult result = validate(bean);
        if(MapUtil.isNotEmpty(result.getErrorMsgMap())) {
            if(result.isHasErrors()) {
                throw new BusinessException(EmBusinessError.UNKNOWN_ERROR, result.getErrorMsgMap().toString());
            }
        }
    }

    //实现校验方法并返回校验结果
    private ValidationResult validate(Object bean) {
        //验证器结果
        final ValidationResult result = new ValidationResult();
        //将验证器的结果放入集合
        Set<ConstraintViolation<Object>> constraintViolationSet = validator.validate(bean);
        //如果有错误
        if(constraintViolationSet.size()>0){
            //有错误
            result.setHasErrors(true);
            //打印错误集合 ,同时得到错误信息,和每个错误的属性名字 也就是错误code
            constraintViolationSet.forEach(ConstraintViolation->{
                String errMsg = ConstraintViolation.getMessage();
                String propertyName = ConstraintViolation.getPropertyPath().toString();
                result.getErrorMsgMap().put(propertyName, errMsg);
            });
        }
        return result;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        //将hibernate validator 通过工厂的初始化方式使其实例化
        this.validator = Validation.buildDefaultValidatorFactory().getValidator();
    }
}

3、创建Vo对象

package com.wt.controller.viewobject;

import lombok.*;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;


//这个对象的用处还是蛮大的 一般用于界面封装界面提交的信息
//你想想 每次页面提交 信息的个数和格式 估摸着都和数据库的不一样
//那么我们在输入信息的时候就将信息封装成一个对象  那这个对象到后台去校验 操作

@ToString
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
public class TestVo {
    @NotNull
    private Integer id;

    //这里给他规定字符的格式
    @NotBlank
    @Length(min=1, max=3, message = "名称长度1-3")
    private String name;
    private Integer age;
}

测试

  老规矩还是在controller中进行添加测试模块,如果有不懂的需要看我前面的搭建。我是不会告诉你直接答案的。

    @Resource
    private ValidatorImpl validator;
    

    @GetMapping("/validatorTest")
    public CommonReturnType testException(TestVo testVo) {
        validator.check(testVo);
        return CommonReturnType.create("success");
    }

  这里由于是封装了一个对象,参数是一个参数,所以用那个swagger2并不是很友好,不知道怎么去封装一个对象那就别玩了,还是老老实实去用一下postman,提交id,name。

  输入和他规定不符合的,那么就会出现他提示我的错出来

原文地址:https://www.cnblogs.com/HelloM/p/14250102.html