JAVA接口数据校验代码规范

基本概要

接口数据校验基本上是每个系统必须做的事情,后端服务永远不要将数据校验寄托于前端页面的校验。因为很多时候当别人获取到身份凭证时,就可以通过其他工具调过前端界面进行接口请求,因此接口参数在后端必须再次进行一次校验。而像Spring这种框架提供了校验接口数据的功能,比如Spring Validator可以通过注解配置的方式,校验数据。如果未使用Spring Validator,那么很多校验基本都是在控制层Controller进行接口数据校验。当需要校验参数过多时,Controller层似乎就变成非常臃肿,因此接口数据的校验应该放到接口对象本身去处理。这并不涉及任何技术点,而是提供一种代码处理的思路

整体结构流程

当一个接口确定对外暴露时,就表明这个接口存在一定的风险点,除了需要对请求者身份的校验,更应该对接口参数进行校验。一般接口参数校验的范围包括一下几点:参数为空;参数为NULL;参数长度超长;参数格式不正确,比如手机号格式不对或者邮箱格式不对。很多人希望在控制层Controller进行参数校验,因此导致Controller就因为一个参数校验导致代码是否臃肿和阅读困难。如果以下代码:

在这里插入图片描述
这还是参数较少的情况,如果一个接口需要校验的参数有几十个,那么Controller将变的更加臃肿。因此参数校验这一部分应该放到参数对象中来处理,也就是常说的解铃还须系铃人。

代码实现样例

更佳的处理方法就是将参数校验这一部分的功能移至参数对象本身,也叫做自检。这样的好处就是更小的侵入性以及复用性更高。案例中创建一个请求对象SaveUserRequestVO,用于接受外部传来的数据,并在SaveUserRequestVO中定义一个valid方法来进行自身数据校验。


import com.alibaba.fastjson.JSONObject;
import com.common.exception.BusinessException;
import com.common.exception.ErrorCode;
import lombok.Data;
import org.springframework.util.StringUtils;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;

import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: Greyfus
 * @Create: 2024-07-30 19:50
 * @Version: 1.0.0
 * @Description:保存用户请求参数VO
 */
@Data
public class SaveUserRequestVO implements Serializable {

    //用户名称
    private String userName;

    //用户编码
    private String userCode;

    //手机
    private String phone;

    //年级
    private Integer age;

    //邮箱
    private String email;

    /**
     * 自身参数校验
     *
     * @return Errors
     */
    public void valid() {
        Errors errors = new BeanPropertyBindingResult(this, this.getClass().getName());
        if (StringUtils.isEmpty(userName)) {
            errors.rejectValue("userName", "userName.required", "property userName is missing");
        }
        if (StringUtils.isEmpty(userCode)) {
            errors.rejectValue("userCode", "userCode.required", "property userCode is missing");
        }
        if (StringUtils.isEmpty(phone)) {
            errors.rejectValue("phone", "phone.required", "property phone is missing");
        }
        if (age == null) {
            errors.rejectValue("age", "age.required", "property age is missing");
        }
        if (StringUtils.isEmpty(email)) {
            errors.rejectValue("email", "email.required", "property email is missing");
        }
        if (errors.hasErrors()) {//判断参数是否存在错误
            List<ValidatorError> validatorErrors = errors.getAllErrors().stream().map(error -> {
                return new ValidatorError(((FieldError) error).getField(), error.getDefaultMessage());
            }).collect(Collectors.toList());
            throw new BusinessException(ErrorCode.INVALID_PARAMS.code(), JSONObject.toJSONString(validatorErrors));//抛出自检异常信息
        }
    }
}

ValidatorError用于收集参数校验的错误信息,当某个参数校验不过时,则会调用errors.rejectValue方法将错误信息注册到Errors对象,当校验参数完成,则通过判断Errors是否有注册的错误信息,存在错误信息则将信息存入ValidatorError,再通过ValidatorError把信息返回给客户端。

import lombok.Data;

/**
 * @Author: Greyfus
 * @Create: 2024-07-30 20:19
 * @Version: 数据校验错误对象
 * @Description: 1.0.0
 */
@Data
public class ValidatorError {

    //字段名称
    private String propertyName;

    //错误信息
    private String errorMsg;

    public ValidatorError(String propertyName, String errorMsg) {
        this.propertyName = propertyName;
        this.errorMsg = errorMsg;
    }

    public ValidatorError() {
    }
}

当参数校验逻辑放到参数对象自身后,对Controller层的代码侵入就会变的极小,业务代码也会变的更加清晰,这跟技术并无关联,而是一种解决方法的思路。在Controller层只需调用saveUserRequestVO.valid方法即可完成参数校验,并且可以被重复使用,也减小重复编码的工作量。

import com.common.exception.BusinessException;
import com.common.web.HttpUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * @Author: Greyfus
 * @Create: 2024-07-30 19:49
 * @Version:
 * @Description:
 */
@RequestMapping("web/user")
@Controller
public class UserSaveController extends BaseController {

    @RequestMapping(value = "/save", method = RequestMethod.POST, produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<?> save(@RequestBody SaveUserRequestVO saveUserRequestVO) throws BusinessException {
        saveUserRequestVO.valid();//参数自身校验
        return new ResponseEntity<>(success(), HttpUtils.SUCCESS_HTTP_HEADERS, HttpStatus.OK);//响应成功信息
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值