반응형

MSI MAG323UPF 게이밍 4K IPS HDR600 무결점 UHD 와이드 32인치 구매 후기

 

 

고해상도 및 주사율: MSI MAG323UPF는 32인치 크기의 4K 해상도와 160Hz 주사율을 지원하며,

1ms 응답 속도(오버드라이브 기준)로 빠른 반응이 필요한 게임에 적합합니다.

32인치와 4K라는 점에서 선택했습니다.

 

넓은 색역: MSI MAG323UPF는 100% sRGB와 96~98% DCI-P3를 지원해 생생한 색감을 제공합니다.

특히, 색보정을 통해 색 정확도도 대폭 개선할 수 있습니다.

 

연결성: MSI MAG323UPF는 DisplayPort 1.4, HDMI 2.1, USB-C(90W PD 지원),

USB 허브 등 다수의 포트를 갖춰 다양한 기기와 호환이 가능합니다.

DP포트 연결을 선호하고, USB허브가 간편하여 선택했습니다.

 

HDR 600 인증: MSI MAG323UPF는 최대 600니트의 밝기로 HDR 콘텐츠 감상이 가능합니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

MSI MAG323UPF 광점은 없고, 눈에 띄는 흑점은 없어서 양품을 받은 것 같습니다. 

 

 

반응형
반응형

2024년 정보통신기사 필기 후기

 

 2024년 10월 15일, 가락시장역 IT벤처타워에서 정보통신기사를 보고 왔습니다.

CBT 시험 마지막에 제출을 누르면 각 과목 점수와 평균이 나와, 합불합을 알 수 있습니다.
시험 직후 나온 결과는 55점 55점 70점 60점 80점으로 합격이었습니다.

 

 

필기 시험 난이도 체감

 

1과목부터 풀이를 시작하면서, CBT 문제와는 전혀 다른 생소한 문제들이 많다는 것을 느꼈습니다.
체감상 CBT와의 연계성은 약 15~20% 정도로 매우 낮았습니다.
물론 CBT 문제를 푸는 것도 중요하지만, 문제와 답을 외우는 방식보다는 이론 학습이 더 중요하다고 느꼈습니다.
다행히 저는 CBT 문제 풀이에만 의존하지 않고, 이론 학습도 함께 병행했기 때문에 합격할 수 있었습니다.

 

 

 

필기 시험 공부방법

 

저는 책을 구매해서 이론학습은 하루 2시간 정도 10일정도 했습니다.

이론 학습을 먼저 한 후, CBT문제를 2022년부터 2023년를 5개의 시험 문제를 3회 반복해서 풀었습니다.

학과가 정보통신공학과라 어느정도 베이스가 있어서 가능했던 것 같습니다.

 

 

 

마무리

 

저 같은 경우, 1과목이 특히 어렵게 느껴졌습니다. 반면 2 ~ 5과목은 이론 학습만으로 충분히 커버할 수 있다고 생각했습니다. 2 ~ 5과목은 겹치는 부분도 많아서 이론을 학습하면 어려움 없이 준비할 수 있었지만, 1과목은 마치 전혀 다른 시험처럼 느껴질 정도로 어려웠습니다.

앞으로 시험을 준비하시는 분들께는 1과목에 집중적으로 학습할 것을 권장드립니다.

반면 2에서 5과목은 이론을 이해하고, 흐름을 파악하면서 공부하면 큰 어려움 없이 대비할 수 있습니다.

특히 1과목의 경우, 난이도가 높기 때문에 시간을 더 많이 투자하면 좋을 것 같네요.
2 ~ 5과목은 이론을 충분히 다지고 나면 문제를 풀 때 자연스럽게 적용할 수 있을 것이므로, 이론 학습을 할 수 있는 방법을 찾아 대비하는 것을 추천드립니다.

반응형
반응형

IPSec(Internet Protocol Security)은 인터넷 프로토콜(IP)에서 데이터를 보호하기 위한 보안 프레임워크입니다.
Layer 3에서 암호화를 제공하며, 인증을 통해 데이터의 기밀성, 무결성, 그리고 송신자의 신원을 보장합니다.

 

 

  • 전송 모드: IP 패킷의 페이로드(데이터)만 암호화.
  • 터널 모드: 전체 IP 패킷을 암호화하여 보안 터널을 형성.

 


터널모드

 

터널 모드에서는 전체 IP 패킷이 암호화되어 원래의 IP 헤더도 숨겨지기 때문에,
암호화된 패킷이 네트워크를 통해 전달되기 위해 새로운 외부 IP 헤더가 추가됩니다.
이 새로운 헤더는 목적지에 도달할 때까지의 경로를 결정하는 데 사용됩니다.
네트워크 라우터들은 이 외부 IP 헤더만 보고 패킷을 라우팅합니다.
목적지에 도착하면, VPN 게이트웨이가 패킷을 복호화하고 원래의 IP 헤더와 데이터를 확인해 최종 목적지로 전달합니다.

 

