You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Micronaut中如何校验@QueryValue查询参数的名称合法性?

Micronaut 控制器查询参数名称校验实现方案

方案一:自定义参数绑定器(ArgumentBinder)

这种方式可针对单个控制器方法灵活配置允许的查询参数,步骤如下:

  1. 创建自定义注解,用于标记允许的查询参数名称:
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface AllowedQueryParams {
    String[] value();
}
  1. 实现自定义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;
    }
}
  1. 全局异常处理,将校验抛出的异常转换为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());
    }
}
  1. 在控制器方法中使用注解,添加占位参数触发绑定校验:
@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路径做统一校验,使用过滤器更简单,无需修改控制器方法:

  1. 创建查询参数校验过滤器:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 11:42:25