Heap이란 부모노드가 자식보다 항상 크거나 항상 작은 이진트리이다.
❓ 힙(Heap) 자료구조를 사용하는 이유힙은 최대/최소를 구하는데 특화되어 있는 자료구조
루트의 값만 바로 가져오면 되기 때문에 O(1)의 시간복잡도로 최대값 혹은 최소값 구하기 가능
새로운 값을 추가(add)하거나 삭제(poll)하는 경우, Olog(n)의 시간복잡도를 가진다
Heap은 구현방식에 따라 여러가지 형태를 가질 수 있는데 대표적으로 Max-Heap(최대힙), Min-Heap(최소힙) 이 있다.
최대힙, 최소힙 
Max-Heap(최대힙)
Min-Heap(최소힙)

첫번째 )
[6, 5, 7, 8]을 배열에 담아보고 root가 가장 큰 heap으로 만든다.
순서는 자식이 있는 가장 마지막 부모부터 시작하여,
그리고 부모노드의 값이 자식노드의 값보다 커야한다는 Heap 형태로 만들어준다.
💡 여기서 유의할 점은 자식노드는 바로 근처의 자식뿐만 아니라, 모든 자손을 뜻한다는 것이다. - 세번째 단계에서 해결

public static void main(String[] args) {
int [] arr = new int[] {6,5,7,8};
int temp = arr[1];
arr[1] = arr[3];
arr[3] = temp;
temp = arr[0];
arr[0] = arr[1];
arr[1] = temp;
System.out.println(Arrays.toString(arr));
}
결과 - { 8,6,7,5 }
두번째 ) 부모의 index를 입력하면 왼쪽, 오른쪽 index를 return하는 함수
형제끼리는 규칙이 없지만 부모와 자식간에는 규칙이 있다.
// 부모의 index 입력하면 자식 index 반환하는 함수
public int [] findChild(int index) {
int [] answer = {index*2+1, index*2+2};
return answer;
}
세번째 ) greaterIdx 변수 추가하여 자손까지 정렬해준다.
// 최대힙
public static int[] makeHeap(int[] arr, int parentIdx, int arrSize) {
int leftIdx = 2 * parentIdx + 1;
int rightIdx = 2 * parentIdx + 2;
int greaterIdx = parentIdx;
// 왼쪽이 parent보다 크면 greateridx=leftIdx 6 7 5 -> 7 6 5
if(leftIdx < arrSize && arr[leftIdx] > arr[greaterIdx]){
greaterIdx = leftIdx;
}
//오른쪽 자식이 greater 보다 크면
if(rightIdx < arrSize && arr[rightIdx] > arr[greaterIdx]){
greaterIdx = rightIdx;
}
// swap
if(parentIdx != greaterIdx){
int temp = arr[parentIdx];
arr[parentIdx] = arr[greaterIdx];
arr[greaterIdx] = temp;
makeHeap(arr, greaterIdx, arrSize);
}
return arr;
}
public static void main(String[] args) {
int[] arr = new int[]{6, 5, 7, 8};
arr = new int[]{10, 9, 5, 8, 3, 2, 4, 6, 7, 1};
for (int j = (arr.length-2) / 2; j >= 0 ; j--) {
arr = makeHeap(arr, j, arr.length);
System.out.println(Arrays.toString(arr));
}
// 정렬
for (int i = arr.length - 1; i > 0 ; i--) {
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
arr = makeHeap(arr, 0, i);
System.out.println(Arrays.toString(arr));
}
}

목표
이때까지 만들어 온
"/api/v1/users/join"url은 User에게 전달 받은 userName, password, email 등을 DB에 그대로 저장했다. password와 같은 민감정보는 암호화를 해야하므로 Spring Security 를 사용하여 암호화한다.
애플리케이션의 인증, 인가 등의 보안 기능을 제공하는 스프링 하위 프레임워크
인증(authentication)
: 사용자가 누구인지 확인하는 단계
ex) 로그인
DB에 등록된 id,pw를 사용자가 입력한 id,pw와 비교하여 일치 여부를 확인한다.
로그인에 서버는 사용자에게 토큰을 전달한다.
인가(authorization)
: 애플리케이션 내부의 리소스에 접근 권한 확인.
보통 인증 단계에서 발급 받은 토큰에 인가 내용이 포함되어 있다.
ex) 회원별 접근 가능 게시판 상이
JWT(JSON Web Token)
: 당사자 간에 정보를 JSON 형태로 안전하게 전송하기 위한 토큰
구성요소 - 헤더.내용.서명
헤더: 검증과 관련된 내용 ( 해싱 알고리즘 지정, 토큰 타입 지정)
내용: 토큰에 담는 정보, 클레임,
서명: 인코딩된 헤더, 인코딩된 내용, 비밀키, 헤더의 알고리즘 속성값을 가져와 생성
// HMAC SHA256 알고리즘을 사용해서 서명을 생성한다면?
HMACSHA256 (
base64UrlEncode(header) + "."+
base64UrlEncode(payload),
secret
)
Security 관련 용어들을 카타르 월드컵에 비유해서 설명해보자면,
인증 - 월드컵 구장 안에 들여 보내 주는것
인가 - 그 기능에 권한이 있는지 확인 : VIP석, R석, S석, 일반석
JWT - Claim 좌석번호, 승객이름


💻 SecurityConfig.class
@EnableWebSecurity가 선언된 클래스가 있다면 Spring Security 동작Bean으로 등록하여 사용하도록 변경됨 @Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
.httpBasic().disable() : 기본 설정은 비인증 시 로그인 폼 화면으로 리다이렉트 되며, Rest API이므로 기본설정을 사용하지 않기 위해 disable() 설정.csrf().disable() : 정상적인 사용자가 의도치 않은 위조요청을 보내는 것(Cross site Request forgery; csrf)로부터 보호하는 것을 사용하지 않음 👉 Rest API 서버는 Stateless 상태이므로 서버에 인증정보를 보관하지 않기 때문에.cors() : 교차 출처를 공유할 수 있는 권한을 부여하도록 브라우저에 알려주는 정책(Cross-Origin Resource Sharing; CORS) 으로, 서로 다른 출처를 가진 Application이 서로의 Resource에 접근할 수 있도록 해줌.authorizeRequests() : HttpServletRequest를 이용