터널 모드에서는 원본 패킷(원래의 목적지 IP 주소가 포함된 패킷)이 암호화되며,
그 위에 새로운 외부 IP 헤더가 추가됩니다.
이 새로운 헤더의 목적지는 원래 패킷의 목적지가 아닌, VPN 게이트웨이보안 장비입니다.

 

과정 요약:

  1. 암호화: 원본 패킷(헤더와 데이터) 전체가 암호화됨.
  2. 외부 헤더 추가: 새로운 IP 헤더를 추가하여 네트워크에서 라우팅 가능하게 만듦.
  3. 라우팅: 라우터는 새 헤더를 기반으로 패킷을 목적지로 보냄.
  4. 복호화: VPN 게이트웨이에서 복호화 후 원래 목적지로 전달.

이 과정을 통해 암호화된 패킷이 네트워크를 통해 안전하게 목적지까지 도달할 수 있습니다.


IPSec 과정

1. IKE (Internet Key Exchange): 두 장치 간 인증 및 암호화 키 교환을 수행.

2. SA (Security Association): 암호화 및 인증에 대한 보안 매개변수를 설정.
3. SAD (Security Association Database): 설정된 SA가 저장되고, IPSec 통신에 적용될 때 사용됨.
4. ESP(Encapsulating Security Payload) 또는 AH(Authentication Header): 암호화 및 인증을 적용해 트래픽을 보호.
5. 암호화된 패킷이 안전하게 전송되고 복호화됨.

 

 

 

 



1. IKE (Internet Key Exchange)

두 노드간의 인증은 공개 키 암호화 방식(예: 인증서) 또는 사전 공유 키(PSK)를 사용한다.

  • Phase 1 (보안 채널 설정):
    • 목적: 인증과 키 교환을 통해 안전한 보안 채널 생성.
    • 결과: IKE SA 설정, 이후 IKE 메시지는 보안 채널을 통해 보호됨.
  • Phase 2 (IPSec SA 협상):
    • 목적: 실제 데이터 트래픽을 보호할 SA 설정.
    • 결과: IPSec SA가 설정되고, IPSec 트래픽이 이 SA를 통해 암호화 및 인증됨.



2. SA (Security Association)

두 장치 간 보안 매개변수(암호화 알고리즘, 인증 방법, 키 등)에 대한 합의를 의미합니다.



3.SAD
SA는 SAD(Security Association Database)에 저장

 



4. AH(Authentication Header), ESP(Encapsulating Security Payload)


 AH(Authentication Header)

  1. 해시 값 생성: 송신자가 IP 패킷(헤더 및 데이터)을 전송할 때, 해시 함수(예: HMAC-SHA1)를 이용해 패킷의 무결성을 나타내는 해시 값을 생성합니다. 이 해시 값은 인증 키와 함께 패킷에 포함됩니다.
  2. 수신자가 해시 값 계산: 수신자는 동일한 해시 함수를 사용해 패킷의 해시 값을 다시 계산합니다.
  3. 해시 값 비교: 수신자가 계산한 해시 값과 송신자가 보낸 해시 값을 비교하여 무결성을 확인합니다. 값이 같으면 패킷이 전송 중 변경되지 않았다는 것을 보장합니다.

해시값을 통해 무결성을 검증하기 떄문에, 해시 함수를 이전에 교환하는 과정을 거쳤어야 한다.
해시 함수는 노출되면 안되므로 IKE (Internet Key Exchange) 과정을 거친다.

 


ESP(Encapsulating Security Payload)

  • ESP 헤더: 패킷의 암호화된 페이로드 전에 위치.
  • ESP 트레일러: 암호화된 페이로드 뒤에 위치해 패딩 및 인증 데이터 포함.
  • ESP 인증 데이터: 선택적으로 패킷 무결성 확인.

 


5. 통신

 

 

 

 

 

 

 

 

 

 

 

반응형

'CS > 네트워크' 카테고리의 다른 글

Blocking / Non Blocking, Synchronous / Asynchronous  (0) 2023.10.03
[TCP/IP MODEL]  (0) 2022.08.31
반응형

 

MongoDB는 mysql과는 다르게 Database를 만들고, User를 생성한다.

 

DB생성

use chat

 

user생성
db.createUser({
  user: "root",
  pwd: "root",
  roles: [ "readWrite", "dbAdmin" ]
})

- 유저와 채팅하기 (view - 도서 donation) "채팅하기 버튼"을 눌렀을 시
1. [be] 채팅방 생성
2. [be] 웹소켓 연결
3. [be] 채팅방 구독
4. [fe] 채팅방으로 이동

