8월 2주차 WIL_05

Jobmania·2022년 8월 14일
1

항해 과정 기록

목록 보기
5/19

이번주의 키워드 BE: CORS


CORS란?

정의 : 교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제 -MOZILLA

예시 : https://domain-a.com의 프론트 엔드 JavaScript 코드가 XMLHttpRequest를 사용하여 https://domain-b.com/data.json을
요청하는 경우

웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행하며, API를 사용하는 웹 애플리케이션은 자신의 출처와 동일한 리소스만 불러올 수 있으며, 다른 출처의 리소스를 불러오려면 그 출처에서 올바른 CORS 헤더를 포함한 응답을 반환해야 합니다.

뭔가 아직 잘 모르겠다!!! 세부적으로 알아보자!!

SOP(Same Origin Policy)

다른 출처의 리소스를 사용하는 것을 제한하는 방식

출처(Origin)이란?

여기서 Protol, Host, Port중 하나라도 다르면 다른 출처라고 판단을 한다.

왜 SOP를 쓸까??

만약 해커가 나의 토큰을 탈취해 작업을 하려고 하더라도!! 서버는 Cross Origin이라 판단하고 받아들이지 않는다

그렇다면 다른 출처의 리소스가 필요하다면?? 그래서 필요한 것이 CORS!!

즉, 다른 출처의 자원을 공유!, CORS를 정리하면
-> 다른 출처에 접근하는 것을 브라우저에게 알려주는 체제!!

CORS 접근제어 시나리오

  • 프리플라이트 요청(Preflight Request)
    사전 확인 작업. 다른 도메인의 리소스에 요청이 가능한지 확인 작업
    요청이 가능하다면 실제 요청(Actual Request)을 보낸다
  • 단순요청 (Simple Request)
    Preflight 없이 바로 요청을 보낸다.
  • 인증정보 포함 요청(Credentialed Request)

Preflight에 대해서 알아보자!

2개의 요청이 보낸 화면

  • 요청 예시
    Preflight 요청 및 응답


    Max-Age는 캐시 기간, 86400초 동안 보관하여 이 시간 안에는 요청 Actual Request만 보내도 된다.
    추가적으로 Response의 응답코드는 200대, 응답바디는 비어있으면 좋다.

Simple Request

사용하기 위해선 다음과 같은 조건이 만족 해야한다.

  • GET, POST, HEAD 메서드 중에 하나여야 됨.

  • Content-Type (아래 셋 중에 하나 )
    A. application/x-www-form-urlencoded
    B. multipart/form-data
    C. text/plain

  • Header는 Accept, Accept-Language, Content-Language, Content-Type만 허용된다.

    이 모든 조건을 만족해야한다.

    한번 요청을 보냄!!

그렇다면 왜 Preflight가 필요한가??

CORS를 모르는 서버를 위해서!!

예시(서버는 CORS 설정이 없다)

  • preflight가 없을 시
    이미 서버는 받은 요청을 끝냈지만 브라우저에서 CORS에러를 줌..
  • preflight가 있을시
    실제 요청이 없기 때문에 서버에서는 작업을 하지 않았음.

++추가적인 설명
Preflight가 왜 있는가에 대해서는 쉽게 말해서 CORS spec이 생기기 이전에 만들어진 서버들은 브라우저의 SOP(same origin policy) request만 가능하다는 가정하에 만들어졌는데, cross-site request가 CORS로 인해서 가능해졌기 떄문에 이런 서버들은 cross-site request에 대한 security mechanism이 없다보니 보안적으로 문제가 생길수 있으니 이런 서버들을 보호하기 위해 CORS spec에 preflight request를 포함한겁니다. Preflight request로 서버가 CORS를 인식하고 핸들할수있는지 먼저 확인을 함으로써 CORS를 인식하지 못하는 서버들을 보호할수있는 매커니즘 입니다.

Credentialed Request

인증 관련 헤더를 포함할 때 사용하는 요청이다.

클라이언트 측 / Credentials : include
서버측 / Access-Control-Allow-Credentials : true
*** 여기서 Access-Control-Allow-Origin: 은 사용하면 안됨.
모든 것을 허용한다는 뜻이기 때문에. 모든 것을 허용하는 순간 Error발생함.

