1
1
package org .hswebframework .web .crud .service ;
2
2
3
+ import org .apache .commons .collections4 .CollectionUtils ;
3
4
import org .hswebframework .ezorm .rdb .mapping .defaults .SaveResult ;
4
5
import org .hswebframework .ezorm .rdb .operator .dml .Terms ;
5
6
import org .hswebframework .utils .RandomUtil ;
6
- import org .hswebframework .web .api .crud .entity .QueryParamEntity ;
7
- import org .hswebframework .web .api .crud .entity .TransactionManagers ;
8
- import org .hswebframework .web .api .crud .entity .TreeSortSupportEntity ;
9
- import org .hswebframework .web .api .crud .entity .TreeSupportEntity ;
7
+ import org .hswebframework .web .api .crud .entity .*;
10
8
import org .hswebframework .web .exception .ValidationException ;
11
9
import org .hswebframework .web .id .IDGenerator ;
12
10
import org .hswebframework .web .validator .CreateGroup ;
@@ -86,12 +84,13 @@ default Flux<E> queryIncludeChildren(Collection<K> idList) {
86
84
87
85
return findById (idList )
88
86
.concatMap (e -> !StringUtils .hasText (e .getPath ()) || !duplicateCheck .add (e .getPath ())
89
- ? Mono .just (e )
90
- : createQuery ()
91
- .where ()
92
- //使用path快速查询
93
- .like$ ("path" , e .getPath ())
94
- .fetch ())
87
+ ? Mono .just (e )
88
+ : createQuery ()
89
+ .where ()
90
+ //使用path快速查询
91
+ .like$ ("path" , e .getPath ())
92
+ .fetch (),
93
+ Integer .MAX_VALUE )
95
94
.distinct (TreeSupportEntity ::getId );
96
95
}
97
96
@@ -114,7 +113,7 @@ default Flux<E> queryIncludeParent(Collection<K> idList) {
114
113
.accept (Terms .Like .reversal ("path" , e .getPath (), false , true ))
115
114
.notEmpty ("path" )
116
115
.notNull ("path" )
117
- .fetch ())
116
+ .fetch (), Integer . MAX_VALUE )
118
117
.distinct (TreeSupportEntity ::getId );
119
118
}
120
119
@@ -156,20 +155,18 @@ default Mono<Integer> insert(E data) {
156
155
default Mono <Integer > insertBatch (Publisher <? extends Collection <E >> entityPublisher ) {
157
156
return this
158
157
.getRepository ()
159
- .insertBatch (Flux .from (entityPublisher )
160
- .flatMap (Flux ::fromIterable )
161
- .collectList ()
162
- .flatMap (this ::checkParentId )
163
- .flatMapIterable (Function .identity ())
164
- .flatMap (this ::applyTreeProperty )
165
- .flatMap (e -> Flux .fromIterable (TreeSupportEntity .expandTree2List (e , getIDGenerator ())))
166
- .buffer (getBufferSize ()));
158
+ .insertBatch (new TreeSortServiceHelper <>(this )
159
+ .prepare (Flux .from (entityPublisher )
160
+ .flatMapIterable (Function .identity ()))
161
+ .doOnNext (e -> e .tryValidate (CreateGroup .class ))
162
+ .buffer (getBufferSize ()));
167
163
}
168
164
169
165
default int getBufferSize () {
170
166
return 200 ;
171
167
}
172
168
169
+ @ Deprecated
173
170
default Mono <E > applyTreeProperty (E ele ) {
174
171
if (StringUtils .hasText (ele .getPath ()) ||
175
172
ObjectUtils .isEmpty (ele .getParentId ())) {
@@ -182,6 +179,7 @@ default Mono<E> applyTreeProperty(E ele) {
182
179
.thenReturn (ele );
183
180
}
184
181
182
+ @ Deprecated
185
183
//校验是否有循环依赖,修改父节点为自己的子节点?
186
184
default Mono <E > checkCyclicDependency (K id , E ele ) {
187
185
if (ObjectUtils .isEmpty (id )) {
@@ -197,6 +195,7 @@ default Mono<E> checkCyclicDependency(K id, E ele) {
197
195
.then (Mono .just (ele ));
198
196
}
199
197
198
+ @ Deprecated
200
199
default Mono <Collection <E >> checkParentId (Collection <E > source ) {
201
200
202
201
Set <K > idSet = source
@@ -221,107 +220,126 @@ default Mono<Collection<E>> checkParentId(Collection<E> source) {
221
220
222
221
return this
223
222
.createQuery ()
223
+ .select ("id" )
224
224
.in ("id" , readyToCheck )
225
- .count ()
226
- .doOnNext (count -> {
227
- if (count != readyToCheck .size ()) {
228
- throw new ValidationException ("parentId" , "error.tree_entity_parent_id_not_exist" );
225
+ .fetch ()
226
+ .doOnNext (e -> readyToCheck .remove (e .getId ()))
227
+ .then (Mono .fromSupplier (() -> {
228
+ if (!readyToCheck .isEmpty ()) {
229
+ throw new ValidationException (
230
+ "error.tree_entity_parent_id_not_exist" ,
231
+ Collections .singletonList (
232
+ new ValidationException .Detail (
233
+ "parentId" ,
234
+ "error.tree_entity_parent_id_not_exist" ,
235
+ readyToCheck ))
236
+ );
229
237
}
230
- })
231
- . thenReturn ( source );
238
+ return source ;
239
+ }) );
232
240
233
241
}
234
242
243
+ @ Deprecated
235
244
//重构子节点的path
236
- default Mono <Void > refactorChildPath (K id , String path , Consumer <E > pathAccepter ) {
237
- return this
238
- .createQuery ()
239
- .where ("parentId" , id )
240
- .fetch ()
241
- .flatMap (e -> {
242
- if (ObjectUtils .isEmpty (path )) {
243
- e .setPath (RandomUtil .randomChar (4 ));
244
- } else {
245
- e .setPath (path + "-" + RandomUtil .randomChar (4 ));
246
- }
247
- pathAccepter .accept (e );
248
- if (e .getParentId () != null ) {
249
- return this
250
- .refactorChildPath (e .getId (), e .getPath (), pathAccepter )
251
- .thenReturn (e );
252
- }
253
- return Mono .just (e );
254
- })
255
- .as (getRepository ()::save )
256
- .then ();
245
+ default void refactorChildPath (K id , Function <K , Collection <E >> childGetter , String path , Consumer <E > pathAccepter ) {
246
+
247
+ Collection <E > children = childGetter .apply (id );
248
+ if (CollectionUtils .isEmpty (children )) {
249
+ return ;
250
+ }
251
+ for (E child : children ) {
252
+ if (ObjectUtils .isEmpty (path )) {
253
+ child .setPath (RandomUtil .randomChar (4 ));
254
+ } else {
255
+ child .setPath (path + "-" + RandomUtil .randomChar (4 ));
256
+ }
257
+ pathAccepter .accept (child );
258
+ this .refactorChildPath (child .getId (), childGetter , child .getPath (), pathAccepter );
259
+ }
260
+
257
261
}
258
262
259
263
@ Override
264
+ @ Transactional (rollbackFor = Throwable .class ,
265
+ transactionManager = TransactionManagers .reactiveTransactionManager )
260
266
default Mono <SaveResult > save (Publisher <E > entityPublisher ) {
261
- return Flux
262
- .from (entityPublisher )
263
- //1.先平铺
264
- .flatMapIterable (e -> TreeSupportEntity .expandTree2List (e , getIDGenerator ()))
265
- .collectList ()
266
- .flatMap (this ::checkParentId )
267
- .flatMapIterable (list -> {
268
- Map <K , E > map = list
269
- .stream ()
270
- .filter (e -> e .getId () != null )
271
- .collect (Collectors .toMap (TreeSupportEntity ::getId , Function .identity ()));
272
- //2. 重新组装树结构
273
- return TreeSupportEntity .list2tree (list ,
274
- this ::setChildren ,
275
- (Predicate <E >) e -> this .isRootNode (e ) || map .get (e .getParentId ()) == null );
276
-
277
- })
278
- //执行验证
267
+ return new TreeSortServiceHelper <>(this )
268
+ .prepare (Flux .from (entityPublisher ))
279
269
.doOnNext (e -> e .tryValidate (CreateGroup .class ))
280
- //再次平铺为
281
- .flatMapIterable (e -> TreeSupportEntity .expandTree2List (e , getIDGenerator ()))
282
- //重构path
283
- .as (this ::tryRefactorPath )
284
270
.buffer (getBufferSize ())
285
271
.flatMap (this .getRepository ()::save )
286
272
.reduce (SaveResult ::merge );
287
273
288
274
}
289
275
276
+ @ Deprecated
290
277
default Flux <E > tryRefactorPath (Flux <E > stream ) {
291
278
Flux <E > cache = stream .cache ();
292
279
Mono <Map <K , E >> mapping = cache
293
280
.filter (e -> null != e .getId ())
294
281
.collectMap (TreeSupportEntity ::getId , Function .identity ())
295
282
.defaultIfEmpty (Collections .emptyMap ());
296
283
297
- //查询出旧数据
298
- Mono <Map <K , E >> olds = cache
299
- .filter (e -> null != e .getId ())
300
- .map (TreeSupportEntity ::getId )
301
- .as (this ::findById )
302
- .collectMap (TreeSupportEntity ::getId , Function .identity ())
303
- .defaultIfEmpty (Collections .emptyMap ());
304
-
284
+ Mono <Map <K , E >> allDataFetcher =
285
+ cache
286
+ .filter (e -> null != e .getId ())
287
+ .flatMapIterable (e -> e .getParentId () != null ?
288
+ Arrays .asList (e .getId (), e .getParentId ()) :
289
+ Collections .singleton (e .getId ()))
290
+ .collect (Collectors .toSet ())
291
+ .flatMap (list -> this
292
+ .queryIncludeChildren (list )
293
+ .collect (
294
+ Collectors .toMap (
295
+ TreeSupportEntity ::getId ,
296
+ Function .identity ()
297
+ )
298
+ ));
305
299
306
300
return Mono
307
- .zip (mapping , olds )
301
+ .zip (mapping , allDataFetcher )
308
302
.flatMapMany (tp2 -> {
309
- Map <K , E > map = tp2 .getT1 ();
303
+ //本次提交的数据
304
+ Map <K , E > thisTime = tp2 .getT1 ();
305
+ //旧的数据
310
306
Map <K , E > oldMap = tp2 .getT2 ();
311
307
308
+ Map <K , E > allMap = new LinkedHashMap <>(oldMap );
309
+ allMap .putAll (thisTime );
310
+
311
+ //子节点映射
312
+ Map <K , Map <K , E >> childMapping = new LinkedHashMap <>();
313
+
314
+ List <E > all = new ArrayList <>(oldMap .values ());
315
+ all .addAll (thisTime .values ());
316
+
317
+ for (E value : all ) {
318
+ if (isRootNode (value ) || value .getId () == null ) {
319
+ continue ;
320
+ }
321
+ childMapping
322
+ .computeIfAbsent (value .getParentId (), ignore -> new LinkedHashMap <>())
323
+ .put (value .getId (), value );
324
+ }
325
+
326
+ Function <K , Collection <E >> childGetter
327
+ = id -> childMapping
328
+ .getOrDefault (id , Collections .emptyMap ())
329
+ .values ();
312
330
return cache
313
- .flatMap (data -> {
331
+ .concatMap (data -> {
314
332
E old = data .getId () == null ? null : oldMap .get (data .getId ());
315
333
K parentId = old != null ? old .getParentId () : data .getParentId ();
316
- E oldParent = parentId == null ? null : oldMap .get (parentId );
334
+ E oldParent = parentId == null ? null : allMap .get (parentId );
335
+
317
336
if (old != null ) {
318
337
K newParentId = data .getParentId ();
319
338
//父节点发生变化,更新所有子节点path
320
339
if (!Objects .equals (parentId , newParentId )) {
321
- List <Mono <Void >> jobs = new ArrayList <>();
322
340
Consumer <E > childConsumer = child -> {
323
341
//更新了父节点,但是同时也传入的对应的子节点
324
- E readyToUpdate = map .get (child .getId ());
342
+ E readyToUpdate = thisTime .get (child .getId ());
325
343
if (null != readyToUpdate ) {
326
344
readyToUpdate .setPath (child .getPath ());
327
345
}
@@ -330,51 +348,39 @@ default Flux<E> tryRefactorPath(Flux<E> stream) {
330
348
//变更到了顶级节点
331
349
if (isRootNode (data )) {
332
350
data .setPath (RandomUtil .randomChar (4 ));
333
- jobs .add (this .refactorChildPath (old .getId (), data .getPath (), childConsumer ));
351
+ this .refactorChildPath (old .getId (), childGetter , data .getPath (), childConsumer );
352
+ //重新保存所有子节点
353
+ return Flux
354
+ .fromIterable (childGetter .apply (old .getId ()))
355
+ .concatWithValues (data );
334
356
} else {
335
- if (null != oldParent ) {
336
- data .setPath (oldParent .getPath () + "-" + RandomUtil .randomChar (4 ));
337
- jobs .add (this .refactorChildPath (old .getId (), data .getPath (), childConsumer ));
338
- } else {
339
- jobs .add (this .findById (newParentId )
340
- .flatMap (parent -> {
341
- data .setPath (parent .getPath () + "-" + RandomUtil .randomChar (4 ));
342
- return this .refactorChildPath (data .getId (), data .getPath (), childConsumer );
343
- })
344
- );
357
+ E newParent = allMap .get (newParentId );
358
+ if (null != newParent ) {
359
+ data .setPath (newParent .getPath () + "-" + RandomUtil .randomChar (4 ));
360
+ this .refactorChildPath (data .getId (), childGetter , data .getPath (), childConsumer );
361
+ //重新保存所有子节点
362
+ return Flux .fromIterable (childGetter .apply (data .getId ()))
363
+ .concatWithValues (data );
345
364
}
346
365
}
347
- return Flux .merge (jobs )
348
- .then (Mono .just (data ));
366
+ return Mono .just (data );
349
367
} else {
350
- //父节点未变化则使用原始的path
351
- Consumer < E > pathRefactor = ( parent ) -> {
352
- if (old .getPath ().startsWith (parent .getPath ())) {
368
+
369
+ if ( oldParent != null ) {
370
+ if (old .getPath ().startsWith (oldParent .getPath ())) {
353
371
data .setPath (old .getPath ());
354
372
} else {
355
- data .setPath (parent .getPath () + "-" + RandomUtil .randomChar (4 ));
373
+ data .setPath (oldParent .getPath () + "-" + RandomUtil .randomChar (4 ));
356
374
}
357
- };
358
- if (oldParent != null ) {
359
- pathRefactor .accept (oldParent );
360
- } else if (parentId != null ) {
361
- return findById (parentId )
362
- .switchIfEmpty (Mono .fromRunnable (() -> {
363
- data .setParentId (null );
364
- data .setLevel (1 );
365
- data .setPath (old .getPath ());
366
- }))
367
- .doOnNext (pathRefactor )
368
- .thenReturn (data );
369
375
} else {
370
376
data .setPath (old .getPath ());
371
377
}
372
-
373
378
}
374
379
}
375
380
return Mono .just (data );
376
381
});
377
- });
382
+ })
383
+ .distinct (TreeSupportEntity ::getId );
378
384
}
379
385
380
386
@ Override
0 commit comments