springmvc,springboot统一校验自定义异常全局异常处理(代码片段)

诺浅 诺浅     2022-12-05     671

关键词:

引入jar包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

写一个DTO用来接收客户端传送的参数

@Data
public class AuditListDto 
    @ApiModelProperty(value = "提交人ID", required = true)
    @NotNull
    private Long commitPersonnelId;

    @ApiModelProperty(value = "提交人名称", required = true)
    @NotNull
    private String commitPersonnelName;

    @ApiModelProperty(value = "巡检设备表ID集合", required = true)
    @NotEmpty
    private List<Long> inspectionEquipmentIds;

在Controller的方法里面上加上@Validated注解

@PostMapping("submitAccept")
@ApiOperation(value = "06.巡检数据提交验收", notes = "巡检数据提交验收")
@ApiOperationSupport(order = 22)
public ResultData<Void> submitAccept(@Validated @RequestBody AuditListDto conditionDto) 
    service.submitAccept(conditionDto);
    return ResultData.success();

定义一个统一异常拦截器

package com.yxk.config;

import com.yxk.utils.ResultData;
import com.yxk.utils.ResultDataException;
import com.yxk.utils.Utils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;

@RestControllerAdvice
public class GlobalExceptionHandler 

    private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class.getName());

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResultData<?> handleException(HttpRequestMethodNotSupportedException e) 
        return ResultData.failed(ResultData.NOT_SUPPORTED_HTTP_METHOD, "不支持' " + e.getMethod() + "'请求");
    

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResultData<?> handleException(MissingServletRequestParameterException e) 
        return ResultData.failed(ResultData.MISSING_HTTP_PARAMETER,
                "缺少必要参数" + e.getParameterName() + ", 类型:" + e.getParameterType());
    

    @ExceptionHandler(BindException.class)
    public ResultData<?> handleException(BindException e) 
        return ResultData.failed(ResultData.BIND_ERROR, e.getFieldErrors().get(0).getDefaultMessage());
    

    @ExceptionHandler(ResultDataException.class)
    public ResultData<?> handleResultDataException(ResultDataException e) 
        logger.info("", e);
        return e.toResultData();
    

    @ExceptionHandler(DataIntegrityViolationException.class) // uk/fk
    public ResultData<?> handleDataIntegrityViolationException(DataIntegrityViolationException e) 
        final String delFK = "Cannot delete or update a parent row: a foreign key constraint fails";
        final String saveFK = "Cannot add or update a child row: a foreign key constraint fails";
        final String UK = "Duplicate entry";
        final String truncation = "Data truncation";//

        logger.error("", e);

        if (e instanceof DuplicateKeyException) 
            // pk (not to here, except direct insert by native sql)
            return ResultData.failed(ResultData.INTEGRITY_VIOLATION, "重复的id");
        

        Throwable root = ExceptionUtils.getRootCause(e);
        if (root != null) 
            String err = Utils.findStr(root.getMessage(), UK);
            if (err != null)  // uk
                return ResultData.failed(ResultData.DUPLICATE_ENTRY, "重复数据,不能保存", err);
            
            err = Utils.findStr(root.getMessage(), delFK);
            if (err != null) // fk: Cannot delete or update a parent row: a foreign key constraint fails
                return ResultData.failed(ResultData.DUPLICATE_ENTRY, "数据已被使用,不能删除", err);
            
            err = Utils.findStr(root.getMessage(), saveFK);
            if (err != null) // fk: Cannot add or update a child row: a foreign key constraint fails
                return ResultData.failed(ResultData.DUPLICATE_ENTRY, "无效的引用id,不能保存", err);
            
            err = Utils.findStr(root.getMessage(), truncation);
            if (err != null) // Data truncation: Out of range value for column 'fee'
                return ResultData.failed(ResultData.DUPLICATE_ENTRY, "数据截断(值超出范围)", err);
            
            return ResultData.failed(ResultData.DUPLICATE_ENTRY, "数据不完整", root.getMessage());
        

        return ResultData.failed(ResultData.INTEGRITY_VIOLATION, "数据不完整");
    

    /**
     * 处理@Validated参数校验失败异常
     *
     * @param exception 异常类
     * @return 响应
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultData<?> validExceptionHandler(MethodArgumentNotValidException exception) 
        BindingResult result = exception.getBindingResult();
        StringBuilder stringBuilder = new StringBuilder();
        if (result.hasErrors()) 
            List<ObjectError> errors = result.getAllErrors();
            if (errors != null) 
                StringBuilder finalStringBuilder = stringBuilder;
                errors.forEach(p -> 
                    FieldError fieldError = (FieldError) p;
                    logger.warn("Bad Request Parameters: dto entity [],field [],message []", fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage());
                    finalStringBuilder.append(String.format("%s[%s]%s", p.getObjectName(), ((FieldError) p).getField(), p.getDefaultMessage())).append(",");
                );
            
            if (stringBuilder.length() > 0) 
                stringBuilder = stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            
        

        return ResultData.failed(ResultData.VALIDATE_ERROR, stringBuilder.toString());
    

    @ExceptionHandler(RuntimeException.class)
    public ResultData<?> handlerUnknown(RuntimeException e) 
        logger.error("", e);
        Throwable root = ExceptionUtils.getRootCause(e);
        if (root != null) 
            return ResultData.failed(ResultData.UNKNOWN_ERROR, "未知错误", root.getMessage());
        
        return ResultData.failed(ResultData.UNKNOWN_ERROR, "未知错误", e.getMessage());

    


自定义异常

public class ResultDataException extends RuntimeException 
    private static final long serialVersionUID = -9041090610418135434L;

    public static ResultDataException of(int code, String message) 
        return new ResultDataException(code, message);
    

    public static ResultDataException of(int code, String message, Object data) 
        return new ResultDataException(code, message, null, data);
    

    public static ResultDataException duplicateKey(String message) 
        return new ResultDataException(ResultData.DUPLICATE_KEY, message);
    

    public static ResultDataException notfound(String message) 
        return new ResultDataException(ResultData.NOT_FOUND, message);
    

    public static ResultDataException notfound(Long id) 
        return new ResultDataException(ResultData.NOT_FOUND, "记录不存在: " + id);
    

    public static ResultDataException validateRequired(String field) 
        return new ResultDataException(ResultData.VALIDATE_ERROR, field + " 不能为空");
    

    public static ResultDataException validteInvalidFormat(String field, String value) 
        return new ResultDataException(ResultData.VALIDATE_ERROR, field + " 无效格式: " + value);
    

    public static ResultDataException validteTooLong(String field, int maxLength, String value) 
        return new ResultDataException(ResultData.VALIDATE_ERROR,
                String.format("[%s]超长(%d, %d): %s", field, maxLength, value.length(), value));
    

    private final int code;
    private final String internalError;
    private final Object data;

    public ResultDataException(int code, String message) 
        this(code, message, null);
    

    public ResultDataException(int code, String message, String internalError) 
        this(code, message, internalError, null);
    

    public ResultDataException(int code, String message, String internalError, Object data) 
        super(message);
        this.code = code;
        this.internalError = internalError;
        this.data = data;
    

    @SuppressWarnings("unchecked")
    public <T> ResultData<T> toResultData() 
        return (ResultData<T>) ResultData.of(code, super.getMessage(), internalError, data);
    


public class ResultData<T> 

    public static <T> ResultData<T> of(int code, String message, T data) 
        return of(code, message, null, data);
    

    public static <T> ResultData<T> of(int code, String message, String internalError, T data) 
        ResultData<T> ret = new ResultData<>();
        ret.code = code;
        ret.msg = message;
        ret.internalError = internalError;
        ret.data = data;
        return ret;
    

    public static <T> ResultList<T> ofList(int code, String message, String internalError, List<T> data) 
        ResultList<T> result = of(data, data == null ? 0 : data.size());
        result.setCode(code);
        result.setMsg(message);
        result.setInternalError(internalError);
        return result;
    

    public static <T> ResultData<T> of(T data) 
        return of(SUCCESS, null, data);
    

    public static <T> ResultList<T> of(List<T> data) 
        return of(data, data.size());
    

    public static <T> ResultList<T> of(List<T> data, long total) 
        ResultList<T> ret = new ResultList<>();
        ret.setData(data);
        ret.setTotal(total);
        return ret;
    

    public static <T> ResultData<T> success(T data) 
        return of(SUCCESS, null, data);
    

    // success (no ret data)
    public static <T> ResultData<T> success() 
        return of(SUCCESS, null, null);
    

    public static <T> ResultData<T> success(String message, T data) // success with message
        return of(SUCCESS, message, data);
    
    //

    public static <T> ResultData<T> failed(int code, String message) 
        return failed(code, message, null);
    

    public static <T> ResultData<T> failed(int code, String message, String internalError) 
        return of(code, message, internalError, null);
    

    public static <T> ResultData<T> unknown(String message) 
        return ofspringboot输入参数统一校验

1引入springbootvalidate   maven依赖<!--验证--><dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId></depend 查看详情

springboot--注解字段校验,并统一设置返回值(代码片段)

Springboot--注解字段校验,并统一设置返回值引包:importorg.springframework.validation.annotation.Validated;<!--web--><dependency> <groupId>org.springframework.boot</groupId> <art 查看详情

springboot统一参数校验统一异常统一响应,这才是优雅的处理方式!(代码片段)

前言本篇主要要介绍的就是controller层的处理,一个完整的后端请求由4部分组成:接口地址(也就是URL地址)请求方式(一般就是get、set,当然还有put、delete)请求数据(request,有head跟body)响应数据(response)本篇将解决以... 查看详情

springboot参数联合校验,自定义分组校验

...多个参数需要联合校验,不能都为空,即至少有一个有值springboot提供的校验注解都无法满足,一般在controller写if判断springboot提供了自定义分组校验的功能,可以避免在controller写if校验参数实现步骤:@GroupSequenceProvider(value=UserStor... 查看详情

重学springboot系列之统一全局异常处理(代码片段)

重学SpringBoot系列之统一全局异常处理设计一个优秀的异常处理机制异常处理的乱象例举该如何设计异常处理开发规范自定义异常和相关数据结构该如何设计数据结构枚举异常的类型自定义异常请求接口统一响应数据结构使用示... 查看详情

自定义参数校验以及统一处理结果集(代码片段)

自定义参数校验以及统一处理结果集1.引入校验组件2.定义统一返回结果3.返回值统一包装处理4.@RestControllerAdvice+ResponseBodyAdvice统一处理5.@RestControllerAdvice+@ExceptionHandler处理6.方法基本参数校验原理7.方法级别的参数... 查看详情

springboot中集成参数校验

SpringBoot中集成参数校验引入依赖自定义参数校验创建自定义注解自定义校验逻辑在校验对象的属性上加上注解分组校验定义分组接口在UserVO对象参数分配分组在需要参数校验的方法指定分组SprinBoot集成参数校验Validator,以及... 查看详情

springboot中关于自定义注解校验

参考技术A1.例如我想要校验某个入参是否是json字符串,假设我的自定义注解为@JSONStringAnnotation,并在某个bean中的customFields字段使用:2.新建注解接口类:3.新建具体的校验类:以上就完成了对一个字段的自定义注解校验,是不是... 查看详情

springboot系列之自定义枚举类的数据校验注解

SpringBoot系列之自定义枚举类的数据校验注解业务场景:数据校验,需要对枚举类型的数据传参,进行数据校验,不能随便传参。拓展,支持多个参数的枚举数据校验在网上找到很多参考资料,所以本博客基于这些博客进行拓展... 查看详情

springboot中集成参数校验(代码片段)

SpringBoot中集成参数校验引入依赖自定义参数校验创建自定义注解自定义校验逻辑在校验对象的属性上加上注解分组校验定义分组接口在UserVO对象参数分配分组在需要参数校验的方法指定分组SprinBoot集成参数校验Validator,以及... 查看详情

手把手写一个基于springboot框架下的参数校验组件

手把手写一个基于SpringBoot框架下的参数校验组件(JSR-303) 前言          之前参与的新开放平台研发的过程中,由于不同的接口需要对不同的入参进行校验,这就涉及到通用参数的校验封装,如果不进行封装,那么... 查看详情

商城项目10_jsr303常用注解在项目中如何使用统一处理异常分组校验功能自定义校验注解(代码片段)

...章目录①.JSR303校验概述、注解②.项目中JSR303如何使用③.统一异常处理@ExceptionHandler④.处理错误状态码⑤.分组校验功能(多场景校验)⑥.自定义校验注解①.JSR303校验概述、注解①.JSR是JavaSpecificationRequests的缩写,意思是Java规范... 查看详情

瞧瞧人家用springboot写的后端api接口,那叫一个优雅

...数校验,这样代码更加简洁,也方便统一管理。实际上,springboot有个validation的组件,我们可以拿来即用。引入这个包即可:引入包后,参数校验就非常简洁啦,如下:然后在UserParam参数对象中,加入@Validated注解哈,把错误信息... 查看详情

springboot自定义注解实现token校验

原文链接: https://blog.csdn.net/qq_33556185/article/details/105420205https://blog.csdn.net/weixin_43877725/article/details/1075546381.定义Token的注解,需要Token 查看详情

springboot如何进行参数校验,老鸟们都这么玩的!(代码片段)

大家好,我是飘渺。前几天写了一篇SpringBoot如何统一后端返回格式?老鸟们都是这样玩的!阅读效果还不错,而且被很多号主都转载过,今天我们继续第二篇,来聊聊在SprinBoot中如何集成参数校验Validator&#... 查看详情

springboot拦截器使用和常用功能统一封装(代码片段)

文章目录1.拦截器1.1拦截器的使用1.2拦截器的原理2.用户登录权限校验3.统一异常处理4.统一数据返回格式1.拦截器1.1拦截器的使用Spring中提供了拦截器HandlerInteceptor,它的具体使用分为以下两个步骤:创建自定义拦截器ÿ... 查看详情

springboot2统一异常处理

springmvc 针对controller层异常统一处理非常简单,使用 @RestControllerAdvice 或 @RestControllerAdvice 注解就可以轻@RestControllerAdvicepublicclassGatewayExceptionHandler{/*@ExceptionHandler(Exception. 查看详情

阿昌教你自定义注解验证bean对象(代码片段)

前言在之前阿昌写过一篇【Springboot的注解字段校验,并统一设置返回值】的文章,讲了常见的一些注解,和自定义的报错返回处理器,没看过的可以去看一下。在Springboot中本身就可以通过大量的注解来实现对一... 查看详情