vue + jpa project (28) - 공통코드 연관(join)조회 백엔드 재수정 본문

프로그램/Vue.js

vue + jpa project (28) - 공통코드 연관(join)조회 백엔드 재수정

반응형

이번 장에서는 Join 공통코드 리스트에 대한 백엔드를 좀 더 개선시켜보겠다.

 

백엔드는 알고 있겠지만 패턴이 두가지여서 두가지에 대한 부분을 각각 개선시켜보겠다. 

그리고 패턴에 대한 각각의 장점 또는 단점도 확인을 해보겠다.

 

우선 첫번째 패턴인 상세코드를 기준으로 한 연관관계 조회 처리 부분이다.

 

 

2. 상세코드 Dto 수정

   검색조건을 처리하기 위하여 게시판의 Dto 처럼 아래와 같이 수정한다.

... 중략
    private String searchKey;        // 추가된 항목
    private String searchValue;      // 추가된 항목
    
    // where 절 처리 메소드
    public BooleanExpression makeSearchCondition(Object qEntity, String gubun) {

        if(qEntity instanceof QCodeDetailEntity) {
            
            // searchKey가 적용이 되는 부분
            // group_name은 비교하지 못한다.
            if("group_code".equals(gubun) && "group_code".equals(searchKey)) {
                if(StringUtils.hasLength(searchValue)) {
                    
                    if(searchValue.split(",").length > 0) {
                        return ((QCodeDetailEntity)qEntity).groupCode.in(searchValue.replaceAll(" ", "").split(","));
                    } else {
                        return ((QCodeDetailEntity)qEntity).groupCode.contains(searchValue);
                    }
                }
            } else if("code_value".equals(gubun) && "code_value".equals(searchKey)) {
                if(StringUtils.hasLength(searchValue)) {
                    
                    if(searchValue.split(",").length > 0) {
                        return ((QCodeDetailEntity)qEntity).codeValue.in(searchValue.replaceAll(" ", "").split(","));
                    } else {
                        return ((QCodeDetailEntity)qEntity).codeValue.contains(searchValue);
                    }
                }
            } else if("code_name".equals(gubun) && "code_name".equals(searchKey)) {
                if(StringUtils.hasLength(searchValue)) {
                    
                    if(searchValue.split(",").length > 0) {
                        return ((QCodeDetailEntity)qEntity).codeName.in(searchValue.replaceAll(" ", "").split(","));
                    } else {
                        return ((QCodeDetailEntity)qEntity).codeName.contains(searchValue);
                    }
                }
            }
            
            // searchKey가 적용이 안되는 부분은 개별값이 있으면 적용된다.
            if("group_code".equals(gubun)) {
                if(StringUtils.hasLength(groupCode)) {
                    return ((QCodeDetailEntity)qEntity).groupCode.eq(groupCode);
                }
            }
            
            if("code_value".equals(gubun)) {
                if(StringUtils.hasLength(codeValue)) {
                    return ((QCodeDetailEntity)qEntity).codeValue.eq(codeValue);
                }
            }
            
            if("code_name".equals(gubun)) {
                if(StringUtils.hasLength(codeName)) {
                    return ((QCodeDetailEntity)qEntity).codeName.eq(codeName);
                }
            }
            
            if("use_yn".equals(gubun)) {
                if(StringUtils.hasLength(useYn)) {
                    return ((QCodeDetailEntity)qEntity).useYn.eq(useYn);
                }
            }
            
            if("reg_date".equals(gubun)) {
                if(StringUtils.hasLength(regDate)) {
                    return ((QCodeDetailEntity)qEntity).regDate.
                            between(
                                    LocalDateTime.parse(regDate + " 000000", DateTimeFormatter.ofPattern("yyyyMMdd HHmmss")),
                                    LocalDateTime.parse(regDate + " 235959", DateTimeFormatter.ofPattern("yyyyMMdd HHmmss"))
                            );
                }
            }
        }
    }

우선 크게보면 상단 절반과 하단 절반의 처리 부분이 나뉘어져 있다. 

상단 절반은 searchKey와 searchValue 값으로 처리가 되는 부분이고, 하단 절반은 개별항목 별로 값을 콕 찍어서 