- 하단 "Chat" 누르면
1. [be] 웹소켓 연결
2. [fe] 채팅방 리스트 이동
3. [be] 채팅방 리스트 조회 내려주기

- "유저와 채팅"을 눌렀을 시
1. [be] 채팅방 구독
2. [be] 채팅 기록 가져오기

- 채팅방 나갔을 시 작업
1. [be] 채팅방 구독 해제
- 하단 다른 component 로 이동 시
1. [be] 웹소켓 해제
반응형
반응형

현재 중고책 기부 프로젝트를 진행하고 있습니다.
유저들끼리 중고책 기부를 하기 위해 채팅이 필요하며,
다수가 참여하는 유저 채팅보다는 일대일 채팅만 필요한 상황입니다.

 

일대일 채팅만 구현해야 한다고 가정

 

user1이 user2 에게 채팅 신청을 한다.

user2는 user1이 채팅 신청한 것을 알아야 한다.

 

user1 user2의 채팅방이 데이터 베이스에 저장된다.

user1, user2는 각각 해당 채팅방을 검색할 수 있어야 한다.

어떻게 저장을 하는 것이 효율적일까?

 

해당 채팅방에 채팅을 하면, 채팅을 한 사람이 누군지만 기록하면 된다.

채팅 기록은 채팅방 id 와 연관관계를 형성하고 있기 때문이다.

 

 

기본적인 스키마 디자인

 

ChatRoom: 
chatRoomId (PK)
participant1 (user1의 ID)
participant2 (user2의 ID)


Message: 
messageId (PK)
chatRoomId (FK, ChatRoom 참조)
senderId (메시지를 보낸 사용자의 ID)

content (메시지 내용)
timestamp (메시지가 보내진 시간)

 

고민했던 것

participant1 (user1의 ID)
participant2 (user2의 ID)

순서를 어떻게 처리하는게 효율적일까? 중복을 방지해야 할 수도 있다.

 

1. nickname 정렬을 한다.

nickname을 바로 알 수 있지만, member-id를 통해 nickname을 받아와야 한다.

 

2. member-id 정렬을 한다.

member-id 가 RequestHeader를 통해 들어오기 때문에 바로 조회할 수 있다.

닉네임은 알 수 없다.

 

중복방지는 필요가 없었다. 유저끼리 여러 책을 교환하는 상황이 나올 수 있다.

 

 

해결방법

nickname, member-id 둘다 message에 저장하기로 했다.

message 데이터를 구별하기 위해 member 서버에 다시 요청을 계속 보내는 것이 부담스럽다.

DB저장 공간을 희생시키며 요청 횟수를 줄이기로 했다.

 

Message: 
messageId (PK)
chatRoomId (FK, ChatRoom 참조)
senderId (메시지를 보낸 사용자의 ID)

senderNickname (메시지를 보낸 사용자의 닉네임) 추가

content (메시지 내용)
timestamp (메시지가 보내진 시간)

 

 

User Flow

사용자가 자신이 참여하고 있는 채팅방을 본다.

ChatRoom - participant1 (user1의 ID), participant2 (user2의 ID) 둘중 하나라도 매칭되면 해당 채팅방을 보여준다.

 

사용자가 채팅방 하나를 누를경우 해당 채팅방 채팅기록을 보여준다.

채팅 기록들은 senderId가 자신이라면 오른쪽으로 배치, 아니라면 왼쪽으로 배치

 

 

추가적인 고려 상황

채팅 기록은 무조건 실시간으로 구현해야 한다.

하지만, 채팅방 리스트는 실시간으로 구현해야 할까?
알림이 오면 채팅방 리스트를 볼텐데, 그때 http통신을 다시 하지 않을까?

사용자 편의성을 위해 실시간으로 채팅방 리스트까지도 실시간으로 구현하는게 좋을 것 같다.

그리고 채팅방마다 마지막 채팅 내역 또한 실시간 기능이다.

읽지 않은 채팅 개수 까지는 필요하지 않을 것 같다. (추후 고려 사항)

 

 

WebSocket을 사용할까? SSE를 사용할까? 이 부분도 기술 스택을 무엇을 이용해야 할지 생각해봐야 한다.

> WebSocket을 사용하기로 했다.


채팅방 리스트까지 실시간으로 구현하려면, WebSocket을 채팅방을 클릭하면 WebSocket 통신을 열어야 하고,
채팅 기록만 실시간으로 구현한다면, 채팅방을 누른 이후부터 WebSocket 통신을 열어야 한다.

> 사용자 편의성을 위해 채팅방 리스트까지 실시간으로 구현하기로 했다.
   채팅 위젯을 열면, ws 연결

 

구현해야 할 실시간 기능들

> 채팅 방 추가, 채팅 방의 마지막 채팅, 채팅 내부 기록

