<dependency>
<groupId>tw.com.softleader.data.jakarta</groupId>
<artifactId>specification-mapper-starter</artifactId>
<version>${specification-mapper.version}</version>
</dependency>
specification-mapper-starter 整合了 specification-mapper 及 Spring Data JPA, 並提供了 Query by Spec 的查詢方式等
Query by Spec (QBS) 是一個 user-friendly 的查詢方式, 可以動態的建立查詢條件 (Specifications), 透過 QBS interface 就可以執行查詢語句!
Getting Started
只要在 pom.xml
中加入 dependency, 此 Starter 在 Spring Boot 啟動過程就會自動的配置一切, 讓你可以零配置的就開始使用, 包含了:
- Query By Spec 的設定
- 註冊預設的
SpecMapper
自動配置預設是啟用的, 你可以透過 properties 中的 spec.mapper.enabled
控制, 如要關閉則:
spec:
mapper:
enabled: false
Query by Spec
Query by Spec (QBS) 提供了 QueryBySpecExecutor<T>
包含了許多查詢方法:
public interface QueryBySpecExecutor<T> {
List<T> findBySpec(Object spec);
List<T> findBySpec(Object spec, Sort sort);
Page<T> findBySpec(Object spec, Pageable pageable);
// … more functionality omitted.
}
只要在原本的 repository interface 中去繼承 QueryBySpecExecutor<T>
就可以直接使用了:
public interface PersonRepository
extends JpaRepository<Person, Long>, QueryBySpecExecutor<Person> {
...
}
@Service
public class PersonService {
@Autowired PersonRepository personRepository;
public List<Person> findPeople(PersonCriteria criteria) {
return personRepository.findBySpec(criteria);
}
}
Customize the QBS Base Repository
在配置的過程中, QBS 會自動配置 Spring Data JPA 的 Base Repository, 預設的實作為 QueryBySpecExecutorImpl
由於 Java 只能單一繼承, 為了應用程式可以保留原有的 Parent Base Repository, QBS 還多提供了 QueryBySpecExecutorAdapter
擴展點
你的應用程式可以視情況選擇繼承 QueryBySpecExecutorImpl
或實作 QueryBySpecExecutorAdapter
去客製化 Base Repository, 如:
class MyRepositoryImpl<T, ID> extends SimpleJpaRepository<T, ID>
implements QueryBySpecExecutorAdapter<T> {
@Setter
@Getter
private SpecMapper specMapper;
private final EntityManager entityManager;
MyRepositoryImpl(JpaEntityInformation entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
// Keep the EntityManager around to used from the newly introduced methods.
this.entityManager = entityManager;
}
@Override
public Class<T> getDomainClass() {
return super.getDomainClass();
}
@Transactional
public <S extends T> S mySave(S entity) {
// implementation goes here
}
}
並且透過 properties 中的 spec.mapper.repository-base-class
設定成自定義的 base repository 的 fulll package name, 如:
spec:
mapper:
repository-base-class: com.acme.example.MyRepositoryImpl
Default SpecMapper
此 Starter 會在 App 啟動的過程中自動的配置一個 Default SpecMapper 並註冊到 Spring @Bean 中, 你可以透過 Autowired 的方式跟 Spring 取得.
例如, 我想要在轉換成 Specification 後, 先做一些加強再去查詢, 則範例如下:
class PersonService {
@Autowired SpecMapper specMapper;
@Autowired PersonRepository personRepository;
List<Person> getPersonByCriteria(PersonCriteria criteria) {
var spec = specMapper.toSpec(criteria);
// Perform additional operations on the spec, ex:
// spec = spec.and((root, query, criteriaBuilder) -> {
// ...
// });
return personRepository.findAll(spec);
}
}
Customize SpecificationResolver
只要將你自定義的 SpecificationResolver
註冊成 Spring @Bean, 在 App 啟動的過程中就會自動的偵測並加入到 Default SpecMapper 中!
例如, 我想要增加自定義的 Spec Annotation, 配置範例如下:
@Configuration
class MyConfig {
@Bean
SpecificationResolver myResolver() {
return ...
}
}
如果你的 SpecificationResolver
需要用到 SpecMapper
本身, 則你可以包裝成 SpecificationResolverCodecBuilder
, 在建構 resolver 時就會把 SpecCodec
, 即 SpecMapper
的 interface, 傳進去, 例如:
@Configuration
class MyConfig {
@Bean
SpecificationResolverCodecBuilder myResolver() {
return MySpecificationResolver::new;
}
}
class MySpecificationResolver implements SpecificationResolver {
private final SpecCodec codec;
MySpecificationResolver(SpecCodec codec) {
// Keep the SpecCodec around to used.
this.codec = codec;
}
// implementation goes here
}
Customize SkippingStrategy
只要將你自定義的 SkippingStrategy
註冊成 Spring @Bean, 在 App 啟動的過程中就會自動的偵測並加入到 Default SpecMapper 中!
配置範例如下:
@Configuration
class MyConfig {
@Bean
SkippingStrategy mySkippingStrategy() {
return ...
}
}
Customize ASTWriterFactory
透過 properties 中的 spec.mapper.impersonate-logger
, 可以設定 Logging 過程中, 是否要偽裝成實際處理的 object logger, 預設是關閉的, 若要開啟範例如下:
spec:
mapper:
# 是否要偽裝成實際處理的 object logger, 預設關閉
impersonate-logger: true
若你需要完整的客製化, 只要將你自定義的 ASTWriterFactory
註冊成 Spring @Bean, 在 App 啟動的過程中就會自動的偵測並加入到 Default SpecMapper 中!
配置範例如下:
@Configuration
class MyConfig {
@Bean
ASTWriterFactory myASTWriterFactory() {
return ...
}
}
Customize Default SpecMapper
當然, 你也可以完全的客製化 SpecMapper
, 只要將你的 SpecMapper
註冊成 Spring @Bean, App 啟動的過程中就會略過 Default SpecMapper 的配置而優先採用的你所註冊的那個!
配置範例如下:
@Configuration
class MyConfig {
@Bean
SpecMapper mySpecMapper() {
return SpecMapper.builder()
. ...
.build();
}
}