第十七章第七节:Controller控制层统一异常处理(表单校验异常处理 含枚举类型)

@ControllerAdvice注解会自动感知指定包下的异常,所有的异常都会自动交由注解了ControllerAdvice的类来处理

1、修改保存方法,把异常处理相关代码去掉

com.applesnt.onlinemall.product.controller.BrandController

 /**
 * 品牌信息保存
 * @Valid:实体类开启校验
 */
@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand){
        brandService.save(brand);
        return R.ok();
}

2、创建统一异常处理类

com.applesnt.onlinemall.product.exception.ExceptionControllerAdvice

package com.applesnt.onlinemall.product.exception;

import com.applesnt.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@Slf4j
//@ResponseBody:返回json数据
@ResponseBody
//@ControllerAdvice:表示自动感知哪个包下的异常
@ControllerAdvice(basePackages = "com.applesnt.onlinemall.product.controller")
public class ExceptionControllerAdvice {

    /*自动处理Exception类型的异常*/
    @ExceptionHandler(value = Exception.class)
    public R handleValidException(Exception e){
        log.info("数据校验出现问题:{},异常类型是:{}",e.getMessage(),e.getClass());
        return R.error();
    }
}

3、postman访问测试

http://localhost:88/api/product/brand/save

日志打印:
数据校验出现问题:Validation failed for argument [0] in public com.applesnt.common.utils.R com.applesnt.onlinemall.product.controller.BrandController.save(com.applesnt.onlinemall.product.entity.BrandEntity) with 3 errors: [Field error in object 'brandEntity' on field 'sort': rejected value [null]; codes [NotNull.brandEntity.sort,NotNull.sort,NotNull.java.lang.Integer,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [brandEntity.sort,sort]; arguments []; default message [sort]]; default message [排序不能为空]] [Field error in object 'brandEntity' on field 'firstLetter': rejected value [null]; codes [NotBlank.brandEntity.firstLetter,NotBlank.firstLetter,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [brandEntity.firstLetter,firstLetter]; arguments []; default message [firstLetter]]; default message [检索首字母不能为空]] [Field error in object 'brandEntity' on field 'descript': rejected value [null]; codes [NotNull.brandEntity.descript,NotNull.descript,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [brandEntity.descript,descript]; arguments []; default message [descript]]; default message [介绍不能为空]] ,
异常类型是:class org.springframework.web.bind.MethodArgumentNotValidException

4、修改为统一处理表单校验异常

从刚才的日志打印已知数据校验异常类型为MethodArgumentNotValidException
把自动处理的异常类型改为MethodArgumentNotValidException即可

com.applesnt.onlinemall.product.exception.ExceptionControllerAdvice

package com.applesnt.onlinemall.product.exception;

import com.applesnt.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
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;

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

@Slf4j
//@ResponseBody:返回json数据
@ResponseBody
//@ControllerAdvice:表示自动感知哪个包下的异常
@ControllerAdvice(basePackages = "com.applesnt.onlinemall.product.controller")
public class ExceptionControllerAdvice {
   /*
    * 校验异常处理方法
    */
    /*自动处理MethodArgumentNotValidException类型的异常*/
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleValidException(MethodArgumentNotValidException exception){
        Map<String,String> errorMap = new HashMap<>();
        //得到异常对象BindingResult
        BindingResult result = exception.getBindingResult();
        //遍历异常对象里的error信息
        result.getFieldErrors().forEach((item)->{
            //把字段名称和错误信息封装到map中
            errorMap.put(item.getField(),item.getDefaultMessage());
        });
        return R.error(400,"数据校验错误").put("data",errorMap);
    }
}

5、postman访问测试

http://localhost:88/api/product/brand/save

6、定义一个全局异常方法

定义一个全局异常方法捕获没有定义的异常类型
我们可以定义很多个指定类型的异常处理方法,
package com.applesnt.onlinemall.product.exception;

import com.applesnt.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
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;
import java.util.HashMap;
import java.util.Map;

@Slf4j
//@ResponseBody:返回json数据
@ResponseBody
//@ControllerAdvice:表示自动感知哪个包下的异常
@ControllerAdvice(basePackages = "com.applesnt.onlinemall.product.controller")
public class ExceptionControllerAdvice {

    /*
    * 校验异常处理方法
    * */
    /*自动处理MethodArgumentNotValidException类型的异常*/
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleValidException(MethodArgumentNotValidException exception){
        Map<String,String> errorMap = new HashMap<>();
        //得到异常对象BindingResult
        BindingResult result = exception.getBindingResult();
        //遍历异常对象里的error信息
        result.getFieldErrors().forEach((item)->{
            //把字段名称和错误信息封装到map中
            errorMap.put(item.getField(),item.getDefaultMessage());
        });
        return R.error(400,"数据校验错误").put("data",errorMap);
    }

    /*
    * 全局校验异常方法
    * */
    @ExceptionHandler(value = Throwable.class)
    public R handleException(Throwable throwable){
        log.info("全局异常:{},异常类型是:{}",throwable.getMessage(),throwable.getClass());
        return R.error(100,throwable.getMessage());
    }
}

7、定义一个异常枚举类(onlinemall-common项目中)

com.applesnt.common.exception.BizCodeEnum(Enum类型)

package com.applesnt.common.exception;

import lombok.Getter;

/**
 * @author menghaibin
 * @project onlinemall
 * @date 2021/6/10-14:06
 * @describe 异常处理枚举类
 */
/***
 * 错误码列表:
 *  10: 通用
 *      001:参数格式校验
 *  11: 商品
 *  12: 订单
 *  13: 购物车
 *  14: 物流
 */
@Getter
public enum BizCodeEnum {

    UNKNOW_EXCEPTION(10000,"系统未知错误"),
    VALID_EXCEPTION(10001,"数据校验不正确"),
    ;
    private Integer code;
    private  String msg;

    BizCodeEnum(Integer code,String msg){
        this.code = code;
        this.msg = msg;
    }
}

8、修改相关的异常消息体

com.applesnt.onlinemall.product.controller.BrandController

//获取枚举类型的消息体
return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(),BizCodeEnum.VALID_EXCEPTION.getMsg()).put("data",errorMap);
posted @ 2021-06-10 14:06  努力的校长  阅读(273)  评论(0)    收藏  举报