• 기간 10월 014일(금)~10월 21일(목)
  • 스프링 cors

CORS란?

 

CORS는 Cross-Origin Resource Sharing의 약자로 직역하면 "교차 출처 리소스 공유" 이다.

 

좀 더 쉽게 말하면 동일한 출처가 아닌 다른 출처에서 데이터를 주고 받는 것을 허용하는 정책이다.

 

출처:https://developer.mozilla.org/ko/docs/Web/HTTP/CORS

 

교차 출처 리소스 공유 (CORS) - HTTP | MDN

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

developer.mozilla.org

 

Same Origin Policy(동일 출처 정책)

동일한 출처는 URL 중에서도 프로토콜, 도메인 주소, 포트 번호가 같은 것을 의미한다.

출처:https://ko.wikipedia.org/wiki/%EB%8F%99%EC%9D%BC-%EC%B6%9C%EC%B2%98_%EC%A0%95%EC%B1%85

 

동일-출처 정책 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 동일-출처 정책(영어: same-origin policy)는 웹 애플리케이션의 중요한 보안 모델이다. 동일-출처 정책은 주로 스크립트로부터의 데이터 접근에 적용된다. 즉, 일치

ko.wikipedia.org

같은 origin을 가진 경우에만 통신을 허용하여 웹 브라우저에서는 다른 origin을 가진 서버에 API를 호출할려고 하면 요청 자체를 막아버린다.

Simple Request (단순 요청)

 

단순 요청은 위의 예비 요청과는 달리 서버에 바로 본격적으로 요청을 시작한다.

 

그렇다면 미리 확인하지도 않고 어떻게 안전하게 리소스를 요청하는 것일까?

 

그 방법은 조금 까다로운 조건들을 거는 것이다.

 

1. Access-Control-Request-Method를 통해 요청할 때 메서드는 HTTP 메서드가 아닌 GET,HEAD,POST 중 하나여야 한다.

 

2. Access-Control-Request-Headers 통해 요청을 보낼 때 Accept  Accept-Language,Content-Language, Content-TypeDPR, Downlink, Save-Data, Viewport-Width 중 하나여야 한다.

 

3. Content-Type을 사용할 경우 application/x-www-form-urlencoded, multipart/form-data, text/plain 중 하나여야 한다.

 

 

스프링에서  Cors해결 방법

@Configuration

  public class CorsConfig {

    @Bean

    public CorsFilter corsFilter(){

         UrlBasedCorsConfigurationSource source =new UrlBasedCorsConfigurationSource();

         CorsConfiguration config = new CorsConfiguration();

         config.setAllowCredentials(true);// 내서버가 응답을 할 떄 json을 자바스크립트에서 처리할 수 있게 할지를 설정하는 것 

          config.addAllowedOrigin("http://localhost:3000");//포트 ip의 응답을 허용하겠다.

          config.addAllowedHeader("*");//모든 header의 응답을 허용하겠다.

          config.addAllowedMethod("*");//모든 post,get,putmdelete,patch 요청울 허용하겠다.

          config.addExposedHeader("*");

          source.registerCorsConfiguration("/api/**",config);

                             return new CorsFilter(source);

           }

}

 

클레스 하나 만들어주고 Security에 필터체인 등록을 해주면 아주 잘 실행이 된다!

 

 

 

배운것

백엔드에서 기능구현후 배포하를 하고 프론트에게 주소를 알려주었는데 데이터를 받아오는 도중 proxy오류가 떠서 코스에 대해서 찾아보았고, 예전에도 혼자서 프론트엔드랑 포트 다르게 연동했을때도 이런 오류가 있었기 때문에 무슨 이유인지 바로 알 수 있어서  오류해결방법을 찾는 것은 어렵지 않았다.

ec2에서 보안 규약에 포트 열어주고 해봤지만 프론트 쪽에서 데이터를 볼수 없어서 더 찾아본 결과, 예전에 코스 찾아서 프로젝트에 적용시킨 적이 있어 그걸 가져와 적용시키니 잘 데이터가 넘어가고 프론트쪽에서도 데이터를 잘 받았다.

아쉬운점/느낀점