반응형
반응형

Data

Docker에서 볼륨을 지정할 때, -v 옵션 뒤에 경로가 아닌 단순한 문자열(예: myvolume)을 지정하면, 

Docker는 이를 네임드 볼륨(named volume)으로 간주합니다. 반면에 슬래시(/)를 포함한 경로 형태(예: /path/on/host:/path/in/container)를 지정하면 바인드 마운트(bind mount)로 간주합니다.

예를 들면:

네임드 볼륨:
docker run -v myvolume:/path/in/container my_image
위의 명령어는 myvolume이라는 네임드 볼륨을 컨테이너의 /path/in/container 위치에 마운트합니다.

바인드 마운트:
docker run -v /path/on/host:/path/in/container my_image
위의 명령어는 호스트의 /path/on/host 디렉토리를 컨테이너의 /path/in/container 위치에 마운트합니다.

결론적으로, 슬래시(/)가 없는 단순한 문자열을 지정하면 Docker는 이를 네임드 볼륨으로 인식합니다.

 

바인드 마운트


호스트의 특정 디렉토리를 컨테이너에 마운트합니다.
-v 왼쪽경로디렉토리(로컬):오른쪽 경로디렉토리(컨테이너)
이 명령어를 사용하여 호스트의 디렉토리를 컨테이너에 마운트합니다.
주의점으로 bind mount가 컨테이너 내부의 폴더에 우선시 되므로, 기존에 컨테이너 안에 있던 데이터가 덮어쓰일 수 있습니다.
로컬 디렉토리가 우선되며, 로컬을 변경하면 컨테이너에 즉시 반영

 

도커 파일 캐싱

Docker는 이미지를 빌드할 때 효율적으로 처리하기 위해 캐싱 메커니즘이 있습니다.

Dockerfile의 각 줄은 독립적인 레이어로 생성되며, 이전에 빌드했을 때 변경되지 않은 레이어는 캐싱되어 재사용됩니다.

이 Dockerfile을 처음 빌드할 때, 모든 단계가 실행되어 새 이미지가 생성됩니다. 

하지만 COPY 단계에서 소스 코드에 변경사항이 발생하면, 이후의 모든 단계는 캐시를 사용하지 않고 다시 실행됩니다.

캐싱 전략
변경 빈도가 높은 단계는 Dockerfile의 하단에 위치시키는 것이 좋습니다. 

그렇게 하면 변경 빈도가 낮은 단계는 최대한 캐싱을 활용할 수 있습니다.

예를 들어, 애플리케이션의 종속성을 설치하는 단계와 소스 코드를 복사하는 단계가 있다면, 

종속성 설치 단계를 먼저 위치시키고 소스 코드 복사 단계를 그 이후에 위치시키는 것이 좋습니다. 

그러면 종속성 변경이 없는 경우에는 캐싱을 효율적으로 활용할 수 있습니다.

 

도커 컴포즈의 목적

다중 컨테이너 관리: docker-compose는 여러 서비스로 구성된 애플리케이션을

각 서비스의 이미지, 환경 변수, 포트, 볼륨 등을 설정

의존성 관리: 서비스 간의 의존 관계를 정의

예를 들어, 백엔드 서비스가 데이터베이스 서비스를 필요로 할 경우,

docker-compose를 사용하여 백엔드가 데이터베이스가 준비된 후에 시작

일관된 환경: 개발, 테스팅, 스테이징, 프로덕션 등 다양한 환경에서

동일한 docker-compose.yml 파일을 사용하여 애플리케이션을 실행


한 번의 명령으로 서비스 관리: 

docker-compose up 명령을 사용하여 모든 서비스를 시작하거나 

docker-compose down 명령을 사용하여 모든 서비스를 종료

이미지 다운로드: docker-compose를 사용하면 docker-compose.yml에 정의된 모든 이미지를 

한 번의 명령으로 다운로드 (docker-compose pull). 

 

배포 순서: ci.yml build -> docker-compose.yml -> cd.yml deploy

 

 

반응형

' > docker' 카테고리의 다른 글

[Docker] 도커로 스프링 프로젝트 배포하기  (0) 2022.10.18
[Docker] 도커 기초  (0) 2022.08.13
반응형

 

Blocking / Non Blocking Synchronous / Asynchronous

 

 

Blocking / Non Blocking

  • Blocking / Non Blocking은 호출되는 함수가 바로 제어권을 리턴 하느냐 마느냐 가 관심사
    • 제어권을 리턴하지 않으면 Blocking
    • 제어권을 리턴하면 NonBlocking
    제어권이 누구한테 있는지?

