Develope Story

2019-08-29 [Spring-study] QnA 4단계 - 객체 관계 매핑

|

QnA 4단계 - 객체 관계 매핑

요구사항

  • 답변 추가하기
  • 답변 수정, 삭제기능

개인 요구사항

  • 비밀번호 암호화

공부한 내용

Cascade Type 종류

  • CascadeType.PERSIST 엔티티를 영속화 할 때이 필드에 보유 된 엔티티도 유지합니다. EntityManager가 flush 중에 새로운 엔티티를 참조하는 필드를 찾고이 필드가 CascadeType.PERSIST를 사용하지 않으면 오류이므로이 Cascade 규칙의 자유로운 적용을 제안합니다.
  • CascadeType.MERGE 엔티티 상태를 병합 할 때, 이 필드에 보유 된 엔티티도 병합하십시오.
  • CascadeType.REFRESH 엔티티를 새로 고칠 때, 이 필드에 보유 된 엔티티도 새로 고칩니다.
  • CascadeType.REMOVE 엔티티를 삭제할 때, 이 필드에 보유 된 엔티티도 삭제하십시오.
  • CascadeType.DETACH 부모 엔티티가 detach()를 수행하게 되면, 연관된 엔티티도 detach() 상태가 되어 변경사항이 반영되지 않는다.
  • CascadeType.ALL 모든 Cascade 적용

https://postitforhooney.tistory.com/entry/JavaJPAHibernate-CascadeType%EB%9E%80-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%A2%85%EB%A5%98

FetchType

  • EAGER - 즉시 로딩 : 엔티티 조회 시 연관된 엔티티도 함께 조회
    • 연관된 엔티티 같이 업데이트
  • LAZY - 지연 로딩 : 엔티티를 실제 사용 할때 조회.
    • ex) 댓글 더보기

SLF4J 로그 사용

slf4j 추상 -> logger

System.out을 사용 하지 않는 이유

  • 리소스를 너무 많이 잡아 먹음
  • 계층적인 로그(우선순위) 처리
    • trace, debug, info, warn, error 순 -> 높
  • 여러가지 장점 링크 참조

기능 (Facade pattern)

  • API
  • Binding
    • SLF4J 인터페이스를 로깅 구현체와 연결하는 어댑터 역할
  • Bridging
    • 다른 로깅 API로의 Logger 호출을 SLF4J 인터페이스로 연결(redirect)하여 SLF4J API가 대신 처리하는 어댑터 역할

참고 https://gmlwjd9405.github.io/2019/01/04/logging-with-slf4j.html

Facade pattern(최광훈교수님꺼 퍼옴)

  • 서브 시스템의 세부 클래스들을 직접 사용하지 못하도록 막고 이 클래스들을 대표하는 클래스들을 통해서 간적접으로 사용하게 하는 방법

​ 예제) 컴파일러 서브 시스템, 가상 메모리 프레임워크

  • 장점 :

    1) 사용자와 서브 시스템 간의 결합도를 줄인다.

    2) 서브 시스템 내부의 특정 클래스들만 공개하고 나머지는 숨길 수 있다.

###BCrypt 비밀번호 암호화 => bcryptpasswordencoder로 변경함

BCrypt.hashpw(password, BCrypt.gensalt(10))

비밀번호를 해싱하는 메소드

  • 비밀번호가 길어지면 해싱하는 시간 길어져서 제한하기 위해 BCrypt.gensalt(10) 사용
BCrypt.checkpw(password, hashedPassword)

암호화된 비밀번호와 비교

궁금증

=> 스크린샷 2019-09-04 오후 5.08.47

크롬 개발자 도구에 password가 나타나는 문제점을 해결하지 못함

참고 https://stackoverflow.com/questions/3353930/password-sent-via-post-secure

=> https를 써야함 + I use javascript to hash the password before submitting the form.

  • 프론트로 js로 암호화 한번 걸침

리뷰

혁진이형

  • JpaRepository와 CrudRepository 의 차이점에 대해서 말씀해주세요

  • JpaRepository 는 PagingAndSortingRepository 와 CrudRepository 확장
  • PagingAndSortingRepository 와 CrudRepository 기능
  • CrudRepository = CRUD 기능 제공
  • PagingAndSortingRepository = 페이지 매김 및 정렬 레코드를 수행하는 메소드를 제공

  • JpaRepository = 일괄 처리에서 지속성 컨텍스트를 삭제하고 레코드를 삭제하는 것과 같은 JPA 관련 메소드를 제공

위에서 언급 한 상속 때문에 JpaRepository는 CrudRepository 및 PagingAndSortingRepository의 모든 기능을 갖습니다. 따라서 JpaRepository와 PagingAndSortingRepository가 제공하는 기능을 저장소에 필요로하지 않는다면 CrudRepository를 사용

https://codeday.me/ko/qa/20190306/7467.html

  • Date 클래스의 사용을 지양해야하는 이유와 대안책을 말해주세요

