Benx Blog

九月 5, 2014

Diigo Diary 09/05/2014

Filed under: Diigo Diary — benxshen @ 8:30 上午
    • CREATE_IF_NOT_FOUND (default)

      CREATE_IF_NOT_FOUND combines CREATE  and USE_DECLARED_QUERY. It looks up a declared query  first, and if no declared query is found, it creates a custom method  name-based query. This is the default lookup strategy and thus will  be used if you do not configure anything explicitly. It allows quick  query definition by method names but also custom-tuning of these  queries by introducing declared queries as needed.

    • To find out how many pages you get for a query entirely you  have to trigger an additional count query. By default this query  will be derived from the query you actually trigger.
    • Example 1.8. Using exclude-filter element

      <repositories base-package="com.acme.repositories">   <context:exclude-filter type="regex" expression=".*SomeRepository" /> </repositories>

      This example excludes all interfaces ending in  SomeRepository from being  instantiated.

    • 1.3 Custom implementations for Spring Data repositories

      Often it is necessary to provide a custom implementation for a few  repository methods. Spring Data repositories easily allow you to provide  custom repository code and integrate it with generic CRUD abstraction and  query method functionality.

      1.3.1 Adding custom behavior to single repositories

      To enrich a repository with custom functionality you first define  an interface and an implementation for the custom functionality. Use the  repository interface you provided to extend the custom interface.

      Example 1.11. Interface for custom repository functionality

      interface UserRepositoryCustom {    public void someCustomMethod(User user); }


      Example 1.12. Implementation of custom repository functionality

      class UserRepositoryImpl implements UserRepositoryCustom {    public void someCustomMethod(User user) {     // Your custom implementation   } }
      [Note] Note

      The implementation itself does not depend on Spring Data and  can be a regular Spring bean. So you can use standard dependency  injection behavior to inject references to other beans like a  JdbTemplate, take part in aspects, and so  on.


      Example 1.13. Changes to the your basic repository interface

      public interface UserRepository extends CrudRepository<User, Long>, UserRepositoryCustom {    // Declare query methods here }

      Let your standard repository interface extend the custom  one. Doing so combines the CRUD and custom functionality and makes it  available to clients.

    • Configuration

      If you use namespace configuration, the repository  infrastructure tries to autodetect custom implementations by scanning  for classes below the package we found a repository in. These classes  need to follow the naming convention of appending the namespace  element’s attribute repository-impl-postfix to the found  repository interface name. This postfix defaults to  Impl.

      Example 1.14. Configuration example

      <repositories base-package="com.acme.repository" />  <repositories base-package="com.acme.repository" repository-impl-postfix="FooBar" />


      The first configuration example will try to look up a class  com.acme.repository.UserRepositoryImpl to act  as custom repository implementation, whereas the second example will  try to lookup  com.acme.repository.UserRepositoryFooBar.

    • Manual wiring

      The preceding approach works well if your custom implementation  uses annotation-based configuration and autowiring only, as it will be  treated as any other Spring bean. If your custom implementation bean  needs special wiring, you simply declare the bean and name it after  the conventions just described. The infrastructure will then refer to  the manually defined bean definition by name instead of creating one  itself.

      Example 1.15. Manual wiring of custom implementations (I)

      <repositories base-package="com.acme.repository" />  <beans:bean id="userRepositoryImpl" class="…">   <!-- further configuration --> </beans:bean>
    • 1.3.2 Adding custom behavior to all repositories
    • @EnableSpringDataWebSupport
    • The @EnableSpringDataWebSupport annotation registers a few  components we will discuss in a bit. It will also detect Spring HATEOAS  on the classpath and register integration components for it as well if  present.
      • Basic web support

        The configuration setup shown above will register a few basic  components:

        • A DomainClassConverter to enable  Spring MVC to resolve instances of repository managed domain  classes from request parameters or path variables.

        • HandlerMethodArgumentResolver  implementations to let Spring MVC resolve  Pageable and  Sort instances from request  parameters.

    • DomainClassConverter

      The DomainClassConverter allows you to  use domain types in your Spring MVC controller method signatures  directly, so that you don’t have to manually lookup the instances  via the repository:

      Example 1.22. A Spring MVC controller using domain types in method  signatures

      @Controller @RequestMapping("/users") public class UserController {    @RequestMapping("/{id}")   public String showUserForm(@PathVariable("id") User user, Model model) {      model.addAttribute("user", user);     return "userForm";   } }
    • HandlerMethodArgumentResolvers for Pageable and Sort

      The configuration snippet above also registers a  PageableHandlerMethodArgumentResolver as well  as an instance of  SortHandlerMethodArgumentResolver. The  registration enables Pageable and  Sort being valid controller method  arguments

      Example 1.23. Using Pageable as controller method argument

      @Controller @RequestMapping("/users") public class UserController {    @Autowired UserRepository repository;    @RequestMapping   public String showUsers(Model model, Pageable pageable) {      model.addAttribute("users", repository.findAll(pageable));     return "users";   } }
      • Hypermedia support for Pageables

        Spring HATEOAS ships with a representation model class  PagedResources that allows enrichting the content of a Page instance  with the necessary Page metadata as well as links to let the clients  easily navigate the pages. The conversion of a Page to a  PagedResources is done by an implementation of the Spring HATEOAS  ResourceAssembler interface, the PagedResourcesAssembler.

        Example 1.24. Using a PagedResourcesAssembler as controller method  argument

        @Controller  class PersonController {     @Autowired PersonRepository repository;     @RequestMapping(value = "/persons", method = RequestMethod.GET)    HttpEntity<PagedResources<Person>> persons(Pageable pageable,      PagedResourcesAssembler assembler) {       Page<Person> persons = repository.findAll(pageable);      return new ResponseEntity<>(assembler.toResources(persons), HttpStatus.OK);   } }


        Enabling the configuration as shown above allows the  PagedResourcesAssembler to be used as  controller method argument. Calling  toResources(…) on it will cause the  following:

        • The content of the Page will  become the content of the PagedResources  instance.

        • The PagedResources will get a  PageMetadata instance attached populated  with information form the Page and  the underlying PageRequest.

        • The PagedResources gets  prev and next links attached depending  on the page’s state. The links will point to the URI the method  invoked is mapped to. The pagination parameters added to the  method will match the setup of the  PageableHandlerMethodArgumentResolver to  make sure the links can be resolved later on.

        Assume we have 30 Person instances in the  database. You can now trigger a request GET  http://localhost:8080/persons and you’ll see something similar  to this:

        { "links" : [ { "rel" : "next",                  "href" : "http://localhost:8080/persons?page=1&size=20 }    ],    "content" : [       … // 20 Person instances rendered here   ],    "pageMetadata" : {      "size" : 20,      "totalElements" : 30,      "totalPages" : 2,      "number" : 0   } 
    • The PageableArgumentResolver  automatically resolves request parameters to build a  PageRequest instance. By default it expects the  following structure for the request parameters.

      Table 1.2. Request parameters evaluated by  PageableHandlerMethodArgumentResolver

      page Page you want to retrieve, 0 indexed and defaults to  0.
      size Size of the page you want to retrieve, defaults to  20.
      sort A collection of sort directives in the format  ($propertyname,)+[asc|desc]?.
    • Example 1.28. Pagiination URL Parameter Examples

      To retrieve the third page with a maximum page size of 100  with the data sorted by the email property in ascending order use  the following url parameter:

      ?page=2&size=100&sort=email,asc

      To sort the data by multiple properties in different sort  order use the following url parameter

      ?sort=foo,asc&sort=bar,desc


      In case you need multiple  Pageables to be resolved from the  request (for multiple tables, for example) you can use Spring’s  @Qualifier annotation to distinguish  one from another. The request parameters then have to be prefixed with  ${qualifier}_. So for a method signature like  this:

      public String showUsers(Model model,        @Qualifier("foo") Pageable first,       @Qualifier("bar") Pageable second) { … }

      you have to populate foo_page and  bar_page and the related subproperties.

    • Example 2.5. Annotation based named query configuration

      @Entity @NamedQuery(name = "User.findByEmailAddress",   query = "select u from User u where u.emailAddress = ?1") public class User {  }


      Declaring interfaces

      To allow execution of these named queries all you need to do is  to specify the UserRepository as  follows:

      Example 2.6. Query method declaration in UserRepository

      public interface UserRepository extends JpaRepository<User, Long> {    List<User> findByLastname(String lastname);    User findByEmailAddress(String emailAddress); }
    • Example 2.8. Advanced LIKE expressions in  @Query

      public interface UserRepository extends JpaRepository<User, Long> {    @Query("select u from User u where u.firstname like %?1")   List<User> findByFirstnameEndsWith(String firstname); }
    • Example 2.9. Declare a native query at the query method using  @Query

      public interface UserRepository extends JpaRepository<User, Long> {    @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?0", nativeQuery = true)   User findByEmailAddress(String emailAddress); }
    • Table 2.4. Supported variables inside SpEL based query templates

      Variable Usage Description
      entityName select x from #{#entityName} x Inserts the entityName of the domain type associated  with the given Repository. The entityName is  resolved as follows: If the domain type has set the name  property on the @Entity annotation then it will  be used. Otherwise the simple class-name of the domain type  will be used.
    • @Entity public class User {   @Id  @GeneratedValue  Long id;     String lastname; }  public interface UserRepository extends JpaRepository<User,Long> {   @Query(“select u from #{#entityName} u where u.lastname = ?1″)  List<User> findByLastname(String lastname); }
    • 2.3.7 Modifying queries

      All the sections above describe how to declare queries to access a  given entity or collection of entities. Of course you can add custom  modifying behaviour by using facilities described in Section 1.3, “Custom implementations for Spring Data repositories”. As this approach is  feasible for comprehensive custom functionality, you can achieve the  execution of modifying queries that actually only need parameter binding  by annotating the query method with @Modifying:

      Example 2.13. Declaring manipulating queries

      @Modifying @Query("update User u set u.firstname = ?1 where u.lastname = ?2") int setFixedFirstnameFor(String firstname, String lastname);
    • This will trigger the query annotated to the method as updating  query instead of a selecting one. As the  EntityManager might contain outdated  entities after the execution of the modifying query, we do not  automatically clear it (see JavaDoc of  EntityManager.clear()  for details) since this will effectively drop all non-flushed changes  still pending in the EntityManager. If  you wish the EntityManager to be cleared  automatically you can set @Modifying  annotation’s clearAutomatically attribute to  true.
    • 2.3.9 Configuring Fetch- and LoadGraphs

      The JPA 2.1 specification introduced support for specifiying  Fetch- and LoadGraphs that we also support via the  EntityGraph annotation which allows to  reference a NamedEntityGraph definition,  that can be annotated on an entity, to be used to configure the fetch  plan of the resulting query. The type (Fetch / Load) of the fetching can  be configured via the type attribute on the  EntityGraph annotation. Please have a  look at the JPA 2.1 Spec 3.7.4 for further reference.

      Example 2.15. Defining a named entity graph on an entity.

      @Entity @NamedEntityGraph(name = "GroupInfo.detail",   attributeNodes = @NamedAttributeNode("members")) public class GroupInfo {    // default fetch mode is lazy.   @ManyToMany   List<GroupMember> members = new ArrayList<GroupMember>();    … }


      Example 2.16. Referencing a named entity graph definition on an repository  query method.

      @Repository public interface GroupRepository extends CrudRepository<GroupInfo, String> {    @EntityGraph(value = "GroupInfo.detail", type = EntityGraphType.LOAD)   GroupInfo getByGroupName(String name);  }
    • Spring Data JPA takes the concept of a specification from Eric  Evans’ book “Domain Driven Design", following the same semantics and  providing an API to define such  Specifications using the JPA criteria API.  To support specifications you can extend your repository interface with  the JpaSpecificationExecutor  interface:

      public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor {  … }
    • Okay, why not simply create a query for this kind of data access?  You’re right. Using a single Specification  does not gain a lot of benefit over a plain query declaration. The power  of Specifications really shines when you  combine them to create new Specification  objects. You can achieve this through the  Specifications helper class we provide to build  expressions like this:

      Example 2.25. Combined Specifications

      MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR); List<Customer> customers = customerRepository.findAll(   where(isLongTermCustomer()).or(hasSalesOfMoreThan(amount)));
    • Example 2.28. Using @Transactional at query methods

      @Transactional(readOnly = true) public interface UserRepository extends JpaRepository<User, Long> {    List<User> findByLastname(String lastname);    @Modifying   @Transactional   @Query("delete from User u where u.active = false")   void deleteInactiveUsers(); }

      Typically you will want the readOnly flag set to  true as most of the query methods will only read data. In contrast to  that deleteInactiveUsers() makes use of the  @Modifying annotation and overrides the  transaction configuration. Thus the method will be executed with  readOnly flag set to false.

    • 2.7 Locking

      To specify the lock mode to be used the  @Lock annotation can be used on query  methods:

      Example 2.29. Defining lock metadata on query methods

      interface UserRepository extends Repository<User, Long> {    // Plain query method   @Lock(LockModeType.READ)   List<User> findByLastname(String lastname); }
    • This method declaration will cause the query being triggered to be  equipped with the LockModeType  READ. You can also define locking for CRUD methods by  redeclaring them in your repository interface and adding the  @Lock annotation:

      Example 2.30. Defining lock metadata on CRUD methods

      interface UserRepository extends Repository<User, Long> {    // Redeclaration of a CRUD method   @Lock(LockModeType.READ);   List<User> findAll(); }
    • As of Spring Data JPA 1.5, auditing can be enabled by annotating a  configuration class with the @EnableJpaAuditing  annotation.

      Example 2.33. Activating auditing via Java configuration

      @Configuration @EnableJpaAuditing class Config {    @Bean   public AuditorAware<AuditableUser> auditorProvider() {     return new AuditorAwareImpl();   } }
    • I’d like to get more detailed logging information on what  methods are called inside  JpaRepository, e.g. How can I gain  them?

      You can make use of  CustomizableTraceInterceptor provided by  Spring:

      <bean id="customizableTraceInterceptor" class="   org.springframework.aop.interceptor.CustomizableTraceInterceptor">   <property name="enterMessage" value="Entering $[methodName]($[arguments])"/>   <property name="exitMessage" value="Leaving $[methodName](): $[returnValue]"/> </bean>  <aop:config>   <aop:advisor advice-ref="customizableTraceInterceptor"     pointcut="execution(public * org.springframework.data.jpa.repository.JpaRepository+.*(..))"/> </aop:config>
    • To find out how many pages you get for a query entirely you  have to trigger an additional count query. By default this query  will be derived from the query you actually trigger.

Posted from Diigo. The rest of my favorite links are here.

發表迴響 »

仍無迴響。

RSS feed for comments on this post. TrackBack URI

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s

在WordPress.com寫網誌.

%d 位部落客按了讚: