[Spring JPA #25] Spring JPA Specification

| Spring JPA Specification


Spring JPA Specification은 Spring JPA에서 제공하는 검색 조건을 메서드 형태로 추상화하여 Repository 인터페이스에서 해당 검색 조건을 조합하고 쿼리하기 쉽게 할 수 있는 기능입니다.


| Spring JPA Specification 예제


프로젝트 구조

+---src
| +---main
| | +---java
| | | \---com
| | | \---tutorial
| | | \---springboot
| | | Application.java
| | | Comment.java
| | | CommentRepository.java
| | | CommentSpecs.java
| | |
| | \---resources
| | | application.properties
| | |
| | +---static
| | \---templates
| \---test
| \---java
| \---com
| \---tutorial
| \---springboot
| ApplicationTests.java

의존성 관리

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

설정 관리


Intllij 기준 Setting -> Compiler -> Annotation Processor에 다음과 같이 설정합니다.



설정후 mvn compile 명령어로 아래와 같은 도메인 클래스를 생성해야 합니다.

@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Comment.class)
public abstract class Comment_ {

public static volatile SingularAttribute<Comment, Post> post;
public static volatile SingularAttribute<Comment, String> comment;
public static volatile SingularAttribute<Comment, Boolean> best;
public static volatile SingularAttribute<Comment, Long> id;
public static volatile SingularAttribute<Comment, Integer> up;
public static volatile SingularAttribute<Comment, Integer> down;

public static final String POST = "post";
public static final String COMMENT = "comment";
public static final String BEST = "best";
public static final String ID = "id";
public static final String UP = "up";
public static final String DOWN = "down";

}

소스 코드

@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Entity
@Data
public class Comment {

@Id
@GeneratedValue
private Long id;

private String comment;

@ManyToOne
private Post post;

private int up;

private int down;

private boolean best;
}

public interface CommentRepository extends JpaRepository<Comment, Long>, JpaSpecificationExecutor<Comment> {
}

  • JpaSpecifiactionExecutor를 추가하여 Specification을 Repository의 메서드에서 사용할 수 있게 명시해야합니다.
public class CommentSpecs {

public static Specification<Comment> isBest() {
return new Specification<Comment>() {
@Override
public Predicate toPredicate(Root<Comment> root,
CriteriaQuery<?> query,
CriteriaBuilder builder) {
return builder.isTrue(root.get(Comment_.best));
}
};
}

public static Specification<Comment> isGood() {
return new Specification<Comment>() {
@Override
public Predicate toPredicate(Root<Comment> root,
CriteriaQuery<?> criteriaQuery,
CriteriaBuilder criteriaBuilder) {
return criteriaBuilder.greaterThan(root.get(Comment_.up), 10);
}
};
}
}
  • Comment 엔티티의 스펙을 정의합니다. Predicate 인터페이스를 반환하여 이 조건이 맞는지 확인하는 절차를 거치게 됩니다. CriteriaBuilder 클래스를 통하여 조건문을 정의할 수 있고 정의된 스펙들은 조합하여 쓸 수 있습니다.


테스트 코드

@RunWith(SpringRunner.class)
@DataJpaTest
public class ApplicationTests {

@Autowired
CommentRepository commentRepository;

@Test
public void specs() {
commentRepository.findAll(CommentSpecs.isBest());
}
}


https://www.inflearn.com/course/스프링-데이터-jpa

이 글을 공유하기

댓글(1)

  • 2021.01.24 17:15 신고

    궁금한게 staticmetamodel 어노테이션을 써서
    클래스를 만들어서 따로 사용하는 이유가 있나요?
    root.get(object) 를 써서 사용할수도 있는데

Designed by JB FACTORY