SpringBoot实现对象参数的优雅校验

    在以往,前端向后台传递参数时,要在业务实现中,优先对参数进行逐个校验,以实现在真正业务前对输入的参数进行“去伪”,这样会导致业务中存在大量的重复的参数校验代码,以下使用@Valid(jakarta.validation.Valid)和@Validated(org.springframework.validation.annotation.Validated)实现对对象参数的校验或分组校验,从此业务的业务,校验的归校验!

一、环境版本

  • JDK21
  • SpringBoot3.3.0
  • Knife4.5.0
  • Maven3.9.6
  • IDEA2024.1

二、引入依赖

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.0</version>
    <relativePath/>
</parent>
<dependencies>
    ...
    <!-- 数据校验 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    ...
</dependencies>

二、@Valid@Validated区别

区别 @Valid @Validated
提供者 JSR-303规范 Spring
是否支持分组 不支持 支持
标注位置 - METHOD
- FIELD
- CONSTRUCTOR
- PARAMETER
- TYPE_USE
- TYPE
- METHOD
- PARAMETER
嵌套校验 支持 不支持

三、@Valid校验

1.@Valid主要用法

  • 在实体中的属性上,添加不同的注解(如下)来完成不同的校验。
  • 在接口类中的接收数据参数中添加 @Valid 注解。

2.实体注解详解

@NotEmpty:元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank:验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格。
@Null:只能为null
@NotNull:不为null
@Email:验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式
@AssertFalse:必须为false
@AssertTrue:必须为true
@DecimalMax(value):不大于指定值的数字
@DecimalMin(value):不小于指定值的数字
@Digits(integer,fraction):一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Max(value):不大于指定值的数字
@Min(value):不小于指定值的数字
@Future:必须是一个将来的日期(不包含现在)
@FutureOrPresent:必须是一个将来的日期(包含现在)
@Past:必须是一个过去的日期(不包含现在)
@PastOrPresent:必须是一个过去的日期(包含现在)
@Pattern(value):符合指定的正则表达式
@Size(max,min):限定字符长度在min到max之间
@Positive:数值是否是正数
@PositiveOrZero:数值是否是正数和0
@Negative:数值是否是负数
@NegativeOrZero:数值是否是负数和0

四、@Validated校验

    该注解属于Spring框架中的注解,见于spring-context-6.1.8.jar中的org.springframework.validation.annotation