그래서 CORS를 해결해보자!!

  1. 프론트 프록시 서버 설정(개발 환경)

    프론트서버에서 8080포트로 연결해준다.
  2. 직접 헤더에 설정해주기
  3. 스프링 부트를 이용하기(ㅋㅋ)
    이 방법은 조금 더 공부가 필요하다.

출처 : https://www.youtube.com/watch?v=-2TgkKYmJt4


N+1 문제

연관 관계가 설정된 엔티티를 조회할 경우에 조회된 데이터 갯수(n) 만큼 연관관계의 조회 쿼리가 추가로 발생하여 데이터를 읽어오는 현상.

  • 예시

JpaRepository를 extends 한 Interface 객체인 TeamRepository에서 findAll을 호출을 하면

발생 이유

N+1 문제가 발생하는 이유는 JPA가 JPQL을 분석해서 SQL을 생성할 때는 글로벌 Fetch 전략을 참고하지 않고 오직 JPQL 자체만을 사용한다. 즉, 아래와 같은 순서로 동작한다.

Fetch 전략이 즉시 로딩인 경우

  1. findAll()을 한 순간 select t from Team t 이라는 JPQL 구문이 생성되고 해당 구문을 분석한 select * from team 이라는 SQL이 생성되어 실행된다. ( SQL 로그 중 Hibernate: select team0.id as id1_0, team0.name as name2_0 from team team0_ 부분 )
  2. DB의 결과를 받아 team 엔티티의 인스턴스들을 생성한다.
  3. team과 연관되어 있는 user 도 로딩을 해야 한다.
  4. 영속성 컨텍스트에서 연관된 user가 있는지 확인한다.
  5. 영속성 컨텍스트에 없다면 2에서 만들어진 team 인스턴스들 개수에 맞게 select * from user where team_id = ? 이라는 SQL 구문이 생성된다. ( N+1 발생 )

Fetch 전략이 지연 로딩인 경우

  1. findAll()을 한 순간 select t from Team t 이라는 JPQL 구문이 생성되고 해당 구문을 분석한 select * from team 이라는 SQL이 생성되어 실행된다. ( SQL 로그 중 Hibernate: select team0.id as id1_0, team0.name as name2_0 from team team0_ 부분 )
  2. DB의 결과를 받아 team 엔티티의 인스턴스들을 생성한다.
  3. 코드 중에서 team 의 user 객체를 사용하려고 하는 시점에 영속성 컨텍스트에서 연관된 user가 있는지 확인한다
  4. 영속성 컨텍스트에 없다면 2에서 만들어진 team 인스턴스들 개수에 맞게 select * from user where team_id = ? 이라는 SQL 구문이 생성된다. ( N+1 발생)

해결방법

Fetch Join ,EntityGraph 어노테이션 , Batch Size 등의 방법

  1. Fetch Join
    별도의 메소드를 만들어줘야 하며 @Query 어노테이션을 사용해서 "join fetch 엔티티.연관관계_엔티티" 구문을 만들어 주면 된다.

나의 의견: 음 아직까지는 어려운 내용이라.. 흠...Query문을 이해하는 것이 먼저인 것! 하지만 inner join user user2 on users1.usersid=user2.id 해당내용을 유심히 보면 !

실무에서 N+1문제로 DB가 죽어버리는 문제를 방지하기 위해서는 어떻게 해야 할까?

우선 연관관계에 대한 설정이 필요하다면 FetchType을 성능 최적화를 하기 어려운 즉시 로딩(EAGER)을 사용하는 게 아니라 지연 로딩 (LAZY) 모드로 사용을 하고 성능 최적화가 필요한 부분에서는 Fetch 조인을 사용한다.
또한 기본적으로 Batch Size의 값을 1000 이하로 설정한다. (대부분의 DB에서 IN절의 최대 개수 값 : 1000)

그 외에 팀바팀이긴 한데 꼭 연관관계 설정이 필요 없다면 N+1 문제로 인하여 DB가 죽어버리는 불상사를 막기 위해 연관관계를 끊어버리고 사용하는 것도 방법이다.

출처: https://programmer93.tistory.com/83

@Transient 어노테이션

단순히 “컬럼을 제외한다.” 라기보단 영속 대상에서 제외시키기 위해 사용한다.

엔티티 객체의 상태가 영속 상태(managed, persistent state)일 때, 비로소 엔티티 매니저에 의해 관리됩니다. 영속 상태의 엔티티 객체는 엔티티 매니저에 의해 [1]변화에 대한 자동 감지(Dirty Checking), [2]CRUD SQL 자동 생성 작업 및 그외 일련의 모든 JPA의 내부적인 동작 프로세스에서 활용됩니다.

