Java 8

1. Java 8 설치

sudo yum install -y java-1.8.0-openjdk-devel.x86_64

2. ec2의 Java 버전 변경

sudo /usr/sbin/alternatives --config java

3. 확인

java -version

 

타임존 변경

1. 기본 타임존 UTC를 한국 시간 KST로 변경

sudo rm /etc/localtime
sudo ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime

2. 확인

date

사용자 요청 처리

1. 사용자는 어플리케이션의 서비스 주소로 접속 (80, 443)

2. nginx는 사용자의 요청을 현재 연결된 Spring Boot1(8081)로 요청을 전달

(Spring Boot2(8082)는 nginx와 연결된 상태가 아니므로 요청을 못 받음)

 

배포

1. 새로운 배포가 필요하면 현재 nginx와 연결되지 않은 Spring Boot2(8082)로 배포

(nginx는 Spring Boot1(8081)를 바라보기 때문에, Spring Boot2(8082)에 배포하는 동안 서비스는 중단되지 않음)

2. 배포가 끝나면 Spring Boot2(8082)를 실행시키고, 정상 구동 중인지 확인

3. Spring Boot2(8082)가 정상 구동 중이면, nginx reload명령으로 Spring Boot1(8081) 대신 Spring Boot2(8082)를 바라보도록 nginx설정을 다시 불러옴 (reload는 0.1초 이내에 완료됨)

 

 

Spring Boot와 JPA로 간단한 게시판을 구현할 수 있습니다.

Spring Security로 소셜 로그인(구글, 네이버) 기능을 개발할 수 있습니다.

개발한 게시판 어플리케이션을 Travis CI를 활용하여 빌드하고, aws S3와 codedeploy를 활용하여 ec2에 배포해볼 수 있습니다.

2개의 Spring Boot profile를 구성하고,  nginx를 활용하여 무중단 배포 환경도 구성해볼 수 있습니다.

 

목차

01장 인텔리제이로 스프링 부트 시작하기
_1.1 인텔리제이 소개
_1.2 인텔리제이 설치하기
_1.3 인텔리제이 커뮤니티에서 프로젝트 생성하기
_1.4 그레이들 프로젝트를 스프링 부트 프로젝트로 변경하기
_1.5 인텔리제이에서 깃과 깃허브 사용하기

02장 스프링 부트에서 테스트 코드를 작성하자
_2.1 테스트 코드 소개
_2.2 Hello Controller 테스트 코드 작성하기
_2.3 롬복 소개 및 설치하기
_2.4 Hello Controller 코드를 롬복으로 전환하기

03장 스프링 부트에서 JPA로 데이터베이스 다뤄보자
_3.1 JPA 소개
__Spring Data JPA
__실무에서 JPA
__요구사항 분석
_3.2 프로젝트에 Spring Data Jpa 적용하기
_3.3 Spring Data JPA 테스트 코드 작성하기
_3.4 등록/수정/조회 API 만들기
_3.5 JPA Auditing으로 생성시간/수정시간 자동화하기
__LocalDate 사용
__JPA Auditing 테스트 코드 작성하기

04장 머스테치로 화면 구성하기
_4.1 서버 템플릿 엔진과 머스테치 소개
__머스테치란
__머스테치 플러그인 설치
_4.2 기본 페이지 만들기
_4.3 게시글 등록 화면 만들기
_4.4 전체 조회 화면 만들기
_4.5 게시글 수정, 삭제 화면 만들기
__게시글 수정
__게시글 삭제

05장 스프링 시큐리티와 OAuth 2.0으로 로그인 기능 구현하기
_5.1 스프링 시큐리티와 스프링 시큐리티 Oauth2 클라이언트
_5.2 구글 서비스 등록
_5.3 구글 로그인 연동하기
__스프링 시큐리티 설정
__로그인 테스트
_5.4 어노테이션 기반으로 개선하기
_5.5 세션 저장소로 데이터베이스 사용하기
_5.6 네이버 로그인
__네이버 API 등록
__스프링 시큐리티 설정 등록
_5.7 기존 테스트에 시큐리티 적용하기

