当前位置: 首页 > news >正文

使用JDK的数据校验和Spring的自定义注解校验前端传递参数的两种方法

第一种:JDK的数据校验注解

    @PostMapping("/test")public String test(QueryParam param, @RequestHeader(value = "App_key") String App_key,@RequestHeader(value = "App_secret") String App_secret) throws IOException {param.setApp_key(App_key);param.setApp_secret(App_secret);return service.test(param);}
@Data
public class QueryParam {private String url;private String App_key;private String App_secret;
}

QueryParam 里面的 url 为必传参数,当前端没有传递的时候,我需要报错提示前端,需要怎么做呢?

  1. 在QueryParam 里面的 url 字段上加上JDK的 NotBlank 注解
@Data
public class QueryParam {@NotBlank(message = "url参数不能为空")private String url;private String App_key;private String App_secret;
}
  1. 在接口的 QueryParam 参数前面加上 @Valid 注解
    @PostMapping("/test")public String test(@Valid QueryParam param, @RequestHeader(value = "App_key") String App_key,@RequestHeader(value = "App_secret") String App_secret) throws IOException {param.setApp_key(App_key);param.setApp_secret(App_secret);return service.test(param);}
  1. 在全局异常控制器中获取到 @NotBlank 注解上的描述信息,并返回给前端。
package com.tyler.web.exception;/*** 全局异常处理器*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {/*** 方法参数校验失败*/@ExceptionHandler(MethodArgumentNotValidException.class)public Result<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {e.printStackTrace();String errorMessage = e.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage) // 获取注解中定义的 message.findFirst().orElse("参数校验错误");return Result.fail(400, errorMessage, e.getMessage());}
}

这样写完之后就可以开启校验了。返回给前端的效果如下:

{"code": 400,"flag": false,"desc": "url参数不能为空","cause": "Validation failed for argument [0] in public java.lang.String com.yxai.web.controller.transfer.TransferController.entityExtraction(com.yxai.common.params.QueryParam,byte[],java.lang.String,java.lang.String) throws java.io.IOException: [Field error in object 'queryParam' on field 'url': rejected value [null]; codes [NotBlank.queryParam.url,NotBlank.url,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [queryParam.url,url]; arguments []; default message [url]]; default message [url参数不能为空]] ","traceId": "3806dae5-d8bc-48b0-8164-b947483c83e1","data": null
}

第二种:使用Spring的自定义注解校验

现在我想对接口上的 App_key 和 App_secret 做校验,这两个 header 也是必传字段,我需要怎么做呢?

在 Spring Boot 里可以借助@Validated注解和自定义校验注解达成对请求头参数的校验。当用户未传递App_key和App_secret时,就会给出相应的报错提示。

下面是具体的实现步骤与代码示例:

1. 自定义校验注解

先创建自定义的校验注解,用来校验请求头参数是否为空。