기본 날짜 클래스 문제점 ( date, calendar ) https://d2.naver.com/helloworld/645609

  • 불변 객체 x = 변한다

    • Set 을통해서 데이터를 수정 할 수 있음.

      • 해결책
      private final Date startTime;
      private final Date endTime;
          
      public Constructor(Date startTime, Date endTime){
        this.startTime = startTime;
        //방어 복사 기법 활용
        this.endTime = new Date(endTime.getTime());
      }
          
      public Date getStarTime(){
        return this.startTime;
      }
          
      //방어 복사 기법 활용
      public Date getEndTime(){
        return new Date(this.endTime.getTime());
      }
      
      • 생성자와 접근자 모두 변경 불가능 클래스

        https://ktko.tistory.com/entry/Effective-Java-39-필요하다면-방어적-복사본을-만들라

  • 헷갈리는 월 지정

    calender.set(1582, Calender.OCTOBER, 4) = calender.set(1582, 10 - 1, 4);
    
  • 일관성 없는 요일 상수

    Calendar.get(Calendar.DAY_OF_WEEK) 일요일 1, 수요일 4

    Date.getDay() 일요일 0, 수요일 3

    • Calender와 Date.getDay()의 요일 상수가 다름
  • Date와 Calendar 객체의 역할 분담

  • 오류에 둔감한 시간대 ID 지정

    @Test
    public void shouldSetGmtWhenWrongTimeZoneId(){  
        TimeZone zone = TimeZone.getTimeZone("Seoul/Asia");
        assertThat(zone.getID()).isEqualTo("GMT");
    }
    

    ‘Asia/Seoul’대신 ‘Seoul/Asia’로 잘못 지정한 코드 - 테스트 통과됨. ㅠ

  • 기타 java.util.Date 하위 클래스의 문제

    • 먼솔인지..
  • 시간 API

결론 : Joda-Time 의 LocalDate, LocalTime, LocalDateTime 많이 씀(https://jeong-pro.tistory.com/163)

  • 생성자 시점에 Date를 초기화 해주면 어떤 문제가 있을까요?

  • 나도 테스트를 해본게 아니라서 틀릴 수도 있는데,Answer에 Entity 어노테이션이 붙어있잖아? JPA는 DB에 이 클래스 정보를 바탕으로 테이블을 만들거나, 이미 있으면 매핑을 시켜그리고 DB 안에 있는 하나의 row 데이터를 findby 로 가져온다고 했을 때,해당 row 를 매핑한 새로운 객체(answer) 가 반환이 되겠지?(그 객체 안에 있는 date는 뭐 아마 처음에 값을 save 했을 때 객체를 만들었을 테니까 그때 생성자를 통해 date가 초기화 되었을거고.)그렇게 초기화 되어서 DB에 저장되어있던 데이터를 다시 findby로 가져와서 새로운 answer 객체에 매핑을 하잖아?그러면 새로운 answer 객체가 생성되면서 기본 생성자가 date를 초기화 시키겠지?그럼 처음에 db에 있었던 date 값과 그걸 매핑 시키는 과정에서 date가 달라지겠지?라는 생각으로 리뷰를 달았었는데,답변 달면서 생각해보니까 생성자를 호출하고 나서 JPA가 DB에서 가져온 값들을 (reflection을 통해) 객체의 필드에 꽃아 넣을 것 같다는 생각이 들어서 결국 date 값 db에서 가져옴 -> 객체 초기화 과정에서 new date 해서 날짜가 달라짐 -> JPA가 가져온 db date 데이터가 필드에 꽃아넣어짐 -> 결국 new date 해서 나온 값 무시될 것 같다는 생각이 들긴한다.결론은 정말 궁금하면 정말 그런지 테스트 해보시고 저도 알려주세요 내가 아는 좋은 방법은 timestamp? 같은 어노테이션을 쓰는 것? (jpa date 같은걸로 검색해서 찾아보면 많이 나올거야)

Entity Listener

@PrePersist, @PreUpdate

prepersist , preupdate 사용법

https://vladmihalcea.com/prepersist-preupdate-embeddable-jpa-hibernate/

-> @CreationTimestamp, @UpdateTimestamp

  • 자동으로 시간 설정해줌…

  • cascade type과 fetchtype 에 대해 설명해주실 수 있나요?

  • getQuestionById 메서드에서 바로 get 을 하시는데, get을 사용하면 어떤 문제가 발생할까요?

    https://tuhrig.de/find-vs-get/

**find **

public interface CrudRepository<T,ID> {
    ...
    Optional<T> findById(ID id);
    Iterable<T> findAll();
    ...
}

Find = 리턴값이 optional 임

optional https://www.daleseo.com/java8-optional-after/

get() 메소드는 비어있는 Optional 객체를 대상으로 호출할 경우, 예외를 발생시키므로 다음과 같이 객재 존재 여부를 bool 타입으로 반환하는 isPresent()라는 메소드를 통해 null 체크가 필요합니다.

Optional의 값을 get 할경우 isPresent()를 통해서 null 값을 체크 해야하는 데 이렇게 사용할 시 Optional을 사용하지 않는 것과 동일하게 됩니다. 그래서 orElseThrow 같이 null 일때 예외처리를 통해 해결하였습니다.

  • password Encoder 를 bean으로 등록해놓고 주입받아서 사용하면 어떨까요?

http://wonwoo.ml/index.php/post/1701

Comments