======================================================================================================================================================================

 

결론 : 1.조인해서 한번의 Query 로 Load 하려면 @EntityGraph 를 사용하여야 한다.

2. @NamedEntityGraph 선언할때 @NamedAttributeNode 에 원쿼리로 가져올 항목을 명시한다.

3. Repository 메소드에 @EntityGraph 선언하여 value에 사용할 @NamedEntityGraph 명을 적고, type 은 = EntityGraph.EntityGraphType. LOAD , FETCH 선택 사용.

4. 조인해서 가져오는 항목외에 다른 객체필드에 LAZY ,EAGER 를 선언해서 적어준다.

 

자세한 내용은 아래 참조.

======================================================================================================================================================================

 

엔티티 필드에 사용하는 LAZY, EAGER 를 Repository(메소드) 마다 다르게 사용하기 위해서 @NamedEntityGraph , @EntityGraph 를 사용한다.

@NameEntityGraph [  name  = 이름을 선언 , attributeNodes = 조인해서 가져올 항목들 선언 ]

@EntityGraph [ value = NameEntityGraph name 값 , type = FETCH,LOAD 선택 ] 

 

  • FETCH: entity graph에 명시한 attribute는 EAGER로 패치하고, 나머지 attribute는 LAZY로 패치
  • LOAD: entity graph에 명시한 attribute는 EAGER로 패치하고, 나머지 attribute는 entity에 명시한 fetch type이나 디폴트 FetchType으로 패치 (e.g. @OneToMany는 LAZY, @ManyToOne은 EAGER 등이 디폴트이다.)

* 이슈가 생겨서 쿼리수정이 필요할때

FETCH 로 선언했었을때 : EAGER 로 변경하고 싶을때 attribute 에 추가, LAZY 로 변경하고싶을경우 attribute에서 제거.

LOAD 로 선언했었을때  : EAGER 로 변경하고 싶을때 attribute 에 추가, LAZY 로 변경하고싶을경우 Entity 속성을 수정.

(여기서 Entity를 수정하는건 다른 API에 영향이 가기 때문에, FETCH 로 선언을 해서 사용하는게 추후 쿼리 이슈가 발생 했을경우 수정이 자유롭지 않을까 싶다.)

 


참고 : attributePaths 는 value 를 사용안하고 바로 필드를 적을때 사용.(value를 사용하는게 명시적으로 좋을듯하다) , subgraphs ( 2개이상 엔티티 조인할때 필요 )

 

Organization.java

@NamedEntityGraph(name = "Organization.subOrgList", attributeNodes = {@NamedAttributeNode("subOrganizationList")},subgraphs = {@NamedSubgraph(name = "subOrg",attributeNodes = @NamedAttributeNode("subOrganizationList"))})

public class Organization extends AbstractEntity implements AggregateRoot {

    ...................

    ...................

}

 

OrganizationRepository.java

@RepositoryRestResource

public interface OrganizationRepository extends

        JpaRepository<Organization, Long>, QuerydslPredicateExecutor<Organization>

        , QuerydslBinderCustomizer<QOrganization> {

 

    @EntityGraph(value = "Organization.subOrgList",attributePaths = {"parent"},type = EntityGraph.EntityGraphType.LOAD)

    Optional<Organization> findFirstByOrganizationCode(String organizationCode);

 

    @EntityGraph(value = "Organization.subOrgList",attributePaths = {"parent"},type = EntityGraph.EntityGraphType.LOAD)

    Page<Organization> findAll(Pageable pageable);

 

    List<Organization> findAllBy();

    ....

}

 

========================================================================================================================================================

LAZY , EAGER 차이

fetch= FetchType.LAZY:데이터를 가져다 쓰는 시점에 쿼리를 실행한다. ( 즉 projection 으로 사용하지 않는 필드를 조회하는 API 를 호출할땐 쿼리가 실행되지 않음 )

 

fetch= FetchType.EAGER:데이터를 가져옴 조인해서 가져온다.( 단 Page<Entity> findAll(Pageable pageable) 메소드에는 적용되지 않음. @EntityGraph 사용해줘야됨 )

 

 

public class Organization extends AbstractEntity implements AggregateRoot {

    .....................

    .....................

 

 

    @OneToMany(mappedBy="parent", fetch= FetchType.LAZY, cascade=CascadeType.ALL)

    @RestResource(exported=false)

    @JsonManagedReference

    public List<Organization> subOrganizationList;

}

 

ex) projection 으로  subOrganizationList

$(document).click(function(e){ //문서 body를 클릭했을때

    //User 영역 컨트롤

    if(e.target.className =="btn-user"){ //유저정보 클릭 버튼

        $(".user").toggle();

    }else if( $(".user").has(e.target).length > 0 ){ //유저정보 영역

        return false;

    }else { //그외 지역

        $(".user").css("display","none");

    }

});

btn-user 은 클릭했을떄 영역을 여는거고, use 는 그 영역이다.

'Web개발 > Javascript' 카테고리의 다른 글

이모티콘 오라클,Mysql 저장에러 정규식 체크  (1) 2019.06.06

<button> 태그에 type="button" 이 없고 부모 element 에 <form> 태그가 있을경우.

IE11에서 테스트 결과 <button> 을 submit 해버림. IE 에서는 default 를 submit 으로 자동지정하나 봄