하지만 영속 대상에서 제외된다면, 더는 해당 필드나 메서드는 엔티티 매니저의 관리 대상에서 제외됨을 의미합니다. 즉 해당 필드에 대해 @Transient 애노테이션을 선언하게 되면 영속 대상에서 제외되어 앞서 설명한 [1,2] 작업들을 수행하지 않습니다. 이러한 결과를 토대로 “테이블의 컬럼과 매핑을 하지 않는다.”라고 이해하셔도 무방합니다.

그래서 어떻게 사용하는데??

  1. 필드방식

    2.메소드방식

나의 생각 : 메소드방식은 처음봐서 .. 왜사용하는지 부터 알아봐야될듯.

출처 : https://gmoon92.github.io/jpa/2019/09/29/what-is-the-transient-annotation-used-for-in-jpa.html


추가적인 키워드

  1. API란 무엇인가?
  2. Client와 Sever란 무엇인가?
  3. WAS란 무엇인가? Web Server와 차이점은 무엇인가?
  4. HTTP 프로토콜이란 무엇인가?
  5. Restful API는 무엇인가?

지난 WIL에 기록 : https://velog.io/@jobmania/8%EC%9B%94-1%EC%A3%BC%EC%B0%A8-WIL01


매니저님의 심화주차 과제 피드백

1. Restful한 설계를 잘 했나요?

이미지만 수정하는 경우 PATHCH 메소드만 사용하는 등 전반적으로 깔끔했던 API설계였습니다.

토큰을 이용하는 쪽은 /auth 라는 url이 모두 달려있습니다. 이 부분을 클라이언트에서 알 필요가 있을까요?
/auth 를 통해 security에서 .antMatchers("/api/post/**").permitAll() 를 피해가려는 목적은 이해됩니다. 하지만 이런식으로 구성하는게 Restful한 설계와는 차이가 있는 듯 보입니다. POST - /api/post 로도 원하시는 대로 구현 할 수 있는 방법을 찾아보시는 것을 추천드립니다!

2.엔티티 설계가 잘 되어있나요?

heart의 개수를 @column통해서 DB에 단순히 업데이트 마다 1씩 늘려주는 것을 저장하기 보다는
@transient를 통해서 List의 size를 측정하는 것으로도 할 수 있어 보입니다.

3.객체지향 설계를 적용했나요?

Comment와 post말고도 heart쪽에도 Member를 연관관계로 꼭 지정했어야 했는지 생각하면 좋을 듯 합니다.
Member라는 객체가 너무 많은 곳에 사용되고 있는 것 같습니다.
서로 참조가 생기므로 변경 시, 다른한쪽이 한쪽에 영향을 줄 수 있음을 유의하시면 좋을 듯 합니다.

4.예외처리가 미흡한 부분은 없나요?

Post post = isPresentPost(id);
if (null == post) {
return ResponseDto.fail("NOT_FOUND", "존재하지 않는 게시글 id 입니다.");
}

를 하여 null체크를 하는 방식보다는 post orElseThrow를 발생시켜서 RestControllerAdvice으로 받는게 더 좋아 보입니다.

현재는 MethodArgumentNotValidException만 글로벌로 예외처리를 하는데 저런 엔티티를 repo에서 찾아올 수 없을 때도
글로벌로 처리하면 더욱 가독성이 좋은 코드가 될 것 같네요.

git ignore를 통해 jwt 키같은 것도 노출시키지 않고 숨기는 것도 좋습니다.


이번 주차 정리

220807

Git 내용
풀리퀘스트
리베이스


POST맨
1. LINK를 IMPORT한다.
https://www.getpostman.com/collections/698d3d71ba96ca6f610e


220808

Git 전략을 세워보자 !!
Git을 기능별로 나눠야 된다....

1단계. 누가 이 작업 할 것인지 정한다. - Issue
2단계. 각자 맡은 것을 작업한다. - Branch
3단계. 각자 작업을 프로젝트에 합친다. - merge
(경우에 따라). 작업한 내용을 리뷰하고 최종적으로 프로젝트에 반영한다. - PR 후 merge

깃에서 Issue에 커밋 #1한걸 인식해서 보여준다.!!

Merge 시 병합할 대상에 체크아웃(예로들면 메인브런치 선택)하고
나온 브런치와 병합..

