feat: 框架代码全面升级webflux,兼容原

This commit is contained in:
wangyu 2021-12-07 17:02:56 +08:00
parent 5ef117cfae
commit b83b7edaa3
61 changed files with 918 additions and 295 deletions

View File

@ -23,6 +23,11 @@
<artifactId>spring-data-mongodb</artifactId> <artifactId>spring-data-mongodb</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId> <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>

View File

@ -1,6 +1,6 @@
package com.flyfish.framework.annotations; package com.flyfish.framework.annotations;
import com.flyfish.framework.repository.impl.DefaultRepositoryFactoryBean; import com.flyfish.framework.repository.factory.DefaultRepositoryFactoryBean;
import com.flyfish.framework.repository.impl.DefaultRepositoryImpl; import com.flyfish.framework.repository.impl.DefaultRepositoryImpl;
import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.AliasFor;
import org.springframework.data.mongodb.config.EnableMongoAuditing; import org.springframework.data.mongodb.config.EnableMongoAuditing;

View File

@ -0,0 +1,29 @@
package com.flyfish.framework.annotations;
import com.flyfish.framework.repository.factory.DefaultReactiveRepositoryFactoryBean;
import com.flyfish.framework.repository.impl.DefaultReactiveRepositoryImpl;
import org.springframework.core.annotation.AliasFor;
import org.springframework.data.mongodb.config.EnableReactiveMongoAuditing;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
import java.lang.annotation.*;
@EnableReactiveMongoRepositories(
repositoryFactoryBeanClass = DefaultReactiveRepositoryFactoryBean.class,
repositoryBaseClass = DefaultReactiveRepositoryImpl.class
)
@EnableReactiveMongoAuditing
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableReactiveMongoRepo {
/**
* 扫描的基本路径
*
* @return 结果
*/
@AliasFor(annotation = EnableReactiveMongoRepositories.class)
String[] basePackages() default "com.flyfish.framework";
}

View File

@ -10,6 +10,6 @@ import org.springframework.data.repository.NoRepositoryBean;
* @param <T> 泛型 * @param <T> 泛型
*/ */
@NoRepositoryBean @NoRepositoryBean
public interface DefaultReactiveRepository<T> extends ReactiveMongoRepository<T, String> { public interface DefaultReactiveRepository<T> extends ReactiveMongoRepository<T, String>, ReactiveQueryModelExecutor<T> {
} }

View File

@ -80,7 +80,7 @@ public interface QueryModelExecutor<T> {
* @param values 集合 * @param values 集合
* @return 结果 * @return 结果
*/ */
List<T> findAllByValues(String key, List<Object> values); List<T> findAllByValues(String key, List<?> values);
/** /**
* Checks whether the data store contains elements that match the given {@link Qo}. * Checks whether the data store contains elements that match the given {@link Qo}.

View File

@ -65,7 +65,7 @@ public interface ReactiveQueryModelExecutor<T> {
* @param pageable may be {@link Pageable#unpaged()}, must not be {@literal null}. * @param pageable may be {@link Pageable#unpaged()}, must not be {@literal null}.
* @return a {@link Page} of entities matching the given {@link Qo}. * @return a {@link Page} of entities matching the given {@link Qo}.
*/ */
Page<T> findAll(Qo<T> query, Pageable pageable); Mono<Page<T>> findAll(Qo<T> query, Pageable pageable);
/** /**
* Returns the number of instances matching the given {@link Qo}. * Returns the number of instances matching the given {@link Qo}.
@ -73,7 +73,7 @@ public interface ReactiveQueryModelExecutor<T> {
* @param query the {@link Qo} to count instances for, must not be {@literal null}. * @param query the {@link Qo} to count instances for, must not be {@literal null}.
* @return the number of instances matching the {@link Qo}. * @return the number of instances matching the {@link Qo}.
*/ */
long count(Qo<T> query); Mono<Long> count(Qo<T> query);
/** /**
* 通过特定键的集合查询 * 通过特定键的集合查询
@ -82,7 +82,7 @@ public interface ReactiveQueryModelExecutor<T> {
* @param values 集合 * @param values 集合
* @return 结果 * @return 结果
*/ */
List<T> findAllByValues(String key, List<Object> values); Flux<T> findAllByValues(String key, List<?> values);
/** /**
* Checks whether the data store contains elements that match the given {@link Qo}. * Checks whether the data store contains elements that match the given {@link Qo}.
@ -90,5 +90,13 @@ public interface ReactiveQueryModelExecutor<T> {
* @param query the {@link Qo} to use for the existence check, must not be {@literal null}. * @param query the {@link Qo} to use for the existence check, must not be {@literal null}.
* @return {@literal true} if the data store contains elements that match the given {@link Qo}. * @return {@literal true} if the data store contains elements that match the given {@link Qo}.
*/ */
boolean exists(Qo<T> query); Mono<Boolean> exists(Qo<T> query);
/**
* 删除全部
*
* @param qo 查询实体
* @return 结果
*/
Mono<Void> deleteAll(Qo<T> qo);
} }

View File

@ -0,0 +1,26 @@
package com.flyfish.framework.repository.factory;
import com.flyfish.framework.repository.impl.DefaultReactiveRepositoryImpl;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.data.mongodb.repository.support.ReactiveMongoRepositoryFactory;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.lang.NonNull;
public class DefaultReactiveRepositoryFactory extends ReactiveMongoRepositoryFactory {
/**
* Creates a new {@link ReactiveMongoRepositoryFactory} with the given {@link ReactiveMongoOperations}.
*
* @param mongoOperations must not be {@literal null}.
*/
public DefaultReactiveRepositoryFactory(ReactiveMongoOperations mongoOperations) {
super(mongoOperations);
this.setRepositoryBaseClass(DefaultReactiveRepositoryImpl.class);
}
@Override
@NonNull
protected Class<?> getRepositoryBaseClass(@NonNull RepositoryMetadata metadata) {
return DefaultReactiveRepositoryImpl.class;
}
}

View File

@ -0,0 +1,26 @@
package com.flyfish.framework.repository.factory;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.data.mongodb.repository.support.ReactiveMongoRepositoryFactoryBean;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.lang.NonNull;
public class DefaultReactiveRepositoryFactoryBean<T extends Repository<S, String>, S>
extends ReactiveMongoRepositoryFactoryBean<T, S, String> {
/**
* Creates a new {@link ReactiveMongoRepositoryFactoryBean} for the given repository interface.
*
* @param repositoryInterface must not be {@literal null}.
*/
public DefaultReactiveRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
}
@Override
@NonNull
protected RepositoryFactorySupport getFactoryInstance(@NonNull ReactiveMongoOperations operations) {
return new DefaultReactiveRepositoryFactory(operations);
}
}

View File

@ -1,8 +1,10 @@
package com.flyfish.framework.repository.impl; package com.flyfish.framework.repository.factory;
import com.flyfish.framework.repository.impl.DefaultRepositoryImpl;
import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactory; import org.springframework.data.mongodb.repository.support.MongoRepositoryFactory;
import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.lang.NonNull;
public class DefaultRepositoryFactory extends MongoRepositoryFactory { public class DefaultRepositoryFactory extends MongoRepositoryFactory {
@ -13,11 +15,12 @@ public class DefaultRepositoryFactory extends MongoRepositoryFactory {
*/ */
public DefaultRepositoryFactory(MongoOperations mongoOperations) { public DefaultRepositoryFactory(MongoOperations mongoOperations) {
super(mongoOperations); super(mongoOperations);
this.setRepositoryBaseClass(DefaultRepositoryFactory.class); this.setRepositoryBaseClass(DefaultRepositoryImpl.class);
} }
@Override @Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) { @NonNull
return DefaultRepositoryFactory.class; protected Class<?> getRepositoryBaseClass(@NonNull RepositoryMetadata metadata) {
return DefaultRepositoryImpl.class;
} }
} }

View File

@ -1,9 +1,10 @@
package com.flyfish.framework.repository.impl; package com.flyfish.framework.repository.factory;
import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean; import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactorySupport; import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.lang.NonNull;
public class DefaultRepositoryFactoryBean<T extends Repository<S, java.lang.String>, S> public class DefaultRepositoryFactoryBean<T extends Repository<S, java.lang.String>, S>
extends MongoRepositoryFactoryBean<T, S, String> { extends MongoRepositoryFactoryBean<T, S, String> {
@ -18,7 +19,8 @@ public class DefaultRepositoryFactoryBean<T extends Repository<S, java.lang.Stri
} }
@Override @Override
protected RepositoryFactorySupport getFactoryInstance(MongoOperations operations) { @NonNull
protected RepositoryFactorySupport getFactoryInstance(@NonNull MongoOperations operations) {
return new DefaultRepositoryFactory(operations); return new DefaultRepositoryFactory(operations);
} }
} }

View File