@Entity 를 넣으면 @Id 가 필수로 들어가야 된다. (pk 를 인식하기위해)

 

@Id 로 들어가있는값이 save(id) 가 될경우 id값이 기존에 들어가있으면 update( merge() ) 가 처리가 되고 기존에 없는값이면 insert( persist() ) 처리가 된다.

 

즉 PK가 없이 계속 insert 를 하려고 했을경우, 다른방법을 사용해야 한다.

 

전 native 쿼리를 사용해서 insert 문을 적었습니다.

 

 

request 에서 URL 정보를 가져왔을때, url 에 있는값이 PathVariable 인지 알수가 없음.

 

그래서 URL 에서 pathVariable 변수명으로 치환하기 위한 로직. (이 URL 을 가져와서 URL 별 권한이 있는지 DB에서 조회하기 위해서 사용함)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    
/*
*  3. PathVariable 정보 Map 으로 가져오기
*/
Map<StringString> pathVariables = (Map<StringString>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
 
// URL 에서 PathVariable 부분을 replace
Iterator<String> itr = pathVariables.keySet().iterator();
String key = null;
String value = null;
String[] splitStr = url.split("/");
while (itr.hasNext()) {
    key = (Stringitr.next();
    value = pathVariables.get(key);
    for (int i = 0; i < splitStr.length; i++) {
        if (splitStr[i].equals(value)) {
            splitStr[i] = "{" + key + "}";            
            }
    }
    url = String.join("/"Arrays.asList(splitStr));

 

'Web개발 > Java' 카테고리의 다른 글

날짜 유효성 체크 어노테이션  (0) 2019.12.04
@SpringBootTest 와 @WebMvcTest 차이  (0) 2019.07.07

PUT, DELETE 메소드로는 Web 서비스와 함께 원격지 웹 서버에 파일을 생성하거나 삭제하는 FTP와 유사한 기능을 구현할 수 있다.

 

그러면 get 이랑 post 만 써서 rest api 를 만들어야 되나???

Nope !

 

Url 파라미터로 _method=PUT , _method=DELETE 를 사용하고

웹서버 Filter 에서 _method 파라미터의 value값을 http method로 변경하는 spring filter 가 "HiddenHttpMethodFilterConfiguration" 이다.

 

사용은 간단하다. 아래클래스 하나 만들면 끝.

 

그러면 GET,POST 메소드만 Request 를 받도록 제한을 하려면??????

 

CorsWebFilter 를 사용하면 된다.

========================================================================

 

1
2
3
4
5
6
7
8
@Configuration 
public class HiddenHttpMethodFilterConfiguration { 
 
@Bean 
public HiddenHttpMethodFilter hiddenHttpMethodFilter() { 
    return new HiddenHttpMethodFilter(); 
   } 
}

버튼 한개당 API 를 여러개 호출할경우

 

버튼은 권한 있지만 API 는 권한관리 를 어떻게 할것인가.

 

테이블관계가 메뉴:버튼(1:N) 으로 API 별로 권한을 체크하려니 테이블 관계 버튼:API 가 (N:N) 관계가 되면서 권한 체크가 쉽지 않게 되었다. (버튼 한개에 API 한개를 호출하면 좋겠지만 MSA 프로젝트를 한다면 그럴거 같지는 않음)

 

1. '메뉴기능 테이블'에 버튼권한을 다 넣고, 거기에 모든 API 를 관리하는 테이블에 넣은후 권한을 체크.

 // API 추가시 계속 URL 을 관리해야하는 번거로움. (conference에 추가하는거나 비슷한거 같기도하고...)

 

2. URL 패턴을 관리해서 특정URL 패턴에서만 URL 권한을 체크하도록

ex) Intercepter 에서 !URL.startsWith("/uploads") 이럴때 권한 체크. 등으로 처리

 // 2번과 같이 처리하려면 시작부터 url 패턴을 정해두어야함.

API Server 앞에 NginX 를 프록시서버로 뒀을때 , API Server 에서 아무리 Header 정보 아무리 찾아봐도,

Client 정보를 알수가 없다. Nginx 가 헤더정보를 안 넘겨주기 때문이다.

 

이럴경우 Nginx 헤더 설정이 필요하다.

 

위에 언급한 Nginx 같은걸 Ingress(라우터 외부에서 라우터 내부로 유입되는 패킷을 필터링) 서버 라 부른다.

API Server 앞에 NginX 를 프록시서버로 뒀을때 , API Server 에서 아무리 Header 정보 아무리 찾아봐도,

Client 정보를 알수가 없다. Nginx 가 헤더정보를 안 넘겨주기 때문이다.

이럴경우 Nginx 헤더 설정이 필요하다.
위에 언급한 Nginx 같이 클러스터 외부에서 내부로 접근하는 요청들을 어떻게 처리할지 정의해둔 규칙들의 모음을
 쿠버네티스에서는 Ingress 서버 라 부른다.
 
 Ingress로 Nginx 를 사용할경우 yaml 템플렛 annotations 부분에 아래와 같이 추가하면 클라이언트 정보를 알 수 있다.

 
metadata:
   annotations:
      proxy_set_header X-Forwarded-For $proxy_protocol_addr;
      proxy_set_header X-Real-IP $proxy_protocol_addr;

참고 : https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/

+ Recent posts