지금은 프론트와 백앤드 끼리 협업을 하면서 프로젝트를 진행중이다. 처음 같이 협업을 하는 과정이라 어떻게 해야할지 처음에는 어려웠지만 지금은 프론트 분들과 소통을 하면서 안되는 곳을 같이 찾아보고 같이 해결해 나가고 있다.

'항해 99(9기) > 항해 일일' 카테고리의 다른 글

항해 99 36일차  (0) 2022.10.25
항해 99 35일차  (0) 2022.10.24
항해 99 33일차  (0) 2022.10.21
항해 99 32일차  (0) 2022.10.20
항해 99 31일차  (0) 2022.10.19

Mono와 Flux

 

Spring Webflux에서 사용하는 reactive library가 Reactor이고 Reactor가 Reactive Streams의 구현체입니다.

Flux와 Mono는 Reactor 객체이며, 차이점은 발행하는 데이터 갯수입니다.

 

  • Flux : 0 ~ N 개의 데이터 전달
  • Mono : 0 ~ 1 개의 데이터 전달

보통 여러 스트림을 하나의 결과를 모아줄 때 Mono를, 각각의 Mono를 합쳐서 하나의 여러 개의 값을 여러개의 값을 처리할 떄 Flux를 사용합니다.

그런데 Flux도 0~1개의 데이터 전달이 가능한데, 굳이 한개까지만 데이터를 처리할 수 있는 Mono라는 타입이 필요할까요? 데이터 설계를 할때 결과가 없거나 하나의 결과값만 받는 것이 명백한 경우,  List나 배열을 사용하지 않는 것처럼, Multi Result가 아닌 하나의 결과셋만 받게 될 경우에는 불필요하게 Flux를 사용하지 않고 Mono를 사용하게 됩니다. 

 

Spring Webflux에서 사용하는 reactive library가 Reactor이고 Reactor가 Reactive Streams의 구현체입니다.

Flux와 Mono는 Reactor 객체이며, 차이점은 발행하는 데이터 갯수입니다.

 

  • Flux : 0 ~ N 개의 데이터 전달
  • Mono : 0 ~ 1 개의 데이터 전달

보통 여러 스트림을 하나의 결과를 모아줄 때 Mono를, 각각의 Mono를 합쳐서 하나의 여러 개의 값을 여러개의 값을 처리할 떄 Flux를 사용합니다.

그런데 Flux도 0~1개의 데이터 전달이 가능한데, 굳이 한개까지만 데이터를 처리할 수 있는 Mono라는 타입이 필요할까요? 데이터 설계를 할때 결과가 없거나 하나의 결과값만 받는 것이 명백한 경우,  List나 배열을 사용하지 않는 것처럼, Multi Result가 아닌 하나의 결과셋만 받게 될 경우에는 불필요하게 Flux를 사용하지 않고 Mono를 사용하게 됩니다. 

'항해 99(9기) > 항해 일일' 카테고리의 다른 글

항해 99 35일차  (0) 2022.10.24
항해 99(9기) 5주차 WTL 회고  (0) 2022.10.23
항해 99 32일차  (0) 2022.10.20
항해 99 31일차  (0) 2022.10.19
항해 99 30일차  (0) 2022.10.18

Querydsl

셋팅

buildscript {
   ext {
      queryDslVersion = "5.0.0"
   }
}
plugins {
   id 'org.springframework.boot' version '2.7.5'
   id 'io.spring.dependency-management' version '1.0.15.RELEASE'
   //querydsl 추가
   id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
   id 'java'
}

group = 'com.prac'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
   compileOnly {
      extendsFrom annotationProcessor
   }
}

repositories {
   mavenCentral()
}

dependencies {
   implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
   implementation 'org.springframework.boot:spring-boot-starter-web'
   compileOnly 'org.projectlombok:lombok'
   developmentOnly 'org.springframework.boot:spring-boot-devtools'
   implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.8'
   // QueryDSL
   implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
   implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
   implementation "com.querydsl:querydsl-core:${queryDslVersion}" // 한개 더 추가!

   runtimeOnly 'mysql:mysql-connector-java'
   annotationProcessor 'org.projectlombok:lombok'
   testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
   useJUnitPlatform()
}

