接口参数校验

news2025/1/8 21:41:11

方式一:使用hibernate-validator注解方式参数校验


类似的框架太多了。缺点:返回的提示信息顺序不太确定

文档:https://hibernate.org/validator/documentation/

参考资料:https://blog.csdn.net/weixin_45080272/article/details/128413908

<dependency>
  <groupId>org.hibernate.validator</groupId>
  <artifactId>hibernate-validator</artifactId>
</dependency>

① 在实体类的字段上添加参数校验的注解,如@Max、@Min、@NotNull等校验规则

/**
 * 模板类型:1-同城寄,2-省内寄,3-经济区互寄,4-跨省
 */
@ApiModelProperty(value = "模板类型:1-同城寄,2-省内寄,3-经济区互寄,4-跨省", required = true)
@Max(value = 4, message = "类型值必须是1、2、3、4")
@Min(value = 1, message = "类型值必须是1、2、3、4")
@NotNull(message = "模板类型不能为空")
private Integer templateType;

② 在对应controller类上添加@@Validated 注解,表示开启参数校验

@Slf4j
@Validated // 开启参数校验
@RestController
@Api(tags = "运费管理")
@RequestMapping("/carriages")
public class CarriageController {
    ......
}    

对于表单、url参数校验,在controller方法入参上添加校验规则:

image.png
常见的校验注解:

  • @Null 被注释的元素必须为 null
  • @NotNull 被注释的元素必须不为 null
  • @AssertTrue 被注释的元素必须为 true
  • @AssertFalse 被注释的元素必须为 false
  • @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
  • @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
  • @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
  • @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
  • @Size(max=, min=) 被注释的元素的大小必须在指定的范围内
  • @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
  • @Past 被注释的元素必须是一个过去的日期
  • @Future 被注释的元素必须是一个将来的日期
  • @Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
  • Hibernate Validator 提供的校验注解:
    • @NotBlank(message =) 验证字符串非null,且长度必须大于0
    • @Email 被注释的元素必须是电子邮箱地址
    • @Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
    • @NotEmpty 被注释的字符串的必须非空
    • @Range(min=,max=,message=) 被注释的元素必须在合适的范围内

对于controller方法入参的实体类数进行校验:(需要在方法形参前面添加@Valid注解,这样实体类里的字段校验规则才能生效)

@PostMapping
public CarriageDTO saveOrUpdate(@Valid @RequestBody CarriageDTO carriageDto) {
    return carriageService.saveOrUpdate(carriageDto);
}

但是这样操作太耦合了,每次使用都要往形参对象上加注解。

补充:使用AOP切面方式,在方法入参时对请求体对象进行参数校验

/**
 * 请求参数校验切面,统一对Controller中@RequestBody映射的对象进行校验,在Controller方法中无需单独处理
 */
@Aspect // 声明当前类为切面
@Slf4j
@EnableAspectJAutoProxy // 开启AOP注解功能
@Component
public class ValidatedAspect {

    @Resource
    private Validator validator; //javax提供的参数校验

    /**
     * 定义切面---在controller方法入参时对请求体对象进行参数校验(校验规则在实体类中)
     *
     * @param proceedingJoinPoint 切入点对象
     * @return
     * @throws Throwable
     */
    // @Around: 环绕通知,可以在目标方法执行前后进行一些处理,方法参数与原方法一致, 返回值类型与原方法返回值类型一致
    // 切点表达式: "execution(* com.sl..controller.*Controller.*(..))",匹配所有controller方法
    @Around("execution(* com.sl..controller.*Controller.*(..))")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // 获取@RequestBody映射的对象:请求体对象
        Object body = AspectUtil.getBody(proceedingJoinPoint);
        // 不为空的body进行拦截校验
        if (!ObjectUtil.isEmpty(body)) {
            // 进行校验
            // validator.validate(body):验证实体对象中的所有约束,他把校验失败的字段信息封装成一个Set集合返回
            Set<ConstraintViolation<Object>> validateResult = validator.validate(body);
            if (CollUtil.isNotEmpty(validateResult)) {
                //如果校验结果不为空,表示没有通过校验,则抛出异常,由统一异常处理机制进行处理,响应400
                String info = JSONUtil.toJsonStr(validateResult.stream()
                        .map(ConstraintViolation::getMessage).collect(Collectors.toList()));
                throw new SLException(info, HttpStatus.BAD_REQUEST.value());
            }
        }
        //校验通过,执行原方法:roceedingJoinPoint.proceed(传原方法的入参)
        return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
    }
}
/**
 * 切面工具类
 * 
 * @author 白豆五
 * @date 2023/09/04
 * @since JDK8
 */
@Slf4j
public class AspectUtil {