가져오도록 하기 위함인 부분이다. 하단 절반은 향후에 검색조건이 많은 경우에 사용하면 되겠다.

 

그런데 주석을 한번 보면 group_name을 프론트에 조회조건이 있지만 여기서는 사용하지 못한다. 

왜냐면 지금 패턴은 상세코드 (code_detail) 테이블을 우선 조회하여 뽑아온 뒤에 그에 맞는 그룹코드(code_group) 

데이터를 가져오는 형태이기 때문에 조회조건을 처리하는 시점에는 상세코드 밖에 없기 때문이다. 

여기서 이 패턴의 단점이 드러난다.  단순한 조회의 경우에는 괜찮지만 복잡한 조건이 필요한 경우에는 사용하기가 

어려워 진다.

 

2. 공통코드 레파지토리 수정

   공통코드 레파지토리 중에서 첫번째 패턴에 대해서 수정하려고 한다.

    searchCodeDetailCondition 메소드 부분이다.

... 중략
JPAQuery<CodeDetailEntity> query = queryFactory.selectFrom(b)
        .where(
                // searchKey를 위해서 각 항목별로 호출이 필요하다.
                codeDetailDto.makeSearchCondition(b, "group_code"),       // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(b, "code_value"),       // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(b, "code_name"),        // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(b, "use_yn"),           // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(b, "reg_date")          // searchKey 및 개별사용 동시 처리
              );
... 중략

기존에 하드코딩된 where 절을 가변쿼리로 동작하도록 수정하였다. 

그리고 주석으로 얘길했지만 searchKey를 사용하지 않고 직접 호출을 하는게 하나도 없더라도 각각의 호출이 필요하다.

위의 CodeDetailDto.java 파일에서 봤겠지만 해당 항목에 대해서 searchKey 동작에서도 필요하기 때문이다.

아무튼 두가지의 조회조건에 대한 동시처리로 사용된다.

 

 

이제 두번째 패턴인 그룹코드를 기준으로 한 연관Join 조회 처리 부분이다.

 

 

3.  상세코드 Dto 추가 수정

  그룹코드 기준 리스트를 가져오지만 상세코드 Dto에 가변쿼리를 처리하였다. 

 물론 CodeGroupDto.java에 조건을 넣어도 무방하지만 프론트에서 전송되는 값이 CodeDetailDto 로 넘어오기 때문에

 상세코드Dto에 추가하는 게 좀 더 수월할 것이다.

...중략
    private String groupCode;
    private String groupName;       // 추가된 항목
    private String codeValue;

...중략
        if(qEntity instanceof QCodeDetailEntity) {
...중략        
        }

        if(qEntity instanceof QCodeGroupEntity) {
            
            if("group_code".equals(gubun) && "group_code".equals(searchKey)) {
                if(StringUtils.hasLength(searchValue)) {
                    
                    if(searchValue.split(",").length > 0) {
                        return ((QCodeGroupEntity)qEntity).groupCode.in(searchValue.replaceAll(" ", "").split(","));
                    } else {
                        return ((QCodeGroupEntity)qEntity).groupCode.contains(searchValue);
                    }
                }
            } else if("group_name".equals(gubun) && "group_name".equals(searchKey)) {
                if(StringUtils.hasLength(searchValue)) {
                    
                    if(searchValue.split(",").length > 0) {
                        return ((QCodeGroupEntity)qEntity).groupName.in(searchValue.replaceAll(" ", "").split(","));
                    } else {
                        return ((QCodeGroupEntity)qEntity).groupName.contains(searchValue);
                    }
                }
            }
            
            // searchKey가 적용이 안되는 부분은 개별값이 있으면 적용된다.
            if("group_code".equals(gubun)) {
                if(StringUtils.hasLength(groupCode)) {
                    return ((QCodeGroupEntity)qEntity).groupCode.eq(groupCode);
                }
            }

            if("group_name".equals(gubun)) {
                if(StringUtils.hasLength(groupName)) {
                    return ((QCodeGroupEntity)qEntity).groupName.eq(groupName);
                }
            }
            
            if("use_yn".equals(gubun)) {
                if(StringUtils.hasLength(useYn)) {
                    return ((QCodeGroupEntity)qEntity).useYn.eq(useYn);
                }
            }
            
            if("reg_date".equals(gubun)) {
                if(StringUtils.hasLength(regDate)) {
                    return ((QCodeGroupEntity)qEntity).regDate.
                            between(
                                    LocalDateTime.parse(regDate + " 000000", DateTimeFormatter.ofPattern("yyyyMMdd HHmmss")),
                                    LocalDateTime.parse(regDate + " 235959", DateTimeFormatter.ofPattern("yyyyMMdd HHmmss"))
                            );
                }
            }
        }

