给定多个REST资源来收集订单信息。
/order/{id}
/order/{id}/positions
/order/{id}/invoice
/order/{id}/shipment
在Srping Boot 2应用程序中,它跨多个控制器实现,例如: OrderController
,InvoiceController
等
目前,每个控制器都使用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
但似乎不是正确的方法,因为它只提供了一个布尔接口。
答案 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());
}