【问题标题】:Is it possible to conditionally assign the value of Required in @RequestParam?是否可以有条件地在@RequestParam 中分配Required 的值?
【发布时间】:2019-06-28 01:37:59
【问题描述】:

我的控制器中有 2 个 @RequestParam 参数。我想根据条件设置两个参数的必需值。条件可能是,如果传递了一个参数,则必须传递另一个参数。所以将 other 的 required 设置为 true ,反之亦然。否则,如果没有传递任何参数,则将两者都设置为 false。

@RestController
public class TestController {

@GetMapping("/test")
public void test(@RequestParam(value = "a", required = (b !=null) String a, 
@RequestParam(value = "b", required = (a !=null) )  String b,) {
     {

     }

}

在@RequestParam() 中使用变量名的语法是错误的,但我想解释一下我想要什么。

【问题讨论】:

  • 不,你不能。您可以创建一个对象,绑定两个变量并为此创建一个单独的验证器。但它不适用于简单的参数。
  • 为什么不创建一个 bean 并将工作交给它呢?然后你可以有 getter 方法来执行你的检查。 myBean.getA 和 myBean.getB 都包含其相应的逻辑

标签: java spring rest spring-boot


【解决方案1】:

您可以使用以下两种方式之一:

  1. 使用 Spring AOP 并为该请求创建一个环绕方面 映射
  2. 使用 HandlerInterceptorAdapter 拦截对给定 URI 的请求

1.使用 Spring AOP

创建如下注释:

public @interface RequestParameterPairValidation {

}

然后你可以用它来注释你的请求映射方法:

@GetMapping("/test")
@RequestParameterPairValidation
public void test(
   @RequestParam(value = "a", required = false) String a, 
   @RequestParam(value = "b", required = false)  String b) {
      // API code goes here...
}

围绕注释创建一个方面。比如:

@Aspect
@Component
public class RequestParameterPairValidationAspect {
    @Around("@annotation(x.y.z.RequestParameterPairValidation) && execution(public * *(..))")
    public Object time(final ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] requestMappingArgs = joinPoint.getArgs();
        String a = (String) requestMappingArgs[0];
        String b = (String) requestMappingArgs[1];

        boolean requestIsValid = //... execute validation logic here

        if (requestIsValid) {
           return joinPoint.proceed();
        } else {
           throw new IllegalArgumentException("illegal request");
        }
    }
}

请注意,由于请求无效,因此在此处返回 400 BAD REQUEST 是一个不错的选择。当然,这取决于上下文,但这是一般的经验法则。

2。使用 HandlerInterceptorAdapter

创建一个新的拦截器映射到您想要的 URI(在本例中为 /test):

@Configuration  
public class CustomInterceptor extends WebMvcConfigurerAdapter  {  

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
       registry
         .addInterceptor(new CustomRequestParameterPairInterceptor())
         .addPathPatterns("/test");
    }
} 

在自定义拦截器中定义验证逻辑:

public class CustomRequestParameterPairInterceptor extends HandlerInterceptorAdapter {

    @Override
    public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object obj, Exception exception) throws Exception {

    }

    @Override
    public void postHandle(HttpServletRequest req, HttpServletResponse res, Object obj, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
       // Run your validation logic here
    }
}

我会说第二个选项是最好的选项,因为您可以直接控制请求的答案。在这种情况下,它可能是 400 BAD REQUEST,或任何其他对您的情况更有意义的东西。

【讨论】:

    【解决方案2】:

    您可以在此处以智能方式使用 Optional,如下所示:

    @GetMapping("/test")
    @RequestParameterPairValidation
    public void test(@RequestParam("a") Optional<String> a,
        @RequestParam("b") Optional<String> b){
    
    
        String aVal = a.isPresent() ? a.get() : null;
        String bVal = b.isPresent() ? b.get() : null;
    
        //go for service call here based on your logic
    }
    

    我希望这能满足您的要求。

    【讨论】:

    • 我的这个假设可能是错误的,但我想说,如果 a/b 不满足互斥要求,那么这个问题与 API 调用最终返回的错误更相关。使用 Optional> 只会给你一种语义方式来知道值是否存在。它不负责验证。
    【解决方案3】:

    您可以在 Spring 中使用 Java EE @Size Validation 注解(但您必须在类路径上有 Java EE 验证 API 实现器,即 hibernate )。使用 hibernate,你可以使用 maven 导入这个依赖

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.0.10.Final</version>
    </dependency>
    

    那么整个事情就变成了:

    @RestController
    @Validated
    public class TestController {
    
    @GetMapping("/test")
    public void test(@RequestParam(value = "a", required = true )  @Size(min=1) String a, 
    @RequestParam(value = "b", required = true) @Size(min=1)   String b) {
         {
    
         }
    
    }
    

    【讨论】:

      【解决方案4】:

      在 Java 中,您只能将常量作为任何注解的参数传递。 这就是为什么不可能这样做。 但是,您可以在方法本身中验证所有此类事情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-31
        • 2011-10-05
        • 2011-11-01
        • 2011-05-18
        • 2021-02-18
        • 2019-11-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多