그리고 하단에 추가된 내용 중에서 code_value, code_name에 대한 조건은 없다. 

왜냐면 상단에 이미 추가된 내용에 해당 조건을 처리하는 부분이 이미 있기 때문이다. 

다음에 나올 백엔드 레파지토리 부분에서 각각의 엔티티를 따로 던질 것이기 때문이다.

 

 

4. 백엔드 호출 부분 추가 수정

    백엔드에 호출하는 부분에서 검색조건을 넘기는 부분을 추가한다.

    searchCodeGroupCondition 메소드 부분이다.

... 중략
JPAQuery<CodeGroupEntity> query = queryFactory.selectFrom(a)
		.leftJoin(a.codeDetailEntity, b)
        .on(
                codeDetailDto.makeSearchCondition(a, "group_code")
            )
        .where(
                // searchKey를 위해서 각 항목별로 호출이 필요하다.
                codeDetailDto.makeSearchCondition(a, "group_code"),     // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(a, "group_name"),     // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(b, "code_value"),     // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(b, "code_name"),      // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(a, "use_yn"),         // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(a, "reg_date")        // searchKey 및 개별사용 동시 처리
            );
... 중략

기존의 on 절에 입력된 하드코딩 값 대신에 가변 처리로 입력하였고, where 절에도 해당 조건을 가변쿼리로 처리되도록

하였다. 여기까지 수정하고 한번 실행시켜 보자.

 

첫번째 패턴에 대한 화면인 상세기준리스트는 잘 동작을 하는데 그룹기준 리스트를 누르는 순간 오류가 발생한다.

Cannot invoke "com.querydsl.core.types.Expression.accept(com.querydsl.core.types.Visitor, Object)" because "expr" is null

 

이유는 on절에는 null을 반환할 수 없다. 즉 정확히 고정된 값만 on절에 넣을 수가 있다. 

프론트에서 아래 소스에서 useYn 부분의 주석을 풀고, 위의 레파지토리도 다시 수정해보자.

CodeJoinList.vue

...중략
    fnGroupJoinList() {

      this.requestBody = { // 데이터 전송
        searchKey: this.search_key,
        searchValue: this.search_value,
        useYn : 'Y',	<-- 주석해제
        page: this.page,
        size: this.size
      }
CommonCodeRepositoryCondition.java

... 중략
JPAQuery<CodeGroupEntity> query = queryFactory.selectFrom(a)
		.leftJoin(a.codeDetailEntity, b)
        .on(
                codeDetailDto.makeSearchCondition(a, "use_yn")
            )
        .where(
                // searchKey를 위해서 각 항목별로 호출이 필요하다.
                codeDetailDto.makeSearchCondition(a, "group_code"),     // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(a, "group_name"),     // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(b, "code_value"),     // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(b, "code_name"),      // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(a, "use_yn"),         // searchKey 및 개별사용 동시 처리
                codeDetailDto.makeSearchCondition(a, "reg_date")        // searchKey 및 개별사용 동시 처리
            );
... 중략

이렇게 되면 useYn 값은 무조건 넘어올 것이고 on절에는 null이 발생되지 않을 것이다. 

 

이제 다시 로그인한 뒤에 재 조회 해보자.

이제는 아래와 같이 잘 동작을 할 것이다.

상세코드기준 리스트

 

그룹코드기준 리스트

 

일단 어느 정도 개선이 잘 되었다. 

다음 장에서는 그룹코드기준 리스트를 대상으로 좀 더 세부적인 부분을 한번 더 들여다 보겠다.

반응형

프로그램/Vue.js Related Articles

MORE

Comments