完善的java后台参数校验(包含单个参数校验,对象校验)

java后台参数校验

一. 单个参数的校验方式
实现原理:@ControllerAdvice,@Validated注解对参数进行校验
实现方式:
1.创建统一的系统常量

package com.hm.middle_service.common;

/**
 * @Author:huangzhimin
 * @Date:2020/6/2 描述:系统编码
 **/
public class CodeConst {
    /**
     * 操作成功编码
     */
    public static final String SUCESS_CODE = "succes";
    public static final String SUCESS_CODE_MSG = "操作成功";
    /**
     * 操作失败编码
     */
    public static final String FAIL_CODE = "fail";
    public static final String FAIL_CODE_MSG = "操作失败";

    /**
     * 参数异常
     */
    public static final String PARAMETER_EXCEPTION_CODE = "parameter_exception";
    public static final String PARAMETER_EXCEPTION_CODE_MSG = "参数异常";
}

2.创建统一的返回结果集

import com.hm.middle_service.common.CodeConst;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
 * Author:huangzhimin
 * Date:2020/5/8
 * 描述:用户返回给前端
 **/
@Getter
@Setter
@ToString
public class ResultBean<T> {
    /**
     * 系统编码
     */
    private String code;
    /**
     * 系统信息
     */
    private String msg;
    /**
     * 结果集
     */
    private T data;

    /**
     * 默认的构造函数
     */
    public ResultBean(){
        this.code = CodeConst.SUCESS_CODE;
        this.msg = CodeConst.SUCESS_CODE_MSG;
    }
//这里使用了lombok组件,不想用的话,直接使用get,set 方法即可
}

3.创建集中校验类

import com.hm.middle_service.bean.ResultBean;
import com.hm.middle_service.common.CodeConst;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * Author:huangzhimin
 * Date:2020/5/8
 * 描述:单个参数校验
 **/
@ControllerAdvice
public class ExceptionAdvice {
    @ResponseBody
    @ExceptionHandler(value = ConstraintViolationException.class)
    public ResultBean ConstraintViolationExceptionHandler(ConstraintViolationException ex) {
        ResultBean resultVO = new ResultBean();
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();
        List<String> msgList = new ArrayList<>();
        while (iterator.hasNext()) {
            ConstraintViolation<?> cvl = iterator.next();
            resultVO.setMsg(cvl.getPropertyPath().toString().split("\\.")[1] + " " + cvl.getMessageTemplate());
            resultVO.setCode(CodeConst.PARAMETER_EXCEPTION_CODE);
        }

        return resultVO;
    }

    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public ResultBean Exception(HttpServletRequest request,Exception e){
        ResultBean resultBean = new ResultBean();
        resultBean.setCode(CodeConst.FAIL_CODE);
        resultBean.setMsg(CodeConst.FAIL_CODE_MSG);
        return resultBean;
    }
}

4.在controller层实现校验
实现方式:在controller上添加注解@Validated

import com.hm.middle_service.bean.ResultBean;
import com.hm.middle_service.bean.UserBean;
import com.hm.middle_service.service.MiddleService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;

/**
 * Author:huangzhimin
 * Date:2020/3/5
 * 描述:
 **/
@Validated
@RestController
@RequestMapping("api/middle")
public class MiddleController {    
    @ResponseBody
    @RequestMapping("getNameByID")
    public ResultBean getNameByID(@NotNull(message = "不能为空") Integer id){
        //参数如果是int 型的需要用Integer 接受,不然可能导致错误捕获不到
        ResultBean resultBean = new ResultBean();
        try {
            if (id == 123){
                resultBean.setData("黄治敏");
            }else{
                resultBean.setData("查无此人");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return resultBean;
    }
}

5.试验结果userId不填时的校验结果

二.对实体类对象进行校验
1.添加一个校验配置类

import com.hm.middle_service.bean.ResultBean;
import com.hm.middle_service.common.CodeConst;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

import java.util.List;

/**
 * Author:huangzhimin
 * Date:2020/5/8
 * 描述:
 **/
@Component
@Aspect
public class BindingResultAop {
    /**
     * Path=com.aop.controller
     * 设置切入点: Path为路径根据实际情况替换即可
     */
    @Pointcut("execution(* com.hm.middle_service.controller..*.*(..))")
    public void method() {

    }
    /**
     * 检查 Controller 方法的参数是否合法 环绕通知:目标方法执行前后分别执行一些代码,发生异常的时候执行另外一些代码
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("method()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        BindingResult bindingResult = null;
        for (Object arg : joinPoint.getArgs()) {// 遍历被通知方法(controller方法)的参数列表
            if (arg instanceof BindingResult) {// 参数校验结果会存放在BindingResult中
                bindingResult = (BindingResult) arg;
            }
        }
        if (bindingResult != null) {
            if (bindingResult.hasErrors()) {// 检查是否存在校验错误
                List<FieldError> errors = bindingResult.getFieldErrors();// 获取字段参数不合法的错误集合
                for (FieldError error : errors) {
                    ResultBean resultVO = new ResultBean();
                    resultVO.setMsg(error.getField() + " " + error.getDefaultMessage());
                    resultVO.setCode(CodeConst.PARAMETER_EXCEPTION_CODE);
                    return resultVO;
                }
            }
        }
        return joinPoint.proceed();// 执行目标方法
    }
}

2.创建要校验的bean

import com.hm.middle_service.util.Insert;
import com.hm.middle_service.util.Update;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import javax.validation.constraints.NotNull;

/**
 * Author:huangzhimin
 * Date:2020/5/8
 * 描述:对对象进行校验
 **/
@Getter
@Setter
@ToString
public class ValueBean {
    /**
     * 主键
     */
    @NotNull(message = "主键不能空",groups = {Update.class})
    private Integer id;
    /**
     * name
     */
    @NotNull(message = "用户名不能为空",groups = {Insert.class,Update.class})
    private String name;
    /**
     * 年龄
     */
    @NotNull(message = "年龄不能为空",groups = {Insert.class,Update.class})
    private Integer age;
}

注:group 为分组,该类在不同请求中要校验的参数也不同,故需要进行分组处理,Insert.class,Update.class 为两个接口,只是用于标注分组
3.分组举例

public interface Insert {
}

4具体的请求校验方式为

@PostMapping("insertValueBean")
public ResultBean getUserBean(@Validated(Insert.class)@RequestBody ValueBean valueBean, BindingResult bindingResult){
    ResultBean resultBean = new ResultBean();
    try {
        resultBean.setData(valueBean);
    }catch (Exception e){
        e.printStackTrace();
        resultBean.setCode(CodeConst.FAIL_CODE);
        resultBean.setMsg(CodeConst.FAIL_CODE_MSG);
    }

    return resultBean;
}

@PostMapping("updateValueBean")
public ResultBean updateValueBean(@Validated(Update.class)@RequestBody ValueBean valueBean,BindingResult bindingResult){
    ResultBean resultBean = new ResultBean();
    try {
        resultBean.setData(valueBean);
    }catch (Exception e){
        e.printStackTrace();
        resultBean.setCode(CodeConst.FAIL_CODE);
        resultBean.setMsg(CodeConst.FAIL_CODE_MSG);
    }

    return resultBean;
}

注意点:@Validated(Update.class) 标注使用什么组进行校验 ,BindingResult bindingResult 为固定参数
如有问题欢迎大家联系:1411773544@qq.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值