【问题标题】:Validate URL path for several controller methods验证几个控制器方法的 URL 路径
【发布时间】:2018-11-07 17:20:44
【问题描述】:

给定多个 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,但它似乎不是正确的方法,因为它只提供了一个布尔接口。

【问题讨论】:

  • 你不会在每个映射中都需要那个特定的Order 吗?为什么不将orderRepository.findById(..).orElseThrow(..) 放在一个单独的方法中,并为每个方法调用它?
  • @g00glen00b 我不是在每种情况下都需要订单。调用特定方法以确保验证是当前实现。但是在创建以/order/{id}/ 开头的新方法时,您可能会忘记调用

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


【解决方案1】:

这通常是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方法,可以检查订单是否存在。如果不存在,则会抛出异常,并将@ValidOrderId注解的message()属性作为消息使用。

最后一步是将@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());
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-31
    相关资源
    最近更新 更多