06장 AWS 서버 환경을 만들어보자 - AWS EC2
_6.1 AWS 회원 가입
_6.2 EC2 인스턴스 생성하기
_6.3 EC2 서버에 접속하기
_6.4 아마존 리눅스 1 서버 생성 시 꼭 해야 할 설정들

07장 AWS에 데이터베이스 환경을 만들어보자 - AWS RDS
_7.1 RDS 인스턴스 생성하기
_7.2 RDS 운영환경에 맞는 파라미터 설정하기
_7.3 내 PC에서 RDS에서 접속해 보기
__Database 플러그인 설치
_7.4 EC2에서 RDS에서 접근 확인

08장 EC2 서버에 프로젝트를 배포해 보자
_8.1 EC2에 프로젝트 Clone 받기
_8.2 배포 스크립트 만들기
_8.3 외부 Security 파일 등록하기
_8.4 스프링 부트 프로젝트로 RDS 접근하기
__RDS 테이블 생성
__프로젝트 설정
__EC2 설정
_8.5 EC2에서 소셜 로그인하기

09장 코드가 푸시되면 자동으로 배포해 보자 - Travis CI 배포 자동화
_9.1 CI & CD 소개
_9.2 Travis CI 연동하기
__Travis CI 웹 서비스 설정
__프로젝트 설정
_9.3 Travis CI와 AWS S3 연동하기
__AWS Key 발급
__Travis CI에 키 등록
__S3 버킷 생성
__.travis.yml 추가
_9.4 Travis CI와 AWS S3, CodeDeploy 연동하기
__EC2에 IAM 역할 추가하기
__CodeDeploy 에이전트 설치
__CodeDeploy를 위한 권한 생성
__CodeDeploy 생성
__Travis CI, S3, CodeDeploy 연동
_9.5 배포 자동화 구성
__deploy.sh 파일 추가
__.travis.yml 파일 수정
__appspec.yml 파일 수정
__실제 배포 과정 체험
_9.6 CodeDeploy 로그 확인

10장 24시간 365일 중단 없는 서비스를 만들자
_10.1 무중단 배포 소개
_10.2 엔진엑스 설치와 스프링 부트 연동하기
_10.3 무중단 배포 스크립트 만들기
__profile API 추가
__real1, real2 profile 생성
__엔진엑스 설정 수정
__배포 스크립트들 작성
_10.4 무중단 배포 테스트

11장 1인 개발 시 도움이 될 도구와 조언들
_11.1 추천 도구 소개
__댓글
__외부 서비스 연동
__방문자 분석
__CDN
__이메일 마케팅
_11.2 1인 개발 팁
_11.3 마무리

'' 카테고리의 다른 글

그림으로 공부하는 오라클 구조:개정판  (0) 2021.07.12

https://programmers.co.kr/learn/courses/30/lessons/42889

 

코딩테스트 연습 - 실패율

실패율 슈퍼 게임 개발자 오렐리는 큰 고민에 빠졌다. 그녀가 만든 프랜즈 오천성이 대성공을 거뒀지만, 요즘 신규 사용자의 수가 급감한 것이다. 원인은 신규 사용자와 기존 사용자 사이에 스

programmers.co.kr

import java.util.*;

