Browse Source

增加before操作事件

zhou-hao 3 years ago
parent
commit
e70a72d13b

+ 5 - 0
hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/annotation/EnableEntityEvent.java

@@ -19,6 +19,11 @@ import java.lang.annotation.*;
  * @see org.hswebframework.web.crud.events.EntityDeletedEvent
  * @see org.hswebframework.web.crud.events.EntityCreatedEvent
  * @see org.hswebframework.web.crud.events.EntitySavedEvent
+ * @see org.hswebframework.web.crud.events.EntityBeforeSaveEvent
+ * @see org.hswebframework.web.crud.events.EntityBeforeModifyEvent
+ * @see org.hswebframework.web.crud.events.EntityBeforeDeleteEvent
+ * @see org.hswebframework.web.crud.events.EntityBeforeCreateEvent
+ * @see org.hswebframework.web.crud.events.EntityBeforeQueryEvent
  */
 @Target({ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)

+ 19 - 4
hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/configuration/AutoDDLProcessor.java

@@ -8,8 +8,12 @@ import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata;
 import org.hswebframework.ezorm.rdb.operator.DatabaseOperator;
 import org.hswebframework.web.api.crud.entity.EntityFactory;
 import org.hswebframework.web.crud.entity.factory.MapperEntityFactory;
+import org.hswebframework.web.crud.events.EntityBeforeQueryEvent;
+import org.hswebframework.web.crud.events.EntityDDLEvent;
+import org.hswebframework.web.event.GenericsPayloadApplicationEvent;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.transaction.ReactiveTransactionManager;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
@@ -43,6 +47,9 @@ public class AutoDDLProcessor implements InitializingBean {
     @Autowired
     private EntityFactory entityFactory;
 
+    @Autowired
+    private ApplicationEventPublisher eventPublisher;
+
     private boolean reactive;
 
     @Override
@@ -60,7 +67,12 @@ public class AutoDDLProcessor implements InitializingBean {
             if (reactive) {
                 Flux.fromIterable(entities)
                     .doOnNext(type -> log.trace("auto ddl for {}", type))
-                    .map(resolver::resolve)
+                    .map(type -> {
+                        RDBTableMetadata metadata = resolver.resolve(type);
+                        EntityDDLEvent event = new EntityDDLEvent(type,metadata);
+                        eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, type));
+                        return metadata;
+                    })
                     .flatMap(meta -> operator
                             .ddl()
                             .createOrAlter(meta)
@@ -73,11 +85,14 @@ public class AutoDDLProcessor implements InitializingBean {
                     .then()
                     .block(Duration.ofMinutes(5));
             } else {
-                for (Class<?> entity : entities) {
-                    log.trace("auto ddl for {}", entity);
+                for (Class<?> type : entities) {
+                    log.trace("auto ddl for {}", type);
                     try {
+                        RDBTableMetadata metadata = resolver.resolve(type);
+                        EntityDDLEvent event = new EntityDDLEvent(type,metadata);
+                        eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, type));
                         operator.ddl()
-                                .createOrAlter(resolver.resolve(entity))
+                                .createOrAlter(metadata)
                                 .autoLoad(false)
                                 .commit()
                                 .sync();

+ 21 - 0
hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeCreateEvent.java

@@ -0,0 +1,21 @@
+package org.hswebframework.web.crud.events;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.hswebframework.web.event.DefaultAsyncEvent;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @see org.hswebframework.web.crud.annotation.EnableEntityEvent
+ * @param <E>
+ */
+@AllArgsConstructor
+@Getter
+public class EntityBeforeCreateEvent<E> extends DefaultAsyncEvent implements Serializable {
+
+    private final List<E> entity;
+
+    private final Class<E> entityType;
+}

+ 24 - 0
hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeDeleteEvent.java

@@ -0,0 +1,24 @@
+package org.hswebframework.web.crud.events;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.hswebframework.web.event.DefaultAsyncEvent;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @param <E>
+ * @see org.hswebframework.web.crud.annotation.EnableEntityEvent
+ */
+@AllArgsConstructor
+@Getter
+public class EntityBeforeDeleteEvent<E> extends DefaultAsyncEvent implements Serializable {
+
+    private static final long serialVersionUID = -7158901204884303777L;
+
+    private final List<E> entity;
+
+    private final Class<E> entityType;
+
+}

+ 26 - 0
hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeModifyEvent.java

@@ -0,0 +1,26 @@
+package org.hswebframework.web.crud.events;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.hswebframework.web.event.DefaultAsyncEvent;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @see org.hswebframework.web.crud.annotation.EnableEntityEvent
+ * @param <E>
+ */
+@AllArgsConstructor
+@Getter
+public class EntityBeforeModifyEvent<E> extends DefaultAsyncEvent implements Serializable{
+
+    private static final long serialVersionUID = -7158901204884303777L;
+
+    private final List<E> before;
+
+    private final List<E> after;
+
+    private final Class<E> entityType;
+
+}

+ 24 - 0
hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeQueryEvent.java

@@ -0,0 +1,24 @@
+package org.hswebframework.web.crud.events;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.hswebframework.ezorm.core.param.QueryParam;
+import org.hswebframework.web.api.crud.entity.QueryParamEntity;
+import org.hswebframework.web.event.DefaultAsyncEvent;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @see org.hswebframework.web.crud.annotation.EnableEntityEvent
+ * @param <E>
+ */
+@AllArgsConstructor
+@Getter
+public class EntityBeforeQueryEvent<E> extends DefaultAsyncEvent implements Serializable {
+
+    private final QueryParam param;
+
+    private final Class<E> entityType;
+
+}

+ 21 - 0
hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityBeforeSaveEvent.java

@@ -0,0 +1,21 @@
+package org.hswebframework.web.crud.events;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.hswebframework.web.event.DefaultAsyncEvent;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @see org.hswebframework.web.crud.annotation.EnableEntityEvent
+ * @param <E>
+ */
+@AllArgsConstructor
+@Getter
+public class EntityBeforeSaveEvent<E> extends DefaultAsyncEvent implements Serializable {
+
+    private final List<E> entity;
+
+    private final Class<E> entityType;
+}

+ 13 - 0
hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityDDLEvent.java

@@ -0,0 +1,13 @@
+package org.hswebframework.web.crud.events;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata;
+
+@AllArgsConstructor
+@Getter
+public class EntityDDLEvent<E> {
+    private Class<E> type;
+
+    private RDBTableMetadata table;
+}

+ 206 - 129
hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/events/EntityEventListener.java

@@ -17,7 +17,11 @@ import org.hswebframework.web.event.AsyncEvent;
 import org.hswebframework.web.event.GenericsPayloadApplicationEvent;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.scheduling.annotation.Async;
 import reactor.core.publisher.Mono;
+import reactor.function.Function3;
+import reactor.util.function.Tuple2;
+import reactor.util.function.Tuples;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -54,21 +58,23 @@ public class EntityEventListener implements EventListener {
                 mapping.getEntityType().getAnnotation(EnableEntityEvent.class) == null) {
             return;
         }
-
+        if (type == MappingEventTypes.select_before) {
+            handleQueryBefore(mapping, context);
+        }
         if (type == MappingEventTypes.insert_before) {
             boolean single = context.get(MappingContextKeys.type).map("single"::equals).orElse(false);
             if (single) {
-                handleSingleOperation(mapping.getEntityType(), context, EntityCreatedEvent::new);
+                handleSingleOperation(mapping.getEntityType(), context, EntityBeforeCreateEvent::new, EntityCreatedEvent::new);
             } else {
-                handleBatchOperation(mapping.getEntityType(), context, EntityCreatedEvent::new);
+                handleBatchOperation(mapping.getEntityType(), context, EntityBeforeCreateEvent::new, EntityCreatedEvent::new);
             }
         }
         if (type == MappingEventTypes.save_before) {
             boolean single = context.get(MappingContextKeys.type).map("single"::equals).orElse(false);
             if (single) {
-                handleSingleOperation(mapping.getEntityType(), context, EntitySavedEvent::new);
+                handleSingleOperation(mapping.getEntityType(), context, EntityBeforeSaveEvent::new, EntitySavedEvent::new);
             } else {
-                handleBatchOperation(mapping.getEntityType(), context, EntitySavedEvent::new);
+                handleBatchOperation(mapping.getEntityType(), context, EntityBeforeSaveEvent::new, EntitySavedEvent::new);
             }
         }
         if (type == MappingEventTypes.update_before) {
@@ -80,178 +86,249 @@ public class EntityEventListener implements EventListener {
         }
     }
 
-    protected Mono<Void> sendUpdateEvent(List<?> olds, EventContext context) {
+    protected void handleQueryBefore(EntityColumnMapping mapping, EventContext context) {
+        context.get(MappingContextKeys.reactiveResultHolder)
+               .ifPresent(holder -> {
+                   context.get(MappingContextKeys.queryOaram)
+                          .ifPresent(queryParam -> {
+                              EntityBeforeQueryEvent event = new EntityBeforeQueryEvent<>(queryParam, mapping.getEntityType());
+                              eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, mapping.getEntityType()));
+                              holder
+                                      .before(
+                                              event.getAsync()
+                                      );
+                          });
+               });
+    }
+
+    protected List<Object> createAfterData(List<Object> olds,
+                                           EventContext context) {
         List<Object> newValues = new ArrayList<>(olds.size());
-        EntityColumnMapping mapping = context.get(MappingContextKeys.columnMapping).orElseThrow(UnsupportedOperationException::new);
+        EntityColumnMapping mapping = context
+                .get(MappingContextKeys.columnMapping)
+                .orElseThrow(UnsupportedOperationException::new);
         TableOrViewMetadata table = context.get(ContextKeys.table).orElseThrow(UnsupportedOperationException::new);
-        RDBColumnMetadata idColumn = table.getColumns().stream().filter(RDBColumnMetadata::isPrimaryKey).findFirst().orElse(null);
+        RDBColumnMetadata idColumn = table
+                .getColumns()
+                .stream()
+                .filter(RDBColumnMetadata::isPrimaryKey)
+                .findFirst()
+                .orElse(null);
         if (idColumn == null) {
-            return Mono.empty();
+            return Collections.emptyList();
         }
         for (Object old : olds) {
-            Object newValue = context.get(MappingContextKeys.instance)
+            Object newValue = context
+                    .get(MappingContextKeys.instance)
                     .filter(Entity.class::isInstance)
                     .map(Entity.class::cast)
                     .orElseGet(() -> {
                         return context.get(MappingContextKeys.updateColumnInstance)
-                                .map(map -> {
-                                    return FastBeanCopier.copy(map, FastBeanCopier.copy(old, mapping.getEntityType()));
-                                })
-                                .map(Entity.class::cast)
-                                .orElse(null);
+                                      .map(map -> {
+                                          return FastBeanCopier.copy(map, FastBeanCopier.copy(old, mapping.getEntityType()));
+                                      })
+                                      .map(Entity.class::cast)
+                                      .orElse(null);
                     });
             if (newValue != null) {
                 FastBeanCopier.copy(old, newValue, FastBeanCopier.include(idColumn.getAlias()));
             }
             newValues.add(newValue);
         }
-        EntityModifyEvent event = new EntityModifyEvent(olds, newValues, mapping.getEntityType());
-        eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, mapping.getEntityType()));
-        return event.getAsync();
+        return newValues;
     }
 
-    protected Mono<Void> sendDeleteEvent(List<?> olds, EventContext context) {
+    protected Mono<Void> sendUpdateEvent(List<Object> before,
+                                         List<Object> after,
+                                         Class<Object> type,
+                                         Function3<List<Object>, List<Object>, Class<Object>, AsyncEvent> mapper) {
 
-        EntityColumnMapping mapping = context.get(MappingContextKeys.columnMapping).orElseThrow(UnsupportedOperationException::new);
-        TableOrViewMetadata table = context.get(ContextKeys.table).orElseThrow(UnsupportedOperationException::new);
+        AsyncEvent event = mapper.apply(before, after, type);
+        eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, type));
+        return event.getAsync();
+    }
+
+    protected Mono<Void> sendDeleteEvent(List<Object> olds,
+                                         Class<Object> type,
+                                         BiFunction<List<Object>, Class<Object>, AsyncEvent> eventBuilder) {
 
-        EntityDeletedEvent deletedEvent = new EntityDeletedEvent(olds, mapping.getEntityType());
-        eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, deletedEvent, mapping.getEntityType()));
+        AsyncEvent deletedEvent = eventBuilder.apply(olds, type);
+        eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, deletedEvent, type));
         return deletedEvent.getAsync();
     }
 
     protected void handleUpdateBefore(DSLUpdate<?, ?> update, EventContext context) {
         Object repo = context.get(MappingContextKeys.repository).orElse(null);
+        EntityColumnMapping mapping = context
+                .get(MappingContextKeys.columnMapping)
+                .orElseThrow(UnsupportedOperationException::new);
+
         if (repo instanceof ReactiveRepository) {
+
             context.get(MappingContextKeys.reactiveResultHolder)
-                    .ifPresent(holder -> {
-                        AtomicReference<List<?>> updated = new AtomicReference<>();
-                        holder.after(v -> {
-                            return Mono.defer(() -> {
-                                List<?> _tmp = updated.getAndSet(null);
+                   .ifPresent(holder -> {
+                       AtomicReference<Tuple2<List<Object>, List<Object>>> updated = new AtomicReference<>();
 
-                                if (CollectionUtils.isNotEmpty(_tmp)) {
-                                    return sendUpdateEvent(_tmp, context);
-                                }
-                                return Mono.empty();
-                            });
-                        });
-                        holder.before(
-                                ((ReactiveRepository<?, ?>) repo).createQuery()
-                                        .setParam(update.toQueryParam())
-                                        .fetch()
-                                        .collectList()
-                                        .doOnSuccess(updated::set)
-                                        .then()
-                        );
-                    });
-        }else if (repo instanceof SyncRepository) {
+                       holder.after(v -> {
+                           return Mono.defer(() -> {
+                               Tuple2<List<Object>, List<Object>> _tmp = updated.getAndSet(null);
+                               if (_tmp != null) {
+                                   return sendUpdateEvent(_tmp.getT1(), _tmp.getT2(), (Class) mapping.getEntityType(), EntityModifyEvent::new);
+                               }
+                               return Mono.empty();
+                           });
+                       });
+
+                       holder.before(
+                               ((ReactiveRepository<Object, ?>) repo)
+                                       .createQuery()
+                                       .setParam(update.toQueryParam())
+                                       .fetch()
+                                       .collectList()
+                                       .flatMap((list) -> {
+                                           List<Object> after = createAfterData(list, context);
+                                           updated.set(Tuples.of(list, after));
+                                           return sendUpdateEvent(list,
+                                                                  after,
+                                                                  (Class) mapping.getEntityType(),
+                                                                  EntityBeforeModifyEvent::new);
+
+                                       })
+                                       .then()
+                       );
+                   });
+        } else if (repo instanceof SyncRepository) {
             QueryParam param = update.toQueryParam();
-            SyncRepository<?, ?> syncRepository = ((SyncRepository<?, ?>) repo);
-            List<?> list = syncRepository.createQuery()
-                    .setParam(param)
-                    .fetch();
-            sendUpdateEvent(list,context).block();
+            SyncRepository<Object, ?> syncRepository = ((SyncRepository<Object, ?>) repo);
+            List<Object> list = syncRepository.createQuery()
+                                              .setParam(param)
+                                              .fetch();
+            sendUpdateEvent(list,
+                            createAfterData(list, context),
+                            (Class<Object>) mapping.getEntityType(),
+                            EntityBeforeModifyEvent::new).block();
         }
     }
 
     protected void handleUpdateBefore(EventContext context) {
         context.<DSLUpdate<?, ?>>get(ContextKeys.source())
-                .ifPresent(dslUpdate -> {
-                    handleUpdateBefore(dslUpdate, context);
-                });
+               .ifPresent(dslUpdate -> {
+                   handleUpdateBefore(dslUpdate, context);
+               });
 
     }
 
     protected void handleDeleteBefore(EventContext context) {
+        EntityColumnMapping mapping = context
+                .get(MappingContextKeys.columnMapping)
+                .orElseThrow(UnsupportedOperationException::new);
         context.<DSLDelete>get(ContextKeys.source())
-                .ifPresent(dslUpdate -> {
-                    Object repo = context.get(MappingContextKeys.repository).orElse(null);
-                    if (repo instanceof ReactiveRepository) {
-                        context.get(MappingContextKeys.reactiveResultHolder)
-                                .ifPresent(holder -> {
-                                    AtomicReference<List<?>> deleted = new AtomicReference<>();
-                                    holder.after(v -> {
-                                        return Mono.defer(() -> {
-                                            List<?> _tmp = deleted.getAndSet(null);
-                                            if (CollectionUtils.isNotEmpty(_tmp)) {
-                                                return sendDeleteEvent(_tmp, context);
-                                            }
-                                            return Mono.empty();
-                                        });
-                                    });
-                                    holder.before(
-                                            ((ReactiveRepository<?, ?>) repo).createQuery()
-                                                    .setParam(dslUpdate.toQueryParam())
-                                                    .fetch()
-                                                    .collectList()
-                                                    .doOnSuccess(deleted::set)
-                                                    .then()
-                                    );
-                                });
-                    } else if (repo instanceof SyncRepository) {
-                        QueryParam param = dslUpdate.toQueryParam();
-                        SyncRepository<?, ?> syncRepository = ((SyncRepository<?, ?>) repo);
-                        List<?> list = syncRepository.createQuery()
-                                .setParam(param)
-                                .fetch();
-                        sendDeleteEvent(list,context).block();
-                    }
-                });
+               .ifPresent(dslUpdate -> {
+                   Object repo = context.get(MappingContextKeys.repository).orElse(null);
+                   if (repo instanceof ReactiveRepository) {
+                       context.get(MappingContextKeys.reactiveResultHolder)
+                              .ifPresent(holder -> {
+                                  AtomicReference<List<Object>> deleted = new AtomicReference<>();
+                                  holder.after(v -> {
+                                      return Mono
+                                              .defer(() -> {
+                                                  List<Object> _tmp = deleted.getAndSet(null);
+                                                  if (CollectionUtils.isNotEmpty(_tmp)) {
+                                                      return sendDeleteEvent(_tmp, (Class) mapping.getEntityType(), EntityDeletedEvent::new);
+                                                  }
+                                                  return Mono.empty();
+                                              });
+                                  });
+                                  holder.before(((ReactiveRepository<Object, ?>) repo)
+                                                        .createQuery()
+                                                        .setParam(dslUpdate.toQueryParam())
+                                                        .fetch()
+                                                        .collectList()
+                                                        .filter(CollectionUtils::isNotEmpty)
+                                                        .flatMap(list -> {
+                                                            deleted.set(list);
+                                                            return this
+                                                                    .sendDeleteEvent(list, (Class) mapping.getEntityType(), EntityBeforeDeleteEvent::new);
+                                                        })
+                                  );
+                              });
+                   } else if (repo instanceof SyncRepository) {
+                       QueryParam param = dslUpdate.toQueryParam();
+                       SyncRepository<Object, ?> syncRepository = ((SyncRepository<Object, ?>) repo);
+                       List<Object> list = syncRepository.createQuery()
+                                                         .setParam(param)
+                                                         .fetch();
+                       this.sendDeleteEvent(list, (Class) mapping.getEntityType(), EntityBeforeDeleteEvent::new)
+                           .block();
+                   }
+               });
     }
 
     protected void handleUpdateAfter(EventContext context) {
 
     }
 