깃전략에 대해 좋은 기술 블로그 !!
https://techblog.woowahan.com/2553/

+++깃 푸쉬시 본인 브런치에만 푸시가 가능하다!!
다른곳에 푸쉬는 곧 풀리퀘스트 (변경점 적용) 이다!!


!!! 백엔드, 프론트 엔드 협업에 관해서
API명세서를 잘 짜야된다... ( 안바뀌는게 좋기때문)
일의 순서가
백앤드+ 디자인 )) -> 프론트엔드)) 이기때문에
프론트엔드는 API명세서를 보고 만든다.
그래서 백엔드쪽은 응답을 줄때 변수 명,타입 및 에러발생시 코드를 보내도록 설정할 수 있다. ..


  • JPA 연관관계에 대해서
    Many to Many는 어렵다...(휘림님 발표아이디어 참고)
    단방향을 지양하고 양방향을 써라!!!

양방향 연결관계
ex)ONE 코멘트 MANY SUB코멘트

java mappedBy 에 대해서
Data table에 없는 테이블을 불러옴

객체이름을 잘써야됨..

  • 오직 주인만 FK를 관리한다.(MANY쪽) JoinCoulm 기입
  • 주인이 아닌 곳에서는 mappedBy기입으로 주인을 명시해야한다.
  • Owner
    그럼 주인은 어떻게 정하는 게 좋을까. 김영한 강사님의 팁은 다음과 같다.
  1. FK가 있는 곳을 주인으로 한다.
  2. 객체의 개념에 따라서 Team의 members에도 member를 추가하고, member에도 team을 추가하는 식으로 양쪽 다 삽입하는 것도 실수를 줄이기 위한 방법이다.
  3. 설계는 단방향으로 하되, 반대로 접근이 필요해진 곳에 양방향을 추가하는 식으로 코드를 작성한다.

https://kok202.tistory.com/138


!! 캐스케이드에 관해서
https://data-make.tistory.com/668
https://velog.io/@max9106/JPA%EC%97%94%ED%8B%B0%ED%8B%B0-%EC%83%81%ED%83%9C-Cascade
** orphanRemoval = true

@OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER, orphanRemoval = true)

보통 1:N 관계 테이블 설정할때 저렇게 옵션을 추가해준다.
자식 엔티티의 변경이 있다면
JPA 에서 자식엔티티의 수정은 insert update update delete 순으로 이어지는데
변경된 자식을 먼저 insert 하고
기존의 자식을 NULL로 update 한다.
그리고 orphanRemoval 옵션을 true 로 하면 기존 NULL처리된 자식을 DELETE 한다. 
PK(JoinColumn)값이 NULL로 변한 자식은 고아객체라고 하여 연결된 점이 없는 객체이다. 
orphanRemoval옵션은 바로 이 고아객체를 삭제해주는 역활을 한다.
출처: https://dev-elop.tistory.com/entry/JPA-orphanRemoval-용도 [현직개발자:티스토리]


EAGER(즉시로딩), LAZY(지연로딩) --->>> 패치조인에 대해서
즉시로딩은 현업에서 거의 안쓴다. 왜냐 모두 끌어 오기 때문
지연로딩은 해당 객체를 들고오고 필요할때 get.~~을 쓴다.
LAZY + 패치조인을 같이 쓰면 좋다..


질문점 .
Mypage는 repo를 안만들어도 된다>?? ㅇㅇ
신뢰성문제....
패러다임 불일치...?


  • AOP를 쓰는이유에 대해서 검색
  • 트랜잭셔널 쓰는 이유에 대해서 검색..\

    안정상 이유 / db적용되기전 영속성컨테스트

  • Bean에 대해 검색....
  • 디버깅을 통해서 jwt, filter, 흐름을 파악하자..

S3
https://www.sunny-son.space/spring/Springboot%EB%A1%9C%20S3%20%ED%8C%8C%EC%9D%BC%20%EC%97%85%EB%A1%9C%EB%93%9C/


220809

풀리퀘스트 작성법

  • 제목 : 짧게
  • desc : 내용들
    누가 :
    기능 :
    부가설명 : 등등 자세하게

엔티티삭제시(캐스케이드)
https://hungseong.tistory.com/59


*** 무한루프 해결하기 (N+1문제)
1. 자동으로 만든 @id로 무한루프를 해결하겠다.
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=rorean&logNo=221593255071