Synchronous / Asynchronous

  • Synchronous / Asynchronous는 호출되는 함수의 작업 완료 여부를 누가 신경 쓰냐 가 관심사
    • 호출되는 함수의 작업 완료를 호출한 함수가 확인하면 Synchronous (동기)
    • 호출되는 함수의 작업 완료를 호출된 함수가 확인하면 Asynchronous (비동기)
    호출한 함수의 완료 여부를 누가 확인하는지?
  • 비동기 방식은 멀티 스레드 , 단일 스레드?요점은 비동기 방식은 스레드를 효율적으로 운용하여 반응성을 향상시키는 것비동기 방식 DB I/O가 발생하면 DB I/O는 다른 스레드에게 넘기고, 나머지 작업을 수행
  • 기존 방식 DB I/O가 발생하면 다른 작업을 수행하지 않고, DB데이터가 올 때까지 기다림.
  • 단일 스레드에서도 가능하다고는 하는데, 사실은 다른 프로세스의 스레드를 사용한다.
    다른 스레드 또는 다른 프로세스의 스레드를 사용하므로 결국, 멀티 스레드가 맞다.
  • 동기?
    **작업의 완료 확인 방식에서의 동기(synchronous):** 
    작업을 호출한 쪽이 결과가 반환될 때까지 기다린다는 의미입니다. 
    비동기(asynchronous)는 작업의 완료를 기다리지 않고 다른 작업을 수행하며, 
    작업의 결과는 나중에 돌려받습니다.(콜백, 이벤트, 프로미스 등을 통해).
    
    **쓰레딩과 Race Condition 문맥에서의 동기(synchronization)**: 
    쓰레드 간의 실행 순서나 자원 접근을 조절하는 방식을 의미합니다. 
    즉, 어떤 일련의 작업이 '동기화' 되어 있다면, 그 작업들은 미리 정의된 어떠한 
    순서에 따라 실행되어야 하며, 이를 통해 레이스 컨디션을 방지할 수 있습니다.
    
    **Synchronous (동기):** 시간에 대한 것
    동기 방식은 하나의 작업이 완료되어야 다음 작업이 시작됩니다. 
    여기서는 `시간의 흐름`에 집중이 되어 있습니다.
    **-> 시간**
    
    **Synchronization (동기화):** 상태나 데이터의 일관성 
    여러 프로세스나 쓰레드가 동시에 어떠한 자원을 접근할 때 그 순서와 방식을 
    조절하여 `데이터의 일관성`을 유지하는 것을 의미합니다.
    **-> 상태**
    
  • → 동기가 헷갈리는 이유

 

 

결론

  1. Blocking + Synchronous: 요청을 보내고 응답을 받을 때까지 아무 것도 하지 않는 상태로 대기.이렇게 되면 시스템의 효율성이 떨어짐 긴 대기 시간 동안 다른 중요한 작업을 처리할 수 없게 된다.
  2. Non-Blocking + Asynchronous: 요청을 보내고 바로 다른 작업을 계속 진행. 응답이 오면 해당 응답을 처리하는 콜백 함수나 이벤트 리스너를 통해 처리함 이 방식은 시스템의 효율성, 반응성을 크게 향상 시킬 수 있다.

→ 결국, 작업 시간이 긴 여러 DB I/O, 네트워크 처리는 비동기 방식이 좋다는 내용 👍

 

 


 

예시

프론트

왜 Javascript에서 axios 호출을 비동기식이라고 하는지?

Web APIs Ajax 요청, setTimeout(), 이벤트 핸들러의 등록과 같이 웹 브라우저에서 제공하는 기능들을 말한다.

이러한 요청들의 처리가 JavaScript 엔진의 쓰레드와는 다른 쓰레드들에서 이뤄진다는 점이다.

JavaScript 엔진의 스택에서 실행된 비동기 함수가 요청하는 비동기 작업에 대한 정보와 콜백 함수를 웹 API를 통해

브라우저에게 넘기면, 브라우저는 이러한 요청들을 별도의 쓰레드에 위임 해당 요청이 완료되는 순간 콜백 함수를 JavaScript 엔진의 태스크 큐라는 곳에 집어넣는다.

→ JS가 비동기 함수를 실행하면, JS는 이 함수들에 대해 신경 쓰지 않는다. (비동기)

호출된 함수는 브라우저가 신경 쓰며, 작업을 완료하면 JS에게 Call Back 을 준다.

async function fetchExternalData() {
  const response = await fetch('<http://external-service/data>');
  const data = await response.json();

  // 위 요청-응답을 비동기로 브라우저에게 넘겨 처리하고, 아래 작업을 바로 실행함
  otherWork();

  return data;
}

 

 

백엔드

**WebFlux**는 Spring 5에서 도입된 반응형 프로그래밍 모델로, Non-Blocking + Asynchronous 방식 WebFlux는 Project Reactor를 기반으로 하며, **Mono**와 **Flux**라는 반응형 스트림 타입을 제공

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

