Back/Spring Java

JPA findAll Specification

밍꿔 2020. 1. 14. 17:41


반응형

 

 

JPA에서 다중 파라미터 처리를 진행 할 때 아래의 예제 처럼 작성하면 기능 구현이 가능하다.

 

Page<AdminUser> adminUsers = null;
        if(adminUserApiRequest.getAccount() == null && adminUserApiRequest.getRole() == null)
        {
            adminUsers = adminUserRepository.findAll(pageable);
        }
        else if(adminUserApiRequest.getAccount() != null && adminUserApiRequest.getRole() == null)
        {
            adminUsers = adminUserRepository.findAllByAccount(pageable, adminUserApiRequest.getAccount());
        }
        else if(adminUserApiRequest.getRole() != null && adminUserApiRequest.getAccount() == null)
        {
            adminUsers = adminUserRepository.findAllByRole(pageable, adminUserApiRequest.getRole());
        }
        else
        {
            adminUsers = adminUserRepository.findAllByAccountAndRole(pageable, adminUserApiRequest.getAccount(), adminUserApiRequest.getRole());
        }

 

단, 이와 같은 방식은 파라미터 변경(추가, 삭제, 수정) 이 일어날 경우 소스 수정은 불가피 하다.

 

 

따라서 파라미터의 변경에 종속되지 않게 작성하기 위해 Specification를 사용하였다.

 

아래의 예제를 보면,

 

public Header<List<AdminUserApiResponse>> search(Pageable pageable, AdminUserApiRequest adminUserApiRequest) {
	// convertObjectToMap - Object를 Map형태로 형변환
        Map<String, Object> searchRequest = CommonObjectUtils.convertObjectToMap(adminUserApiRequest);
        Map<String, Object> searchKeys = new HashMap<>();

        for (String key : searchRequest.keySet()) {
            String value = String.valueOf(searchRequest.get(key));
            if(value != null && !value.isEmpty() && !"null".equals(value)){
                searchKeys.put(key, searchRequest.get(key));
            }
        }

        Page<AdminUser> adminUsers =  adminUserRepository.findAll(adminUserSpecification.searchWith(searchKeys), pageable);          
                
			.
			.
			.
                   
		      생략
}             

 

우선 첫번째로 화면에서 넘어온 adminUser객체를 Map형태로 변환시켜 세팅.

 

 

그 이후 새로 정의 한 findAll의 첫번째 매개변수에 사용된 searchWith이라는 함수의 

 

import com.example.study.model.entity.AdminUser;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Component
public class AdminUserSpecification{

    public static Specification<AdminUser> searchWith(Map<String, Object> searchKeyword) {
        return (Specification<AdminUser>) ((root, query, builder) -> {
            List<Predicate> predicate = getPredicateWithKeyword(searchKeyword, root, builder);
            return builder.and(predicate.toArray(new Predicate[0]));
        });
    }

    private static List<Predicate> getPredicateWithKeyword(Map<String, Object> searchKeyword, Root<AdminUser> root, CriteriaBuilder builder) {
        List<Predicate> predicate = new ArrayList<>();
        for (String key : searchKeyword.keySet()) {
            predicate.add(builder.equal(root.get(key), searchKeyword.get(key)));
        }
        return predicate;
    }
    
}

 

넘어온 searchKeyword 크기만큼 List<Predicate>에 담아서 그 내용을 CriteriaBuilder에 and하여 추가 하는 방식이다.

 

위의 내용은 넘어온 파라미터에 대해 모두 and조건으로 값이 동일할때의 케이스이며 or조건으로 Like, >, < 등의

 

조건은 새로 구성 해야됨.

 

 

반응형

'Back > Spring Java' 카테고리의 다른 글

CamelCase, SnakeCase Convert Function  (0) 2020.01.14
Class Object Entity convert to Map  (0) 2020.01.14
BeanUtils.copyProperties  (0) 2019.12.23
Blob형태의 이미지 파일 입출력  (0) 2019.12.19
Spring Security Login  (2) 2019.12.18