//querydsl 추가 시작
def querydslDir = "$buildDir/generated/querydsl"

querydsl {
   jpa = true
   querydslSourcesDir = querydslDir
}
sourceSets {
   main.java.srcDir querydslDir
}
compileQuerydsl{
   options.annotationProcessorPath = configurations.querydsl
}

configurations {
   compileOnly {
      extendsFrom annotationProcessor
   }
   querydsl.extendsFrom compileClasspath
}
//querydsl 추가 끝

또한 우상단의 gradle 탭에서 Tasks -> other -> compileQuerydsl을 누르면

 

 

build/generated/.../QHello 객체가 생성된 것을 확인할 수 있다. 이것은 상단 환경설정 부분에서 

 

def querydslDir = "$buildDir/generated/querydsl"

 

라고 Q객체가 생성되는 루트를 설정해줬기 때문이다.

 

Querydsl 사용하는 방법

// 기존 방법 1. 
public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom {} 


// 기존 방법2
public class MemberRepositoryCustom extends QuerydslRepositorySupport {}

// 추천하는 방법
@Repository
@RequiredArgsConstructor 
public class MemberRepositoryCustom {
    private final JpaQueryFactory queryFactory; // 물론 이를 위해서는 빈으로 등록을 해줘야 한다. 
}

JpaQueryFactory 빈으로 등록하는 방법

@Configuration
public class QuerydslConfiguration {
    @Autowired
    EntityManager em;

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
       return new JPAQueryFactory(em);
    }
}

 

'항해 99(9기) > 항해 일일' 카테고리의 다른 글

항해 99(9기) 5주차 WTL 회고  (0) 2022.10.23
항해 99 33일차  (0) 2022.10.21
항해 99 31일차  (0) 2022.10.19
항해 99 30일차  (0) 2022.10.18
항해 99 29일차  (0) 2022.10.17

SPRING 5.0 을 이용한 채팅 서버 만들어 보기

 

기존에 사용하던 JPA로 하고 싶어서 이것저것 셋팅해보다가 안되서 포기했지만 클론코딩인 만큼 여러가지 찾아본 거 기입해보았다.

Spring WebFlux

기존에 사용하던 Spring MVC 와 별개로 reactive 하게 요청을 처리할 수 있도록 Spring 5 에서 추가된 모듈이다.

 

R2DBC

Spring Framework 에서 database 연결은 동기로 사용하던 것을 비동기로 요청을 처리할 수 있도록 지원해주는 모듈이다. 현재는 데이터베이스에 따라서 지원하는게 각각 다르다.

 

차이점

                                 SQL 데이터베이스                                            NoSQL 데이터베이스

데이터 스토리지 모델 고정 행과 열이 있는 테이블 문서: JSON 문서, 키-값: 키-값 쌍, 와이드 열: 행과 동적 열이 있는 테이블, 그래프: 노드 및 가장자리
개발 연혁 데이터 중복을 줄이는 데 중점을 둔 1970년대에 개발 2000년대 후반에 개발되어 민첩한 및 DevOps 관행에 따라 확장과 신속한 애플리케이션 변경을 가능하게 합니다.
예제 Oracle, MySQL, Microsoft SQL Server 및 PostgreSQL 문서: MongoDB 및 CouchDB, 키-값: Redis and DynamoDB, 와이드 컬럼: 카산드라와 HBase, 그래프: Neo4j 및 Amazon Neptune
기본 목적 범용 문서: 범용, 키-값: 간단한 조회 쿼리로 대량의 데이터, 와이드 컬럼: 예측 가능한 쿼리 패턴을 가진 대량의 데이터, 그래프: 연결된 데이터 간의 관계 분석 및 트래버스잉
스키마 딱딱한 유연한
스케일링 수직(더 큰 서버로 확장) 수평(상용 서버 간 확장)
다중 기록 ACID 거래 지원 대부분은 다중 레코드 ACID 트랜잭션을 지원하지 않습니다. 그러나 MongoDB와 같은 일부는 그렇게합니다.
조인 일반적으로 필수 일반적으로 필요하지 않음
데이터-객체 매핑 ORM(객체-관계형 매핑) 필요 많은 사람들이 ORM을 필요로하지 않습니다. MongoDB 문서는 가장 널리 사용되는 프로그래밍 언어의 데이터 구조에 직접 매핑됩니다.

 