class Solution {
    public int[] solution(int N, int[] stages) {
        int[] answer = new int[N];
        double[] fr = new double[N];	// 실패율 저장, 배열의 '인덱스+1' 은 스테이지
        double[] ascFr = new double[N];	// 오름차순 실패율
        
        for (int i = 0; i < answer.length; i++) {
        	int curStage = i+ 1;	// 검사대상 스테이지
        	int son = 0;	// 분자
        	int mom = 0;	// 분모
			for (int j = 0; j < stages.length; j++) {
				if(stages[j] >= curStage) {
					mom++;
					if(stages[j] == curStage) {
						son++;
					}
				}				
			}
			if(mom == 0) mom = 1;	// 분모가 0이면 안됨
			
			double failureRate = son / (double) mom;	// 실패율 계산
			
			fr[i] = failureRate;	// 실패율
			ascFr[i] = failureRate;	// 오름차순 실패율
		}        
        	Arrays.sort(ascFr);	// 실패율 오름차순 정렬
        
        for (int i = ascFr.length - 1; i >= 0; i--) {	// '실패율 배열 - 오름차순 실패율 배열' 매핑시켜서 스테이지를 찾음
			for (int j = 0; j < fr.length; j++) {
				if(ascFr[i] == fr[j]) {	
					answer[(ascFr.length - 1) - i] = j+1;	// 스테이지 기록
					fr[j] = -1;	// 찾은 실패율은 -1로 해서 또 안찾도록
					break;
				}
			}			
		}
        return answer;
    }
}

https://programmers.co.kr/learn/courses/30/lessons/64061

 

코딩테스트 연습 - 크레인 인형뽑기 게임

[[0,0,0,0,0],[0,0,1,0,3],[0,2,5,0,1],[4,2,4,4,2],[3,5,1,3,1]] [1,5,3,5,1,2,1,4] 4

programmers.co.kr

- 인형을 담는 바구니는 stack으로 구현

- 인형을 뽑아서 바구니에 넣기 전에 peek로 동일한 인형을 뽑았는지 확인을 한다. 동일한 answer를 2 증가시키고, pop 해서 동일한 인형을 제거

import java.util.*;

class Solution {
    public int solution(int[][] board, int[] moves) {
        
        int answer = 0;
        
        Stack<Integer> stk = new Stack<Integer>();	// 바구니    
        
        for (int i = 0; i < moves.length; i++) {	// 이동시키기
			int crainPosition = moves[i] - 1;
			for (int j = 0; j < board.length; j++) {				
				if(board[j][crainPosition] != 0) {					
					int doll = board[j][crainPosition];	// 뽑은 인형
					board[j][crainPosition] = 0; // 뽑은 자리는 빈자리로 설정
					
					// 바구니에 넣기
					if(stk.isEmpty()) {		// 비어있으면 그냥 넣음
						stk.push(doll);
					} else {	// 비어있지 않으면, 어떤 인형인지 확인
						if(doll == stk.peek()) {	// 같은 인형이면
							answer+=2;	// 인형제거는 항상 2개씩임
							stk.pop();
						} else {
							stk.push(doll);	// 다른 인형이면
						}
					}					
					break;
				}
			}
		}        
        return answer;
    }
}

'JAVA > 프로그래머스' 카테고리의 다른 글

34. LEVEL1 - 실패율  (0) 2021.08.27
32. LEVEL1 - 비밀지도  (0) 2021.08.26
32. LEVEL1 - 키패드 누르기  (0) 2021.08.26
31. LEVEL1 - 직업군 추천하기  (0) 2021.08.26
30. LEVEL 1 - 숫자 문자열과 영단어  (0) 2021.08.25

https://programmers.co.kr/learn/courses/30/lessons/17681

 

코딩테스트 연습 - [1차] 비밀지도

비밀지도 네오는 평소 프로도가 비상금을 숨겨놓는 장소를 알려줄 비밀지도를 손에 넣었다. 그런데 이 비밀지도는 숫자로 암호화되어 있어 위치를 확인하기 위해서는 암호를 해독해야 한다. 다

programmers.co.kr