2.참조가 되는 앞부분 및 뒷부분을 설정하여 시작과 끝을 설정하겠다.
https://velog.io/@2yeseul/JPA-Infinite-Recursion

  1. Return시 DTO를 사용해서 애초에 무한루프에 들지 않게 한다.
    https://friends-aihaja.tistory.com/entry/5-%EC%96%91%EB%B0%A9%ED%96%A5-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84%EC%99%80-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84-%EC%A3%BC%EC%9D%B8

@RequestPart 사용용도 DTO랑 File을 같이 받기 위해서 .. 사용한다


--
repository 사용하기
https://jobc.tistory.com/120
스프링에서 DB에 ID를 인식하는 이유 ORM(JPA)
spring = postId
spring -> orm (postId -> POST_ID) -> DB


포스트맨에서 코드를 프론트엔드와 협업할때 많이 참고한다.


220810

applicaton,properties , 안나오게 하기 기억하기(스프링심화과제)


findby, findall 구분하기
https://velog.io/@lsj8367/findAll-findById%EC%9D%98-%EC%B0%A8%EC%9D%B4


테스트코드 Assertion.assertthat():
@Test /어노테이션 써야됨...


@Bulder.Default로 초기값 설정 가능하다!!


엔티티에서 SETTER를 사용하면 안되는 이유
https://velog.io/@langoustine/setter%EB%A5%BC-%EC%93%B0%EC%A7%80%EB%A7%90%EB%9D%BC%EA%B3%A0


220811

기억보단 기록을.


야자반 숙제 해설

  1. 단방향(oneToMany / ManyToOne)
    -게시글 1 : 댓글 N -> post에만 연관관계 걸어보기(oneToMany) 원하는 대로 성공했으면(db에서 확인해보기) / post 연관관계 주석 처리 후 댓글에만 ManyToOne으로만 해보기
    (JoinColumn에 무엇을 작성해야할지 생각하면서)

    단방향 :
    Join Colum
    ex)ManyToOne , OneToMany
    생성한다. mappedby를 적지 않는다.

  2. 양방향(oneToMany - ManyToOne)
    -게시글 1: 댓글 N -> 양쪽 다 걸고 mappedBy와 JoinColumn은 어디다 해야하는지 직접 찾아보고 적용해보고 h2디비에 어떻게 쌓이는지 확인하기

  3. ManyToMany로 구현해보기(@JoinTable 사용)
    -게시글 N: N - 좋아요 - N:N 댓글
    *추가 - oneToMany - ManyToOne으로 풀어내보기(게시글-좋아요-댓글)
    좋아요 구현시 N 게시글 N좋아요에 대해서 중간엔티티를 받아서 생성한다.
    매니투 매니를 쓰면 객체지향적으로 수정하기 어렵다. !!

  1. Cascade , ophanremoval 사용하면서 엔티티가 어떻게 저장,삭제되는지 직접 확인해보기
    **** ophanremoval을 사용하면 내가 사용한 하위객체를 삭제하고 싶을때!!
    All = post를 했을때 comment를 빈객체를 생성한다.
    commentRepository를 안쓰고도 삭제가능하다.
    post.getcommentlist().get(i).reomve()
    참고 : https://modimodi.tistory.com/22
  • 부모 엔티티 삭제
    CascadeType.REMOVE와 orphanRemoval = true는 부모 엔티티를 삭제하면 자식 엔티티도 삭제한다.
  • 부모 엔티티에서 자식 엔티티 제거
    CascadeType.REMOVE는 자식 엔티티가 그대로 남아있는 반면, orphanRemoval = true는 자식 엔티티를 제거한다.
  1. @id @GenerateValue(strategy = GenerationType.IDENTITY) , AUTO의 차이점 직접 해보면서 경험해보기
    Auto
    전체 게시를을 id를 달다.
    identity(게시물 댓글 각각 id) // 이게더 좋음.
  1. 회원 엔티티에 CITY,STREET,ZIPCODE는 (주소관련)은 별도의 클래스생성하여 @Embbeded , @Embeddable로 추가해보기

    한객체의 여러정보를 넣고 싶을때
    db에 하나 저장하는데 2개의 열이 생성.

  1. 게시글의 카테고리를 @Enumerated 로 해보기
    저장할때 EnumType.ORDINAL,STRING 에 따른 차이점 알아보기
    -> 게시글 저장할때 카테고리로 숫자(0,1)로 넣어줘서 저장해보기, GAME,MUSIC처럼 Enum으로 넣어서 save해보기
    카테고리, 남녀 , 중간에 변경불가 .. 그안에 있는 값만 사용할 수 있다.
    db에
    Ordinal는 id가 들어감
    String으로 하면 앞의 String이 들어감..
  1. @transient 를 사용하여서 게시글의 댓글 수(size)를 객체에 저장해보기(DB저장 X)
    -> db에 저장할 정도까지는 아닌데
    객체지향적으로 설계를 하기 위함 ex)조회수,, 하트수 등등
  1. LAZY로딩 , EAGER로딩 사용해서 불러와보기
    게시글-댓글 연관관계시 LAZY했을 떄 게시글만 불러왔을 때 쿼리가 어떻게 나가는지
    -> 댓글을 불러오려면 어떻게 해야하는지
    게시글-댓글 연관관계시 EAGER했을 떄 게시글만 불러왔을 때 쿼리가 어떻게 나가는지
    즉시로딩은 연관관계를 다불러옴
    지연로딩은 필요한거 한게만 불러옴..

    Eager / N+1 문제