Netty

네티는 이벤트를 Inbound 이벤트, Outbound 이벤트로 구분한다.

클라이언트로 부터 데이터 수신할 때 발생하는 이벤트에 관심이 있다면, Inbound 이벤트 중 하나인 '데이터 수신 이벤트'를 담당하는 메서드에 원하는 로직을 넣으면 된다.

네티는 기본적으로, 적절한 추상화 모델을 제공하여 개발자가 간단한 코드작성만으로 안정적이고 빠른 네트워크 어플리케이션을 개발할 수 있게 도와준다.

 

웹소켓과 SSE(Server-Sent-Event)에 차이점

 

Socket과 SSE에 가장 큰 차이점을 하나 말해보라고 한다면 Socket은 양방향(bidirectional)으로 데이터를 주고 받을 수 있지만 SSE(Server-Sent-Event)를 사용하게 되면 클라이언트는 데이터를 받을 수만(mono-directional) 있게 됩니다. 그러니까 어떤 기능이 필요한지에 따라서 뭐를 사용할지 결정하면 된다. 

웹소켓과 SSE에 가장 큰 차이점은 통신 방향이다.!

  Socket Server-Sent-Event
브라우저 지원 대부분 브라우저에서 지원  대부분 모던 브라우저 지원(polyfills 가능)
통신 방향 양방향 일방향(서버에서 클라이언트로)
리얼타임 Yes Yes
데이터 형태 Binary, UTF-8 UTF-8
자동 재접속 No Yes(3초마다 제시도)
최대 동시 접속 수 브라우저 연결 한도는 없지만 서버 셋업에 따라 다름  HTTP를 통해서 할 때는 브라우저당 6개 까지 가능 / HTTP2로는 100개가 기본
프로토콜 websocket HTTP
베터리 소모량 작음
Firewall 친화적 Nope Yes

 

import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.data.mongodb.repository.Tailable;
import reactor.core.publisher.Flux;

public interface ChatRepository extends ReactiveMongoRepository<Chat,String> {

    @Tailable // 커서를 안닫고 계속 유지한다.
    @Query("{sender:?0,receiver:?1}") // MongoDB 문법
    Flux<Chat> mFindBySender(String sender, String receiver); // Flux(흐름) response를 유지하면서 데이터를 계속 흘려보내기
}

 

일반적인 Http 프로토콜을 사용하면 예를들어 데이터가 1,2,3 건 있을때 이것들을 한번에 모아 처리한다.


하지만 채팅은 이렇게 하면 안되고 데이터가 요청될때마다 응답해야하므로 SSE 프로토콜을 사용한다.

 

 

@Tailable은 데이터를 하나 보낸 후에 닫는게 아니라 계속 커서를 유지해서 데이터가 들어오면 받게 한다.

 

Flux(흐름 )는 데이터를 한번만 받고 닫는게 아니라 들어오는 대로 계속 흘려보내 response를 유지한다.

 

 

'항해 99(9기) > 항해 일일' 카테고리의 다른 글

항해 99 33일차  (0) 2022.10.21
항해 99 32일차  (0) 2022.10.20
항해 99 30일차  (0) 2022.10.18
항해 99 29일차  (0) 2022.10.17
항해 99 25일차  (0) 2022.10.13

CI(Continuous Integration) 지속적인 통합/CD(Continuous Delivery)지속적인 제공

 

CI(Continuous Integration) 지속적인 통합

1.버그수정이나 새로만드는 기능들이 지속적으로 main repository 주기적으로 build되고   test 되서 merge 되는 것을 말함 .

      주기적으로 빈번하게 머지를 해야하는데 그로 인한 머지 충돌을 해결하는데 시간을 많이 쓴다.그래서 최대한 작은 단위로 나누어서 개발하고 통합해나가는 것이 중요하다.

 