class Solution {
    public String[] solution(int n, int[] arr1, int[] arr2) {
        String[] answer = new String[n];
        
        for (int i = 0; i < n; i++) {
        	
        	StringBuilder sb = new StringBuilder();
        	
        	Long num1 = 0L;
        	Long num2 = 0L;	
			
        	String arr1Binary = Integer.toBinaryString(arr1[i]);    // 1번 지도 이진수 변환
			num1  = Long.parseLong(arr1Binary);
			
			String arr2Binary = Integer.toBinaryString(arr2[i]);    // 2번 지도 이진수 변환
			num2  = Long.parseLong(arr2Binary);
			
			String sum = String.valueOf(num1 + num2);   // 1번 지도 + 2번 지도
			
			if(sum.length() < n) {  // 합친 결과의 길이가 n보다 작으면, 작은만큼 앞에 0을 붙임
				StringBuilder pad = new StringBuilder();
				for (int j = 0; j < n - sum.length(); j++) {
					pad.append("0");
				}
				sum = pad.toString() + sum;
			}

			for (int j = 0; j < sum.length(); j++) {
				if(sum.charAt(j) == '0') {  // 0 이면 공백
					sb.append(" ");
				}else { // 0 아니면 벽#
					sb.append("#");
				}
			}			
			answer[i] = sb.toString();  // 결과 기록
		}
        return answer;
    }
}

https://programmers.co.kr/learn/courses/30/lessons/67256

 

코딩테스트 연습 - 키패드 누르기

[1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5] "right" "LRLLLRLLRRL" [7, 0, 8, 2, 8, 3, 1, 5, 7, 6, 2] "left" "LRLLRRLLLRR" [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] "right" "LLRLLRLLRL"

programmers.co.kr

 

class Solution {
    
    int[][] keypad= {
			{1,2,3},
			{4,5,6},
			{7,8,9},
			{-1, 0, -1}
	};
	
    	// 왼손, 오른손 초기 위치
	int leftNum = -1;
	int rightNum = -1;
    
    public String solution(int[] numbers, String hand) {
        StringBuilder answer = new StringBuilder();			
				        
        for (int i = 0; i < numbers.length; i++) {
			if(numbers[i] == 1 || numbers[i] == 4 || numbers[i] == 7) { // 1,4,7 은 왼손으로 누름
				answer.append("L");
				leftNum = numbers[i];   // 왼손 위치 기록
			} else if(numbers[i] == 3 || numbers[i] == 6 || numbers[i] == 9) {  // 3,6,9 는 오른손으로 누름
				answer.append("R");
				rightNum = numbers[i];  // 오른손 위치 기록
			} else {
				answer.append(findHand(numbers[i], hand));  // 2,5,8,0 누를 손 찾기
			}
		}
        return answer.toString();
    }
    
    private String findHand(int targetNum, String hand) {
			
		int leftDist = 0;   // targetNum ~ 왼손 거리
		int rightDist = 0;  // targetNum ~ 오른손 거리

        	// 왼손, 오른손, 누를번호의 2차원 배열 상의 인덱스
		int leftIndex1 = 0;
		int leftIndex2 = 0;
		
		int rightIndex1 = 0;
		int rightIndex2 = 0;
		
		int targetIndex1 = 0;
		int targetIndex2 = 0;
		
		// 왼손의 2차원 배열 인덱스 찾기
		for (int i = 0; i < keypad.length; i++) {
			for (int j = 0; j < keypad[0].length; j++) {
				if(keypad[i][j] == leftNum) {
					leftIndex1 = i;
					leftIndex2 = j;
                    			break;
				}                
			}            
		}
		
		// 오른손의 2차원 배열 인덱스 찾기
		for (int i = 0; i < keypad.length; i++) {
			for (int j = 0; j < keypad[0].length; j++) {
				if(keypad[i][j] == rightNum) {
					rightIndex1 = i;
					rightIndex2 = j;
                    			break;
				}
			}
		}
		
		// 누를번호의 2차원 배열 인덱스 찾기
		for (int i = 0; i < keypad.length; i++) {
			for (int j = 0; j < keypad[0].length; j++) {
				if(keypad[i][j] == targetNum) {
					targetIndex1 = i;
					targetIndex2 = j;
                    			break;
				}
			}
		}
		
		leftDist = Math.abs(leftIndex1 - targetIndex1) + Math.abs(leftIndex2 - targetIndex2);   // targetNum ~ 왼손 거리
		rightDist = Math.abs(rightIndex1 - targetIndex1) + Math.abs(rightIndex2 - targetIndex2);    // targetNum ~ 오른손 거리
		        
		if(leftDist > rightDist) {  // 오른손이 가까움
			rightNum = targetNum;
			return "R";
		}			
		else if(leftDist < rightDist) { // 왼손이 가까움
			leftNum = targetNum;
			return "L";
		}			
		else {  // 거리가 같으면
			if("right".equals(hand)) {  // 오른손잡이
				rightNum = targetNum;
				return "R";
			}				
			else {  // 왼손잡이
				leftNum = targetNum;
				return "L";
			}				
		}
	}
}