`,此注解比较强大之处在于支持分组校验,分组是在实体类验证中常用的一种技术,它允许你根据不同的场景对验证规则进行分组,从而在不同的情况下应用不同的验证规则。

定义常用的校验组后,不仅可以单独使用,还可以联合使用。

1.自定义校验组

    以下为校验组空接口,作用于对象的属性参数上;名称可以自定义,以下仅列举部分,实际应用中可以根据需要进行自定义创建。

校验新增组

package cn.keyidea.common.valid;

/**
 * 空间接,区分校验场景,校验添加组
 *
 * @author qyd
 * @date 2022-10-18
 */
public interface GroupAdd {

}

校验更新组

package cn.keyidea.common.valid;

/**
 * 空间接,区分校验场景,校验更新组
 *
 * @author qyd
 * @date 2022-10-18
 */
public interface GroupUpdate {

}

校验校验自定义组(包含ID)

该校验组常和GroupUpdate联合使用,在涉及包括ID变更的接口中常用。

package cn.keyidea.common.valid;

/**
 * 空间接,区分校验场景,校验自定义组(包含ID)
 *
 * @author qyd
 * @date 2022-10-18
 */
public interface GroupCustomWithId {

}

校验状态组

package cn.keyidea.common.valid;

/**
 * 空间接,区分校验场景,校验状态组
 *
 * @author qyd
 * @date 2022-10-18
 */
public interface GroupStatus {

}

校验登录组

package cn.keyidea.common.valid;

/**
 * 空间接,区分校验场景,校验登录组
 *
 * @author qyd
 * @date 2022-10-18
 */
public interface GroupLogin {

}

校验修改密码组

package cn.keyidea.common.valid;

/**
 * 空间接,区分校验场景,校验修改密码组
 *
 * @author qyd
 * @date 2022-10-18
 */
public interface GroupChangePwd {

}

校验自定义分组

package cn.keyidea.common.valid;

/**
 * 空间接,区分校验场景,自定义校验
 *
 * @author qyd
 * @date 2024-05-25
 */
public interface GroupCustom {

}

在实际开发中,甚至可以按照每个控制器进行分类创建每个对象下的各自校验组,但出于抽象与简化,上述的校验组已经可以满足绝大多数场景使用。

2.使用示例

这里以数据新增和数据更新为典型场景进行示范

  • 分别以数据添加和数据更新为场景,以系统配置类为示例进行
  • 新增数据时,使用GroupAdd进行分组校验
  • 数据更新时,使用GroupUpdate进行分组校验
  • 使用分组校验时需使用@Validated注解;并且一般只作用于对象参数上!

系统配置控制器端配置<SysController.java>

package cn.keyidea.sys.controller;

import cn.keyidea.common.annotation.SysLogAnnotation;
import cn.keyidea.common.bean.BaseRes;
import cn.keyidea.common.config.InitConfigProperties;
import cn.keyidea.common.constant.ConstantsExpand;
import cn.keyidea.common.valid.GroupAdd;
import cn.keyidea.common.valid.GroupUpdate;
import cn.keyidea.sys.entity.SysConfig;
import cn.keyidea.sys.service.SysConfigService;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

/**
 * 系统配置控制器
 *
 * @author qyd
 * @date 2022-10-17
 */
@ApiSupport(order = 7)
@Tag(name = "7-系统配置", description = "系统配置")
@RestController
@RequestMapping("/sys/sysConfig")
public class SysConfigController
{

    private final static Logger logger = LoggerFactory.getLogger(SysConfigController.class);

    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private InitConfigProperties initConfigProperties;

  ......
    @SysLogAnnotation(module = "配置管理", serviceDesc = "配置管理-配置新增", serviceType = ConstantsExpand.ServiceType.ADD)
    @ApiOperationSupport(author = "qyd", order = 2, includeParameters = {
            "sysConfig.sysConfigName",
            "sysConfig.sysConfigCode",
            "sysConfig.sysConfigValue",
            "sysConfig.remark"
    })
    @Operation(summary = "配置新增", description = "")
    @PostMapping("add")
    public BaseRes add(@Validated(GroupAdd.class) @RequestBody SysConfig sysConfig)
    {
        return sysConfigService.add(sysConfig);
    }

    @SysLogAnnotation(module = "配置管理", serviceDesc = "配置管理-配置更新", serviceType = ConstantsExpand.ServiceType.UPDATE)
    @ApiOperationSupport(author = "qyd", order = 3, includeParameters = {
            "sysConfig.id",
            "sysConfig.sysConfigName",
            "sysConfig.sysConfigValue",
            "sysConfig.remark"
    })
    @Operation(summary = "配置更新", description = "配置key值一旦设置便不可更改,除非删除")
    @PutMapping("/update")
    public BaseRes update(@Validated(GroupUpdate.class) @RequestBody SysConfig sysConfig)
    {
        return sysConfigService.update(sysConfig);
    }
  ......

}

系统配置实体类<SysConfig.java>

package cn.keyidea.sys.entity;

import cn.keyidea.common.bean.BaseModel;
import cn.keyidea.common.valid.GroupAdd;
import cn.keyidea.common.valid.GroupUpdate;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;

/**
 * 系统配置表
 *
 * @author qyd
 * @date 2022-10-17
 */
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@TableName("sys_config")
@Table(name = "sys_config")
@Schema(name = "SysConfig", description = "系统配置")
@Comment("系统配置表")
public class SysConfig extends BaseModel {

    @NotBlank(message = "配置名称不能为空", groups = {GroupAdd.class, GroupUpdate.class})
    @Schema(description = "配置名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "名称1")
    @Column(name = "name", columnDefinition = "varchar(50) not null COMMENT '配置名称'")
    private String name;

    /**
     * 参见:{@link cn.keyidea.common.constant.Constants.SYS_CONFIG_CODE}
     */
    @NotBlank(message = "配置标识值为空", groups = {GroupAdd.class, GroupUpdate.class})
    @Schema(description = "配置标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "code1")
    @Column(name = "code", columnDefinition = "varchar(50) not null COMMENT '配置标识'")
    private String code;

    @NotBlank(message = "配置项值为空", groups = {GroupAdd.class, GroupUpdate.class})
    @Schema(description = "配置项值", requiredMode = Schema.RequiredMode.REQUIRED, example = "value1")
    @Column(name = "value", columnDefinition = "varchar(50) not null COMMENT '配置项值'")
    private String value;

    @Schema(description = "配置项描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "说明/描述")
    @Column(name = "remark", columnDefinition = "varchar(255) COMMENT '配置项描述'")
    private String remark;

}

由于系统配置实体类继承了基类,基类(<BaseModel.java>)中也进行了校验分组

package cn.keyidea.common.bean;

import cn.keyidea.common.valid.GroupChangePwd;
import cn.keyidea.common.valid.GroupCustomWithId;
import cn.keyidea.common.valid.GroupUpdate;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.io.Serial;
import java.io.Serializable;
import java.util.Date;


/**
 * 实体父类
 * <p>
 * 特殊说明:
 * 继承此基类的实体类,如果使用lombok的@Data注解时,主要同时添加@EqualsAndHashCode(callSuper = true)注解
 * 1)注解@EqualsAndHashCode(callSuper = true),就是用自己的属性和从父类继承的属性来生成hashcode;
 * 2)注解@EqualsAndHashCode(callSuper = false),就是只用自己的属性来生成hashcode;
 * 3)@Data相当于@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode这5个注解的合集, 和@EqualsAndHashCode默认是false。
 * <p>
 * MappedSuperclass注解说明:
 * 1.@MappedSuperclass注解仅仅能标准在类上;这个注解标识在父类上面的,用来标识父类
 * 2.标注为@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,可是他的属性都将映射到其子类的数据库字段中
 * 3.标注为@MappedSuperclass的类不能再标注@Entity或@Table注解
 * <p>
 * EntityListeners注解及相关说明:
 * EntityListeners:该注解用于指定Entity或者superclass上的回调监听类
 * AuditingEntityListener:这是一个JPA Entity Listener,用于捕获监听信息,当Entity发生持久化和更新操作时
 *
 * @author qyd
 * @date 2022-10-17
 */
@SuperBuilder   // @SuperBuilder支持对基类成员属性的构造;如果子类继承了BaseModel,也需要使用该注解
@AllArgsConstructor // 全参构造函数
@NoArgsConstructor  // 空参构造函数
@Data
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Schema(name = "BaseModel", description = "实体父类")
public class BaseModel implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    @NotNull(message = "ID不能为NUll", groups = {GroupUpdate.class, GroupChangePwd.class, GroupCustomWithId.class})
    @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
    @Id
    @Column(name = "id", columnDefinition = "int(10) COMMENT '自增长ID'")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @Column(name = "create_time", updatable = false, columnDefinition = "datetime not null COMMENT '创建时间'")
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;

    @Schema(description = "创建人ID", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
    @Column(name = "create_by", updatable = false, columnDefinition = "int(10) not null COMMENT '创建人ID'")
    @TableField(value = "create_by", fill = FieldFill.INSERT)
    private Integer createBy;

    @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @Column(name = "update_time", columnDefinition = "datetime COMMENT '更新时间'")
    @TableField(value = "update_time", fill = FieldFill.UPDATE)
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;

    @Schema(description = "更新人ID", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
    @Column(name = "update_by", columnDefinition = "int(10) COMMENT '更新人ID'")
    @TableField(value = "update_by", fill = FieldFill.UPDATE)
    private Integer updateBy;

}

五、自定义注解1:实现枚举校验

1.自定义枚举注解类<EnumValue.java>

package cn.keyidea.common.annotation;


import jakarta.validation.Constraint;
import jakarta.validation.Payload;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * 枚举校验注解, 处理类参见:{@link EnumValueValidator}
 *
 * @author qyd
 * @date 2021-11-09
 */
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {EnumValueValidator.class})
public @interface EnumValue {

    // 默认错误消息
    String message() default "必须为指定值";

    String[] strValues() default {};

    int[] intValues() default {};

    // 分组
    Class<?>[] groups() default {};

    // 负载
    Class<? extends Payload>[] payload() default {};

    // 指定多个时使用
    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
    @Retention(RUNTIME)
    @Documented
    @interface List {
        EnumValue[] value();
    }
}

2.自定义枚举注解处理类<EnumValueValidator.java>

支持整型枚举和字符串枚举。

package cn.keyidea.common.annotation;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;

/**
 * 枚举校验注解处理类, 注解类参见:{@link EnumValue}
 *
 * @author qyd
 * @date 2021-11-09
 */
public class EnumValueValidator implements ConstraintValidator<EnumValue, Object> {

    private String[] strValues;
    private int[] intValues;

    @Override
    public void initialize(EnumValue constraintAnnotation) {
        strValues = constraintAnnotation.strValues();
        intValues = constraintAnnotation.intValues();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
        if (value instanceof String) {
            for (String s : strValues) {
                if (s.equals(value)) {
                    return true;
                }
            }
        } else if (value instanceof Integer) {
            for (int s : intValues) {
                if (s == ((Integer) value).intValue()) {
                    return true;
                }
            }
        }
        return false;
    }
}

3.使用示例

    在属性字段进行枚举的字段上添加注解@EnumValue,并在intValues中枚举出正常的数据,不在此列中的数据将会报错,并由全局异常捕获类处理返回。

/**
 * 切片标志:
 * 该标志由运营单位生成,并对空口无线资源进行标记和对用户进行标记,取值为“0、1、2、3、4、5
 * 取值为“0”时表示没有切片标志,取值为“>0”时表示对应的切片标志
 * <p>
 * 参见{@link Resource#getSliceId()}
 */
@EnumValue(intValues = {0, 1, 2, 3, 4, 5}, groups = {GroupAdd.class, GroupUpdate.class})
@NotNull(message = "切片标志不能为NULL", groups = {GroupAdd.class, GroupUpdate.class})
@Schema(description = "切片标志:[0,5]", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@Column(name = "slice_id", columnDefinition = "int(10) not null COMMENT '切片标志:[0,5]'")
private Integer sliceId;

除了支持枚举整型外,还支持枚举字符串,在此不表;另外自定义枚举类也支持分组校验。

六、配置全局异常返回

    由于使用上述校验时,报错会报MethodArgumentNotValidException异常,因此在全局异常捕获类中,对该类进行单独处理,实现数据返回的统一封装,统一返回封装类见附录A<BaseRes.java>

AppExceptionHandler全局异常捕获处理

package cn.keyidea.common.config;

import cn.keyidea.common.bean.BaseRes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理
 *
 * @author LiGang
 * @date 2019-05-29
 */
@RestControllerAdvice
public class AppExceptionHandler {

    private final static Logger logger = LoggerFactory.getLogger(AppExceptionHandler.class);


    @ExceptionHandler(value = {BusinessException.class})
    public BaseRes business(BusinessException ex) {
        logger.error("业务异常:" + ex.getMessage());
        return BaseRes.invalidParam("业务异常:" + ex.getMessage());
    }

    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public BaseRes methodArgumentNotValidException(MethodArgumentNotValidException ex) {
        String field = ex.getBindingResult().getFieldError().getField().replace("parameter.", "");
        String message = ex.getBindingResult().getFieldError().getDefaultMessage();
        logger.error("验证失败:字段[" + field + "]" + message);
        return BaseRes.invalidParam("验证失败:字段[" + field + "]" + message);
    }

    // 专门用于GET分页查询时,使用注解@ModelAttribute接收对象参数时,添加了@Valid等校验时的验证使用
    @ExceptionHandler(value = {BindException.class})
    public BaseRes bindException(BindException ex) {
        String field = ex.getBindingResult().getFieldError().getField().replace("parameter.", "");
        String message = ex.getBindingResult().getFieldError().getDefaultMessage();
        logger.error("验证失败:字段[" + field + "]" + message);
        return BaseRes.invalidParam("验证失败:字段[" + field + "]" + message);
    }

    @ExceptionHandler(value = {AuthorizationException.class})
    public BaseRes authorizationException(AuthorizationException ex) {
        logger.error("没有权限:" + ex.getMessage());
        return BaseRes.fail("没有权限:" + ex.getMessage());
    }

    @ExceptionHandler(value = {Exception.class})
    public BaseRes exception(Exception ex) {
        logger.error("系统异常:" + ex.getMessage());
        ex.printStackTrace();
        return BaseRes.fail("系统异常:" + ex.getMessage());
    }
}

附录A<BaseRes.java>

package cn.keyidea.common.bean;

import cn.keyidea.common.constant.StatusCode;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.io.Serializable;

/**
 * 通用响应封装,范式返回(Swagger要求)
 *
 * @author qyd
 */
@Data
public class BaseRes<T> implements Serializable {

    /**
     * 错误码
     */
    @Schema(name = "code", description = "错误码,当code为1000时返回正常,其余返回异常", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
    public Integer code;

    /**
     * 错误提示信息
     */
    @Schema(name = "msg", description = "错误提示信息,当code为非1000时返回提示信息", requiredMode = Schema.RequiredMode.REQUIRED, example = "请求成功")
    public String msg;

    /**
     * 附加返回数据
     */
    @Schema(name = "data", description = "附加返回数据,当code为1000时返回数据")
    public T data;

    public static class DataList<T> {
        /**
         * 记录总数
         */
        @Schema(name = "total", description = "记录总数")
        public Integer total;
        /**
         * 数据列表
         */
        @Schema(name = "list", description = "数据列表")
        public T list;

        public DataList(Integer total, T list) {
            this.total = total;
            this.list = list;
        }
    }

    /**
     * 给ObjectMapper用的,代码中不要调用
     */
    public BaseRes() {

    }

    /**
     * 自定义返回码和提示消息
     *
     * @param code 错误码
     * @param msg  提示文字
     */
    public BaseRes(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public BaseRes(int code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    /**
     * 返回成功,但是没有附加数据
     *
     * @return BaseRes对象
     */
    public static BaseRes success() {
        return new BaseRes(StatusCode.SUCCESS.getCodeValue(), "请求成功");
    }

    /**
     * 返回成功,带附加数据
     *
     * @param data 附加数据
     * @return BaseRes对象
     */
    public static BaseRes successData(Object data) {
        BaseRes value = new BaseRes(StatusCode.SUCCESS.getCodeValue(), "请求成功");
        value.data = data;
        return value;
    }

    /**
     * 返回参数无效响应
     *
     * @return BaseRes对象
     */
    public static BaseRes invalidParam() {
        return new BaseRes(StatusCode.INVALID_PARAM.getCodeValue(), "参数无效");
    }

    /**
     * 返回参数无效响应,自定义错误提示
     *
     * @param msg 提示文字
     * @return BaseRes对象
     */
    public static BaseRes invalidParam(String msg) {
        return new BaseRes(StatusCode.INVALID_PARAM.getCodeValue(), msg);
    }

    /**
     * 返回系统忙无效响应
     *
     * @return BaseRes对象
     */
    public static BaseRes systemBusy() {
        return new BaseRes(StatusCode.SYSTEM_BUSY.getCodeValue(), "系统忙");
    }

    /**
     * 返回master key无效响应
     *
     * @return BaseRes对象
     */
    public static BaseRes invalidMasterkey() {
        return new BaseRes(StatusCode.INVALID_MASTER_KEY.getCodeValue(), "没有接口访问权限");
    }

    /**
     * 返回失败,附带说明
     *
     * @return BaseRes对象
     */
    public static BaseRes fail(String msg) {
        return new BaseRes(StatusCode.FAILURE.getCodeValue(), msg);
    }

    /**
     * 返回错误信息时,仍然返回数据
     *
     * @param data 数据集
     * @param msg  错误信息
     * @return BaseRes对象
     */
    public static BaseRes failData(Object data, String msg) {
        return new BaseRes(StatusCode.FAILURE.getCodeValue(), msg, data);
    }

    /**
     * 登录失效的错误
     *
     * @return BaseRes对象
     */
    public static BaseRes invalidToken() {
        return new BaseRes(StatusCode.INVALID_TOKEN.getCodeValue(), "请先登录");
    }

    /**
     * 检查响应处理是否成功
     *
     * @return 成功返回true,否则false
     */
    @JsonIgnore
    public boolean isSuccess() {

        return (this.code.equals(StatusCode.SUCCESS.getCodeValue()));
    }

    /**
     * 返回分页列表数据
     *
     * @param total 记录总数
     * @param list  列表数据
     * @return rsp
     */
    public static BaseRes list(long total, Object list) {
        DataList data = new DataList((int) total, list);

        return BaseRes.successData(data);
    }
}

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354

推荐阅读更多精彩内容