2. 통합을 위한 단계(빌드,테스트,머지)의 자동화

    주기적으로 머지된 코드의 변경사항이 자동으로 빌드가되어서 코드변경사항 이후에도 빌드가 성공적으로 되는지 확인이 되어야 하고 , 새로 추가된 코드의 변경사항 뿐만아니라 기존의 코드에 버그사항이 없는지 자동으로 테스트가 되어야 한다.

    자동으로 추가된 스크립트를 통해 추가된 코드와 함게 리파지토리에 빌드가 되고 빌드가 된다면 UNIT TEST 또는 INTEGRATION TEST 등등 여러가지 테스트들도 실행이 된다.

 

   장점- 주기적으로 머지되기 때문에 머지 충돌을 피할 수 있어서 개발 생산성을 높일 수 있고 머지된 코드들은 자동으로 빌드되고 테스트 되기 때문에 코드의 결함이나 문제점이 빠르게 발견되고 처리할 수 있다. 왜냐하면 주기적으로 머지를 하기 때문에 코드의 변경사항이 작아서 문제의 상황이 작기 때문에 고립된 아주 작은 문제까지 발견할 수 있다. 최종적으로 이런사항들을 통해 최고의 퀄리티된 코드를 짤 수 있다.

 

CD(Continuous Delivery)지속적인 제공

1. CI에서 일어난 작업들이 Prepare Release과정을 거치고 직접 개발자나 검증팀이 DEPLOY RELEASE 과정을 거치고 최종적으로 사용자에게 배포해도 된 상태가 되면 수동적으로 배포.

 

CD(Continuos Deployment)지속적인 배포

1. 딜리버리와 살짝 비슷하지만 수동이아닌 자동으로 배포

 

 

CODE->BUILD->TEST-RELEASE->DEPLOY

 

CICD의 툴은 JENKINS , BUILDKITE, GitHub Actions, Gitlab CI/CD, Bitbucket Pipelines 등등......

'항해 99(9기) > 항해 일일' 카테고리의 다른 글

항해 99 32일차  (0) 2022.10.20
항해 99 31일차  (0) 2022.10.19
항해 99 29일차  (0) 2022.10.17
항해 99 25일차  (0) 2022.10.13
항해 99 23일차  (0) 2022.10.11

JPA CascadeType 종류

 

1. 배경

- JPA 개인 프로젝트를 진행하던 중, 게시판과 파일, 댓글에서 @OneToMany - @ManyToOne의 관계에서 영속성 관리에서 문제가 발생되었으며, 영속성에서 참조된 객체를 지워주지 않았기 때문에 발생하였다. 더 정확한 내용은 알아볼 예정이다.

 

Entity의 상태

  • Transient : JPA가 모르는 상태 (단순 객체 생성)
  • Persistent : JPA가 관리중인 상태 (1차 캐시, Dirty Checking, Write Behind, ...)
  • Detached : JPA가 더이상 관리하지 않는 상태
  • Removed : JPA가 관리하긴 하지만 삭제하기로 한 상태

 

 2. 내용

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

즉시 로딩 지연로딩

JPA에서는 데이터를 조회할 때 즉시 로딩(EAGER)과 지연 로딩(LAZY) 두 가지 방식이 있다. 이 두 가지 방식을 간단하게 설명하면 즉시 로딩은 데이터를 조회할 때 연관된 데이터까지 한 번에 불러오는 것이고, 지연 로딩은 필요한 시점에 연관된 데이터를 불러오는 것이라고 할 수 있다.

즉시 로딩(EAGER)

  • @xxToxx(fetch = fetchType.EAGER)

다음과 같이 Member 엔티티와 Team 엔티티가 N:1 매핑으로 관계를 맺고 있다.

 

지연 로딩(LAZY)

  • @xxToxx(fetch = fetchType.LAZY)

아래와 같이 지연 로딩으로 설정하고 Member를 조회해보면 즉시 로딩 방식과 달리 Team을 조회하는 쿼리가 생성되지 않고 Member를 조회하는 쿼리만 나가고, 실제로 팀을 사용하는 시점에 Team을 조회하는 쿼리가 나간다.

'항해 99(9기) > 항해 일일' 카테고리의 다른 글

항해 99 31일차  (0) 2022.10.19
항해 99 30일차  (0) 2022.10.18
항해 99 25일차  (0) 2022.10.13
항해 99 23일차  (0) 2022.10.11
항해 99 20일차  (0) 2022.10.08

+ Recent posts