https://programmers.co.kr/learn/courses/30/lessons/84325

 

코딩테스트 연습 - 4주차

개발자가 사용하는 언어와 언어 선호도를 입력하면 그에 맞는 직업군을 추천해주는 알고리즘을 개발하려고 합니다. 아래 표는 5개 직업군 별로 많이 사용하는 5개 언어에 직업군 언어 점수를 부

programmers.co.kr

 

 

import java.util.*;

class Solution {
    public String solution(String[] table, String[] languages, int[] preference) {
        String answer = "";        
        
        Arrays.sort(table); // 나중에 사전순으로 빠른 직업군을 찾기 위해서 미리 정렬
        List<String> lang = Arrays.asList(languages);   // 개발자가 선호하는 언어 List
        
        int[] score = new int[5];	// 직업군별 점수 기록용
        String[] jobs = new String[5];  // 직업군
        
        // 직업군 별 점수 집계
        for (int i = 0; i < table.length; i++) {			
			String[] jobLan = table[i].split(" ");
			jobs[i] = jobLan[0];    // 직업군을 jobs 배열에 기록 [CONTENTS, GAME, HARDWARE, PORTAL, SI]
			int subScore = 0;	// 각 직업군별 총 점수 기록
			for (int j = 1; j < jobLan.length; j++) {				
				if(lang.indexOf(jobLan[j]) != -1) {	// 각 직업군에 개발자의 선호 언어가 있으면 (없으면 -1 반환)
					subScore += (6 - j) * preference[lang.indexOf(jobLan[j])];  // 직업군별 언어 점수 * 언어선호도 합계 계산
				}				
			}
			score[i] = subScore;    // 직업군별 점수 기록
		}      
        
        // 최고점
        int maxScore = 0;
        for (int i = 0; i < score.length; i++) {
			if(maxScore < score[i]) {
				maxScore = score[i];
			}
		}
    
        // jobs에 직업군이 사전순 정렬되 있으므로, 최고점 찾으면 바로 끝냄
        for (int i = 0; i < score.length; i++) {
			if(maxScore == score[i]) {
				answer = jobs[i];
				break;
			}
		}
        
        return answer;
    }
}

https://programmers.co.kr/learn/courses/30/lessons/81301

 

코딩테스트 연습 - 숫자 문자열과 영단어

네오와 프로도가 숫자놀이를 하고 있습니다. 네오가 프로도에게 숫자를 건넬 때 일부 자릿수를 영단어로 바꾼 카드를 건네주면 프로도는 원래 숫자를 찾는 게임입니다. 다음은 숫자의 일부 자

programmers.co.kr

class Solution {

	String[] numWord = {"zero","one","two","three","four","five","six","seven","eight","nine"};

	public int solution(String s) {
		
        int answer = 0;
        String targetStr = "";
        
        for (int i = 0; i < s.length(); i++) {			
			if('a' <= s.charAt(i) && s.charAt(i) <= 'z') {	// 문자를 만나면
				targetStr+=String.valueOf(s.charAt(i));
				int num = findNum(targetStr);
				if(num == -1) {	// 못찾음
					continue;
				}else {	// 찾음
					answer = (answer * 10) + num;
					targetStr = "";
				}
			}else {
				answer = (answer * 10) + (s.charAt(i)-'0');	// 숫자를 만나면
			}
		}    
        return answer;
    }