-    protected void handleBatchOperation(Class clazz, EventContext context, BiFunction<List<?>, Class, AsyncEvent> mapper) {
+    protected void handleBatchOperation(Class clazz, EventContext context,
+                                        BiFunction<List<?>, Class, AsyncEvent> before,
+                                        BiFunction<List<?>, Class, AsyncEvent> after) {
 
         context.get(MappingContextKeys.instance)
-                .filter(List.class::isInstance)
-                .map(List.class::cast)
-                .ifPresent(lst -> {
-                    AsyncEvent event = mapper.apply(lst, clazz);
-                    Object repo = context.get(MappingContextKeys.repository).orElse(null);
-                    if (repo instanceof ReactiveRepository) {
-                        Optional<ReactiveResultHolder> resultHolder = context.get(MappingContextKeys.reactiveResultHolder);
-                        if (resultHolder.isPresent()) {
-                            resultHolder
-                                    .get()
-                                    .after(v -> {
-                                        eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, clazz));
-                                        return event.getAsync();
-                                    });
-                            return;
-                        }
-                    }
-                    eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, clazz));
-                    //block非响应式的支持
-                    event.getAsync().block();
-                });
+               .filter(List.class::isInstance)
+               .map(List.class::cast)
+               .ifPresent(lst -> {
+                   AsyncEvent afterEvent = after.apply(lst, clazz);
+                   AsyncEvent beforeEvent = before.apply(lst, clazz);
+                   Object repo = context.get(MappingContextKeys.repository).orElse(null);
+                   if (repo instanceof ReactiveRepository) {
+                       Optional<ReactiveResultHolder> resultHolder = context.get(MappingContextKeys.reactiveResultHolder);
+                       if (resultHolder.isPresent()) {
+                           eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz));
+                           ReactiveResultHolder holder = resultHolder.get();
+                           if (null != beforeEvent) {
+                               holder.before(beforeEvent.publish(eventPublisher));
+                           }
+                           holder.after(v -> {
+                               eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz));
+                               return afterEvent.getAsync();
+                           });
+                           return;
+                       }
+                   }
+                   eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz));
+                   //block非响应式的支持
+                   afterEvent.getAsync().block();
+               });
     }
 