@Service
public class ExternalService {

    @Autowired
    private WebClient webClient;

    public Mono<String> fetchExternalData() {
        String data = webClient.get()
                        .uri("/data")
                        .retrieve()
                        .bodyToMono(String.class);

				// 위 요청-응답을 비동기로 처리하고, 아래 작업을 바로 실행함
				otherWork();
    }
}

 

 


 

 

! 질문

비동기 방식이 무엇인가?

→ DB I/O, 네트워크 작업 등의 시간 소요가 큰 작업의 완료를 기다리지 않고, 해당 작업 완료 시 콜백을 통해 결과를 받아오면서 동시에 다른 작업을 계속 수행하는 방식을 의미합니다.

WebFlux, axios를 추가로 설명하면 👍

 

(네트워크에서) 동기 방식이 무엇인가?

→ 여러 개의 요청-응답을 순차적으로 처리하여, 실행하는 것입니다.

반응형

'CS > 네트워크' 카테고리의 다른 글

IPSec(Internet Protocol Security)  (0) 2024.09.20
[TCP/IP MODEL]  (0) 2022.08.31
반응형

JPA

https://jsonobject.tistory.com/605

 

Jackson 라이브러리는 기본적으로 엔티티의 Getter 메서드를 사용하여 JSON을 생성합니다.

따라서 Getter 메서드가 있고, 그 메서드가 연관 엔티티에 대한 접근을 포함하고 있다면,

Jackson은 해당 메서드를 호출하게 됩니다.

 

FetchType.LAZY로 설정된 연관 엔티티가 있을 경우,

Jackson이 해당 연관 엔티티의 Getter 메서드를 호출하면, JPA는 연관된 엔티티를 로드하려고 시도합니다.

만약 이 시점에서 JPA 세션이 닫혀 있으면 **LazyInitializationException**이 발생하게 됩니다.

 

해결방법

→ 연관엔티티가 있다면 Jackson 라이브러리가 Getter를 동작시키기 때문에 DTO를 사용해줘야 함

 

Jackson의 @JsonIgnore 어노테이션 사용: LAZY로 설정된 연관 엔티티의 Getter 메서드에

@JsonIgnore 어노테이션을 추가하여 Jackson이 해당 메서드를 호출하는 것을 방지합니다.

근데 결국, 연관 엔티티를 보내야 되는 경우가 있을 것이고, 그냥 DTO를 사용하는 방법이 제일 좋다.

반응형
반응형

React

렌더링 방식

  1. 내부 상태값(state)이나 중앙 상태값(redux store 등)이 변경되는 경우
  2. 부모 컴포넌트가 재렌더링되는 경우, 자식 컴포넌트도 재렌더링.

React 컴포넌트에서 return nul*을 사용하면 해당 컴포넌트는 아무것도 렌더링되지 않습니다.
이 방식을 사용하면 조건에 따라 특정 컴포넌트를 출력하지 않도록 만들 수 있습니다.

useEffect(() => {
        // 데이터를 비동기적으로 가져옵니다.
        fetchDataFromAPI().then(responseData => {
            setData(responseData);
        });
    }, []);

    // 데이터가 없을 경우 아무것도 렌더링하지 않습니다.
    if (!data) {
        return null;
    }

 

렌더링 순서

  1. 컴포넌트 함수 호출
  2. 컴포넌트 본문 호출
  3. useEffect

→ 컴포넌트 함수가 가장 먼저 호출되므로 if(!data) return loading 같은 걸로 처리

if (!data) {
    return <div>Loading...</div>;
}

 

useState

상태를 업데이트하는 함수(set)는 상태값을 변경하고 컴포넌트를 재렌더링합니다.

useEffect 첫째, 컴포넌트가 마운트된 직후에 코드를 실행하고, 둘째, 특정 상태가 변경될 때 코드를 실행합니다.

useState → 컴포넌트 렌더링 → useEffect

 

 


 

useEffect

 

  • 의존성 배열이 없는 경우 (useEffect에 두 번째 매개 변수가 전혀 주어지지 않은 경우),
    useEffect 내의 코드는 컴포넌트가 렌더링 될 때마다 실행됩니다. (무조건 실행)
  • 빈 의존성 배열이 있는 경우 (useEffect(fn, [])), useEffect 내의 코드는 컴포넌트가 처음 마운트될 때
    한 번만 실행되고, 그 후에는 실행되지 않습니다. (딱 한번)
  • 의존성 배열이 있는 경우 (useEffect(fn, [dep1, dep2, ...])), useEffect 내의 코드는 컴포넌트가
    처음 마운트될 때와 의존성 배열의 어떤 값이 변경될 때마다 실행됩니다. (감지 대상)
