Micronaut中如何校验@QueryValue查询参数的名称合法性?
Micronaut 控制器查询参数名称校验实现方案
方案一:自定义参数绑定器(ArgumentBinder)
这种方式可针对单个控制器方法灵活配置允许的查询参数,步骤如下:
- 创建自定义注解,用于标记允许的查询参数名称:
import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface AllowedQueryParams { String[] value(); }
- 实现自定义ArgumentBinder,负责校验请求中的查询参数是否在允许列表内:
import io.micronaut.core.bind.ArgumentBinder; import io.micronaut.core.convert.ArgumentConversionContext; import io.micronaut.http.HttpRequest; import io.micronaut.http.bind.binders.TypedRequestArgumentBinder; import jakarta.inject.Singleton; import java.util.Set; import java.util.stream.Collectors; @Singleton public class AllowedQueryParamsBinder implements TypedRequestArgumentBinder<Void> { @Override public ArgumentBinder.BindingResult<Void> bind(ArgumentConversionContext<Void> context, HttpRequest<?> request) { AllowedQueryParams annotation = context.getAnnotation(AllowedQueryParams.class).orElse(null); if (annotation == null) { return ArgumentBinder.BindingResult.EMPTY; } Set<String> allowedParams = Set.of(annotation.value()); Set<String> requestParams = request.getParameters().names().stream().collect(Collectors.toSet()); // 检查未知参数 for (String param : requestParams) { if (!allowedParams.contains(param)) { throw new IllegalArgumentException("无效的查询参数: " + param); } } return ArgumentBinder.BindingResult.success(null); } @Override public Class<Void> getType() { return Void.class; } }
- 全局异常处理,将校验抛出的异常转换为400 Bad Request响应:
import io.micronaut.http.HttpResponse; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Error; import jakarta.inject.Singleton; @Singleton @Controller public class GlobalExceptionHandler { @Error(exception = IllegalArgumentException.class) public HttpResponse<String> handleIllegalArgument(IllegalArgumentException e) { return HttpResponse.badRequest(e.getMessage()); } }
- 在控制器方法中使用注解,添加占位参数触发绑定校验:
@Get("/files") @Produces({"application/json"}) FileSystemNodes readFiles( @Nullable @QueryValue("project") String project, @Nullable @QueryValue("store") String store, @Nullable @QueryValue("path") String path, @NotNull @Header("Authorization") String authorization, @NotNull @Header("TenantID") String tenantID, // 绑定自定义注解,指定允许的查询参数 @AllowedQueryParams({"project", "store", "path"}) Void dummyParam) { // 原有业务逻辑实现 }
方案二:路径级过滤器拦截
如果仅需针对/files路径做统一校验,使用过滤器更简单,无需修改控制器方法:
- 创建查询参数校验过滤器:
import io.micronaut.http.HttpRequest; import io.micronaut.http.HttpResponse; import io.micronaut.http.annotation.Filter; import io.micronaut.http.filter.HttpFilter; import io.micronaut.http.filter.ServerFilterChain; import org.reactivestreams.Publisher; import java.util.Set; @Filter("/files") public class QueryParamValidationFilter implements HttpFilter { // 定义允许的查询参数集合 private static final Set<String> ALLOWED_PARAMS = Set.of("project", "store", "path"); @Override public Publisher<HttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) { Set<String> requestParams = request.getParameters().names(); // 遍历检查每个参数 for (String param : requestParams) { if (!ALLOWED_PARAMS.contains(param)) { return Publisher.just(HttpResponse.badRequest("无效的查询参数: " + param)); } } return chain.proceed(request); } }
方案对比
- 方案一:适合多端点有不同参数规则的场景,每个方法可独立配置允许的参数。
- 方案二:配置简单,适合单路径或全局统一参数规则的场景,无需修改控制器方法参数。
内容的提问来源于stack exchange,提问作者jJavier52
相关产品推荐
相关产品推荐