@ -1,4 +1,180 @@
package com.flyfish.framework.repository.impl; package com.flyfish.framework.repository.impl;
public class DefaultReactiveRepositoryImpl { import com.flyfish.framework.domain.base.Domain;
import com.flyfish.framework.domain.base.Qo;
import com.flyfish.framework.repository.DefaultReactiveRepository;
import lombok.NonNull;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.mongodb.repository.support.SimpleReactiveMongoRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Optional;
/**
* 默认的异步仓库实现
*
* @param <T> 泛型
*/
public class DefaultReactiveRepositoryImpl<T extends Domain> extends SimpleReactiveMongoRepository<T, String>
implements DefaultReactiveRepository<T> {
private final MongoEntityInformation<T, String> entityInformation;
private final ReactiveMongoOperations mongoOperations;
public DefaultReactiveRepositoryImpl(@NonNull MongoEntityInformation<T, String> entityInformation,
@NonNull ReactiveMongoOperations mongoOperations) {
super(entityInformation, mongoOperations);
this.mongoOperations = mongoOperations;
this.entityInformation = entityInformation;
}
/**
* 通过名称查找一个
*
* @param name 名称
* @return 结果
*/
@Override
public Mono<T> findByName(String name) {
if (StringUtils.isNotBlank(name)) {
return mongoOperations.findOne(Query.query(Criteria.where("name").is(name)),
entityInformation.getJavaType(), entityInformation.getCollectionName());
}
return Mono.empty();
}
/**
* Returns a single entity matching the given {@link Qo} or {@link Optional#empty()} if none was found.
*
* @param query must not be {@literal null}.
* @return a single entity matching the given {@link Qo} or {@link Optional#empty()} if none was found.
* @throws IncorrectResultSizeDataAccessException if the Qo yields more than one
* result.
*/
@Override
public Mono<T> findOne(Qo<T> query) {
return Mono.justOrEmpty(QueryBuildUtils.getQuery(query))
.flatMap(querying -> mongoOperations.findOne(querying, entityInformation.getJavaType(),
entityInformation.getCollectionName()));
}
/**
* Returns all entities matching the given {@link Qo}. In case no match could be found an empty
* {@link Iterable} is returned.
*
* @param query must not be {@literal null}.
* @return all entities matching the given {@link Qo}.
*/
@Override
public Flux<T> findAll(Qo<T> query) {
return Mono.justOrEmpty(QueryBuildUtils.getQuery(query))
.flatMapMany(querying -> mongoOperations.find(querying,
entityInformation.getJavaType(),
entityInformation.getCollectionName()));
}
/**
* Returns all entities matching the given {@link Qo} applying the given {@link Sort}. In case no match could
* be found an empty {@link Iterable} is returned.
*
* @param query must not be {@literal null}.
* @param sort the {@link Sort} specification to sort the results by, may be {@link Sort#empty()}, must not be
* {@literal null}.
* @return all entities matching the given {@link Qo}.
* @since 1.10
*/
@Override
public Flux<T> findAll(Qo<T> query, Sort sort) {
return Mono.justOrEmpty(QueryBuildUtils.getQuery(query))
.flatMapMany(querying -> mongoOperations.find(querying.with(sort),
entityInformation.getJavaType(),
entityInformation.getCollectionName()));
}
/**
* Returns a {@link Page} of entities matching the given {@link Qo}. In case no match could be found, an empty
* {@link Page} is returned.
*
* @param query must not be {@literal null}.
* @param pageable may be {@link Pageable#unpaged()}, must not be {@literal null}.
* @return a {@link Page} of entities matching the given {@link Qo}.
*/
@Override
public Mono<Page<T>> findAll(Qo<T> query, Pageable pageable) {
return Mono.justOrEmpty(QueryBuildUtils.getQuery(query))
.flatMap(querying -> mongoOperations.find(querying.with(pageable),
entityInformation.getJavaType(), entityInformation.getCollectionName())
.collectList()
.flatMap(list -> ReactivePageableExecutionUtils.getPage(list, pageable, this.count(query))))
.defaultIfEmpty(Page.empty());
}
/**
* Returns the number of instances matching the given {@link Qo}.
*
* @param query the {@link Qo} to count instances for, must not be {@literal null}.
* @return the number of instances matching the {@link Qo}.
*/
@Override
public Mono<Long> count(Qo<T> query) {
return Mono.justOrEmpty(QueryBuildUtils.getQuery(query))
.flatMap(querying -> this.mongoOperations.count(querying, entityInformation.getJavaType(),
entityInformation.getCollectionName()))
.defaultIfEmpty(0L);
}
/**
* 通过特定键的集合查询
*
* @param key
* @param values 集合
* @return 结果
*/
@Override
public Flux<T> findAllByValues(String key, List<?> values) {
Criteria criteria = Criteria.where(key).in(values);
Query query = new Query(criteria);
return mongoOperations.find(query,
entityInformation.getJavaType(),
entityInformation.getCollectionName());
}
/**
* Checks whether the data store contains elements that match the given {@link Qo}.
*
* @param query the {@link Qo} to use for the existence check, must not be {@literal null}.
* @return {@literal true} if the data store contains elements that match the given {@link Qo}.
*/
@Override
public Mono<Boolean> exists(Qo<T> query) {
return Mono.justOrEmpty(QueryBuildUtils.getQuery(query))
.flatMap(querying -> mongoOperations.exists(querying,
entityInformation.getJavaType(), entityInformation.getCollectionName()))
.defaultIfEmpty(false);
}
/**
* 删除全部
*
* @param qo 查询实体
* @return 结果
*/
@Override
public Mono<Void> deleteAll(Qo<T> qo) {
return Mono.justOrEmpty(QueryBuildUtils.getQuery(qo))
.flatMap(querying -> mongoOperations.remove(querying, entityInformation.getJavaType(),
entityInformation.getCollectionName()))
.then(Mono.empty());
}
} }

View File