import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;

    // Cleanup function
    return () => {
      document.title = 'React App';
    };
  }, [count]); // 의존성 배열에 "count"를 추가합니다.

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

사용자 액션 → count useState변경 → 컴포넌트 리로딩

 

→ count 때문에 리로딩되어서 useEffect 동작

의존성 배열에 추가된 state에 의해 리로딩 된게 아니라면 useEffect가 동작하지 않는다.
의존성 배열이 없다면 첫 마운트(사이트 진입) 때에만 useEffect가 동작한다.

 

예를 들어, 서버에서 데이터를 비동기적으로 가져오는 경우에는 useEffect를 사용하여 데이터를 가져올 수 있습니다. 이 데이터를 컴포넌트의 상태에 저장하려면 useState를 사용해야 합니다.
그러면 상태가 업데이트되고 컴포넌트가 재렌더링되므로, 사용자는 최신의 데이터를 볼 수 있게 됩니다.

 

 

useEffect는 다음과 같은 다양한 경우에 사용될 수 있습니다:

  1. 비동기 작업: 서버로부터 데이터를 가져오는 등의 비동기 작업을 수행할 때 useEffect를 사용할 수 있습니다.
  2. 이벤트 리스너 설정: window의 resize 이벤트나 키보드 keydown 이벤트 등을 감지하려면 이벤트 리스너를 설정해야 하는데, 이런 작업도 useEffect에서 수행합니다.
  3. DOM 조작: React는 일반적으로 DOM을 직접 조작하지 않고, 상태 업데이트를 통해 간접적으로 DOM을 업데이트하는 것을 선호합니다. 그러나 특정 라이브러리를 사용하거나, 특정 DOM API를 직접적으로 사용해야 하는 경우에는 useEffect를 사용하여 이를 수행할 수 있습니다.
  4. 정리(cleanup) 작업: 컴포넌트가 언마운트되거나, 의존성이 변경될 때 정리 작업을 수행해야 하는 경우에도 useEffect를 사용할 수 있습니다. 예를 들어, 컴포넌트가 언마운트되면 이벤트 리스너를 제거해야 하는데, 이런 작업은 useEffect의 반환 함수에서 수행합니다.

따라서 useEffect는 비동기 작업뿐만 아니라 여러 가지 다른 사이드 이펙트를 처리하는 데 사용됩니다. 비동기 작업은 useEffect를 사용하는 주요한 경우 중 하나일 뿐입니다.

사이드 이펙트(side effect)는 프로그래밍 용어로, 함수나 컴포넌트의 주요 기능 외에 발생하는 부수적인 효과를 의미합니다. 이는 전역 상태를 변경하거나, 외부 네트워크와 통신하거나, DOM을 직접 조작하는 것과 같은 작업을 포함할 수 있습니다.

React에서 사이드 이펙트는 아래와 같은 상황들을 가리킵니다:

  1. 네트워크 요청: 서버에 데이터를 요청하거나, 서버로 데이터를 보내는 등의 네트워크 요청이 사이드 이펙트입니다. 이러한 요청은 종종 비동기적으로 수행됩니다.
  2. 구독(subscriptions): 외부 데이터 소스를 구독하는 것도 사이드 이펙트입니다. 예를 들어, WebSocket 연결을 통해 서버에서 실시간 업데이트를 받거나, 이벤트 리스너를 설정하여 사용자 입력을 감지하는 것이 이에 해당합니다.
  3. 타이머: setTimeout이나 setInterval과 같은 타이머를 설정하는 것도 사이드 이펙트입니다.
  4. 직접적인 DOM 조작: React는 일반적으로 DOM을 직접 조작하지 않고 상태 업데이트를 통해 간접적으로 DOM을 업데이트하는 것을 선호합니다. 그러나 특정 라이브러리를 사용하거나, 특정 DOM API를 직접적으로 사용해야 하는 경우에는 DOM을 직접 조작해야 할 수 있습니다.

 


 

REDUX

Store

state → 상태(데이터)

reducer → 액션(Action)을 수신, 상태(State)를 업데이트

getState → state를 가져와서 rendering

action → 상태를 갖고있는 그냥 메시지같은거

dispatch [dispatch(action)] → action으로 state변경, pub 작업을 한다.

subscribe[useSelector] → state가 변경되면, sub되어 state를 사용하는 컴포넌트들도 갱신 (화면)

      → useSelector를 사용하면 자동 subscribe함. 그래서 안씀

state는 reducers를 통해 변하고,

reducers에 action을 전달한다. action은 변화할 값을 갖고 있으며, dispatch가 action을 사용한다.

컴포넌트쪽에서는 노출된 것은 action이며, dispatch로 action을 전달한다. 한쪽에서 dispatch를 사용하면, 해당 state를 useSelector로 구독하는 모든 컴포넌트들은 상태변화를 감지한다.

