[JPA] DTO 설계 이유
엔티티를 직접 노출하는 것은 좋지 않다 지연로딩으로 이루어진 것의 경우 실제 엔티티 대신에 프록시 존재 jackson 라이브러리는 기본적으로 이 프록시 객체를 json으로 어떻게 생성해야 하는지 모름 → 예외 발생 Hibernate5Module을 스프링 빈으로 등록하면 해결 (Spring boot 사용중) 이 옵션을 사용할 경우 양방향 연관관계는 계속 로딩하게 된다. 따라서 @JsonIgnore 옵션을 한곳에 주어야 한다. Hibernate5Module 등록 build.gradle에 라이브러리 추가 implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5' JpashopApplication에 코드 추가 @Bean Hibernat..
2023.03.18
TIL
[JPA] Entitiy 대신 ResponseDto,RequestDto 사용, 그 이유
V1 엔티티를 Request Body에 직접 매핑 @PostMapping("/api/v1/members") public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member){ Long id = memberService.join(member); return new CreateMemberResponse(id); } 문제점 엔티티에 프레젠테이션 계층을 위한 로직이 추가된다. 엔티티에 API 검증을 위한 로직이 들어간다(@NotEmpty 등) 실무에서는 회원 엔티티를 위한 API가 다양하게 만들어지는데, 한 엔티티에 각각의 API를 위한 모든 요청 요구사항을 담기는 어렵다. 엔티티가 변경되면 API 스펙이 변한다. 결론 API 요청 스펙에 맞..
2023.03.17
TIL
no image
TCP UDP
Transport Layer(4 Layer) 송신자와 수신자를 연결하는 통신 서비스를 제공하는 계층(데이터 전달 담당) 신뢰성 있는 연결을 유지할 수 있도록 도와준다. Endpoint(사용자) 간의 연결을 생성하고, 데이터를 얼마나 보냈는지 얼마나 받았는지, 제대로 받았는지등을 확인한다. 데이터를 보내기 위해 사용하는 프로토콜 : TCP , UDP Network Layer(3 Layer) IP(Internet Protocol)이 활용되는 부분 한 Endpoint가 다른 Endpoint로 가고자 할 경우, 경로와 목적지를 찾아준다. 이를 Routing이라고 하며 대역이 다른 IP들이 목적지를 향해 제대로 찾아갈 수 있도록 돕는 역할을 한다. TCP(Transmission Control Protocal) 인..
2023.03.12
no image
[social-login] kakao 로그인 FE+BE
카카오를 통한 소셜로그인을 구현해보자 1. 프론트단에서 소셜 로그인 진행하는 버튼 구성한다. 2. 사용자는 해당 버튼을 클릭해 로그인 진행한다. - 사용자는 인가코드를 발급받게 되고, 프론트에서 이를 헤더에 실어 서버에 요청을 보낸다 3. 서버는 해당 인가코드를 받고 인가 서버에 필요한 정보들을 담아 Access Token 요청한다. 4. 인가 서버는 검증 후 Access Token 주게 된다. 5. 서버는 받은 Token을 기반으로 자원 서버에 실제로 이메일 정보를 요청하고 검증 후에 이메일 정보를 반환해준다. 6. 해당 이메일 정보를 기반으로 회원가입이 되어있다면 단순 Acceess Token(JWT), Refresh Token(JWT) 발행 회원가입이 되어 있지 않는다면 회원가입 후 발행해준다. 이..
2023.02.20
[백준/JAVA] #1194: 달이 차오른다, 가자.
1194번: 달이 차오른다, 가자. 첫째 줄에 미로의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 50) 둘째 줄부터 N개의 줄에 미로의 모양이 주어진다. 같은 타입의 열쇠가 여러 개 있을 수 있고, 문도 마찬가지이다. 그리고, www.acmicpc.net 🔸 문제 간략하게 살펴보기 빈 칸('.') - 언제나 이동할 수 있다. 벽 ('#') - 절대 이동할 수 없다. 열쇠 ('a', 'b', 'c', 'd', 'e', 'f') -언제나 이동할 수 있다. 이 곳에 처음 들어가면 열쇠를 집는다. 문 ('A', 'B', 'C', 'D', 'E', 'F') - 대응하는 열쇠가 있을 때만 이동할 수 있다. 민식이의 현재 위치 ('0') - 빈 곳이고, 민식이가 현재 서 있는 곳이다. 출구 ('..
2022.10.06
no image
[정처기 필기/실기] 합격 후기
정보처리기사 필기 1트 합격 - 시나공 청보처리기사 실기 3트 합격 - 1트 : 시나공 - 2트 : 시나공 - 3트 : 수제비 + final 실전 모의고사 필기 : 2주 하루 4시간씩 (시나공 1회독 + 문제은행 사이트 n 회독) 최강 자격증 기출문제 전자문제집 CBT 전자문제집, CBT, 컴씨비티, 씨비티, 기사, 산업기사, 기능사, 컴활, 컴퓨터활용능력, 1급, 2급, 워드, 정보처리, 전기, 소방, 기계, 사무자동화, 정보기기, 제과, 제빵, 한국사, 공무원, 수능, 필기, www.comcbt.com 실기 : 한 달 (수제비 2회독+ final 실전 모의고사 3회 분량+ 수제비 카페 매일 1회 방문 1문제풀이) 수제비- IT 커뮤니티 (정보처리기사... : 네이버 카페 수제비-수험생 입장에서 제대로..
2022.06.23
[백준/JAVA] #2562:최댓값
2562번: 최댓값 9개의 서로 다른 자연수가 주어질 때, 이들 중 최댓값을 찾고 그 최댓값이 몇 번째 수인지를 구하는 프로그램을 작성하시오. 예를 들어, 서로 다른 9개의 자연수 3, 29, 38, 12, 57, 74, 40, 85, 61 이 주어 www.acmicpc.net import java.util.*; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int num[] = new int[9]; for(int i=0;i
2022.06.13
[백준/JAVA] EOF(End Of File)
#10951 A+B -4 10951번: A+B - 4 두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오. www.acmicpc.net ☼ EOF(End Of File) - 데이터로부터 더 이상 읽을 수 있는 데이터가 없을 나타냄 hasNextInt() ➜ Scanner 객체에 입력 값이 int 값일 때만 ture 반환 haxNext() ➜ 다음에 가져올 값이 있으면 true , 없으면 false "boolean 타입 반환" next() ➜ 매개변수 혹은 iterator 되는 타입 반환 "숫자 값" ➜ 아무 타입 가능 (int, string 등) 📮개인 공부를 위한 공간으로 틀린 부분이 있을 수도 있습니다.📮 문제점 및 수정 사항이 있을 시, 언제든지 댓글로 피드백 주시기 바랍니다..
2022.06.09

[JPA] DTO 설계 이유

개발의 숩
|2023. 3. 18. 18:53
  • 엔티티를 직접 노출하는 것은 좋지 않다
  • 지연로딩으로 이루어진 것의 경우 실제 엔티티 대신에 프록시 존재
  • jackson 라이브러리는 기본적으로 이 프록시 객체를 json으로 어떻게 생성해야 하는지 모름 → 예외 발생
  • Hibernate5Module을 스프링 빈으로 등록하면 해결 (Spring boot 사용중)
    • 이 옵션을 사용할 경우 양방향 연관관계는 계속 로딩하게 된다. 따라서 @JsonIgnore 옵션을 한곳에 주어야 한다.

 

 

Hibernate5Module 등록

build.gradle에 라이브러리 추가

implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5'

 

JpashopApplication에 코드 추가

@Bean
Hibernate5Module hibernate5Module() {
 return new Hibernate5Module();
}
  • 기본적으로 초기화된 프록시 객체만 노출, 초기화 되지 않은 프록시 객체는 노출 안함

 

다음과 같이 설정하면, 강제로 지연 로딩 가능

Bean
Hibernate5Module hibernate5Module() {
 Hibernate5Module hibernate5Module = new Hibernate5Module();
 //강제 지연 로딩 설정
 hibernate5Module.configure(Hibernate5Module.Feature.FORCE_LAZY_LOADING,
true);
 return hibernate5Module;
}

 

 

주의 : 엔티티를 직접 노출할 때는 양방향 연관관계가 걸린 곳은 꼭! 한곳을 @JsonIgnore 처리 해야 한다

안그러면 양쪽을 서로 호출하면서 무한 루프가 걸린다

 

 

참고 : 정말 간단한 애플리케이션이 아니면 엔티티를 API 응답으로 외부로 노출하는 것은 좋지 않다. 따라서 Hibernate5Module를 사용하기보다는 DTO로 변환해서 반환하는 것이 더 좋은 방법이다

 

 

주의 : 지연 로딩(LAZY)을 피하기 위해 즉시 로딩(EARGR)으로 설정하면 안된다

즉시 로딩때문에 연관관계가 필요 없는 경우에도 데이터를 항상 조회해서 성능 문제가 발생할 수 있다. 즉시 로딩으로 설정하면 성능 튜닝이 매우 어려워 진다

 

 

💡 항상 지연 로딩을 기본으로 하고, 성능 최적화가 필요한 경우에는 fetch join을 사용해라

 

 

'TIL' 카테고리의 다른 글

[JPA] API 개발 고급 정리  (1) 2023.03.21
[JPA] 페이징과 한계돌파  (0) 2023.03.20
[JPA] N+1 문제  (0) 2023.03.19
[JPA] respository에 DTO 사용 ?  (0) 2023.03.18
[JPA] Entitiy 대신 ResponseDto,RequestDto 사용, 그 이유  (0) 2023.03.17

V1 엔티티를 Request Body에 직접 매핑

@PostMapping("/api/v1/members")
    public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member){
        Long id = memberService.join(member);
        return new CreateMemberResponse(id);
    }

문제점

  • 엔티티에 프레젠테이션 계층을 위한 로직이 추가된다.
  • 엔티티에 API 검증을 위한 로직이 들어간다(@NotEmpty 등)
  • 실무에서는 회원 엔티티를 위한 API가 다양하게 만들어지는데, 한 엔티티에 각각의 API를 위한 모든 요청 요구사항을 담기는 어렵다.
  • 엔티티가 변경되면 API 스펙이 변한다.

 

결론

API 요청 스펙에 맞춰 별도의 DTO를 파라미터로 받는다.

 

V2 엔티티 대신에 DTO를 RequestBody에 매핑

@PostMapping("/api/v2/members")
    public CreateMemberResponse saveMemberV2(@RequestBody @Valid CreateMemberRequest request){
        Member member = new Member();
        member.setName((request.getName()));

        Long id = memberService.join(member);
        return new CreateMemberResponse(id);
    }
  • CreateMemberRequest를 Member 엔티티 대신에 RequestBody와 매핑한다.
  • 엔티티와 프레젠테이션 계층을 위한 로직을 분리할 수 있다.
  • 엔티티와 API 스펙을 명확하게 분리할 수 있다.
  • 엔티티가 변해도 API 스펙이 변하지 않는다.

 

참고 : 실무에서는 엔티티를 API 스펙에 노출하면 안된다

 

 

TIL

최근 진행했던 프로젝트에선 requestDto,resposeDto 사용하는 이유를 자세히 알지 못해서, 

계속된 DTO 생성의 번거로움을 느끼고 어느 부분에선 Entity를 사용하여 프로젝트를 진행했다

그러니 나중에 Entity별로 꼬여서 해결방안을 찾다가 Dto를 사용했더니 문제가 해결되었던 기억이 있다.

최근 JPA 강의를 들으며 공부를 하면서 requestDto,responseDto의 중요성을 알게 되었다.

'TIL' 카테고리의 다른 글

[JPA] API 개발 고급 정리  (1) 2023.03.21
[JPA] 페이징과 한계돌파  (0) 2023.03.20
[JPA] N+1 문제  (0) 2023.03.19
[JPA] respository에 DTO 사용 ?  (0) 2023.03.18
[JPA] DTO 설계 이유  (0) 2023.03.18

TCP UDP

개발의 숩
|2023. 3. 12. 22:50

OSI 7layer

Transport Layer(4 Layer)

  • 송신자와 수신자를 연결하는 통신 서비스를 제공하는 계층(데이터 전달 담당)
  • 신뢰성 있는 연결을 유지할 수 있도록 도와준다.
    • Endpoint(사용자) 간의 연결을 생성하고, 데이터를 얼마나 보냈는지 얼마나 받았는지, 제대로 받았는지등을 확인한다.
  • 데이터를 보내기 위해 사용하는 프로토콜 : TCP , UDP

Network Layer(3 Layer)

  • IP(Internet Protocol)이 활용되는 부분
  • 한 Endpoint가 다른 Endpoint로 가고자 할 경우, 경로와 목적지를 찾아준다. 이를 Routing이라고 하며 대역이 다른 IP들이 목적지를 향해 제대로 찾아갈 수 있도록 돕는 역할을 한다.

 

TCP(Transmission Control Protocal)

인터넷상에서 데이터를 메세지의 형태로 보내기 위해 IP와 함께 사용하는 프로토콜

일반적으로 TCP와 IP 함께 사용하는데,

IP가 데이터의 배달을 처리한다면, TCP는 패킷추적 및 관리하게 된다.

TCP(Transmission Control Protocal)

 

TCP 특징

연속성보다 신뢰성이 있는 전송이 중요할 때 사용하는 프로토콜

  • 연결 지향 방식
    • 패킷을 전송하기 위한 논리적 경로를 배정
  • 3-way handshaking과정을 통해 연결을 설정하고 4-way handshaking을 통해 해제한다.
    • 3-way handshaking과정 : 목적지와 수신지를 확실히 하여 정확한 전송을 보장하기 위해 세션을 수립하는 과정을 의미
  • 흐름 제어 및 혼잡 제어
    • 흐름 제어송신하는 곳에서 감당되지 않는 많은 데이터를 빠르게 보내 수신하는 곳에서 문제가 발생하는 것을 막는다.
    • 데이터를 송신하는 곳과 수신하는 곳의 데이터 처리 속도를 조절하여 수신자의 버퍼 오버플로우를 방지하는 것이다.
    • 혼잡 제어정보의 소통량의 과다하면 패킷을 조금만 전송하여 혼잡 붕괴 현상이 일어나는 것을 막는다.
    • 네트워크 내의 패킷 수가 넘치게 증가하지 않도록 패킷 오버플로우는 방지하는 것이다.
  • 높은 신뢰성을 보장한다.
  • UDP보다 속도가 느리다.
    • 연결형 서비스, 3-way handshaking과정, 데이터의 흐름 제어 및 혼잡 제어 기능은 CPU를 사용하기때문에 속도에 영향을 준다.
  • 전이중(Full-Duplex),점대점(Point to Point) 방식

예를 들면 파일 전송과 같은 경우 사용된다.

 

TCP 서버의 특징

  • 서버소켓은 연결만을 담당한다.
  • 연결과정에서 반환된 클라이언트 소켓은 데이터의 송수신에 사용된다
  • 서버와 클라이언트는 1대1로 연결된다.
  • 스트림 전송으로 전송 데이터의 크기가 무제한이다.
  • 패킷에 대한 응답을 해야하기 때문에(시간 지연, CPU 소모) 성능이 낮다
  • Streaming 서비스에 불리하다. (손실된 경우 재전송 요청을 하므로)

 

TCP/IP

  • (참고) Internet Protocol Suite인터넷에서 컴퓨터들이 서로 정보를 주고 받는데 쓰이는 프로토콜의 모음
  • 인터넷 프로토콜 슈트중 TCP와 IP가 가장 많이 쓰이기때문에 TCP/IP 프로토콜 슈트라고도 불린다.
  • Internet Protocol Suite

패킷 통신 방식의 인터넷 프로토콜 IP와 전송 조절 프로토콜 TCP로 이루어져있다.

IP는 패킷 전달 여부를 보증하지 않고, 패킷을 보낸 순서와 받는 순서가 다를 수 있다.

TCP는 IP 위에서 동작하는 프로토콜로, 데이터의 전달을 보증하고 보내는 순서대로 받게 해준다.

HTTP(웹), FTP(원격 터미널 접속), SMTP(전자메일) 등 TCP를 기반으로 한 많은 수의 애플리케이션 프로토콜들이 IP 위에서 동작하기 때문에, 묶어서 TCP/IP로 부르기도 한다.

송신자가 수신자에게 IP 주소를 사용하여 데이터를 전달하고, 그 데이터가 제대로 갔는지, 너무 빠르진 않았는지, 제대로 받았다고 연락은 오는지에 대한 이야기를 하는 것이다

 

 

UDP(User Datagram Protocol)

데이터를 데이터그램 단위로 처리하는 프로토콜

데이터 그램이란 독립적인 관계를 지니는 패킷

연결을 위해 할당되는 논리적인 경로가 없기 때문에 각각의 패킷은 다른 경로로 전송되고, 각각의 패킷은 독립적인 관계를 지니게 되는데, 이렇게 다른 경로로 독립적으로 처리하게 되는 프로토콜

UDP(User Datagram Protocol)

 

UDP 특징

신뢰성보다 연속성이 중요한 서비스에 자주 사용하는 프로토콜

  • 비연결형 서비스로 데이터그램 방식을 제공한다
  • 정보를 주고 받을 때 정보를 보내거나 받는다는 신호절차를 거치지 않는다
  • UDP헤더의 CheckSum 필드를 통해 최소한의 오류만 검출한다
  • 신뢰성이 낮다
  • TCP보다 속도가 빠르다
  • 네트워크 부하가 적다

예를 들면 실시간 서비스(streaming)에 사용된다.

 

UDP 서버의 특징

  • UDP에는 연결 자체가 없어서 (connect 함수 불필요) 서버 소켓과 클라이언트 소켓의 구분이 없다
  • 소켓 대신 IP를 기반으로 데이터를 전송한다
  • 서버와 클라이언트는 1대1, 1대N, N대M등으로 연결될 수 있다
  • 데이터그램(메세지)단위로 전송되며 그 크기는 65535바이트로, 크기가 초과하면 잘라서 보낸다
  • 흐름 제어가 없어서 패킷이 제대로 전송되었는지, 오류는 없는지 확인할 수 없다.
  • 파일 전송과 같은 신뢰성이 필요한 서비스보다 성능이 중요시 되는 경우에 사용된다.

 

 

TCP와 UDP의 비교

TCP와 UDP의 비교

 

참고

패킷(Packet)

인터넷 내에서 데이터를 보내기 위한 경로배정(라우팅)을 효율적으로 하기 위해서 데이터를 여러 개의 조각들로 나누어 전송을 하는데 이때, 이 조각을 **패킷**이라고 한다.

TCP는 패킷을 어떻게 추적 및 관리하는가

데이터는 패킷 단위로 나누어 같은 목적지(IP계층)으로 전송된다.

예를 들어 한줄로 서야하는 A,B,C라는 패킷들이 발신지에서 출발하여 수신지로 간다고 해보자.

그런데 A,B,C가 순차적으로 가는 상황에서 B가 길을 잘못 들어서 분실되었다고 해보자. 하지만 목적지에는 A,B,C가 모두 필요한지 모르고 A,C만 보고 다 왔다고 착각할 수 있다.

그렇기 때문에 A,B,C라는 패킷에 1,2,3이라는 번호를 부여하여 패킷의 분실 확인과 같은 처리를 하여 목적지에서 재조립을 한다.

이런 방식으로 TCP는 패킷을 추적하며, 나누어 보내진 데이터를 받아 조립할 수 있다.

Handshake

3-way handshake

TCP/IP 프로토콜을 이용해서 통신을 하는 응용프로그램이 데이터를 전송하기 전에 먼저 정확한 전송을 보장하기 위해 상대방 컴퓨터와 사전에 세션을 수립하는 과정

3way handshake는 양쪽 모두 데이터를 전송할 준비가 되어있다는 것을 보장하고, 실제로 데이터 전달이 시작하기 전에 다른 한쪽이 준비되었다는 것을 알 수 있도록 해준다

4-way handshake

3way handshake가 연결확립을 위해 진행했다면 4way handshake는 세션을 종료하기 위해 수행되는 절차 를 말한다.

 

TCP 헤더 및 3-way handshake 참고 자료

 

TCP/IP 쉽게 이해하기

IT 분야에서 실무를 담당하시는 분들뿐만 아니라 학생, IT 쪽에 조금이라도 관심이 있는 분들이라면 TCP/IP에 대해 들어보셨을 겁니다. 저 또한 학부시절에 TCP/IP에 대해서 여러 번 들어보았는데요.

aws-hyoh.tistory.com

 

카카오를 통한 소셜로그인을 구현해보자

 

 

 

1. 프론트단에서 소셜 로그인 진행하는 버튼 구성한다.

2. 사용자는 해당 버튼을 클릭해 로그인 진행한다.

- 사용자는 인가코드를 발급받게 되고, 프론트에서 이를 헤더에 실어 서버에 요청을 보낸다

3. 서버는 해당 인가코드를 받고 인가 서버에 필요한 정보들을 담아 Access Token 요청한다.

4. 인가 서버는 검증 후 Access Token 주게 된다.

5. 서버는 받은 Token을 기반으로 자원 서버에 실제로 이메일 정보를 요청하고 검증 후에 이메일 정보를 반환해준다.

6. 해당 이메일 정보를 기반으로 회원가입이 되어있다면 단순 Acceess Token(JWT), Refresh Token(JWT) 발행
 회원가입이 되어 있지 않는다면 회원가입 후 발행해준다.

이렇게 되면 인증에 대해서도 Access Token(JWT)로 인증이 가능하며 만료되더라도 DB에 저장중인 Refresh Token을 통해 재발급하여 인증이 가능하다.

 

 

카카오 로그인 과정

  1. 카카오에 인가 코드 발급 요청
  2. 인가 코드를 백엔드에 알려준다
  3. 로그인 처리를 한 후에 jwt 토큰 발급

 

 

kakao developers 설명을 참고해보자

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

 

 

1. 애플리케이션 등록

  • 애플리케이션 추가하기

내 애플리케이션 > 애플리케이션 추가하기

  • 웹 플랫폼 추가하기

내 애플리케이션 > 앱 설정 > 플랫폼 > Web 선택

 

  • 카카로 로그인 활성화하기

내 애플리케이션 > 제품 설정 > 카카오 로그인

  • Redirect URL 설정

프론트단 페이지 만들어서 설정 !!!!!!

테스트 환경 local, 배포 환경 설정

 

 

2. 프론트

 

//LoginView.vue

<div>
	<img src="../../assets/kakao_login_medium_narrow.png"
      @click="onKakaoLogin"/>
</div>

// kakao login
    const onKakaoLogin=() =>{
      requestKakaoLogin((res)=>{
        window.location.href = res.data;
      })
    };


// userApi.js
// kakao login 동의 얻고 인가코드 요청
 function requestKakaoLogin(callback,errorCallback){
   api.get(`/social/login`)
   .then(callback)
   .catch(errorCallback)
 }

 

카카오 인가코드를 헤더로 받을 페이지 라우터

//index.js
//kakao
  {
    path:"/social/login/kakao/callback",
    name:"kakaoLogin",
    component:kakaoLogin,
  },

 

 

카카오 인가코드 헤더로 받을 페이지

- 헤더 query 가져오기 : $route.query

- 헤더 query code 가져오기 : $route.query.code

설정한 리다이렉트 페이지에 Authentication Code가 오게된다.

이 코드를 통해 실제 서버에서는 Access Token을 발급받고 Access Token으로 이메일 정보를 받아와야한다.

<template>
  <div></div>
</template>

<script>
import router from "@/router";
import { ref } from "vue";
import { requestKakaoCode } from "../../api/userApi.js";
import { useStore } from "vuex";

export default {
    
    created() {
        const code = ref("");
        const store = useStore();
        const setIsLoginTrue = () => store.commit("userStore/SET_IS_LOGIN_TRUE");
        const userinfo = ref([]);
        const setUserInfo = () => store.commit("userStore/SET_USER_INFO", userinfo);
        code.value = this.$route.query.code
        requestKakaoCode(code.value,(res)=>{
            // userInfo 저장 
            userinfo.value.push(res.data);
            setUserInfo();
            setIsLoginTrue();
            router.push({ name: "Home" });
        })
    }
}
</script>

<style>

</style>

 

 

 

3. 백

내 애플리케이션 > 앱 설정 > 앱 키

application.yml 

server:
  port: 백엔드 포트번호

spring:
  redis:
    host: localhost
    port: 레디스 포트번호
  social:
    kakao:
      client_id: REST API 키
      redirect_uri: 등록한 REDIRECT_URI
      scope: account_email
      url:
        login: https://kauth.kakao.com/oauth/authorize
        token: https://kauth.kakao.com/oauth/token
        profile: https://kapi.kakao.com/v2/user/me
  • client_id - 클라이언트를 구분해주는 ID, 등록하면 자동으로 발급해준다.
  • login - 소셜마다 로그인을 진행하는 사이트, 필요한 파라미터를 입력해줘야한다.
  • token - Access Token을 발급받는 url, 필요한 정보를 담아 보내야한다.
  • profile - Access Token을 통해 정보를 받는 url, Access Token을 담아 보내야한다.

 

 

 

다음과 같이 @Value 어노테이션을 활용해 yml의 값을 불러와 필요한 파라미터를 로그인 url에 붙여 url을 완성시킨 후 View에 넘겨 로그인을 완성시키고 있다.

// socialloginController.java
@RequestMapping("/social/login")
public class SocialController {
    @Value("${spring.social.kakao.client_id}")
    private String kakaoClientId;
    @Value("${spring.social.kakao.redirect_uri}")
    private String kakaoRedirect;
    private final Environment env;

    @Autowired
    private UserService userService;

// 인가코드 요청 url 
@GetMapping()
    public String socialKakaoLogin() {
        StringBuilder loginUrl1 = new StringBuilder()
                .append(env.getProperty("spring.social.kakao.url.login"))
                .append("?client_id=").append(kakaoClientId)
                .append("&response_type=code")
                .append("&redirect_uri=").append(kakaoRedirect);
        return loginUrl1.toString();
    }


@ApiOperation(value = "소셜 로그인", notes = "소셜을 통해 로그인을 진행한다.")
    @GetMapping("/kakao/callback/{code}")
    public ResponseEntity<LoginResponseDto> loginByProvider(@PathVariable("code") String authCode) {
        String provider ="kakao";
        LoginResponseDto responseDto = userService.loginUserByProvider(authCode, provider);
        return new ResponseEntity<>(responseDto, HttpStatus.OK);
    }
}

 

 

 

백엔드 소셜로그인 부분은 참고사이트를 따라 구현하였다.

 

 

 

참고 

 

[Security] Spring JWT 인증 With REST API(OAuth2.0 추가) (3)

시작하기에 앞서 지금까지 JWT를 활용하여 로그인을 구현해보았다. 하지만, 우리가 다양한 페이지들을 돌아다니다보면 구글 로그인, 네이버 로그인, 카카오 로그인 등 다양한 소셜 로그인이 존

gilssang97.tistory.com

 

 

[React] 카카오 로그인

카카오 로그인 과정 1. 카카오에 인가 코드 발급 요청 2. 인가 코드를 백엔드에 알려줌 3. 로그인 처리를 한 후에 jwt 토큰 발급 4. 토큰을 로컬 스토리지에 저장 kakao developers를 참고해서 공부하자!

yunae.tistory.com

 

 

 

 

 

프로젝트 진행을 위해 부랴부랴 구현하느라 로직에 대한 정리가 되지 않았는데, 한 번 해결하고나니 로직이 어느정도 정리도 되고 감이 잡힌듯 하다.

 

 

 

 

 

 

📮개인 공부를 위한 공간으로 틀린 부분이 있을 수도 있습니다.📮

문제점 및 수정 사항이 있을 시, 언제든지 댓글로 피드백 주시기 바랍니다.

 

1194번: 달이 차오른다, 가자.

첫째 줄에 미로의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 50) 둘째 줄부터 N개의 줄에 미로의 모양이 주어진다. 같은 타입의 열쇠가 여러 개 있을 수 있고, 문도 마찬가지이다. 그리고,

www.acmicpc.net

 

🔸 문제 간략하게 살펴보기


 빈 칸('.') - 언제나 이동할 수 있다.

 벽 ('#')  - 절대 이동할 수 없다.

 열쇠 ('a', 'b', 'c', 'd', 'e', 'f')  -언제나 이동할 수 있다. 이 곳에 처음 들어가면 열쇠를 집는다.
 문 ('A', 'B', 'C', 'D', 'E', 'F') - 대응하는 열쇠가 있을 때만 이동할 수 있다.

 민식이의 현재 위치 ('0')  - 빈 곳이고, 민식이가 현재 서 있는 곳이다. 

 

 출구 ('1') - 달이 차오르기 때문에, 민식이가 가야하는 곳이다. 이 곳에 오면 미로를 탈출한다. 

 * 같은 타입의 열쇠가 여러 개 있을 수 있고, 문도 마찬가지이다. 그리고, 문에 대응하는 열쇠가 없을 수도 있다.

'0'은 한 개, '1'은 적어도 한 개 있다. 열쇠는 여러 번 사용할 수 있다.

=> 미로를 탈출하는데 걸리는 이동횟수의 최솟값

 

 

 

🔸포인트 

- 미로를 탈출하는데 걸리는 이동횟수의 최솟값 => bfs 

- 방문한 곳 체크 처리, 열쇠 처리, 문 처리

 

🔸방문한 곳 처리

처음엔 2차원 boolean 형으로 방문 여부 처리를 하려다가 이 문제 같은 경우 왔던 길을 재 방문하는 경우가 있기때문에 방문처리에 대해 잘 생각해야 한다.

예제 1을 통한 재방문하는 경우 확인

그렇다고 방문처리를 안한다면 방문했던 부분을 다시 방문할 수도 있으니 방문처리를 해야한다.

 

 

boolean 형 visited [가로][세로][열쇠의 조합] 3차원을 이용해서 처리

-> 열쇠의 조합 : *비트마스킹 이용

 

 

🙋 열쇠 조합을 넣는 이유 ? 

-> 여러 개의 열쇠를 가지고 있을 수 있음

 

이를 쉽게 핸드링하기 위해 | , & 을 가지고 열쇠 추가, 대응하는 열쇠와 문을 손쉽게 찾을 수 있다.

 

열쇠 ('a', 'b', 'c', 'd', 'e', 'f') 0~ 63 조합 => 총 64종류 

 

열쇠 조합 순서

'f','e','d','c','b','a'

 

(1) 열쇠 a일 경우

=> 0 0 0 0 0 1 

 

(2) 열쇠 d 일 경우

=> 0 0 1 0 0 0

 

(1) | (2) 의 결과 = 열쇠 d,a 일 경우

=> 0 0 1  0 0 1

 

// 만약 열쇠면 ? 열쇠면 민식이 주머니에 넣기 ** 언제나 이동가능
					if (map[nx][ny] == 'a' || map[nx][ny] == 'b' || map[nx][ny] == 'c' || map[nx][ny] == 'd'
							|| map[nx][ny] == 'e' || map[nx][ny] == 'f') {
						// 비트마스킹
						int nkey = 1 << (map[nx][ny] - 'a');
						nkey = temp.key | nkey;
						if (!visited[nx][ny][nkey]) {
//							System.out.println("열쇠 획득");
							visited[nx][ny][nkey] = true; // 방문 체크하고
							que.offer(new Minsic(nx, ny, temp.cnt + 1, nkey)); // 이동해보쟈
						}

					}

대응하는 문을 찾을 경우 

(1) 문 A일 경우

=> 0 0 0 0 0 1

 

(2) 가지고 있는 열쇠 d,a인 경우 

=> 0 0 1 0 0 1

 

(1) & (2) 의 결과  

=> 0 0 0 0 0 1

 

(1) & (2) 의 결과가 0 보다 크다면 대응하는 열쇠를 가지고 있다

// 만약 문의 경우 ; 대응하는 열쇠가 있는 경우에만 이동할 수 있고, 대응하는 열쇠가 없는 경우 이동하지 못한다.
					else if (map[nx][ny] == 'A' || map[nx][ny] == 'B' || map[nx][ny] == 'C' || map[nx][ny] == 'D'
							|| map[nx][ny] == 'E' || map[nx][ny] == 'F') {

						int ndoor = 1 << (map[nx][ny] - 'A');

						// 열쇠랑 문이 짝꿍일때
						if ((temp.key & ndoor) > 0) {
							// 이동해보쟈
							if (!visited[nx][ny][temp.key]) {
//								System.out.println("문 열고 이동");
								visited[nx][ny][temp.key] = true;
								que.offer(new Minsic(nx, ny, temp.cnt + 1, temp.key));
							}
						} else {
//							System.out.println("문 못열어 이동 불가");
							continue;
							// 이동불가능
						}

 

 

 

 

 

열쇠와 문을 방문할 경우와 그렇지 않은 경우로 나눠 이동하기 

// 만약 열쇠면 ? 열쇠면 민식이 주머니에 넣기 ** 언제나 이동가능
					if (map[nx][ny] == 'a' || map[nx][ny] == 'b' || map[nx][ny] == 'c' || map[nx][ny] == 'd'
							|| map[nx][ny] == 'e' || map[nx][ny] == 'f') {
						// 비트마스킹
						int nkey = 1 << (map[nx][ny] - 'a');
						nkey = temp.key | nkey;
						if (!visited[nx][ny][nkey]) {
//							System.out.println("열쇠 획득");
							visited[nx][ny][nkey] = true; // 방문 체크하고
							que.offer(new Minsic(nx, ny, temp.cnt + 1, nkey)); // 이동해보쟈
						}

					} // 만약 문의 경우 ; 대응하는 열쇠가 있는 경우에만 이동할 수 있고, 대응하는 열쇠가 없는 경우 이동하지 못한다.
					else if (map[nx][ny] == 'A' || map[nx][ny] == 'B' || map[nx][ny] == 'C' || map[nx][ny] == 'D'
							|| map[nx][ny] == 'E' || map[nx][ny] == 'F') {

						int ndoor = 1 << (map[nx][ny] - 'A');

						// 열쇠랑 문이 짝꿍일때
						if ((temp.key & ndoor) > 0) {
							// 이동해보쟈
							if (!visited[nx][ny][temp.key]) {
//								System.out.println("문 열고 이동");
								visited[nx][ny][temp.key] = true;
								que.offer(new Minsic(nx, ny, temp.cnt + 1, temp.key));
							}
						} else {
//							System.out.println("문 못열어 이동 불가");
							continue;
							// 이동불가능
						}

					} else {
						if (!visited[nx][ny][temp.key]) {
//							System.out.println("이동");
							visited[nx][ny][temp.key] = true;
							que.offer(new Minsic(nx, ny, temp.cnt + 1, temp.key));
						}
					}

 

 

 

 

 

 

 

 

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main{
	static int[] dx = { 0, 0, 1, -1 };
	static int[] dy = { 1, -1, 0, 0 };

	static class Minsic {
		int x, y, cnt;
		// 열쇠 꾸러미들 관리
		int key;

		public Minsic(int x, int y, int cnt, int key) {
			super();
			this.x = x;
			this.y = y;
			this.cnt = cnt;
			this.key = key;
		}

		@Override
		public String toString() {
			return "Minsic [x=" + x + ", y=" + y + ", cnt=" + cnt + ", key=" + key + "]";
		}

	}

	static int N, M;
	static char[][] map;

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		StringTokenizer st = new StringTokenizer(br.readLine());

		N = Integer.parseInt(st.nextToken()); // 세로크기
		M = Integer.parseInt(st.nextToken()); // 가로크기

		map = new char[N][M];
		Minsic start = null;
		for (int i = 0; i < N; i++) { // ->
			String str = br.readLine();
			for (int j = 0; j < M; j++) { // ↓
				map[i][j] = str.charAt(j);
				if (map[i][j] == '0') {
					start = new Minsic(i, j, 0, 0);
				}

			}
		}

		/* 출력 확인용 */
//		for(int i=0;i<N;i++) {
//			for(int j=0;j<M;j++) {
//				System.out.print(map[i][j]+" ");
//			}
//			System.out.println();
//		}
		
		/* 민식이 처음 위치 확잉 */
//		System.out.println(start.toString());
		visited = new boolean[N][M][64];
		int result = bfs(start.x, start.y, start.cnt, start.key);
		System.out.println(result);

	}

	// [x][y][열쇠 조합]
	static boolean[][][] visited;

	// x=Minsic.x y= Minsic.y
	static int bfs(int x, int y, int cnt, int key) {
		Queue<Minsic> que = new ArrayDeque<>();
		// 처음 위치 집어 넣고
		que.offer(new Minsic(x, y, cnt, key));
		visited[x][y][key] = true;
		
		while (!que.isEmpty()) {
			Minsic temp = que.poll();

			// 탈출해보자
			if (map[temp.x][temp.y] == '1') {
				return temp.cnt;
			}

			// 민식이가 갈 수 있는 곳으로 사방탐색을 해보쟈
			for (int d = 0; d < 4; d++) {
				int nx = temp.x + dx[d];
				int ny = temp.y + dy[d];

				if (nx >= 0 && nx < N && ny >= 0 && ny < M && map[nx][ny] != '#') {

//					System.out.println("nx : " + nx + " , ny : " + ny + " , temp.cnt :" + temp.cnt+" ,temp.key :"+temp.key);
					
					
					// 만약 열쇠면 ? 열쇠면 민식이 주머니에 넣기 ** 언제나 이동가능
					if (map[nx][ny] == 'a' || map[nx][ny] == 'b' || map[nx][ny] == 'c' || map[nx][ny] == 'd'
							|| map[nx][ny] == 'e' || map[nx][ny] == 'f') {
						// 비트마스킹
						int nkey = 1 << (map[nx][ny] - 'a');
						nkey = temp.key | nkey;
						if (!visited[nx][ny][nkey]) {
//							System.out.println("열쇠 획득");
							visited[nx][ny][nkey] = true; // 방문 체크하고
							que.offer(new Minsic(nx, ny, temp.cnt + 1, nkey)); // 이동해보쟈
						}

					} // 만약 문의 경우 ; 대응하는 열쇠가 있는 경우에만 이동할 수 있고, 대응하는 열쇠가 없는 경우 이동하지 못한다.
					else if (map[nx][ny] == 'A' || map[nx][ny] == 'B' || map[nx][ny] == 'C' || map[nx][ny] == 'D'
							|| map[nx][ny] == 'E' || map[nx][ny] == 'F') {

						int ndoor = 1 << (map[nx][ny] - 'A');

						// 열쇠랑 문이 짝꿍일때
						if ((temp.key & ndoor) > 0) {
							// 이동해보쟈
							if (!visited[nx][ny][temp.key]) {
//								System.out.println("문 열고 이동");
								visited[nx][ny][temp.key] = true;
								que.offer(new Minsic(nx, ny, temp.cnt + 1, temp.key));
							}
						} else {
//							System.out.println("문 못열어 이동 불가");
							continue;
							// 이동불가능
						}

					} else {
						if (!visited[nx][ny][temp.key]) {
//							System.out.println("이동");
							visited[nx][ny][temp.key] = true;
							que.offer(new Minsic(nx, ny, temp.cnt + 1, temp.key));
						}
					}
				}
			}

		}

		return -1;

	}

}

 

 

비트마스킹 개념 참고

 

 

[알고리즘] 비트마스킹(bitmasking) 이란

안녕하세요, 여행벌입니다. 오늘은 2진수 표기법의 특징을 활용한 비트마스킹 알고리즘에 대해서 포스팅해보겠습니다. [ 비트마스킹 ]  컴퓨터는 내부적으로 모든 자료를 이진수로 표현합니다.

travelbeeee.tistory.com

 

 

 

📮개인 공부를 위한 공간으로 틀린 부분이 있을 수도 있습니다.📮

문제점 및 수정 사항이 있을 시, 언제든지 댓글로 피드백 주시기 바랍니다.

'algorithm > 백준' 카테고리의 다른 글

[백준/JAVA] #2562:최댓값  (0) 2022.06.13

[정처기 필기/실기] 합격 후기

개발의 숩
|2022. 6. 23. 21:05

정보처리기사 필기 1트 합격 - 시나공
청보처리기사 실기 3트 합격
- 1트 : 시나공
- 2트 : 시나공
- 3트 : 수제비 + final 실전 모의고사

필기 : 2주 하루 4시간씩 (시나공 1회독 + 문제은행 사이트 n 회독)

최강 자격증 기출문제 전자문제집 CBT

전자문제집, CBT, 컴씨비티, 씨비티, 기사, 산업기사, 기능사, 컴활, 컴퓨터활용능력, 1급, 2급, 워드, 정보처리, 전기, 소방, 기계, 사무자동화, 정보기기, 제과, 제빵, 한국사, 공무원, 수능, 필기,

www.comcbt.com


실기 : 한 달 (수제비 2회독+ final 실전 모의고사 3회 분량+ 수제비 카페 매일 1회 방문 1문제풀이)

수제비- IT 커뮤니티 (정보처리기사... : 네이버 카페

수제비-수험생 입장에서 제대로 쓴 비법서(정보처리기사, 정보처리기능사, 빅데이터 분석기사 등 시리즈)

cafe.naver.com



시나공 같은 경우,
가독성이 높아 비전공자가 읽기에도 좋은 책이여서 필기를 준비하기에 어려움이 없어 좋았지만 비슷한 문제로 구성되어져 있는 게 아쉬웠던 것 같다.
시나공 실기를 가지고 정보처리기사 실기를 준비하는 경우는 실기시험 내용자체가 개념에 대해 탄탄하게 물어보기때문에 개인적으론 시나공 실기책으로는 공부할 때마다 텅빈느낌이라 수제비 사이트를 참고하였지만, 시나공 책을 베이스로 공부하기엔 개념이 탄탄하게 다져지지 않은 느낌이였다.

수제비 같은 경우,
필기 공부할때 주변에서 사용하는 걸 봤을 떄 예상 문제 난이도도 높았으며, 말도 안되는 오탈자가 많다는 이야기때문에 필기에선 사용하진 않았지만 수제비 실기의 경우, 예상 문제 난이도도 시나공에 비해 높은 편이며, 개념을 더 탄탄하고 중요하지 않다고 생각하는 부분은 과감하게 분량이 적은 것이 마음에 들었다. 무엇보다 예상 문제 난이도가 높은 게 시험대비할 때 좋은 것 같다.

옛날 정보처리기사와 다르게 기출문제를 문제 은행형식으로 공부한다고해서 합격하기엔 어려워진 것 같다.
확실하게 개념에 대해 이해만 한다면 충분히 합격할 수 있지만
개념에서 조금 더 꼬아서 문제를 내는 느낌이라 final 실전 모의고사를 풀어보는 것을 추천한다.

실제 난이도는 시나공 < 수제비 << final 실전 모의고사 느낌이다.

내가 본 시험에선 1번 문제에서 final 실전 모의고사에서 나온 걸보니, 앞으로도 실전 모의고사가 도움이 될 것 같다.
final 실전 모의고사 경우,
수제비보다 더 어려운 모의고사 문제집으로 생각하면 될 것 같다.
실제 문제 유행이 바뀐 20년도 이전 문제도 섞여 있어 1회차부터 어려움을 느꼈다.
시험 3일 남겨놓고 책 배송을 받아 3회까지만 풀었는데도 2회는 딱 60점 1회는 40점대로 불합격점수를 얻어 불안했지만
실전 모의고사 푸는 것보다 3일동안 개념을 익히는 것으로 푸는 게 더 유용했다.



[백준/JAVA] #2562:최댓값

개발의 숩
|2022. 6. 13. 23:01
 

2562번: 최댓값

9개의 서로 다른 자연수가 주어질 때, 이들 중 최댓값을 찾고 그 최댓값이 몇 번째 수인지를 구하는 프로그램을 작성하시오. 예를 들어, 서로 다른 9개의 자연수 3, 29, 38, 12, 57, 74, 40, 85, 61 이 주어

www.acmicpc.net

 

import java.util.*;

public class Main {
	
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int num[] = new int[9];
		
		for(int i=0;i<num.length;i++) {
			num[i]= scanner.nextInt();
		}
        	int count = 0;
		int max = 0;
        
		for(int i=0;i<num.length;i++) {
			if (num[i]>max) {
				max = num[i];
		      		count =i+1;
			}
			
		}
		
		System.out.println(max);
		System.out.println(count);
	}
	
}

 

Arrays.binarysearch() 

 

🙋 질문  ➜ 🙆

🙋: 어느 부분에서 오류가 나는지 이클립스에선 오류없이 잘 돌아가는데 백준에서 제출시 자꾸 실패로 뜬다.

🙆: int max = num[0] ➜ int max = 0 으로 바꾸고 제출하니 성공

 

📮개인 공부를 위한 공간으로 틀린 부분이 있을 수도 있습니다.📮

문제점 및 수정 사항이 있을 시, 언제든지 댓글로 피드백 주시기 바랍니다.

'algorithm > 백준' 카테고리의 다른 글

[백준/JAVA] #1194: 달이 차오른다, 가자.  (0) 2022.10.06

[백준/JAVA] EOF(End Of File)

개발의 숩
|2022. 6. 9. 23:44

#10951 A+B -4

 

10951번: A+B - 4

두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.

www.acmicpc.net

 

EOF(End Of File)

- 데이터로부터 더 이상 읽을 수 있는 데이터가 없을 나타냄

 

hasNextInt()

➜ Scanner 객체에 입력 값이 int 값일 때만 ture 반환

haxNext()

➜ 다음에 가져올 값이 있으면 true , 없으면 false  "boolean 타입 반환"

next()

➜ 매개변수 혹은 iterator 되는 타입 반환 "숫자 값"

➜ 아무 타입 가능 (int, string 등)

 

 

📮개인 공부를 위한 공간으로 틀린 부분이 있을 수도 있습니다.📮

문제점 및 수정 사항이 있을 시, 언제든지 댓글로 피드백 주시기 바랍니다.

 

 

[참고]

 

(JAVA)hasNext() vs next() 메서드 차이점?

정의 Iterator 인터페이스의 메서드로 자주 사용됩니다. Iterator에 추가적인 요소가 있을 때 가져오는 역할을 하는데요. 단순히 영어만 보면 조금 헷갈립니다. hasNext는 "뭔가 다음에 있으면 가져오

yeon-kr.tistory.com

 

 

[백준] 10951번 : A+B - 4 - JAVA [자바]

https://www.acmicpc.net/problem/10951 10951번: A+B - 4 두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오. www.acmicpc.net 문제 간단한 문제지만 의외로 종료시점을 몰라 틀리는 경우들..

st-lab.tistory.com

 

 

 

'JAVA' 카테고리의 다른 글

[백준/JAVA] 버퍼입출력 BufferedReader/BufferedWriter  (0) 2022.06.08