[SPRING] JPA 및 Spring 부트에 대한 검색 기능 구현 [닫기]
SPRINGJPA 및 Spring 부트에 대한 검색 기능 구현 [닫기]
데이터베이스 테이블에 대한 검색 기능을 올바르게 구현하려고합니다. 나는이 접근법을 시도했다 :
제어 장치:
@GetMapping
public Page<TransactionDTO> find(TransactionFilterDTO filter, Pageable page) {
return searchRepository
.findTransactionsByFilter(mapper.toFilter(filter), page)
.map(mapper::toDTO);
}
파일 DTO :
public class TransactionFilterDTO {
private String name;
private Integer id;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime from;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime to;
... // getters and setter
}
검색 구현 :
@Repository
public class TransactionSearchRepositoryImpl implements TransactionSearchRepository {
@Autowired
private TransactionRepository transactionRepository;
@Autowired
private TransactionSpecification specification;
@Override
public Page<Transaction> findTransactionsByFilter(TransactionFilter filter, @Nullable Pageable page) {
List<Transaction> transactions = transactionRepository
.findAll(specification.getFilter(filter));
int totalCount = transactions.size();
if(page != null) {
transactions = transactions
.stream()
.skip(page.getOffset())
.limit(page.getPageSize())
.collect(Collectors.toList());
}
return new PageImpl<>(transactions, page, totalCount);
}
}
저장소:
public interface TransactionSearchRepository {
Page<Transaction> findTransactionsByFilter(TransactionFilter filter, Pageable page);
}
검색 기능을 구현하는 더 좋은 방법이 있습니까? 이 솔루션은 내 견해로는 매우 추악합니다.
해결법
-
==============================
1.이러한 작업을 해결하기 위해 여러 가지 방법을 권장 할 수 있습니다.
이러한 작업을 해결하기 위해 여러 가지 방법을 권장 할 수 있습니다.
1) 단순하지만 융통성 없음 : 필터 속성 (이름, 시작, 끝)에 따라 컨트롤러에서 요청 매개 변수를 사용하고 리포지토리에서 해당 쿼리를 준비하십시오.
제어 장치:
@GetMapping("/q") public List<ResponseDto> getAllByQuery( @RequestParam(value = "name", required = false) String name, @RequestParam(value = "from", required = false) @DateTimeFormat(iso = ISO.DATE) LocalDate from, @RequestParam(value = "to", required = false) @DateTimeFormat(iso = ISO.DATE) LocalDate to, Pageable pageable ) { return service.getByQuery(name, from, to, pageable); }
서비스:
public Page<ResponseDto> getByQuery(String name, LocalDate from, LocalDate to, Pageable pageable) { return repo.getByQuery(name, from, to, pageable).map(mapper::toResponseDto); }
저장소:
@Query("select m from MyEntity m where " + "(?1 is null or upper(m.name) like concat('%', upper(?1), '%')) " + "and (?2 is null or m.createdAt >= ?2) " + "and (?3 is null or m.createdAt <= ?3)") Page<MyEntity> getByQuery(String name, final LocalDate from, final LocalDate to, final Pageable pageable);
그런 다음 요청을 수행하십시오.
GET http://localhost:8080/q?name=john&from=2019-04-19&to=2019-04-19
2) QueryDsl 사용. 프로젝트에 추가하고 (여기에서 세부 사항을 찾을 수 있음) QuerydslPredicateExecutor 및 QuerydslBinderCustomizer에서 리포지토리를 확장하고 '튜닝'을 추가하십시오.
public interface MyEntityRepo extends JpaRepository<MyEntity, Integer>, QuerydslPredicateExecutor<MyEntity>, QuerydslBinderCustomizer<QMyEntity> { @Override default void customize(@NonNull QuerydslBindings bindings, @NonNull QMyEntity entity) { // Make case-insensitive 'like' filter for all string properties bindings.bind(String.class).first((SingleValueBinding<StringPath, String>) StringExpression::containsIgnoreCase); // Add 'between' and 'greater or equal' filter date property bindings.bind(entity.createdAt).all((path, value) -> { Iterator<? extends LocalDate> it = value.iterator(); LocalDate from = it.next(); if (value.size() >= 2) { LocalDate to = it.next(); return Optional.of(path.between(from, to)); // between } else { return Optional.of(path.goe(from)); // greater than or equal } }); }
서비스 방법 추가 :
public Page<ResponseDto> getAllByQueryDsl(Predicate predicate, Pageable pageable) { return repo.findAll(predicate, pageable).map(mapper::toResponseDto); }
컨트롤러 방법 추가 :
@GetMapping("/query-dsl") public Page<ResponseDto> getAllByQueryDsl( @QuerydslPredicate(root = MyEntity.class, bindings = MyEntityRepo.class) Predicate predicate, Pageable pageable ) { return service.getAllByQueryDsl(predicate, pageable); }
그리고 엔티티의 'Date'속성에 @DateTimeFormat 주석을 추가하십시오.
@Entity public class MyEntity { // ... @DateTimeFormat(iso = ISO.DATE) private LocalDate createdAt; }
그런 다음 이러한 요청을 수행 할 수 있습니다.
GET http://localhost:8080/query-dsl?name=john&createdAt=2019-04-15&createdAt=2019-04-19
첫 번째 날짜는 '시작'매개 변수이고 두 번째 날짜는 '끝'매개 변수입니다. 하나의 날짜 만 사용하는 경우 '시작'매개 변수 (보다 크거나 같음)입니다.
3) spec-arg-resolver 라이브러리 사용. 프로젝트에 추가 한 다음 (명령 : 1 및 2 참조) JpaSpecificationExecutor에서 리포지를 확장하십시오.
public interface MyEntityRepo extends JpaRepository<MyEntity, Integer>, JpaSpecificationExecutor<MyEntity> {}
컨트롤러에 이러한 방법을 추가하십시오.
@GetMapping("/specification") public Page<ResponseDto> getAllBySpecification( @And({ @Spec(path = "name", spec = LikeIgnoreCase.class), @Spec(path = "createdAt", params = "from", spec = GreaterThanOrEqual.class), @Spec(path = "createdAt", params = "to", spec = LessThanOrEqual.class) }) Specification<MyEntity> specification, Pageable pageable ) { return service.getAllBySpecification(specification, pageable); }
서비스 업데이트 :
public Page<ResponseDto> getAllBySpecification(final Specification<MyEntity> specification, final Pageable pageable) { return repo.findAll(specification, pageable).map(mapper::toResponseDto); }
그런 다음 데이터를 요청하십시오.
GET http://localhost:8080/specification?name=john&from=2019-04-10&to=2019-04-19
4) 사양 매뉴얼 작성 :
필터 클래스를 작성하십시오.
@Data public class MyFilter implements Specification<MyEntity> { private String name; @DateTimeFormat(iso = ISO.DATE) private LocalDate from; @DateTimeFormat(iso = ISO.DATE) private LocalDate to; @Override public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> query, CriteriaBuilder builder) { List<Predicate> predicates = new ArrayList<>(); if (name != null) predicates.add(builder.like(builder.upper(root.get("name")), "%" + name.toUpperCase() + "%")); if (from != null) predicates.add(builder.greaterThanOrEqualTo(root.get("createdAt"), from)); if (to != null) predicates.add(builder.lessThanOrEqualTo(root.get("createdAt"), to)); return builder.and(predicates.toArray(new Predicate[0])); } }
컨트롤러 메소드를 작성하십시오.
@GetMapping("/filter") public Page<ResponseDto> getAllByMyFilter(MyFilter filter, Pageable pageable) { return service.getAllBySpecification(filter, pageable); }
그런 다음 요청을 실행하십시오.
GET http://localhost:8080/filter?name=john&from=2019-04-10&to=2019-04-19
-
==============================
2.예를 들어 쿼리를 살펴보십시오. 당신은 단순히 사용하여 일부 코드를 제거 할 수 있습니다
예를 들어 쿼리를 살펴보십시오. 당신은 단순히 사용하여 일부 코드를 제거 할 수 있습니다
transactionRepository.findAll(Example.of(transaction));
또한 페이지 매김 및 고급 API 검사 ExampleMatcher 클래스를 지원합니다.
-
==============================
3.이 문제를 해결하는 방법에는 여러 가지가 있습니다. 다음 솔루션도 구현할 수 있습니다. 전의. 귀하의 저장소에서 :
이 문제를 해결하는 방법에는 여러 가지가 있습니다. 다음 솔루션도 구현할 수 있습니다. 전의. 귀하의 저장소에서 :
@Query(value="FROM Students AS student " + " LEFT JOIN FETCH student.school AS school" ....................... ................... + " WHERE LOWER(student.name) LIKE LOWER(CONCAT('%',:criteria, '%')) OR" + " LOWER(student.code) LIKE LOWER(CONCAT('%',:criteria, '%')) OR" ......................... ......................... ......................... + " LOWER(school.name) LIKE LOWER(CONCAT('%',:criteria, '%')) " + " ORDER BY student.name ASC", countQuery=" SELECT COUNT(student) from Students AS student ") public Page<Students> getAllStudentsBySearchCriteria(@Param("criteria")String search, Pageable pageable);
귀하의 서비스에서 :
public Page<Students> getAll(Page pagable) { return studentRepository.getAllStudentsBySearchCriteria(searchString, pageable); }
from https://stackoverflow.com/questions/55707052/implement-search-functionality-for-jpa-and-spring-boot by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 기본으로 돌아 가기 : Apache Camel 경로 및 직접 구성 요소 (0) | 2019.09.14 |
---|---|
[SPRING] 스프링에서 @NumberFormat에 다른 로케일 사용 (0) | 2019.09.14 |
[SPRING] Java의 SOAP 헤더에 자식 요소를 추가하는 방법 (0) | 2019.09.14 |
[SPRING] Thymeleaf-Javascript 코드 내에서 모델 속성을 반복 (0) | 2019.09.13 |
[SPRING] JPA에서 트랜잭션을 롤백하는 방법은 무엇입니까? (0) | 2019.09.13 |