// init

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
  1. 액션 함수를 만든다. (액션은 update data만 갖고 있음)
  2. dispatch()로 액션 함수를 전달한다.
  3. reducer에서 state, 액션함수를 인자로 받아서 변경하고 return
  4. 화면에 rendering 된다

 

ReduxTookit

reducer, action 함수를 같이 만듬

state도 slice안에서 관리함

들어온 param은 전부 payload라는 명칭을 사용

import { createSlice } from '@reduxjs/toolkit';

const chatSlice = createSlice({
  name: 'chat',
  initialState: { messages: [] },
  reducers: {
    addMessage: (state, action) => {
      state.messages.push(action.payload);
    },
    getMessage: (state, action) => {
      return state.messages.find(msg => msg.id === action.payload);
    },
    updateMessage: (state, action) => {
      const message = state.messages.find(msg => msg.id === action.payload.id);
      if (message) message.text = action.payload.text;
    },
    deleteMessage: (state, action) => {
      const index = state.messages.findIndex(msg => msg.id === action.payload);
      if (index !== -1) state.messages.splice(index, 1);
    },
  },
});

export const { addMessage, getMessage, updateMessage, deleteMessage } = chatSlice.actions;

export default chatSlice.reducer;

 

비동기 thunk

thunk를 만들고, slice → extraReducers에서 사용

pending, fulfilled, rejected 3가지 상태가 있다.

// chatSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';

// 비동기 액션을 위한 Thunk
export const fetchMessages = createAsyncThunk(
  'chat/fetchMessages',
  async () => {
    const response = await axios.get('/api/messages');
    return response.data; // 이 값이 액션의 payload로 들어갑니다.
  }
);

const chatSlice = createSlice({
  name: 'chat',
  initialState: { messages: [] },
  reducers: {
    addMessage: (state, action) => {
      state.messages.push(action.payload);
    },
  },
  extraReducers: (builder) => {
    builder.addCase(fetchMessages.pending, (state) => {
        state.status = 'loading';
      })
      .addCase(fetchMessages.fulfilled, (state, action) => {
        state.status = 'succeeded';
        state.messages = action.payload;
      })
      .addCase(fetchMessages.rejected, (state, action) => {
        state.status = 'failed';
        state.error = action.error.message;
      });
  },
});

export const { addMessage } = chatSlice.actions;

export default chatSlice.reducer;

사용

import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchMessages } from './chatSlice';

function Chat() {
  const dispatch = useDispatch();
  const messages = useSelector(state => state.chat.messages);

  useEffect(() => {
    dispatch(fetchMessages());
  }, [dispatch]);

  return (
    <div>
      {messages.map((message, index) => (
        <p key={index}>{message}</p>
      ))}
    </div>
  );
}

export default Chat;

 


설정

import { configureStore, combineReducers } from "@reduxjs/toolkit";
import webSocketSlice from "redux/webSocketSlice";
import chatSlice from "redux/chatSlice";
import chatRoomSlice from "redux/chatRoomSlice";

// rootReducer 생성
const rootReducer = combineReducers({
  webSocket: webSocketSlice.reducer,
  chat: chatSlice.reducer,
  chatRoom: chatRoomSlice.reducer,
});

export const store = configureStore({
  reducer: rootReducer,
});

보통 reducer만 내보낸다고함.

비동기 요청 createAsynThunk는 같은 slice 파일 내에 위치시키고

따로 export해서 사용하는 것 같다.

extraReducers는 사용하지말고, 그냥 createAsyncThunk로 모든것을 처리하자.

반응형
반응형

 

백엔드는 spring security, 프론트엔드는 Vue로 구성해서

로그인, 로그아웃, Post 요청 처리를 하는 도중

계속해서 cookie가 전달되지 않는 문제가 있었다.

 

요청마다 withCredential을 true로 설정해주면 되었는데,

또 다른 문제는 get 요청은 동작하는데 post 요청은 동작하지 않았다.

 

 

 

전역으로 설정하니 post 요청도 해결되었다.

 


 

 

 

알고보니 axios post 메서드에는 매개인자 순서가 있다.

 

post(url, data, config) 순서로 넣어주면 동작한다.

post(url, config) 으로 넣어서 동작하지 않았던 것

 

Axios api가 컴파일 에러, 런타임 에러가 나지않고 동작하여 이걸 눈치채지 못했다.

 

 

 

 


도움이 된 곳

 

https://yamoo9.github.io/axios/guide/api.html#http-%EB%A9%94%EC%84%9C%EB%93%9C-%EB%B3%84%EC%B9%AD

 

반응형

'프로그래밍 > Vue' 카테고리의 다른 글

[Vue] Vue 구조 파악해보기  (0) 2022.10.18

+ Recent posts