Starter Spring Starter
Maven 
Java Module 
Logging <dependency> 
  <groupId> tw.com.softleader.data.jakarta</groupId> 
   <artifactId> specification-mapper-starter</artifactId> 
   <version> ${specification-mapper.version}</version> 
 </dependency> 
requires   specification . mapper ; 
 requires   specification . mapper . starter ; 
 requires   jakarta . persistence ; 
 logging : 
    level : 
      tw.com.softleader.data.jpa.spec.starter :   info 
 
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 啟動過程就會自動的配置一切, 讓你可以零配置的就開始使用, 包含了:
自動配置預設是啟用的, 你可以透過 properties 中的 spec.mapper.enabled 控制, 如要關閉則:
spec : 
    mapper : 
      enabled :   false 
 1 - Query by Spec 介紹與使用 Query by Spec (QBS)
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 Base Repository 在配置的過程中, QBS 會自動配置 Spring Data JPA 的 Base Repository , 預設的實作為 DefaultQueryBySpecExecutor
由於 Java 只能單一繼承, 為了應用程式可以保留原有的 Parent Base Repository, QBS 還多提供了 QueryBySpecExecutorAdapter 擴展點
你的應用程式可以視情況選擇繼承 DefaultQueryBySpecExecutor 或實作 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.example.MyRepositoryImpl 
 2 - Config SpecMapper 自動配置 SpecMapper
Starter 會在 App 啟動的過程中自動的配置一個 Default SpecMapper Spring @Bean  中, 你可以透過 Autowired  的方式跟 Spring 取得.
@Autowired   SpecMapper   specMapper ; 
 例如, 我想要在轉換成 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 ); 
    } 
 } 
 在上述範例中, SpecMapper 被注入到了 PersonService, 開發人員就可以使用 specMapper.toSpec() 將 criteria 物件轉換成 specification, 接著就可以對 specification 做更多的調整, 最後才傳入 personRepository 查詢
Configuration Starter 提供了許多方式讓開發人員調整 Default SpecMapper  的配置
SpecificationResolver SpecificationResolverSpring @Bean , 在 App 啟動的過程中就會自動的偵測及配置
範例如下:
@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 
 } 
 SkippingStrategy SkippingStrategySpring @Bean , 在 App 啟動的過程中就會自動的偵測並加入到 Default SpecMapper  中!
配置範例如下:
@Configuration 
 class  MyConfig   { 
 
    @Bean 
    SkippingStrategy   mySkippingStrategy ()   { 
      return   ... 
    } 
 } 
 ASTWriterFactory 在 Logging  中提供了不同的 Logger Name 策略, 透過 properties 中的 spec.mapper.impersonate-logger, 可以設定是否要偽裝成實際處理的 object logger, 預設是關閉的, 若要開啟範例如下:
spec : 
    mapper : 
      # 是否要偽裝成實際處理的 object logger, 預設關閉 
      impersonate-logger :   true 
 若你需要完整的客製化, 只要將你自定義的 ASTWriterFactory 實作註冊成 Spring @Bean , 在 App 啟動的過程中就會自動的偵測並加入到 Default SpecMapper  中!
配置範例如下:
@Configuration 
 class  MyConfig   { 
 
    @Bean 
    ASTWriterFactory   myASTWriterFactory ()   { 
      return   ... 
    } 
 } 
 Customize SpecMapper 當然, 你也可以完全的客製化 SpecMapper, 只要將你的 SpecMapper 註冊成 Spring @Bean , 就會最優先的使用!
配置範例如下:
@Configuration 
 class  MyConfig   { 
 
    @Bean 
    SpecMapper   mySpecMapper ()   { 
      return   SpecMapper . builder () 
        .   ... 
        . build (); 
    } 
 } 
 
Important 採此模式客製化, App 啟動的過程中就會略過此章節所有配置內容