import com.tyler.web.utils.validator.NotEmptyValidator;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;import static java.lang.annotation.ElementType.*;// 自定义注解,用于校验字符串是否为空
@Target({METHOD,FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = NotEmptyValidator.class)
public @interface NotEmpty {String message() default "该参数为必传参数";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}

2. 实现校验逻辑

接着实现校验注解对应的校验器。

import com.tyler.web.annotation.NotEmpty;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;// 自定义注解的校验器
public class NotEmptyValidator implements ConstraintValidator<NotEmpty, String> {@Overridepublic void initialize(NotEmpty constraintAnnotation) {}@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {return value != null && !value.isEmpty();}
}
  1. 在接口方法上使用校验注解

最后在接口方法的请求头参数上运用自定义的校验注解。

    @PostMapping("/test")public String test(@Valid QueryParam param, @RequestHeader(value = "App_key") @NotEmpty(message = "App_key为必传参数") String App_key,@RequestHeader(value = "App_secret") @NotEmpty(message = "App_secret为必传参数") String App_secret) throws IOException {param.setApp_key(App_key);param.setApp_secret(App_secret);return service.test(param);}

然后在前端试一下不传递 App_key 或 App_secret, 你会发现返回结果如下:

{"code": 200000,"flag": false,"desc": "系统异常","cause": "Required request header 'App_secret' for method parameter type String is not present","traceId": "0fb0ccb5-c2cb-4dfd-b4bf-030a0c18bc89","data": null
}

似乎我们写的代码没有生效。

这个问题在于 Spring 框架在执行自定义校验逻辑之前,就因为请求头缺失而抛出了异常。@RequestHeader注解默认要求参数必须存在,若缺失就会直接抛出异常,不会触发后续的自定义校验。

我们可以把@RequestHeader的required属性设为false,允许请求头缺失,之后再通过自定义校验注解进行检查。以下是修改后的代码:

    @PostMapping("/test")public String test(@Valid QueryParam param, @RequestHeader(value = "App_key", required = false) @NotEmpty(message = "App_key为必传参数") String App_key,@RequestHeader(value = "App_secret", required = false) @NotEmpty(message = "App_secret为必传参数") String App_secret) throws IOException {param.setApp_key(App_key);param.setApp_secret(App_secret);return service.test(param);}

修改点说明:

把@RequestHeader的required属性设置成false,这样即便请求头缺失,Spring 也不会立即抛出异常,而是会继续执行后续的自定义校验逻辑。当App_key或App_secret为空时,@NotEmpty注解会发挥作用,抛出相应的校验异常。

然后前端试一下不传递 App_secret, 会返回如下结果:

{"code": 200001,"flag": false,"desc": "未知异常","cause": "receiptCropAndRecogMulti.App_secret: App_secret为必传参数","traceId": "d6d83dfd-fd05-456e-a3de-ed5f180e3b07","data": null
}

但是我觉得这个返回结果不好看,我想要 desc 返回我定义的描述信息,怎么做呢?

当 App_secret 或 App_key 缺失的时候,代码会抛出 ConstraintViolationException 异常,所以我们需要在全局异常控制器里面捕捉该异常,然后对其进行处理即可。

package com.tyler.web.exception;/*** 全局异常处理器*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {/*** 方法参数校验失败*/@ExceptionHandler(MethodArgumentNotValidException.class)public Result<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {e.printStackTrace();String errorMessage = e.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage) // 获取注解中定义的 message.findFirst().orElse("参数校验错误");return Result.fail(400, errorMessage, e.getMessage());}/*** 自定义注解参数错误*/@ExceptionHandler(ConstraintViolationException.class)public Result<Object> handleBindException(ConstraintViolationException e) {e.printStackTrace();ConstraintViolation<?> violation = e.getConstraintViolations().iterator().next();return Result.fail(400, violation.getMessage(), e.getMessage());}
}

然后再请求一次,返回结果如下:

{"code": 400,"flag": false,"desc": "App_key为必传参数","cause": "entityExtraction.App_key: App_key为必传参数","traceId": "a4537203-3820-4442-9c35-e3a9f653c489","data": null
}

这就是我想要的效果了,到此本教程结束。

http://www.xdnf.cn/news/201295.html

相关文章:

  • vue3+js项目el-table导出excel表(带边框)
  • 【重走C++学习之路】22、C++11语法
  • 深度学习---框架流程
  • vue的生命周期 以及钩子
  • C语言实现卡ID删除与排序
  • 高压场景首选:CKESC ROCK 120A-H CAN 电调技术解析与实测报告
  • 浅谈链表的优化技巧
  • Python对字典列表按某个字段排序
  • 假云阴影模拟
  • MYSQL-OCP官方课程学习截图
  • PCIe-8634四口千兆PoE以太网卡的性能与应用分析
  • 机器学习概述
  • vue3代码规范管理;基于vite和vue3、 eslint、prettier、stylelint、husky规范;git触发eslint校验
  • 铭依眼科亮相“中华眼科菁英“.创新思路赋能近视矫正新高度
  • 光学涡旋干涉仪
  • 鹧鸪云光伏项目智慧施工软件:数字化驱动的光伏建设新范式
  • 数据可视化大屏——物流大数据服务平台
  • 课堂案例分析
  • 01《音量控制器》Unity
  • python使用dlib的5点和68点的人脸检测
  • 2020南京区域赛vp
  • Linux系统之----程序地址空间
  • mac 基于Docker安装minio服务器
  • JavaWeb:vueaxios
  • MetaEditor - 自动交易和技术指标编辑器
  • 知识体系_用户研究_用户体验度量模型
  • Python3:Jupyterlab 安装和配置
  • Java并发探索--上篇
  • SD04_CurSor提示词
  • 计算字符串的编辑距离和单向链表中倒数第k个结点