欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 时评 > 使用JDK的数据校验和Spring的自定义注解校验前端传递参数的两种方法

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

2025/4/29 12:39:48 来源:https://blog.csdn.net/z284747/article/details/147595889  浏览:    关键词:使用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
}

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

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词