验证多个控制器方法的URL路径

时间:2018-05-29 06:38:08

标签: java hibernate rest spring-mvc spring-boot

给定多个REST资源来收集订单信息。

  • /order/{id}
  • /order/{id}/positions
  • /order/{id}/invoice
  • /order/{id}/shipment

在Srping Boot 2应用程序中,它跨多个控制器实现,例如: OrderControllerInvoiceController

目前,每个控制器都使用OrderRepository来确保存在给定id的订单。否则会引发异常。它始终是相同的复制代码。

@RestController
public class OrderController {
    // ...
    @GetMapping("order/{id}")
    public Order getCustomer(@PathVariable final Integer id) {
        return this.orderRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("order not found"));
    }
}

框架是否提供回调来编写订单id只检查一次?

我找到了AntPathMatcher但似乎不是正确的方法,因为它只提供了一个布尔接口。

1 个答案:

答案 0 :(得分:3)

这通常是bean validation的一个好例子。虽然已经内置了对许多验证案例的支持(@Size@NotNull,...),但您也可以编写自己的自定义约束。

首先,您需要定义注释以验证您的ID,例如:

@Documented
@Constraint(validatedBy = OrderIdValidator.class)
@Target({PARAMETER})
@Retention(RUNTIME)
public @interface ValidOrderId {
    String message() default "Invalid order ID";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

由于您的订单ID始终是控制器映射的参数,因此您可以使用ElementType.PARAMETER仅允许方法参数的注释。

下一步是向其添加@Constraint注释并指向自定义验证器类(例如OrderIdValidator):

@Component
public class OrderIdValidator implements ConstraintValidator<ValidOrderId, Integer> {
    private OrderRepository repository;

    public OrderIdValidator(OrderRepository repository) {
        this.repository = repository;
    }

    @Override
    public boolean isValid(Integer id, ConstraintValidatorContext constraintValidatorContext) {
        return repository.existsById(id);
    }
}

通过实施isValid方法,您可以检查订单是否存在。如果它不存在,则抛出异常,message()注释的@ValidOrderId属性将用作消息。

最后一步是将@Validated注释添加到所有控制器,并将@ValidOrderId注释添加到所有订单ID参数,例如:

@Validated // Add this
@RestController
public class OrderController {
    @GetMapping("order/{id}")
    public Order getCustomer(@PathVariable @ValidOrderId final Integer id) { // Add @ValidOrderId
        // Do stuff
    }
}

如果您希望为验证使用不同的响应状态,则可以始终添加使用@ControllerAdvice注释注释的类,并使用以下方法:

@ExceptionHandler(ConstraintViolationException.class)
public void handleConstraints(HttpServletResponse response) throws IOException {
    response.sendError(HttpStatus.BAD_REQUEST.value());
}