	private int findNum(String targetStr) {
		int num = -1;
		for (int i = 0; i < numWord.length; i++) {
			if(targetStr.equals(numWord[i])) {
				num = i;
				break;
			}
		}
		return num;
	}
}

https://programmers.co.kr/learn/courses/30/lessons/81302

 

코딩테스트 연습 - 거리두기 확인하기

[["POOOP", "OXXOX", "OPXPX", "OOXOX", "POXXP"], ["POOPX", "OXPXP", "PXXXO", "OXXXO", "OOOPP"], ["PXOPX", "OXOXP", "OXPOX", "OXXOP", "PXPOX"], ["OOOXX", "XOOOX", "OOOXX", "OXOOX", "OOOOO"], ["PXPXP", "XPXPX", "PXPXP", "XPXPX", "PXPXP"]] [1, 0, 1, 1, 1]

programmers.co.kr

O는 이동이 가능한 통로, X는 이동할 수 없는 벽이라고 생각한다.

각 P마다 이동이 가능한 O를 따라서 2번 이동했을때 P를 만나면 false를 반환하면 된다.

각 P를 시작점으로 BFS를 사용해서 풀이할 수 있다.

 

import java.util.*;

class Solution {
    
    int[][] D = {
			{-1,0},		// 상
			{1,0},		// 하
			{0, -1},	// 좌
			{0,1}		// 우
	};
	
	class Node {	// 노드 클래스
		int row;    // 좌표
		int col;
		int dist;   // 맨해튼 거리
		
		public Node(int row, int col, int dist) {
			this.row = row;
			this.col = col;
			this.dist = dist;
		}		
	}
    
    public int[] solution(String[][] places) {
        int[] answer = new int[5];	// 결과 배열의 길이는 대기실 개수
        
        for (int i = 0; i < answer.length; i++) {	// 대기실을 하나씩 검사
			if(check(places[i])) {
				answer[i] = 1;	// i 대기실이 거리두기를 지키면 1
			}else {
				answer[i] = 0;	// i 대기실이 거리두기를 안지키면 0
			}
		}
        return answer;
    }
    
    public boolean check(String[] places) {	// places는 대기실 하나 
		
		for (int i = 0; i < places.length; i++) {
			for (int j = 0; j < places.length; j++) {
				if(places[i].charAt(j) == 'P') {
					if(!bfs(i, j, places)) {
						return false;
					}
				}
			}
		}		
		return true;		
	}
    
    public boolean bfs(int i, int j, String[] places) {
		Queue<Node> queue = new LinkedList<Node>();
		boolean[][] visit = new boolean[5][5];	// 방문체크
		
		queue.offer(new Node(i, j, 0));	// 시작 Node 넣기
		
		while(!queue.isEmpty()) {
			Node node = queue.poll();	// 큐에서 제거
			visit[node.row][node.col] = true;	// 방문체크					
			
			// 문제 처리
			if((node.dist == 1 || node.dist == 2) && places[node.row].charAt(node.col) == 'P') {				
				return false;   // 2회 이동 안에 P가 있으면 거리두기 안 지킴
			}
			
			// 이동하기
			for (int k = 0; k < 4; k++) {
				int nrow = node.row + D[k][0];	// 이동할 좌표 설정
				int ncol = node.col + D[k][1];
                
				if(nrow < 0 || nrow >= 5 || ncol < 0 || ncol >= 5) 
					continue;	// 범위를 벗어나며 이동 불가
				if(visit[nrow][ncol])
					continue;	// 방문했던 Node면 이동 불가
				if(places[nrow].charAt(ncol) == 'X')
					continue;	// 파티션이면 이동 불가				
				
				queue.add(new Node(nrow, ncol, node.dist + 1));
			}
		}
		return true;
	}
}