是否可以在@RequestParam中有条件地分配Required的值?

时间:2019-02-04 10:17:30

标签: java spring rest spring-boot

我的控制器中有2个@RequestParam参数。我想基于条件设置两个参数的必需值。条件可能就像,如果传递了一个参数,则另一个必须传递。因此,将其他的要求设置为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()中使用变量名的语法是错误的,但是我想解释一下我想要的。

4 个答案:

答案 0 :(得分: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,或者其他更适合您的情况。

答案 1 :(得分:0)

您可以在此处以一种明智的方式在这里使用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
}

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

答案 2 :(得分:0)

您可以在Spring中使用Java EE @Size Validation批注(但您必须在类路径上具有Java EE验证API实现程序,即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) {
     {

     }

}

答案 3 :(得分:-1)

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