【问题标题】:Spring data rest and business rules validationSpring数据休息和业务规则验证
【发布时间】:2018-02-15 09:46:35
【问题描述】:

我想寻求在使用 Spring Data Rest 时应用业务规则的最佳实践。

让我们考虑以下场景:

  • 我在@OneToMany 关系中有CustomerOrder
  • 我有一条业务规则说Customer 需要设置已验证标志才能下订单

所以我需要确保无论何时有人POSTs 到/ordersCustomer 拨打电话都经过验证

我正在考虑使用 beforeSave Validators 将其他服务/存储库自动连接到 Validator 并检查需要检查的内容。

有没有更好的方法来达到同样的效果?

【问题讨论】:

  • 你能准确地说出你想要更好的东西吗?目前的方法有什么问题?
  • 没有真正的问题,但我认为验证器旨在验证没有外部依赖关系的单个实体。我可能错了。我认为这是很常见的用例,我想知道 spring-data-rest 的人打算如何进行跨实体验证。
  • 我更喜欢一种方法,如果用户未经过验证,您可以尽快失败。这可以是过滤器链中的安全过滤器。您可以为此利用 Spring 安全性,或编写自己的自定义解决方案。

标签: spring spring-data-rest business-rules


【解决方案1】:

有几种方法可以解决这个问题。据我所知:

  1. 使用 @PreAuthorize 等 spring 安全注释。但是,这些注释的预期用途是出于安全目的,并且您提到了业务规则。我会将这些用于用户授权规则Spring data rest security chapter

  2. 您自己提到的验证器的使用。 Spring data rest Validators

  3. 使用弹簧数据休息事件Spring data rest events。您可以创建全局事件处理程序,但是在这里您需要确定实体类型。我会使用带注释的事件处理程序来执行业务逻辑Spring data rest annotated event handler

【讨论】:

  • 好的,#2 对我来说仍然是最好的 :) 让我们看看其他人是否有其他想法。否则我接受答案。谢谢
【解决方案2】:

所以只是为了世界的一部分,我正在添加我的解决方案。和#2一起去。

documentation 非常清楚如何进行,所以只分享一些可以节省您时间的技巧。

  1. 你需要assign validators manually,自动发现doesn't work
  2. 手动拼写事件类型容易出错,一些帮助程序Enum 可能会很方便。

喜欢:

/** 
 * "beforeSave" gets called on PATCH/PUT methods
 * "beforeCreate" on POST
 * "beforeDelete" on DELETE
 */
enum Event {
    ON_CREATE("beforeCreate"), ON_UPDATE("beforeSave"), 
 ON_DELETE("beforeDelete");

    private String name;

    Event(String name) {
        this.name = name;
    }
} 

...

private static void addValidatorForEvents(ValidatingRepositoryEventListener eventListener, Validator validator, Event... events) {
    Arrays.asList(events).forEach(event -> eventListener.addValidator(event.name, validator));
}

【讨论】:

    【解决方案3】:

    一个可以用来解决业务规则相关问题的开箱即用解决方案是使用 Spring AOP。您可以做的是定义一个注解(比如@X)并将该注解放在您的 POST 调用之上。

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface X{}
    

    接下来你需要做的是,创建一个切面,并在这个切面中运行你的自定义验证逻辑,如下所示,

    @Aspect
    @Component
    public class CustomAspect {
    
       //You can autowire beans here
    
        @Around("@annotation(qualified name of X)")
        public Object customMethod(ProceedingJoinPoint joinPoint) throws Throwable {
            flag = customLogic();
            if (flag){
               return joinPoint.proceed(); //return if logic passes, otherwise
            }else{
               throw new BusinessRuleException("Business rule violated");
            }
        }
    
        private boolean customLogic(){
         //your custom logic goes here
        }
    }
    

    最后将此注解应用到控制器层中的任何方法之上,例如:

    @X
    @RequestMapping(method = RequestMethod.POST, value = "do-something")
    public void callSomething(HttpServletRequest request) throws Exception {
       // your business logic goes here
    }
    

    上面唯一需要注意的是,您需要将 HttpServletRequest 请求显式传递给您的控制器方法,以便 AOP 方面获得相同的上下文来操作与用户会话相关的属性,如 session_id 等。

    上述解决方案将帮助您在业务逻辑之上添加业务规则,并帮助您进行要在 Web 应用程序中构建的各种预验证。它是 Spring AOP 的一个非常方便的应用程序。如有任何情况请联系

    【讨论】:

    • 这违背了使用spring-data-rest 的目的,因为它会即时为您生成端点,您无权访问它们。
    • 怎么加一个endpoint,反而就像spring security的preauthorize注解一样。唯一的好处是您可以根据自己的选择对其进行自定义。
    • 我没有完全遵循,但是使用 spring 数据休息时,您通常根本不会使用 @RequestMapping 方法创建 Controllers。我建议你检查项目。
    • 哦,我明白了。我的错。感谢您的澄清:)
    猜你喜欢
    • 1970-01-01
    • 2011-04-30
    • 1970-01-01
    • 2014-08-16
    • 2012-07-22
    • 1970-01-01
    • 1970-01-01
    • 2012-06-18
    • 1970-01-01
    相关资源
    最近更新 更多