    /**
     * 获取被拦截方法对象
     * @param pjp {@link ProceedingJoinPoint}
     * @return {@link Method}
     */
    public static Method getMethod(ProceedingJoinPoint pjp) {
        //获取参数的类型
        Signature sig = pjp.getSignature();
        if (sig instanceof MethodSignature) {
            MethodSignature methodSignature = (MethodSignature) sig;
            return methodSignature.getMethod();
        } else {
            throw new IllegalArgumentException("It's not method");
        }
    }

    /**
     * 解析SPEL表达式
     *
     * @param key key
     * @param method {@link   Method}
     * @param args {@code Object[]}
     * @return key
     */
    public static String parse(String key, Method method, Object[] args) {
        if (StringUtils.isNotBlank(key) && key.indexOf("#") > -1) {
            Pattern pattern = Pattern.compile("(\\#\\{([^\\}]*)\\})");
            Matcher matcher = pattern.matcher(key);
            List<String> keys = new ArrayList<>();
            while (matcher.find()) {
                keys.add(matcher.group());
            }
            if (!CollectionUtils.isEmpty(keys)) {
                LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
                String[] paraNameArr = u.getParameterNames(method);
                ExpressionParser parser = new SpelExpressionParser();
                StandardEvaluationContext context = new StandardEvaluationContext();
                for (int i = 0; i < paraNameArr.length; i++) {
                    context.setVariable(paraNameArr[i], args[i]);
                }
                for (String tmp : keys) {
                    key = key.replace(tmp, parser.parseExpression("#" + tmp.substring(2, tmp.length() - 1)).getValue(context, String.class));
                }
                return key;
            }
        }
        return key;
    }

    /**
     * 获取请求体
     *
     * @param pjp {@link ProceedingJoinPoint}
     * @return {@code Object}
     */
    public static Object getBody(ProceedingJoinPoint pjp) {
        Object[] args = pjp.getArgs();
        Method method = getMethod(pjp);

        if (ObjectUtil.isNotEmpty(args)) {
            Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            for (int count = 0; count < parameterAnnotations.length; count++) {
                for (Annotation annotation : parameterAnnotations[count]) {
                    if (annotation instanceof RequestBody) {
                        return args[count];
                    }
                }
            }
        }
        return null;
    }
}


方式二:在程序中使用if语句进行参数校验


最粗暴的方式。