심화주차와 같이 테스트케이스로 작성하셔도 무방합니다. 어렵다면 서비스단에 system out 프린트문으로 구현


깃헙 액션에 대해서 알아보자!!
https://bcp0109.tistory.com/363


220812

@NoArgsConstructor
파라미터가 없는 기본 생성자를 생성해준다.
이 경우 초기값 세팅이 필요한 final 변수가 있을 경우 컴파일 에러가 발생함으로 주의한다.
@NoArgsConstructor(force=true) 를 사용하면 null, 0 등 기본 값으로 초기화 된다.
Board board = new Board();
출처: https://goyunji.tistory.com/98 [개발하는 농부:티스토리]

@AllArgsConstructor
모든 필드 값을 파라미터로 받는 생성자를 만듦

@RequiredArgsConstructor
final이나 @NonNull인 필드 값만 파라미터로 받는 생성자 만듦


static
정적이란 뜻이다. 메서드에 붙이게 되면 이 메서드는 정적 메서드임을 나타낸다. static으로 선언하게 되는 경우 자바가 컴파일 되는 시점에 정의가 된다. 그리고 static 요소를 static이 아닌 요소에서 호출하는 것은 불가능하다.

특히나 main 메서드처럼 프로그램의 시작점이 되는 요소는 객체를 생성하지 않아도 작업을 수행해야 하기 떄문에 static이어야 한다.


220813

기억보단 기록을.

  1. S3 이미지 업로드만 마치면 나머지는 완성가능하다!!

AWS S3

  • 파일 저장소 / 권한에서 사용자 접근권한을 설정할 수 있다.

AWS IAM (Identity and Access Management)

  • 간단히 사용자, 역할을 관리하는 서비스

AWS SDK ( Software Development Kit)

-프로그래밍을 돕는 라이브러리라고 생각하시면 됩니다.
AWS SDK를 이용하시면 개발과 연동해서 AWS를 사용, git bash를 통해 access 키 및 시크릿 키를 기입하고 region 선택.


multipart/form-data (오늘의 중요 포인트!)

모든 문자를 인코딩하지 않음을 명시한다.
이 방식은

요소가 파일이나 이미지를 서버로 전송할 때 주로 사용한다.


S3 업로드 하기
https://devlog-wjdrbs96.tistory.com/323
https://www.sunny-son.space/spring/Springboot%EB%A1%9C%20S3%20%ED%8C%8C%EC%9D%BC%20%EC%97%85%EB%A1%9C%EB%93%9C/


405 에러를 겪었을때
@Getter를 안넣어서 ! ㅠㅠ
https://zzang9ha.tistory.com/320


Security에 대해서 알아보자 !!
SecurityConfig에서 Annotation 검색 실시하라!
1. 들어올때 config를 거친다.
2. CORS공격, 받은토큰을 자동으로 획득하여 사용자인척한다.
3. CSRF토큰. (요즘사용안함)
4. 레포에 접근시 무조건 Tranjactional을 붙여라!


S3 Warning내용:
No content length specified for stream data.


orElse 메소느는 값이 null 이거나 null이 아니어도 실행된다.

orElseGet은 해당값이 null일때만 실행한다.

profile
HelloWorld에서 RealWorld로

0개의 댓글