-    protected void handleSingleOperation(Class clazz, EventContext context, BiFunction<List<?>, Class, AsyncEvent> mapper) {
+    protected void handleSingleOperation(Class clazz,
+                                         EventContext context,
+                                         BiFunction<List<?>, Class, AsyncEvent> before,
+                                         BiFunction<List<?>, Class, AsyncEvent> after) {
         context.get(MappingContextKeys.instance)
-                .filter(Entity.class::isInstance)
-                .map(Entity.class::cast)
-                .ifPresent(entity -> {
-                    AsyncEvent event = mapper.apply(Collections.singletonList(entity), clazz);
-                    Object repo = context.get(MappingContextKeys.repository).orElse(null);
-                    if (repo instanceof ReactiveRepository) {
-                        Optional<ReactiveResultHolder> resultHolder = context.get(MappingContextKeys.reactiveResultHolder);
-                        if (resultHolder.isPresent()) {
-                            resultHolder
-                                    .get()
-                                    .after(v -> {
-                                        eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, clazz));
-                                        return event.getAsync();
-                                    });
-                            return;
-                        }
-                    }
-                    eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, event, clazz));
-                    //block非响应式的支持
-                    event.getAsync().block();
-                });
+               .filter(Entity.class::isInstance)
+               .map(Entity.class::cast)
+               .ifPresent(entity -> {
+                   AsyncEvent afterEvent = after.apply(Collections.singletonList(entity), clazz);
+                   AsyncEvent beforeEvent = before.apply(Collections.singletonList(entity), clazz);
+                   Object repo = context.get(MappingContextKeys.repository).orElse(null);
+                   if (repo instanceof ReactiveRepository) {
+                       Optional<ReactiveResultHolder> resultHolder = context.get(MappingContextKeys.reactiveResultHolder);
+                       if (resultHolder.isPresent()) {
+                           eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, beforeEvent, clazz));
+                           ReactiveResultHolder holder = resultHolder.get();
+                           if (null != beforeEvent) {
+                               holder.before(beforeEvent.publish(eventPublisher));
+                           }
+                           holder.after(v -> {
+                               eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz));
+                               return afterEvent.getAsync();
+                           });
+                           return;
+                       }
+                   }
+                   eventPublisher.publishEvent(new GenericsPayloadApplicationEvent<>(this, afterEvent, clazz));
+                   //block非响应式的支持
+                   afterEvent.getAsync().block();
+               });
     }
 }