public boolean updateStatus(List<String> ids) {
    if(CollUtil.isEmpty(ids)){
         return false;       
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/979186.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++二叉树

代码随想录 (programmercarl.com) 二叉树理论基础篇 #算法公开课 《代码随想录》算法视频公开课 (opens new window) 大纲如下&#xff1a; 说到二叉树&#xff0c;大家对于二叉树其实都很熟悉了&#xff0c;本文呢我也不想教科书式的把二叉树的基础内容再啰嗦一遍&#xf…

npm/yarn link 测试包时报错 Warning: Invalid hook call. Hooks can only be called ...

使用 dumi 开发 React 组件库时&#xff0c;为避免每次修改都发布到 npm&#xff0c;需要在本地的测试项目中使用 npm link 为组件库建立软连接&#xff0c;方便本地调试。 结果在本地测试项目使用 $ npm link 组件库 后&#xff0c;使用内部组件确报错&#xff1a; react.dev…

4.(高级示例篇)leaflet移动端交互示例

注&#xff1a;高级示例博客不提供源码 地图之家总目录&#xff08;订阅之前建议先查看该博客&#xff09; 效果如下所示&#xff1a; leaflet移动端交互示例

2023年必须要知道的AI热词,看这一篇就够了!

2023年是AI工具大爆发的一年&#xff0c;随着AI的快速发展&#xff0c;出现了很多AI相关的名词&#xff0c;今天带你详细了解那些热门的AI词。 思维导图&#xff1a; https://gitmind.cn/app/docs/muksa9nd AI 人工智能 Artificial Intelligence&#xff0c;即人工智能&…

如何在VueJS应用程序中设置Toast通知

通知是开发者提升应用程序互动性和改善用户体验的强大工具。通过利用通知&#xff0c;开发者可以在用户与应用程序互动的同时&#xff0c;有效地向用户传达重要事件。 通知在应用程序中起着至关重要的作用&#xff0c;可以及时通知用户有关各种操作和事件的信息。它们可以用于通…

【sgCreateAPI】自定义小工具:敏捷开发→自动化生成API接口脚本(接口代码生成工具)

<template><div :class"$options.name"><div class"sg-head">接口代码生成工具</div><div class"sg-container"><div class"sg-start "><div style"margin-bottom: 10px;">接口地…

uniapp 网络请求封装(uni.request 与 uView-Plus)

一、背景 在开发项目中&#xff0c;需要经常与后端服务器进行交互&#xff1b;为了提高开发效率和代码维护性&#xff0c;以及降低重复性代码&#xff0c;便对网络请求进行封装统一管理。 二、创建环境文件 2.1、根目录新建utils文件夹&#xff0c;utils文件夹内新建env.js文…

中缀表达式 - 栈实现综合计算器

代码&#xff1a; package Algotithm.stackobject Calculator {def main(args: Array[String]): Unit {val expression "32*6-2"//创建两个栈&#xff1a;数栈、符号栈val numStack, operStack new ArrayStack2(10)//定义需要的相关变量var index, num1, num2, …

iOS开发Swift-9-SFSymbols,页面跳转,view屏幕比例,启动页-和风天气AppUI

1.创建项目 2.设置好测试机型,App显示名称,以及关闭横向展示. 3.下载SF Symbols. https://developer.apple.com/sf-symbols/ 右上角搜索 search ,可以找到很多系统自带图标.选择喜欢的图标,拷贝图标的名字. 插入一个Button,在Image中粘贴图标名称并选择,即可将Button变成想要的…

遥感图像应用:在低分辨率图像上实现洪水损害检测

代码来源&#xff1a;https://github.com/weining20000/Flooding-Damage-Detection-from-Post-Hurricane-Satellite-Imagery-Based-on-CNN/tree/master 数据储存地址&#xff1a;https://github.com/JeffereyWu/FloodDamageDetection/tree/main 数据详情&#xff1a;训练数据…

决策工具箱:战略分析必备工具与框架

跟随时代的步伐&#xff0c;企业战略也在不断演化。无论是初创企业还是知名企业&#xff0c;都需要有效的战略工具来指导其业务发展。探索这些必备工具&#xff0c;并学习如何最大限度地利用它们&#xff0c;是企业的一个学习目标。 战略分析工具和框架有很多&#xff0c;其中…

读懂AUTOSAR规范,之CanIf 发送缓冲(带实例代码)

1. General behavior一般行为 在CanIf范围内,传输过程始于调用CanIf_Transmit(),并在调用上层模块的回调服务<User_TxConfirmation>()时结束。在传输过程中,CanIf、CanDrv和CAN邮箱应共同将要传输的L-PDU仅存储一次在单个位置。根据传输方法,这些位置可以是: • CA…

Java字符串查找

目录 1.查找字符 &#xff08;1&#xff09;以索引查找字符 &#xff08;2&#xff09;以字符查找索引 2.查找字符串 在给定的字符串中查找需要的字符或字符串是常见的操作&#xff0c;以下是String类中常用的查找方法。 1.查找字符 查找字符分为两种情况&#xff1a;一种…

【两周学会FPGA】从0到1学习紫光同创FPGA开发|盘古PGL22G开发板学习之DDR3 IP简单读写测试(六)

本原创教程由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处 适用于板卡型号&#xff1a; 紫光同创PGL22G开发平台&#xff08;盘古22K&#xff09; 一&#xff1a;盘古22K开发板&#xff08;紫光同创PGL22G开发…

【Ubuntu20.04】【验证可行】修改切换输入法的快捷键

网上好多博客都是说添加输入法什么的&#xff0c;没说到关键点。 修改切换输入法的快捷键&#xff0c;是在系统设置的键盘快捷键那里修改的&#xff0c; 不是在输入法那里改的&#xff0c;如下图 看到上面的【Keyboard shortcuts】/ 【Typing】 默认是SuperSpace【微软键盘就…

电梯五方对讲接口说明 Sip五方对讲使用说明

1.2/4线接线模块输出接口;接4方对讲设备:12V&#xff0c;2/4线接线模块供电输入 -:GND&#xff0c;接地 R二/四线R Li二四线L 2.RS-485接口:预留援口&#xff0c;可接读卡器、楼层控制器、探头&#xff0c;需要软件额外开发实现。 3.短路输出接口2:对应短路输入接口&#x…

Vue2+Vue3基础入门到实战项目(六)——课程学习笔记

镇贴&#xff01;&#xff01;&#xff01; day07 vuex的基本认知 使用场景 某个状态 在 很多个组件 来使用 (个人信息) 多个组件 共同维护 一份数据 (购物车) 构建多组件共享的数据环境 1.创建项目 vue create vuex-demo 2.创建三个组件, 目录如下 |-components |--Son1.…

centos密码过期导致navicat无法通过SSH登录阿里云RDS问题

具体错误提示&#xff1a;2013 - Lost connection to server at "hand hake: reading initial communication packet, system error: 0 解决办法&#xff1a;更新SSH服务器密码

超越时间与人力的软件开发智慧:《人月神话》

目录 1、写在前面2、沟通&#xff01;沟通&#xff01;沟通&#xff01;3、“银弹论”4、“人月神话”不能成立的原因5、影响力6、图书推荐 1、写在前面 《人月神话》是由计算机科学家弗雷德里克布鲁克斯所著的一本经典著作&#xff0c;首次出版于1975年。这本书以一个个小故事…

@Controller和@RestController注解区别

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;SpringBoot、Spring、注解、Controller、RestController☀️每日 一言&#xff1a;弗雷尔卓德是个好地方&#xff0c;可以造东西、打架、大吃一顿&#xff0c;啊~~ 甜蜜的家园呐 ——《英雄联盟》…