@ -3,10 +3,8 @@ package com.flyfish.framework.repository.impl;
import com.flyfish.framework.domain.base.Domain; import com.flyfish.framework.domain.base.Domain;
import com.flyfish.framework.domain.base.Qo; import com.flyfish.framework.domain.base.Qo;
import com.flyfish.framework.repository.DefaultRepository; import com.flyfish.framework.repository.DefaultRepository;
import com.flyfish.framework.utils.CopyUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
@ -16,7 +14,7 @@ import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation; import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.mongodb.repository.support.SimpleMongoRepository; import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;
import org.springframework.data.repository.support.PageableExecutionUtils; import org.springframework.data.support.PageableExecutionUtils;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -71,15 +69,11 @@ public class DefaultRepositoryImpl<T extends Domain> extends SimpleMongoReposito
*/ */
@Override @Override
public Optional<T> findOne(Qo<T> query) { public Optional<T> findOne(Qo<T> query) {
Query querying = getQuery(query); return QueryBuildUtils.getQuery(query)
if (null != querying) { .map(querying -> mongoOperations.findOne(querying,
return Optional
.ofNullable(mongoOperations.findOne(querying,
entityInformation.getJavaType(), entityInformation.getJavaType(),
entityInformation.getCollectionName())); entityInformation.getCollectionName()));
} }
return Optional.empty();
}
/** /**
* Returns all entities matching the given {@link Qo}. In case no match could be found an empty * Returns all entities matching the given {@link Qo}. In case no match could be found an empty
@ -90,13 +84,11 @@ public class DefaultRepositoryImpl<T extends Domain> extends SimpleMongoReposito
*/ */
@Override @Override
public Iterable<T> findAll(Qo<T> query) { public Iterable<T> findAll(Qo<T> query) {
Query querying = getQuery(query); return QueryBuildUtils.getQuery(query)
if (null != querying) { .map(querying -> mongoOperations.find(querying,
return mongoOperations.find(querying,
entityInformation.getJavaType(), entityInformation.getJavaType(),
entityInformation.getCollectionName()); entityInformation.getCollectionName()))
} .orElse(Collections.emptyList());
return Collections.emptyList();
} }
/** /**
@ -111,7 +103,11 @@ public class DefaultRepositoryImpl<T extends Domain> extends SimpleMongoReposito
*/ */
@Override @Override
public Iterable<T> findAll(Qo<T> query, Sort sort) { public Iterable<T> findAll(Qo<T> query, Sort sort) {
return Collections.emptyList(); return QueryBuildUtils.getQuery(query)
.map(querying -> mongoOperations.find(querying.with(sort),
entityInformation.getJavaType(),
entityInformation.getCollectionName()))
.orElse(Collections.emptyList());
} }
/** /**
@ -124,14 +120,11 @@ public class DefaultRepositoryImpl<T extends Domain> extends SimpleMongoReposito
*/ */
@Override @Override
public Page<T> findAll(Qo<T> query, Pageable pageable) { public Page<T> findAll(Qo<T> query, Pageable pageable) {
Query querying = getQuery(query); return QueryBuildUtils.getQuery(query).map(querying -> {
if (null != querying) { List<T> queryResult = mongoOperations.find(querying.with(pageable),
querying.with(pageable);
List<T> queryResult = mongoOperations.find(querying,
entityInformation.getJavaType(), entityInformation.getCollectionName()); entityInformation.getJavaType(), entityInformation.getCollectionName());
return PageableExecutionUtils.getPage(queryResult, pageable, () -> count(query)); return PageableExecutionUtils.getPage(queryResult, pageable, () -> count(query));
} }).orElse(Page.empty());
return Page.empty();
} }
/** /**
@ -142,8 +135,9 @@ public class DefaultRepositoryImpl<T extends Domain> extends SimpleMongoReposito
*/ */
@Override @Override
public long count(Qo<T> query) { public long count(Qo<T> query) {
Query q = getQuery(query); return QueryBuildUtils.getQuery(query)
return this.mongoOperations.count(q, entityInformation.getJavaType(), entityInformation.getCollectionName()); .map(q -> this.mongoOperations.count(q, entityInformation.getJavaType(), entityInformation.getCollectionName()))
.orElse(0L);
} }
/** /**
@ -154,7 +148,7 @@ public class DefaultRepositoryImpl<T extends Domain> extends SimpleMongoReposito
* @return 结果 * @return 结果
*/ */
@Override @Override
public List<T> findAllByValues(String key, List<Object> values) { public List<T> findAllByValues(String key, List<?> values) {
Criteria criteria = Criteria.where(key).in(values); Criteria criteria = Criteria.where(key).in(values);
Query query = new Query(criteria); Query query = new Query(criteria);
return mongoOperations.find(query, return mongoOperations.find(query,
@ -170,38 +164,9 @@ public class DefaultRepositoryImpl<T extends Domain> extends SimpleMongoReposito
*/ */
@Override @Override
public boolean exists(Qo<T> query) { public boolean exists(Qo<T> query) {
return false; return QueryBuildUtils.getQuery(query).map(querying -> mongoOperations.exists(querying,
} entityInformation.getJavaType(), entityInformation.getCollectionName()))
.orElse(false);
/**
* 从查询实体抽取内部查询信息
*
* @param qo 查询实体
* @return 结果
*/
private Query getQuery(Qo<T> qo) {
Criteria criteria = null;
if (null != qo.getCriteria()) {
criteria = qo.getCriteria();
} else if (null != qo.getExample()) {
criteria = new Criteria().alike(qo.getExample());
} else {
Class<T> type = qo.pojoType();
if (null != type && !Object.class.equals(type)) {
try {
T pojo = CopyUtils.copyQueryProps(qo, qo.pojoType().newInstance());
criteria = new Criteria().alike(Example.of(pojo));
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
if (criteria != null) {
// 针对删除状态全局筛选
return new Query(Criteria.where("delete").ne(true).andOperator(criteria))
.with(qo.sorts());
}
return null;
} }
} }

View File

@ -0,0 +1,43 @@
package com.flyfish.framework.repository.impl;
import com.flyfish.framework.domain.base.Qo;
import com.flyfish.framework.utils.CopyUtils;
import org.springframework.data.domain.Example;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import java.util.Optional;
abstract class QueryBuildUtils {
/**
* 从查询实体抽取内部查询信息
*
* @param qo 查询实体
* @return 结果
*/
static <T> Optional<Query> getQuery(Qo<T> qo) {
Criteria criteria = null;
if (null != qo.getCriteria()) {
criteria = qo.getCriteria();
} else if (null != qo.getExample()) {
criteria = new Criteria().alike(qo.getExample());
} else {
Class<T> type = qo.pojoType();
if (null != type && !Object.class.equals(type)) {
try {
T pojo = CopyUtils.copyQueryProps(qo, qo.pojoType().newInstance());
criteria = new Criteria().alike(Example.of(pojo));
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
if (criteria != null) {
// 针对删除状态全局筛选
return Optional.of(new Query(Criteria.where("delete").ne(true).andOperator(criteria))
.with(qo.sorts()));
}
return Optional.empty();
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.flyfish.framework.repository.impl;
import reactor.core.publisher.Mono;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.util.Assert;
/**
* Support for query execution using {@link Pageable}. Using {@link ReactivePageableExecutionUtils} assumes that data
* queries are cheaper than {@code COUNT} queries and so some cases can take advantage of optimizations.
*
* @author Mark Paluch
* @since 3.3
*/
abstract class ReactivePageableExecutionUtils {
private ReactivePageableExecutionUtils() {}
/**
* Constructs a {@link Page} based on the given {@code content}, {@link Pageable} and {@link Mono} applying
* optimizations. The construction of {@link Page} omits a count query if the total can be determined based on the
* result size and {@link Pageable}.
*
* @param content must not be {@literal null}.
* @param pageable must not be {@literal null}.
* @param totalSupplier must not be {@literal null}.
* @return the {@link Page}.
*/
public static <T> Mono<Page<T>> getPage(List<T> content, Pageable pageable, Mono<Long> totalSupplier) {
Assert.notNull(content, "Content must not be null!");
Assert.notNull(pageable, "Pageable must not be null!");
Assert.notNull(totalSupplier, "TotalSupplier must not be null!");
if (pageable.isUnpaged() || pageable.getOffset() == 0) {
if (pageable.isUnpaged() || pageable.getPageSize() > content.size()) {
return Mono.just(new PageImpl<>(content, pageable, content.size()));
}
return totalSupplier.map(total -> new PageImpl<>(content, pageable, total));
}
if (!content.isEmpty() && pageable.getPageSize() > content.size()) {
return Mono.just(new PageImpl<>(content, pageable, pageable.getOffset() + content.size()));
}
return totalSupplier.map(total -> new PageImpl<>(content, pageable, total));
}
}

View File

@ -11,7 +11,7 @@ import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.reflections.Reflections; import org.reflections.Reflections;
import org.reflections.scanners.FieldAnnotationsScanner; import org.reflections.scanners.Scanners;
import org.reflections.util.ClasspathHelper; import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder; import org.reflections.util.ConfigurationBuilder;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
@ -45,7 +45,7 @@ public class DictionaryProcessor implements InitializingBean {
.collect(Collectors.toList()); .collect(Collectors.toList());
Reflections reflections = new Reflections(new ConfigurationBuilder() Reflections reflections = new Reflections(new ConfigurationBuilder()
.setUrls(urls) .setUrls(urls)
.setScanners(new FieldAnnotationsScanner())); .setScanners(Scanners.FieldsAnnotated));
Set<Field> fields = reflections.getFieldsAnnotatedWith(DictValue.class); Set<Field> fields = reflections.getFieldsAnnotatedWith(DictValue.class);
if (CollectionUtils.isNotEmpty(fields)) { if (CollectionUtils.isNotEmpty(fields)) {
// 查找是否存在不存在插入存在无视 // 查找是否存在不存在插入存在无视

View File

@ -1,10 +1,10 @@
package com.flyfish.framework.dict.controller; package com.flyfish.framework.dict.controller;
import com.flyfish.framework.beans.annotations.RestMapping; import com.flyfish.framework.beans.annotations.RestMapping;
import com.flyfish.framework.controller.BaseController; import com.flyfish.framework.controller.ReactiveBaseController;
import com.flyfish.framework.dict.domain.AutoComplete; import com.flyfish.framework.dict.domain.AutoComplete;
import com.flyfish.framework.domain.base.NameLikeQo; import com.flyfish.framework.domain.base.NameLikeQo;
@RestMapping("auto-completes") @RestMapping("auto-completes")
public class AutoCompleteController extends BaseController<AutoComplete, NameLikeQo<AutoComplete>> { public class AutoCompleteController extends ReactiveBaseController<AutoComplete, NameLikeQo<AutoComplete>> {
} }

View File

@ -2,7 +2,7 @@ package com.flyfish.framework.dict.controller;
import com.flyfish.framework.beans.annotations.RestMapping; import com.flyfish.framework.beans.annotations.RestMapping;
import com.flyfish.framework.controller.BaseController; import com.flyfish.framework.controller.ReactiveBaseController;
import com.flyfish.framework.dict.domain.Dictionary; import com.flyfish.framework.dict.domain.Dictionary;
import com.flyfish.framework.dict.domain.DictionaryQo; import com.flyfish.framework.dict.domain.DictionaryQo;
@ -12,6 +12,6 @@ import com.flyfish.framework.dict.domain.DictionaryQo;
* @author wangyu * @author wangyu
*/ */
@RestMapping("dictionaries") @RestMapping("dictionaries")
public class DictionaryController extends BaseController<Dictionary, DictionaryQo> { public class DictionaryController extends ReactiveBaseController<Dictionary, DictionaryQo> {
} }

View File

@ -1,7 +1,7 @@
package com.flyfish.framework.dict.repository; package com.flyfish.framework.dict.repository;
import com.flyfish.framework.dict.domain.AutoComplete; import com.flyfish.framework.dict.domain.AutoComplete;
import com.flyfish.framework.repository.DefaultRepository; import com.flyfish.framework.repository.DefaultReactiveRepository;
public interface AutoCompleteRepository extends DefaultRepository<AutoComplete> { public interface AutoCompleteRepository extends DefaultReactiveRepository<AutoComplete> {
} }

View File

@ -1,7 +1,7 @@
package com.flyfish.framework.dict.repository; package com.flyfish.framework.dict.repository;
import com.flyfish.framework.dict.domain.Dictionary; import com.flyfish.framework.dict.domain.Dictionary;
import com.flyfish.framework.repository.DefaultRepository; import com.flyfish.framework.repository.DefaultReactiveRepository;
import java.util.Optional; import java.util.Optional;
@ -10,7 +10,7 @@ import java.util.Optional;
* *
* @author wangyu * @author wangyu
*/ */
public interface DictionaryRepository extends DefaultRepository<Dictionary> { public interface DictionaryRepository extends DefaultReactiveRepository<Dictionary> {
/** /**
* 通过code查找 * 通过code查找

View File

@ -1,9 +1,9 @@
package com.flyfish.framework.dict.service; package com.flyfish.framework.dict.service;
import com.flyfish.framework.dict.domain.AutoComplete; import com.flyfish.framework.dict.domain.AutoComplete;
import com.flyfish.framework.service.impl.BaseServiceImpl; import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
public class AutoCompleteService extends BaseServiceImpl<AutoComplete> { public class AutoCompleteService extends BaseReactiveServiceImpl<AutoComplete> {
} }

View File

@ -3,7 +3,8 @@ package com.flyfish.framework.dict.service;
import com.flyfish.framework.dict.domain.Dictionary; import com.flyfish.framework.dict.domain.Dictionary;
import com.flyfish.framework.dict.repository.DictionaryRepository; import com.flyfish.framework.dict.repository.DictionaryRepository;
import com.flyfish.framework.service.impl.BaseServiceImpl; import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Optional; import java.util.Optional;
@ -14,7 +15,7 @@ import java.util.Optional;
* @author wangyu * @author wangyu
*/ */
@Service @Service
public class DictionaryService extends BaseServiceImpl<Dictionary> { public class DictionaryService extends BaseReactiveServiceImpl<Dictionary> {
/** /**
* 通过code查询 * 通过code查询

View File

@ -1,7 +1,7 @@
package com.flyfish.framework.file.controller; package com.flyfish.framework.file.controller;
import com.flyfish.framework.controller.BaseController; import com.flyfish.framework.controller.ReactiveBaseController;
import com.flyfish.framework.file.domain.Attachment; import com.flyfish.framework.file.domain.Attachment;
import com.flyfish.framework.file.domain.AttachmentQo; import com.flyfish.framework.file.domain.AttachmentQo;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -9,6 +9,6 @@ import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequestMapping("/attachments") @RequestMapping("/attachments")
public class AttachmentController extends BaseController<Attachment, AttachmentQo> { public class AttachmentController extends ReactiveBaseController<Attachment, AttachmentQo> {
} }

View File

@ -57,7 +57,7 @@ public class AttachmentUploadController {
@GetMapping("/downloads/{id}") @GetMapping("/downloads/{id}")
public Mono<Void> downloadAttachment(@PathVariable String id, ServerHttpResponse response) { public Mono<Void> downloadAttachment(@PathVariable String id, ServerHttpResponse response) {
return Mono.justOrEmpty(attachmentService.getById(id)) return attachmentService.getById(id)
.flatMap(attachment -> DownloadUtils.download(configuration.getLocalPath() + .flatMap(attachment -> DownloadUtils.download(configuration.getLocalPath() +
attachment.getPath(), response)); attachment.getPath(), response));
} }

View File

@ -2,7 +2,7 @@ package com.flyfish.framework.file.repository;
import com.flyfish.framework.file.domain.Attachment; import com.flyfish.framework.file.domain.Attachment;
import com.flyfish.framework.repository.DefaultRepository; import com.flyfish.framework.repository.DefaultReactiveRepository;
public interface AttachmentRepository extends DefaultRepository<Attachment> { public interface AttachmentRepository extends DefaultReactiveRepository<Attachment> {
} }

View File

@ -3,7 +3,7 @@ package com.flyfish.framework.file.service;
import com.flyfish.framework.file.domain.Attachment; import com.flyfish.framework.file.domain.Attachment;
import com.flyfish.framework.file.utils.FileSizeUtils; import com.flyfish.framework.file.utils.FileSizeUtils;
import com.flyfish.framework.service.impl.BaseServiceImpl; import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.http.codec.multipart.FilePart; import org.springframework.http.codec.multipart.FilePart;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -12,7 +12,7 @@ import reactor.core.publisher.Mono;
import javax.annotation.Resource; import javax.annotation.Resource;
@Service @Service
public class AttachmentService extends BaseServiceImpl<Attachment> { public class AttachmentService extends BaseReactiveServiceImpl<Attachment> {
private static String URL = "/api/attachment/"; private static String URL = "/api/attachment/";
@Resource @Resource
@ -36,7 +36,7 @@ public class AttachmentService extends BaseServiceImpl<Attachment> {
*/ */
public Mono<Attachment> upload(FilePart part, String name) { public Mono<Attachment> upload(FilePart part, String name) {
return fileService.saveLocal(part) return fileService.saveLocal(part)
.map(path -> { .flatMap(path -> {
Attachment attachment = Attachment.builder() Attachment attachment = Attachment.builder()
.size(FileSizeUtils.size(part.headers().getContentLength())) .size(FileSizeUtils.size(part.headers().getContentLength()))
.path(path) .path(path)

View File

@ -1,6 +1,6 @@
package com.flyfish.framework.form.controller; package com.flyfish.framework.form.controller;
import com.flyfish.framework.controller.BaseController; import com.flyfish.framework.controller.ReactiveBaseController;
import com.flyfish.framework.domain.base.NameLikeQo; import com.flyfish.framework.domain.base.NameLikeQo;
import com.flyfish.framework.form.domain.OnlineForm; import com.flyfish.framework.form.domain.OnlineForm;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -13,5 +13,5 @@ import org.springframework.web.bind.annotation.RestController;
*/ */
@RestController @RestController
@RequestMapping("online-forms") @RequestMapping("online-forms")
public class OnlineFormController extends BaseController<OnlineForm, NameLikeQo<OnlineForm>> { public class OnlineFormController extends ReactiveBaseController<OnlineForm, NameLikeQo<OnlineForm>> {
} }

View File

@ -1,10 +1,10 @@
package com.flyfish.framework.form.repository; package com.flyfish.framework.form.repository;
import com.flyfish.framework.form.domain.OnlineForm; import com.flyfish.framework.form.domain.OnlineForm;
import com.flyfish.framework.repository.DefaultRepository; import com.flyfish.framework.repository.DefaultReactiveRepository;
/** /**
* 在线表单 * 在线表单
*/ */
public interface OnlineFormRepository extends DefaultRepository<OnlineForm> { public interface OnlineFormRepository extends DefaultReactiveRepository<OnlineForm> {
} }

View File

@ -1,7 +1,7 @@
package com.flyfish.framework.form.service; package com.flyfish.framework.form.service;
import com.flyfish.framework.form.domain.OnlineForm; import com.flyfish.framework.form.domain.OnlineForm;
import com.flyfish.framework.service.impl.BaseServiceImpl; import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
/** /**
@ -9,5 +9,5 @@ import org.springframework.stereotype.Service;
* @author wangyu * @author wangyu
*/ */
@Service @Service
public class OnlineFormService extends BaseServiceImpl<OnlineForm> { public class OnlineFormService extends BaseReactiveServiceImpl<OnlineForm> {
} }

View File

@ -1,7 +1,7 @@
package com.flyfish.framework.logging.controller; package com.flyfish.framework.logging.controller;
import com.flyfish.framework.beans.annotations.RestMapping; import com.flyfish.framework.beans.annotations.RestMapping;
import com.flyfish.framework.controller.BaseController; import com.flyfish.framework.controller.ReactiveBaseController;
import com.flyfish.framework.logging.domain.Log; import com.flyfish.framework.logging.domain.Log;
import com.flyfish.framework.logging.domain.LogQo; import com.flyfish.framework.logging.domain.LogQo;
@ -11,6 +11,6 @@ import com.flyfish.framework.logging.domain.LogQo;
* @author wangyu * @author wangyu
*/ */
@RestMapping("logs") @RestMapping("logs")
public class LogController extends BaseController<Log, LogQo> { public class LogController extends ReactiveBaseController<Log, LogQo> {
} }

View File

@ -1,11 +1,11 @@
package com.flyfish.framework.logging.repository; package com.flyfish.framework.logging.repository;
import com.flyfish.framework.logging.domain.Log; import com.flyfish.framework.logging.domain.Log;
import com.flyfish.framework.repository.DefaultRepository; import com.flyfish.framework.repository.DefaultReactiveRepository;
/** /**
* 日志仓库 * 日志仓库
* @author wangyu * @author wangyu
*/ */
public interface LogRepository extends DefaultRepository<Log> { public interface LogRepository extends DefaultReactiveRepository<Log> {
} }

View File

@ -1,7 +1,7 @@
package com.flyfish.framework.logging.service; package com.flyfish.framework.logging.service;
import com.flyfish.framework.logging.domain.Log; import com.flyfish.framework.logging.domain.Log;
import com.flyfish.framework.service.impl.BaseServiceImpl; import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
/** /**
@ -9,7 +9,7 @@ import org.springframework.stereotype.Service;
* @author wangyu * @author wangyu
*/ */
@Service @Service
public class LogService extends BaseServiceImpl<Log> { public class LogService extends BaseReactiveServiceImpl<Log> {
} }

View File

@ -6,13 +6,12 @@ import com.flyfish.framework.logging.config.LoggingTextRegistry;
import com.flyfish.framework.logging.domain.Log; import com.flyfish.framework.logging.domain.Log;
import com.flyfish.framework.logging.domain.LogType; import com.flyfish.framework.logging.domain.LogType;
import com.flyfish.framework.service.AuthenticationLogger; import com.flyfish.framework.service.AuthenticationLogger;
import com.flyfish.framework.service.UserFindService;
import com.flyfish.framework.utils.AuthenticationMessages; import com.flyfish.framework.utils.AuthenticationMessages;
import com.flyfish.framework.utils.UserUtils; import com.flyfish.framework.utils.UserUtils;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap; import reactor.core.publisher.Mono;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Date; import java.util.Date;
@ -29,8 +28,6 @@ public class SimpleAuthenticationLogger implements AuthenticationLogger {
@Resource @Resource
private LogService logService; private LogService logService;
@Resource @Resource
private UserFindService userService;
@Resource
private LoggingTextRegistry registry; private LoggingTextRegistry registry;
/** /**
@ -39,19 +36,19 @@ public class SimpleAuthenticationLogger implements AuthenticationLogger {
* @param user 用户 * @param user 用户
*/ */
@Override @Override
public void success(UserDetails user) { public Mono<Void> success(UserDetails user) {
saveSuccess("LOGIN", "登录成功", user); return saveSuccess("LOGIN", "登录成功", user);
} }
/** /**
* 记录失败 * 记录失败
* *
* @param form 表单 * @param user 表单用户
* @param exception 错误异常 * @param exception 错误异常
*/ */
@Override @Override
public void failure(MultiValueMap<String, String> form, AuthenticationException exception) { public Mono<Void> failure(User user, AuthenticationException exception) {
saveError("LOGIN", "登录失败", form.getFirst("username"), AuthenticationMessages.message(exception)); return saveError("LOGIN", "登录失败", user, AuthenticationMessages.message(exception));
} }
/** /**
@ -60,8 +57,8 @@ public class SimpleAuthenticationLogger implements AuthenticationLogger {
* @param user 用户 * @param user 用户
*/ */
@Override @Override
public void logout(UserDetails user) { public Mono<Void> logout(UserDetails user) {
saveSuccess("LOGOUT", "退出成功", user); return saveSuccess("LOGOUT", "退出成功", user);
} }
/** /**
@ -71,7 +68,7 @@ public class SimpleAuthenticationLogger implements AuthenticationLogger {
* @param message 信息 * @param message 信息
* @param user 用户 * @param user 用户
*/ */
private void saveSuccess(String business, String message, UserDetails user) { private Mono<Void> saveSuccess(String business, String message, UserDetails user) {
User raw = UserUtils.toUser(user); User raw = UserUtils.toUser(user);
Log log = new Log(); Log log = new Log();
log.setType(LogType.AUTHENTICATION); log.setType(LogType.AUTHENTICATION);
@ -85,7 +82,7 @@ public class SimpleAuthenticationLogger implements AuthenticationLogger {
log.setPeriod(0L); log.setPeriod(0L);
log.setStartTime(new Date()); log.setStartTime(new Date());
// 写入日志 // 写入日志
logService.create(log); return logService.create(log).then();
} }
/** /**
@ -93,24 +90,23 @@ public class SimpleAuthenticationLogger implements AuthenticationLogger {
* *
* @param business 业务 * @param business 业务
* @param message 消息 * @param message 消息
* @param username 用户名
* @param error 错误 * @param error 错误
*/ */
private void saveError(String business, String message, String username, String error) { private Mono<Void> saveError(String business, String message, User user, String error) {
Log log = new Log(); Log log = new Log();
log.setType(LogType.AUTHENTICATION); log.setType(LogType.AUTHENTICATION);
log.setSignature(business); log.setSignature(business);
log.setSuccess(false); log.setSuccess(false);
log.setBody("某人尝试使用用户名'" + username + "',密码:******,进行登录"); log.setBody("某人尝试使用用户名'" + user.getUsername() + "',密码:******,进行登录");
log.setModule("登录模块"); log.setModule("登录模块");
log.setBusiness(registry.text(business)); log.setBusiness(registry.text(business));
log.setError(error); log.setError(error);
log.setResponse(message); log.setResponse(message);
log.setOperator(userService.findByUsername(username).map(Domain::getName).orElse("未知")); log.setOperator(user.getName());
log.setPeriod(0L); log.setPeriod(0L);
log.setStartTime(new Date()); log.setStartTime(new Date());
// 写入日志 // 写入日志
logService.create(log); return logService.create(log).then();
} }
} }

View File

@ -16,7 +16,7 @@ import java.lang.annotation.*;
@Target({ElementType.TYPE}) @Target({ElementType.TYPE})
@Documented @Documented
@Import(WebSecurityConfig.class) @Import(WebSecurityConfig.class)
@EnableReactiveMongoRepositories(basePackages = "com.flyfish.framework") @EnableReactiveMongoRepo
@EnableReactiveRedis @EnableReactiveRedis
public @interface EnableAutoSecurity { public @interface EnableAutoSecurity {
} }

View File

@ -40,8 +40,7 @@ public class AuthenticationAuditorImpl extends ResultDataTransformer implements
updating.setId(details.getId()); updating.setId(details.getId());
updating.setErrorCount(0); updating.setErrorCount(0);
updating.setLastTime(new Date()); updating.setLastTime(new Date());
return reactiveUserService.updateSelectiveById(updating) return reactiveUserService.updateSelectiveById(updating).then(authenticationLogger.success(user));
.then(Mono.fromRunnable(() -> authenticationLogger.success(user)));
} }
/** /**
@ -56,10 +55,11 @@ public class AuthenticationAuditorImpl extends ResultDataTransformer implements
return webFilterExchange.getExchange() return webFilterExchange.getExchange()
.getFormData() .getFormData()
.flatMap(data -> { .flatMap(data -> {
String username = data.getFirst("username");
Mono<User> userMono = reactiveUserService.findByUsername(username).defaultIfEmpty(emptyUser(username));
// 当且仅当为凭据错误尝试 // 当且仅当为凭据错误尝试
if (exception instanceof BadCredentialsException) { if (exception instanceof BadCredentialsException) {
return reactiveUserService.findByUsername(data.getFirst("username")) userMono = userMono.flatMap(user -> {
.flatMap(user -> {
User updating = new User(); User updating = new User();
updating.setId(user.getId()); updating.setId(user.getId());
updating.setErrorCount(user.getErrorCount() + 1); updating.setErrorCount(user.getErrorCount() + 1);
@ -67,16 +67,28 @@ public class AuthenticationAuditorImpl extends ResultDataTransformer implements
updating.setStatus(UserStatus.LOCKED); updating.setStatus(UserStatus.LOCKED);
} }
return reactiveUserService.updateSelectiveById(updating); return reactiveUserService.updateSelectiveById(updating);
}) });
.map(user -> data);
} }
return Mono.just(data); return userMono.flatMap(user -> authenticationLogger.failure(user, exception));
}) });
.flatMap(data -> Mono.fromRunnable(() -> authenticationLogger.failure(data, exception)));
} }
@Override @Override
public Mono<Void> logout(UserDetails userDetails) { public Mono<Void> logout(UserDetails userDetails) {
return Mono.fromRunnable(() -> authenticationLogger.logout(userDetails)); return authenticationLogger.logout(userDetails);
} }
/**
* 构造空用户
*
* @param username 用户名
* @return 结果
*/
private User emptyUser(String username) {
User user = new User();
user.setUsername(username);
user.setName("未知");
return user;
}
} }

View File

@ -36,7 +36,7 @@ import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.HttpStatusServerEntryPoint; import org.springframework.security.web.server.authentication.HttpStatusServerEntryPoint;
import org.springframework.security.web.server.context.ServerSecurityContextRepository; import org.springframework.security.web.server.context.ServerSecurityContextRepository;
import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository; import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository;
import org.springframework.util.MultiValueMap; import reactor.core.publisher.Mono;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -74,18 +74,18 @@ public class WebSecurityConfig {
public AuthenticationLogger authenticationLogger() { public AuthenticationLogger authenticationLogger() {
return new AuthenticationLogger() { return new AuthenticationLogger() {
@Override @Override
public void success(UserDetails user) { public Mono<Void> success(UserDetails user) {
return Mono.empty();
} }
@Override @Override
public void failure(MultiValueMap<String, String> form, AuthenticationException exception) { public Mono<Void> failure(User user, AuthenticationException exception) {
return Mono.empty();
} }
@Override @Override
public void logout(UserDetails user) { public Mono<Void> logout(UserDetails user) {
return Mono.empty();
} }
}; };
} }

View File

@ -0,0 +1,33 @@
package com.flyfish.framework.config.audit;
import com.flyfish.framework.domain.base.Domain;
import com.flyfish.framework.utils.UserUtils;
import org.springframework.data.domain.ReactiveAuditorAware;
import org.springframework.lang.NonNull;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
/**
* 用户上下文审查工具
*
* @author wangyu
*/
@Component
public class ReactiveUserAuditor implements ReactiveAuditorAware<String> {
/**
* 在异步上下文中获取结果
*
* @return 结果
*/
@Override
@NonNull
public Mono<String> getCurrentAuditor() {
return ReactiveSecurityContextHolder.getContext()
.map(UserUtils::extractUser)
.map(Domain::getName)
.defaultIfEmpty("匿名用户");
}
}

View File

@ -1,4 +1,4 @@
package com.flyfish.framework.auditor; package com.flyfish.framework.config.audit;
import com.flyfish.framework.context.UserContext; import com.flyfish.framework.context.UserContext;
import com.flyfish.framework.domain.base.Domain; import com.flyfish.framework.domain.base.Domain;

View File

@ -12,6 +12,6 @@ import org.springframework.web.bind.annotation.RestController;
*/ */
@RestController @RestController
@RequestMapping("/roles") @RequestMapping("/roles")
public class RoleController extends BaseController<Role, RoleQo> { public class RoleController extends ReactiveBaseController<Role, RoleQo> {
} }

View File

@ -10,7 +10,6 @@ import com.flyfish.framework.domain.po.Role;
import com.flyfish.framework.domain.po.User; import com.flyfish.framework.domain.po.User;
import com.flyfish.framework.enums.UserStatus; import com.flyfish.framework.enums.UserStatus;
import com.flyfish.framework.service.ReactiveUserService; import com.flyfish.framework.service.ReactiveUserService;
import com.flyfish.framework.service.UserService;
import com.flyfish.framework.utils.Assert; import com.flyfish.framework.utils.Assert;
import com.flyfish.framework.utils.StrengthUtils; import com.flyfish.framework.utils.StrengthUtils;
import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.security.core.context.ReactiveSecurityContextHolder;
@ -24,7 +23,7 @@ import java.util.Optional;
@RestController @RestController
@RequestMapping("/users") @RequestMapping("/users")
public class UserController extends BaseController<User, UserQo> { public class UserController extends ReactiveBaseController<User, UserQo> {
@Resource @Resource
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
@ -38,7 +37,7 @@ public class UserController extends BaseController<User, UserQo> {
*/ */
@PutMapping("{id}/passwords") @PutMapping("{id}/passwords")
@Operation("重置密码") @Operation("重置密码")
public Result<Void> resetPassword(@PathVariable String id, @RequestBody User body, @CurrentUser User user) { public Mono<Result<Void>> resetPassword(@PathVariable String id, @RequestBody User body, @CurrentUser User user) {
Assert.hasText(body.getPassword(), "重置密码必需携带密码!"); Assert.hasText(body.getPassword(), "重置密码必需携带密码!");
Assert.isTrue(Optional.ofNullable(user.getRoles()).map(roles -> roles.stream().anyMatch(Role::getAdmin)) Assert.isTrue(Optional.ofNullable(user.getRoles()).map(roles -> roles.stream().anyMatch(Role::getAdmin))
.orElse(false), "您没有管理员权限,无法重置密码!"); .orElse(false), "您没有管理员权限,无法重置密码!");
@ -48,8 +47,7 @@ public class UserController extends BaseController<User, UserQo> {
updating.setStatus(UserStatus.NORMAL); updating.setStatus(UserStatus.NORMAL);
updating.setErrorCount(0); updating.setErrorCount(0);
updating.setPassword(passwordEncoder.encode(body.getPassword())); updating.setPassword(passwordEncoder.encode(body.getPassword()));
service.updateSelectiveById(updating); return reactiveService.updateSelectiveById(updating).thenReturn(Result.ok());
return Result.ok();
} }
/** /**
@ -61,7 +59,7 @@ public class UserController extends BaseController<User, UserQo> {
*/ */
@PutMapping("/passwords") @PutMapping("/passwords")
@Operation("修改密码") @Operation("修改密码")
public Result<Void> changePassword(@Valid @RequestBody UserPasswordDto passwordDto, @CurrentUser User user) { public Mono<Result<Void>> changePassword(@Valid @RequestBody UserPasswordDto passwordDto, @CurrentUser User user) {
// 检查原密码 // 检查原密码
Assert.isTrue(passwordEncoder.matches(passwordDto.getOldPassword(), user.getPassword()), "原密码不正确!"); Assert.isTrue(passwordEncoder.matches(passwordDto.getOldPassword(), user.getPassword()), "原密码不正确!");
Assert.isTrue(!passwordEncoder.matches(passwordDto.getPassword(), user.getPassword()), "新密码和旧密码一致,输入个新的吧!"); Assert.isTrue(!passwordEncoder.matches(passwordDto.getPassword(), user.getPassword()), "新密码和旧密码一致,输入个新的吧!");
@ -70,8 +68,7 @@ public class UserController extends BaseController<User, UserQo> {
User updating = new User(); User updating = new User();
updating.setId(user.getId()); updating.setId(user.getId());
updating.setPassword(passwordEncoder.encode(passwordDto.getPassword())); updating.setPassword(passwordEncoder.encode(passwordDto.getPassword()));
service.updateSelectiveById(updating); return reactiveService.updateSelectiveById(updating).thenReturn(Result.ok());
return Result.ok();
} }
/** /**
@ -81,12 +78,17 @@ public class UserController extends BaseController<User, UserQo> {
*/ */
@GetMapping("/current") @GetMapping("/current")
public Mono<Result<IUser>> getCurrentUser() { public Mono<Result<IUser>> getCurrentUser() {
UserService userService = getService();
return ReactiveSecurityContextHolder.getContext() return ReactiveSecurityContextHolder.getContext()
.map(context -> (IUser) context.getAuthentication().getPrincipal()) .map(context -> (IUser) context.getAuthentication().getPrincipal())
.map(Result::ok); .map(Result::ok);
} }
/**
* 更新用户状态主要更新部门
*
* @param authorize 鉴权
* @return 结果
*/
@PatchMapping("/status") @PatchMapping("/status")
public Mono<Result<User>> updateStatus(String authorize) { public Mono<Result<User>> updateStatus(String authorize) {
ReactiveUserService reactiveService = (ReactiveUserService) this.reactiveService; ReactiveUserService reactiveService = (ReactiveUserService) this.reactiveService;

View File

@ -7,5 +7,5 @@ import com.flyfish.framework.domain.po.Department;
* *
* @author wybab * @author wybab
*/ */
public interface DepartmentRepository extends DefaultRepository<Department> { public interface DepartmentRepository extends DefaultReactiveRepository<Department> {
} }

View File

@ -8,5 +8,5 @@ import com.flyfish.framework.domain.po.Permission;
* *
* @author wybab * @author wybab
*/ */
public interface PermissionRepository extends DefaultRepository<Permission> { public interface PermissionRepository extends DefaultReactiveRepository<Permission> {
} }

View File

@ -7,5 +7,5 @@ import com.flyfish.framework.domain.po.Role;
* *
* @author wybab * @author wybab
*/ */
public interface RoleRepository extends DefaultRepository<Role> { public interface RoleRepository extends DefaultReactiveRepository<Role> {
} }

View File

@ -1,7 +1,7 @@
package com.flyfish.framework.service; package com.flyfish.framework.service;
import com.flyfish.framework.domain.po.Department; import com.flyfish.framework.domain.po.Department;
import com.flyfish.framework.service.impl.BaseServiceImpl; import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Query;
@ -17,7 +17,7 @@ import java.util.stream.Collectors;
* @author wangyu * @author wangyu
*/ */
@Service @Service
public class DepartmentService extends BaseServiceImpl<Department> { public class DepartmentService extends BaseReactiveServiceImpl<Department> {
@Resource @Resource
private MongoOperations mongoOperations; private MongoOperations mongoOperations;

View File

@ -80,7 +80,7 @@ public class MongoUserDetailsServiceImpl implements MongoUserDetailsService {
public Mono<UserDetails> findByUsername(String s) { public Mono<UserDetails> findByUsername(String s) {
String key = UserCacheKeys.get(s); String key = UserCacheKeys.get(s);
// 优先从缓存读取如果缓存不存在查询转换后放入缓存 // 优先从缓存读取如果缓存不存在查询转换后放入缓存
return reactiveRedisOperations.hasKey(key).flatMap(exists -> exists ? reactiveRedisOperations.get(key) : return reactiveRedisOperations.hasKey(key).flatMap(exists -> Boolean.TRUE.equals(exists) ? reactiveRedisOperations.get(key) :
userService.findByUsername(s).flatMap(this::validate).map(this::mapToUserDetails) userService.findByUsername(s).flatMap(this::validate).map(this::mapToUserDetails)
.flatMap(detail -> reactiveRedisOperations.set(key, detail).thenReturn(detail)) .flatMap(detail -> reactiveRedisOperations.set(key, detail).thenReturn(detail))
) )

View File

@ -2,10 +2,10 @@ package com.flyfish.framework.service;
import com.flyfish.framework.domain.po.Permission; import com.flyfish.framework.domain.po.Permission;
import com.flyfish.framework.service.impl.BaseServiceImpl; import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
public class PermissionService extends BaseServiceImpl<Permission> { public class PermissionService extends BaseReactiveServiceImpl<Permission> {
} }

View File

@ -12,7 +12,7 @@ import reactor.core.publisher.Mono;
* @author wangyu * @author wangyu
*/ */
@Service @Service
public class ReactiveUserService extends BaseReactiveServiceImpl<User> { public class ReactiveUserService extends BaseReactiveServiceImpl<User> implements UserFindService {
/** /**
* 获取用户数据 * 获取用户数据
@ -20,6 +20,7 @@ public class ReactiveUserService extends BaseReactiveServiceImpl<User> {
* @param username 用户 * @param username 用户
* @return 结果 * @return 结果
*/ */
@Override
public Mono<User> findByUsername(String username) { public Mono<User> findByUsername(String username) {
return ((ReactiveUserRepository) repository).findByUsername(username); return ((ReactiveUserRepository) repository).findByUsername(username);
} }

View File

@ -5,39 +5,45 @@ import com.flyfish.framework.domain.PermissionQo;
import com.flyfish.framework.domain.po.Permission; import com.flyfish.framework.domain.po.Permission;
import com.flyfish.framework.domain.po.Role; import com.flyfish.framework.domain.po.Role;
import com.flyfish.framework.enums.RoleType; import com.flyfish.framework.enums.RoleType;
import com.flyfish.framework.service.impl.BaseServiceImpl; import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.util.List; import java.util.Collections;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class RoleService extends BaseServiceImpl<Role> { public class RoleService extends BaseReactiveServiceImpl<Role> {
private final PermissionService permissionService; private final PermissionService permissionService;
/** /**
* 如果是管理员设置拥有所有权限 * 如果是管理员设置拥有所有权限
* *
* @param entity 实体 * @param role 实体
* @return 结果 * @return 结果
*/ */
@Override @Override
public Role create(Role entity) { public Mono<Role> create(Role role) {
if (entity.isSystem()) { return Mono.defer(() -> {
entity.setPermissions(permissionService.getAll()); if (role.isSystem()) {
} else if (BooleanUtils.isTrue(entity.getAdmin())) { return permissionService.getAll().collectList();
} else if (BooleanUtils.isTrue(role.getAdmin())) {
// 如果是管理员拥有所有权限 // 如果是管理员拥有所有权限
PermissionQo qo = new PermissionQo(); PermissionQo qo = new PermissionQo();
qo.setAdmin(false); qo.setAdmin(false);
List<Permission> permissions = permissionService.getList(qo); return permissionService.getList(qo).collectList();
entity.setPermissions(permissions);
} }
if (null == entity.getType()) { return Mono.just(Collections.<Permission>emptyList());
entity.setType(RoleType.PC); })
.flatMap(permissions -> {
role.setPermissions(permissions);
if (null == role.getType()) {
role.setType(RoleType.PC);
} }
return super.create(entity); return super.create(role);
});
} }
} }

View File

@ -1,24 +1,10 @@
package com.flyfish.framework.service; package com.flyfish.framework.service;
import com.flyfish.framework.domain.po.User; import com.flyfish.framework.domain.po.User;
import com.flyfish.framework.repository.UserRepository;
import com.flyfish.framework.service.impl.BaseServiceImpl; import com.flyfish.framework.service.impl.BaseServiceImpl;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Optional;
@Service @Service
public class UserService extends BaseServiceImpl<User> implements UserFindService { public class UserService extends BaseServiceImpl<User> {
/**
* 获取用户数据
*
* @param username 用户
* @return 结果
*/
@Override
public Optional<User> findByUsername(String username) {
return ((UserRepository) repository).findByUsername(username);
}
} }

View File

@ -2,6 +2,7 @@ package com.flyfish.framework.beans.excel;
import com.flyfish.framework.controller.BaseController; import com.flyfish.framework.controller.BaseController;
import com.flyfish.framework.controller.ReactiveBaseController;
import com.flyfish.framework.domain.base.NameLikeQo; import com.flyfish.framework.domain.base.NameLikeQo;
import com.flyfish.framework.domain.po.ExcelMapping; import com.flyfish.framework.domain.po.ExcelMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -13,5 +14,5 @@ import org.springframework.web.bind.annotation.RestController;
*/ */
@RestController @RestController
@RequestMapping("/excel-mappings") @RequestMapping("/excel-mappings")
public class ExcelMappingController extends BaseController<ExcelMapping, NameLikeQo<ExcelMapping>> { public class ExcelMappingController extends ReactiveBaseController<ExcelMapping, NameLikeQo<ExcelMapping>> {
} }

View File

@ -1,13 +1,13 @@
package com.flyfish.framework.beans.excel; package com.flyfish.framework.beans.excel;
import com.flyfish.framework.domain.po.ExcelMapping; import com.flyfish.framework.domain.po.ExcelMapping;
import com.flyfish.framework.repository.DefaultRepository; import com.flyfish.framework.repository.DefaultReactiveRepository;
/** /**
* excel导入方案 * excel导入方案
* *
* @author wangyu * @author wangyu
*/ */
public interface ExcelMappingRepository extends DefaultRepository<ExcelMapping> { public interface ExcelMappingRepository extends DefaultReactiveRepository<ExcelMapping> {
} }

View File

@ -1,9 +1,9 @@
package com.flyfish.framework.beans.excel; package com.flyfish.framework.beans.excel;
import com.flyfish.framework.domain.po.ExcelMapping; import com.flyfish.framework.domain.po.ExcelMapping;
import com.flyfish.framework.service.impl.BaseServiceImpl; import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
public class ExcelMappingService extends BaseServiceImpl<ExcelMapping> { public class ExcelMappingService extends BaseReactiveServiceImpl<ExcelMapping> {
} }

View File

@ -1,13 +1,13 @@
package com.flyfish.framework.beans.meta; package com.flyfish.framework.beans.meta;
import com.flyfish.framework.controller.BaseController; import com.flyfish.framework.controller.ReactiveBaseController;
import com.flyfish.framework.controller.SafeController; import com.flyfish.framework.controller.SafeController;
import com.flyfish.framework.domain.base.NameLikeQo; import com.flyfish.framework.domain.base.NameLikeQo;
import com.flyfish.framework.domain.base.Qo; import com.flyfish.framework.domain.base.Qo;
import com.flyfish.framework.domain.base.Vo; import com.flyfish.framework.domain.base.Vo;
import com.flyfish.framework.repository.DefaultRepository; import com.flyfish.framework.repository.DefaultReactiveRepository;
import com.flyfish.framework.service.BaseService; import com.flyfish.framework.service.BaseReactiveService;
import com.flyfish.framework.service.impl.BaseServiceImpl; import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.AliasFor;
import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Document;
@ -79,19 +79,19 @@ public @interface RestBean {
* *
* @return 结果 * @return 结果
*/ */
Class<? extends DefaultRepository> repoClass() default DefaultRepository.class; Class<? extends DefaultReactiveRepository> repoClass() default DefaultReactiveRepository.class;
/** /**
* 服务类动态生成服务 * 服务类动态生成服务
* *
* @return 结果 * @return 结果
*/ */
Class<? extends BaseService> serviceClass() default BaseServiceImpl.class; Class<? extends BaseReactiveService> serviceClass() default BaseReactiveServiceImpl.class;
/** /**
* controller的类支持自定义 * controller的类支持自定义
* *
* @return 结果 * @return 结果
*/ */
Class<? extends SafeController> controllerClass() default BaseController.class; Class<? extends SafeController> controllerClass() default ReactiveBaseController.class;
} }

View File

@ -114,20 +114,6 @@ public abstract class BaseController<T extends Domain, Q extends Qo<T>> implemen
return Result.accept(service.getList(qo)); return Result.accept(service.getList(qo));
} }
/**
* reactive接口
*/
@PostMapping(value = "", headers = ReactiveConstants.USE_REACTIVE)
public Mono<Result<T>> reactiveCreate(@ValidRequestBody T entity) {
return reactiveService.create(entity).map(Result::accept);
}
@GetMapping(value = "{id}", headers = ReactiveConstants.USE_REACTIVE)
public Mono<Result<T>> reactiveGet(@PathVariable String id) {
return reactiveService.getById(id)
.map(Result::accept)
.defaultIfEmpty(Result.notFound());
}
@PutMapping(value = "{id}", headers = ReactiveConstants.USE_REACTIVE) @PutMapping(value = "{id}", headers = ReactiveConstants.USE_REACTIVE)
public Mono<Result<T>> reactiveUpdate(@ValidRequestBody T entity) { public Mono<Result<T>> reactiveUpdate(@ValidRequestBody T entity) {
@ -136,29 +122,4 @@ public abstract class BaseController<T extends Domain, Q extends Qo<T>> implemen
.defaultIfEmpty(Result.notFound()); .defaultIfEmpty(Result.notFound());
} }
@DeleteMapping(value = "{id}", headers = ReactiveConstants.USE_REACTIVE)
public Mono<Result<T>> reactiveRemove(@PathVariable String id) {
return reactiveService.deleteById(id).map(item -> Result.ok());
}
@GetMapping(value = "/all", headers = ReactiveConstants.USE_REACTIVE)
public Mono<Result<List<T>>> reactiveAll() {
return reactiveService.getAll()
.collectList()
.map(Result::accept)
.defaultIfEmpty(Result.emptyList());
}
@GetMapping(value = "", headers = ReactiveConstants.USE_REACTIVE)
public Mono<Result<List<T>>> reactiveList(@PagedQuery Q qo) {
if (null != qo.getPageable()) {
return reactiveService.getPageList(qo)
.map(Result::accept)
.defaultIfEmpty(Result.emptyPage());
}
return reactiveService.getList(qo).collectList()
.map(Result::accept)
.defaultIfEmpty(Result.emptyList());
}
} }

View File

@ -0,0 +1,103 @@
package com.flyfish.framework.controller;
import com.flyfish.framework.annotations.Operation;
import com.flyfish.framework.bean.Result;
import com.flyfish.framework.bean.SyncVo;
import com.flyfish.framework.configuration.annotations.PagedQuery;
import com.flyfish.framework.configuration.annotations.ValidRequestBody;
import com.flyfish.framework.context.UserContext;
import com.flyfish.framework.domain.base.Domain;
import com.flyfish.framework.domain.base.Qo;
import com.flyfish.framework.service.BaseReactiveService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.CastUtils;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;
import java.util.List;
/**
* 通用RESTful的控制器用于动态提供基础的RESTful接口
* 基于最新知识架构出品
*
* @author wangyu
* @create 2021-12-7
*/
public abstract class ReactiveBaseController<T extends Domain, Q extends Qo<T>> implements SafeController {
@Autowired
protected BaseReactiveService<T> reactiveService;
@Autowired
protected UserContext userContext;
public <S extends BaseReactiveService<T>> S getService() {
return CastUtils.cast(reactiveService);
}
@GetMapping("/exists")
public Mono<Result<Boolean>> exists(@PagedQuery Q qo) {
return reactiveService.exists(qo).map(Result::accept);
}
@GetMapping("/count")
public Mono<Result<Long>> count(@PagedQuery Q qo) {
return reactiveService.count(qo).map(Result::accept);
}
@PostMapping("")
@Operation.Create
public Mono<Result<T>> create(@ValidRequestBody T entity) {
return reactiveService.create(entity).map(Result::accept);
}
@GetMapping("{id}")
public Mono<Result<T>> get(@PathVariable String id) {
return reactiveService.getById(id).map(Result::accept).defaultIfEmpty(Result.notFound());
}
@PutMapping("{id}")
@Operation.Update
public Mono<Result<T>> update(@ValidRequestBody T entity) {
return reactiveService.updateSelectiveById(entity).map(Result::accept).defaultIfEmpty(Result.notFound());
}
@PatchMapping("{id}")
@Operation.Update
public Mono<Result<T>> patch(@RequestBody T entity) {
return reactiveService.updateSelectiveById(entity).map(Result::accept).defaultIfEmpty(Result.notFound());
}
@PutMapping("")
@Operation.UpdateAll
public Mono<Result<List<T>>> updateList(@RequestBody List<T> list) {
return reactiveService.updateBatch(list).collectList().map(Result::accept).defaultIfEmpty(Result.emptyList());
}
@PutMapping("/sync")
@Operation.Sync
public Mono<Result<SyncVo<T>>> syncList(@RequestBody List<T> list) {
return reactiveService.sync(list).map(Result::accept).defaultIfEmpty(Result.accept(SyncVo.<T>builder().build()));
}
@DeleteMapping("{id}")
@Operation.Delete
public Mono<Result<T>> remove(@PathVariable List<String> id) {
return reactiveService.deleteBatchByIds(id).thenReturn(Result.ok());
}
@GetMapping("/all")
public Mono<Result<List<T>>> all(@PagedQuery Q qo) {
if (qo.isEmpty()) {
return reactiveService.getAll().collectList().map(Result::accept).defaultIfEmpty(Result.emptyList());
}
return reactiveService.getList(qo).collectList().map(Result::accept).defaultIfEmpty(Result.emptyList());
}
@GetMapping("")
public Mono<Result<List<T>>> list(@PagedQuery Q qo) {
if (null != qo.getPageable() && qo.getPageable().isPaged()) {
return reactiveService.getPageList(qo).map(Result::accept).defaultIfEmpty(Result.emptyPage());
}
return reactiveService.getList(qo).collectList().map(Result::accept).defaultIfEmpty(Result.emptyList());
}
}

View File

@ -1,8 +1,9 @@
package com.flyfish.framework.service; package com.flyfish.framework.service;
import com.flyfish.framework.domain.po.User;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.MultiValueMap; import reactor.core.publisher.Mono;
/** /**
* 认证日志者 * 认证日志者
@ -16,20 +17,20 @@ public interface AuthenticationLogger {
* *
* @param user 用户 * @param user 用户
*/ */
void success(UserDetails user); Mono<Void> success(UserDetails user);
/** /**
* 记录失败 * 记录失败
* *
* @param form 表单 * @param user 表单
* @param exception 错误异常 * @param exception 错误异常
*/ */
void failure(MultiValueMap<String, String> form, AuthenticationException exception); Mono<Void> failure(User user, AuthenticationException exception);
/** /**
* 记录退出 * 记录退出
* *
* @param user 用户 * @param user 用户
*/ */
void logout(UserDetails user); Mono<Void> logout(UserDetails user);
} }

View File

@ -1,5 +1,7 @@
package com.flyfish.framework.service; package com.flyfish.framework.service;
import com.flyfish.framework.bean.SyncVo;
import com.flyfish.framework.domain.base.Domain;
import com.flyfish.framework.domain.base.Qo; import com.flyfish.framework.domain.base.Qo;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
@ -14,7 +16,7 @@ import java.util.List;
* *
* @author wybab * @author wybab
*/ */
public interface BaseReactiveService<T> { public interface BaseReactiveService<T extends Domain> {
/** /**
* 查询 * 查询
@ -40,6 +42,14 @@ public interface BaseReactiveService<T> {
*/ */
Mono<T> getById(String id); Mono<T> getById(String id);
/**
* 通过实体名称访问
*
* @param name 名称
* @return 结果
*/
Mono<T> getByName(String name);
/** /**
* 根据ID集合来查询 * 根据ID集合来查询
* *
@ -48,6 +58,15 @@ public interface BaseReactiveService<T> {
*/ */
Flux<T> getByIds(List<String> ids); Flux<T> getByIds(List<String> ids);
/**
* 通过某个字段的集合包含查询
*
* @param key
* @param values
* @return 结果
*/
<K> Flux<T> getByValues(String key, List<K> values);
/** /**
* 查询列表 * 查询列表
* *
@ -102,6 +121,22 @@ public interface BaseReactiveService<T> {
*/ */
Mono<Long> count(T entity); Mono<Long> count(T entity);
/**
* 查询总记录数
*
* @param query 查询实体
* @return 结果
*/
Mono<Long> count(Qo<T> query);
/**
* 查询是否存在
*
* @param query 查询
* @return 结果
*/
Mono<Boolean> exists(Qo<T> query);
/** /**
* 插入新记录 * 插入新记录
* *
@ -151,10 +186,37 @@ public interface BaseReactiveService<T> {
*/ */
Mono<Void> deleteBatchByIds(List<String> ids); Mono<Void> deleteBatchByIds(List<String> ids);
/**
* 通过某一个键删除所有
*
* @param qo 查询实体
*/
Mono<Void> deleteAll(Qo<T> qo);
/**
* 通过某一个键删除所有
*
* @param entity 查询
*/
Mono<Void> deleteAll(T entity);
/**
* 删除全部实体危险
*/
Mono<Void> deleteAll();
/** /**
* 批量更新 * 批量更新
* *
* @param entities 要批量更新的集合 * @param entities 要批量更新的集合
*/ */
Flux<T> updateBatch(List<T> entities); Flux<T> updateBatch(List<T> entities);
/**
* 同步数据
*
* @param entities 数据们
* @return 结果
*/
Mono<SyncVo<T>> sync(List<T> entities);
} }

View File

@ -2,6 +2,7 @@ package com.flyfish.framework.service;
import com.flyfish.framework.domain.po.User; import com.flyfish.framework.domain.po.User;
import reactor.core.publisher.Mono;
import java.util.Optional; import java.util.Optional;
@ -16,5 +17,5 @@ public interface UserFindService {
* @param username 用户名 * @param username 用户名
* @return 结果 * @return 结果
*/ */
Optional<User> findByUsername(String username); Mono<User> findByUsername(String username);
} }

View File

@ -2,13 +2,16 @@ package com.flyfish.framework.service.impl;
import com.flyfish.framework.auditor.BeanAuditor; import com.flyfish.framework.auditor.BeanAuditor;
import com.flyfish.framework.auditor.BeanPoster; import com.flyfish.framework.auditor.BeanPoster;
import com.flyfish.framework.bean.SyncVo;
import com.flyfish.framework.domain.base.AuditDomain; import com.flyfish.framework.domain.base.AuditDomain;
import com.flyfish.framework.domain.base.Domain; import com.flyfish.framework.domain.base.Domain;
import com.flyfish.framework.domain.base.Qo; import com.flyfish.framework.domain.base.Qo;
import com.flyfish.framework.exception.biz.InvalidBusinessException;
import com.flyfish.framework.repository.DefaultReactiveRepository; import com.flyfish.framework.repository.DefaultReactiveRepository;
import com.flyfish.framework.service.BaseReactiveService; import com.flyfish.framework.service.BaseReactiveService;
import com.flyfish.framework.utils.Assert; import com.flyfish.framework.utils.Assert;
import com.flyfish.framework.utils.CopyUtils; import com.flyfish.framework.utils.CopyUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example; import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@ -20,10 +23,11 @@ import reactor.core.publisher.Mono;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors;
/** /**
* 基础的Service继承常用的全部Crud操作基于JPARepository * 基础的Service继承常用的全部Crud操作基于JPARepository
* TODO 此方法在更新和查询存在不完善后续完善底层支持用于性能优 * 已完全实现全部webflux功能提供全异步支持系统性能最大
* *
* @param <T> 实体泛型 * @param <T> 实体泛型
*/ */
@ -38,7 +42,6 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
@Autowired @Autowired
private BeanAuditor<AuditDomain> operationAuditor; private BeanAuditor<AuditDomain> operationAuditor;
/** /**
* 查询 * 查询
* *
@ -58,7 +61,7 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
*/ */
@Override @Override
public Mono<T> getOne(Qo<T> query) { public Mono<T> getOne(Qo<T> query) {
return Mono.empty(); return repository.findOne(query);
} }
/** /**
@ -72,6 +75,17 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
return repository.findById(id); return repository.findById(id);
} }
/**
* 通过实体名称访问
*
* @param name 名称
* @return 结果
*/
@Override
public Mono<T> getByName(String name) {
return repository.findByName(name);
}
/** /**
* 根据ID集合来查询 * 根据ID集合来查询
* *
@ -83,6 +97,18 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
return repository.findAllById(ids); return repository.findAllById(ids);
} }
/**
* 通过某个字段的集合包含查询
*
* @param key
* @param values
* @return 结果
*/
@Override
public <K> Flux<T> getByValues(String key, List<K> values) {
return repository.findAllByValues(key, values);
}
/** /**
* 查询列表 * 查询列表
* *
@ -102,7 +128,7 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
*/ */
@Override @Override
public Flux<T> getList(Qo<T> query) { public Flux<T> getList(Qo<T> query) {
return Flux.empty(); return repository.findAll(query);
} }
/** /**
@ -131,7 +157,7 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
*/ */
@Override @Override
public Mono<Page<T>> getPageList(Qo<T> query) { public Mono<Page<T>> getPageList(Qo<T> query) {
return Mono.empty(); return repository.findAll(query, query.getPageable());
} }
/** /**
@ -165,6 +191,28 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
return repository.count(Example.of(entity)); return repository.count(Example.of(entity));
} }
/**
* 查询总记录数
*
* @param query 查询实体
* @return 结果
*/
@Override
public Mono<Long> count(Qo<T> query) {
return repository.count(query);
}
/**
* 查询是否存在
*
* @param query 查询
* @return 结果
*/
@Override
public Mono<Boolean> exists(Qo<T> query) {
return repository.exists(query);
}
/** /**
* 插入新记录 * 插入新记录
* *
@ -172,7 +220,7 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
*/ */
@Override @Override
public Mono<T> create(T entity) { public Mono<T> create(T entity) {
return repository.insert(entity); return repository.insert(audit(entity)).map(this::post);
} }
/** /**
@ -182,7 +230,7 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
*/ */
@Override @Override
public Mono<T> createSelective(T entity) { public Mono<T> createSelective(T entity) {
return repository.insert(entity); return repository.insert(audit(entity)).map(this::post);
} }
/** /**
@ -212,7 +260,7 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
*/ */
@Override @Override
public Mono<T> updateById(T entity) { public Mono<T> updateById(T entity) {
return repository.save(entity); return repository.save(audit(entity)).map(this::post);
} }
/** /**
@ -225,7 +273,8 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
Assert.hasText(entity.getId(), "更新的主键不可为空!"); Assert.hasText(entity.getId(), "更新的主键不可为空!");
return repository.findById(entity.getId()) return repository.findById(entity.getId())
.map(saved -> CopyUtils.copyProps(entity, saved)) .map(saved -> CopyUtils.copyProps(entity, saved))
.flatMap(this::updateById); .flatMap(this::updateById)
.switchIfEmpty(Mono.defer(() -> Mono.error(new InvalidBusinessException("要更新的信息不存在"))));
} }
/** /**
@ -240,6 +289,34 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
.single(); .single();
} }
/**
* 通过某一个键删除所有
*
* @param qo 查询实体
*/
@Override
public Mono<Void> deleteAll(Qo<T> qo) {
return repository.deleteAll(qo);
}
/**
* 通过某一个键删除所有
*
* @param entity 查询
*/
@Override
public Mono<Void> deleteAll(T entity) {
return repository.delete(entity);
}
/**
* 删除全部实体危险
*/
@Override
public Mono<Void> deleteAll() {
return repository.deleteAll();
}
/** /**
* 批量更新 * 批量更新
* *
@ -247,17 +324,42 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
*/ */
@Override @Override
public Flux<T> updateBatch(List<T> entities) { public Flux<T> updateBatch(List<T> entities) {
// Assert.notEmpty(entities, "数据不可为空!"); if (CollectionUtils.isNotEmpty(entities)) {
// entities.forEach(item -> Assert.hasText(item.getId(), "每个对象的id必须附带")); // 带有id的集合
// // 过滤不存在的记录 List<String> ids = entities.stream()
// Map<String, T> savedMap = ((List<T>) repository.findAllById(entities.stream() .filter(Objects::nonNull)
// .map(Domain::getId).collect(Collectors.toList()))).stream() .map(Domain::getId)
// .collect(Collectors.toMap(Domain::getId, t -> t)); .filter(Objects::nonNull)
// List<T> updating = entities.stream() .collect(Collectors.toList());
// .filter(t -> savedMap.containsKey(t.getId())) return Mono.just(ids)
// .map(t -> CopyUtils.copyProps(savedMap.get(t.getId()), t)) .filter(CollectionUtils::isNotEmpty)
// .collect(Collectors.toList()); .flatMapMany(list -> repository.findAllById(list))
return repository.saveAll(entities); .collectMap(Domain::getId, t -> t)
.map(map -> entities.stream()
// 补全已保存信息
.map(t -> map.containsKey(t.getId()) ? CopyUtils.copyProps(t, map.get(t.getId())) : t)
.map(this::audit)
.collect(Collectors.toList()))
.flatMapMany(list -> repository.saveAll(list))
.map(this::post);
}
return Flux.fromIterable(entities);
}
/**
* 同步数据
*
* @param entities 数据们
* @return 结果
*/
@Override
public Mono<SyncVo<T>> sync(List<T> entities) {
return this.updateBatch(entities)
.collectList()
.map(list -> SyncVo.<T>builder()
.success(list.size())
.list(list)
.build());
} }
/** /**
@ -265,7 +367,7 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
* *
* @param entity 实体 * @param entity 实体
*/ */
protected void audit(T entity) { protected T audit(T entity) {
// 用户审查 // 用户审查
if (entity instanceof AuditDomain) { if (entity instanceof AuditDomain) {
operationAuditor.audit((AuditDomain) entity); operationAuditor.audit((AuditDomain) entity);
@ -274,6 +376,7 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
if (auditor != null) { if (auditor != null) {
auditor.audit(entity); auditor.audit(entity);
} }
return entity;
} }
/** /**
@ -289,5 +392,9 @@ public class BaseReactiveServiceImpl<T extends Domain> implements BaseReactiveSe
return entity; return entity;
} }
@SuppressWarnings("unchecked")
public <R extends DefaultReactiveRepository<T>> R getRepository() {
return (R) repository;
}
} }

View File

@ -6,6 +6,7 @@ import com.flyfish.framework.bean.SyncVo;
import com.flyfish.framework.domain.base.AuditDomain; import com.flyfish.framework.domain.base.AuditDomain;
import com.flyfish.framework.domain.base.Domain; import com.flyfish.framework.domain.base.Domain;
import com.flyfish.framework.domain.base.Qo; import com.flyfish.framework.domain.base.Qo;
import com.flyfish.framework.repository.DefaultReactiveRepository;
import com.flyfish.framework.repository.DefaultRepository; import com.flyfish.framework.repository.DefaultRepository;
import com.flyfish.framework.service.BaseService; import com.flyfish.framework.service.BaseService;
import com.flyfish.framework.utils.Assert; import com.flyfish.framework.utils.Assert;
@ -91,9 +92,8 @@ public class BaseServiceImpl<T extends Domain> implements BaseService<T> {
} }
@Override @Override
@SuppressWarnings("unchecked")
public <K> List<T> getByValues(String key, List<K> values) { public <K> List<T> getByValues(String key, List<K> values) {
return repository.findAllByValues(key, (List<Object>) values); return repository.findAllByValues(key, values);
} }
/** /**
@ -276,8 +276,7 @@ public class BaseServiceImpl<T extends Domain> implements BaseService<T> {
*/ */
@Override @Override
public void deleteAll(T entity) { public void deleteAll(T entity) {
Iterable<T> list = repository.findAll(Example.of(entity)); repository.delete(entity);
repository.deleteAll(list);
} }
/** /**
@ -366,7 +365,7 @@ public class BaseServiceImpl<T extends Domain> implements BaseService<T> {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <R extends DefaultRepository<T>> R getRepository() { public <R extends DefaultReactiveRepository<T>> R getRepository() {
return (R) repository; return (R) repository;
} }
} }

View File

@ -3,8 +3,8 @@ package com.flyfish.framework.utils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -71,13 +71,12 @@ public class RedisOperations {
* *
* @param key 可以传一个值 或多个 * @param key 可以传一个值 或多个
*/ */
@SuppressWarnings("unchecked")
public void del(String... key) { public void del(String... key) {
if (key != null && key.length > 0) { if (key != null && key.length > 0) {
if (key.length == 1) { if (key.length == 1) {
redisTemplate.delete(key[0]); redisTemplate.delete(key[0]);
} else { } else {
redisTemplate.delete(CollectionUtils.arrayToList(key)); redisTemplate.delete(Arrays.asList(key));
} }
} }
} }
@ -175,7 +174,7 @@ public class RedisOperations {
* 递增 * 递增
* *
* @param key * @param key
* @param by 要增加几(大于0) * @param delta 要增加几(大于0)
* @return * @return
*/ */
public long incr(String key, long delta) { public long incr(String key, long delta) {
@ -189,7 +188,7 @@ public class RedisOperations {
* 递减 * 递减
* *
* @param key * @param key
* @param by 要减少几(小于0) * @param delta 要减少几(小于0)
* @return * @return
*/ */
public long decr(String key, long delta) { public long decr(String key, long delta) {

View File

@ -12,7 +12,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version> <version>2.6.1</version>
<relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
@ -25,7 +25,7 @@
<jasypt.version>3.0.3</jasypt.version> <jasypt.version>3.0.3</jasypt.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version> <spring-cloud.version>Finchley.SR1</spring-cloud.version>
<jjwt.version>0.11.0</jjwt.version> <jjwt.version>0.11.0</jjwt.version>
<reflection.version>0.9.11</reflection.version> <reflection.version>0.10.2</reflection.version>
</properties> </properties>
<developers> <developers>