+ 18 - 1
hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/EntityEventListenerTest.java

@@ -50,19 +50,32 @@ public class EntityEventListenerTest {
 
     @Test
     public void testInsertBatch() {
+        reactiveRepository.createQuery()
+                          .where(EventTestEntity::getId,"test")
+                          .fetch()
+                          .then()
+                          .as(StepVerifier::create)
+                          .expectComplete()
+                          .verify();
+        Assert.assertEquals(listener.beforeQuery.getAndSet(0), 1);
+
+
         Flux.just(EventTestEntity.of("test2", 1), EventTestEntity.of("test3", 2))
                 .as(reactiveRepository::insert)
                 .as(StepVerifier::create)
                 .expectNext(2)
                 .verifyComplete();
         Assert.assertEquals(listener.created.getAndSet(0), 2);
+        Assert.assertEquals(listener.beforeCreate.getAndSet(0), 2);
 
-        reactiveRepository.createUpdate().set("age",3).where().in("name","test2","test3").execute()
+        reactiveRepository
+                .createUpdate().set("age",3).where().in("name","test2","test3").execute()
                 .as(StepVerifier::create)
                 .expectNext(2)
                 .verifyComplete();
 
         Assert.assertEquals(listener.modified.getAndSet(0), 2);
+        Assert.assertEquals(listener.beforeModify.getAndSet(0), 2);
 
         reactiveRepository.createDelete().where().in("name","test2","test3").execute()
                 .as(StepVerifier::create)
@@ -70,6 +83,7 @@ public class EntityEventListenerTest {
                 .verifyComplete();
 
         Assert.assertEquals(listener.deleted.getAndSet(0), 2);
+        Assert.assertEquals(listener.beforeDelete.getAndSet(0), 2);
 
         reactiveRepository.save(EventTestEntity.of("test2", 1))
                 .then()
@@ -78,6 +92,9 @@ public class EntityEventListenerTest {
                 .verify();
 
         Assert.assertEquals(listener.saved.getAndSet(0), 1);
+        Assert.assertEquals(listener.beforeSave.getAndSet(0), 1);
+
+
 
     }
 

+ 45 - 0
hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/events/TestEntityListener.java

@@ -11,12 +11,57 @@ import java.util.concurrent.atomic.AtomicInteger;
 @Component
 public class TestEntityListener {
 
+    AtomicInteger beforeCreate = new AtomicInteger();
+    AtomicInteger beforeDelete = new AtomicInteger();
     AtomicInteger created = new AtomicInteger();
     AtomicInteger deleted = new AtomicInteger();
 
     AtomicInteger modified = new AtomicInteger();
+    AtomicInteger beforeModify = new AtomicInteger();
 
     AtomicInteger saved = new AtomicInteger();
+    AtomicInteger beforeSave = new AtomicInteger();
+    AtomicInteger beforeQuery = new AtomicInteger();
+
+    @EventListener
+    public void handleBeforeQuery(EntityBeforeQueryEvent<EventTestEntity> event){
+        event.async(Mono.fromRunnable(() -> {
+            System.out.println(event);
+            beforeQuery.addAndGet(1);
+        }));
+    }
+
+    @EventListener
+    public void handleBeforeSave(EntityBeforeSaveEvent<EventTestEntity> event) {
+        event.async(Mono.fromRunnable(() -> {
+            System.out.println(event);
+            beforeSave.addAndGet(event.getEntity().size());
+        }));
+    }
+
+    @EventListener
+    public void handleBeforeDelete(EntityBeforeModifyEvent<EventTestEntity> event) {
+        event.async(Mono.fromRunnable(() -> {
+            System.out.println(event);
+            beforeModify.addAndGet(event.getBefore().size());
+        }));
+    }
+
+    @EventListener
+    public void handleBeforeDelete(EntityBeforeDeleteEvent<EventTestEntity> event) {
+        event.async(Mono.fromRunnable(() -> {
+            System.out.println(event);
+            beforeDelete.addAndGet(event.getEntity().size());
+        }));
+    }
+
+    @EventListener
+    public void handleBeforeCreated(EntityBeforeCreateEvent<EventTestEntity> event) {
+        event.async(Mono.fromRunnable(() -> {
+            System.out.println(event);
+            beforeCreate.addAndGet(event.getEntity().size());
+        }));
+    }
 
     @EventListener
     public void handleCreated(EntityCreatedEvent<EventTestEntity> event) {

+ 3 - 3
pom.xml

@@ -39,7 +39,7 @@
     <packaging>pom</packaging>
 
     <name>hsweb framework</name>
-    <url>http://www.hswebframework.org</url>
+    <url>https://github.com/hs-web</url>
     <inceptionYear>2016</inceptionYear>
     <description>hsweb (haʊs wɛb)
         是一个用于快速搭建企业后台管理系统的基础项目,集成一揽子便捷功能如:通用增删改查,在线代码生成,权限管理(可控制到列和行),动态多数据源分布式事务,动态脚本,动态定时任务,在线数据库维护等等
@@ -48,7 +48,7 @@
     <licenses>
         <license>
             <name>The Apache License, Version 2.0</name>
-            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
         </license>
     </licenses>
 
@@ -90,7 +90,7 @@
         <cglib.version>3.2.2</cglib.version>
         <aspectj.version>1.6.12</aspectj.version>
 
-        <hsweb.ezorm.version>4.0.11</hsweb.ezorm.version>
+        <hsweb.ezorm.version>4.0.12-SNAPSHOT</hsweb.ezorm.version>
         <hsweb.utils.version>3.0.2</hsweb.utils.version>
         <hsweb.expands.version>3.0.2</hsweb.expands.version>
         <swagger.version>2.7.0</swagger.version>