02-1 재활용할 수 있는 블록 함수

 - ES6부터 스코프를 고려한 변수 관리기능 강화 및 변수에 함수를 저장하는 함수표현식 추가.

 

선언식(declaration) : 기존 선언방식

 - function 뒤에 함수 이름을 적고 소괄호()안에 필요한 매개변수를 쉼표(,)로 구분해서 작성, 함수가 수행할 명 령을 중괄호 {}로 감싸서 구현

<!DOCTYPE html>
<html>
<head>
    <title>Page Title</title>
<script>
/*
  함수명(매개변수, ...){
  	// 명령
  }
   - 호출부와 함수의 연결(인터페이스) : 매개변수
*/
function fnSayHello(){
	alert("기존 함수사용방식");
    return;
}

</script>
<body>

    <button onclick="fnSayHello()"> 눌러주세요 </button>

</body>
</html>

 - 함수이름 선언 : fnSayHello
 - alert : 자바스크립트 내장함수 : 문자열을 메시지 창에 표시

 - return : 처리결과 응답 (생략가능 : undefined 반환) 

 - 매개변수 : 없을 시 () 로 생략 가능

 - 버튼 클릭시 fnSayHello() 함수 호출 : onclick

 - 버튼제목 : <button> 테그사이의 문자열이 버튼에 표시됨
 > 이벤트 핸들러 : 키보드나 마우스 버튼을 눌러서 이벤트가 발생하면 자바스크립트 코드와 연결시키는 역할

 

표현식(expression) : ES6+ 함수 표현식

 - 함수명 없이 선언한 후에 객체 변수에 저장 : 함수를 호출할 때는 변수명을 이용 (모던 자바스크립트)

/*
  표현식 함수형 변수 선언
*/
const fnMinusNumbers = function(pNum1, pNum2){
    return pNum1 - pNum2;
}

 - fnMinusNumbers() 함수의 함수 표현식 선언 : 변수명 = 함수명

 - 매개변수 2개를 입력받고 처리결과 반환

/*
  [표현식]
  변수 = function(매개변수, ...){
    // 명령
  }
*/
const fnMinusNumbers = function(pNum1, pNum2){
    return pNum1 - pNum2;
}

<button onclick="console.log(fnMinusNumbers(3, 5))">3 - 5 = ?</button>

자바스크립트의 호이스팅

  • 자바스크립트에서 함수 선언식은 호이스팅 (hoisting)이 적용됨
    - 호이스팅 : 코드를 실행하기 전에 내부에서 변수와 함수의 위치를 맨 위로 옮겨 선언
    > 장점 : 변수나 함수를 좀 더 유연하게 사용
    > 단점 : 오류가 생기면 찾기 어렵다
  • 선언식을 사용한 fnSayHello() 함수 / 표현식을 사용한 fnSayHello2() 함수
     - 선언문 보다 호출문을 먼저 작성했을 때 호이스팅 영향
/*
  [호이스팅]
*/
fnSayHello1();
function fnSayHello1(){
    console.log("선언식 함수 호출");
}

fnSayHello2();
const fnSayHello2 = function(){
    console.log("표현식 함수선언 변수 호출");
}

 - 선언식 함수를 정의하면 호이스팅으로 선언하기 전 코드에서 함수를 사용할 수 있음
 - 표현식 함수선언 변수는 호이스팅 대상이 아니기 때문에 선언하기 전 코드에서 변수(함수)를 사용할 경우 오류발생

 

[DoIt!실습] 함수 선언식과 표현식 실습하기

 - 0201. : Doit 실습 - 함수 선언식과 표현식 실습하기

 - \0201\ex02-01\function.html

<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <title>Page Title</title>
</head>
<body>
    <button onclick="console.log(fnSayHello())" id="clickme">눌러주세요!</button>
    <br/>
    <button onclick="alert(fnPlusNumbers(3,5))">3+5 = ?</button>
    <button onclick="console.log(fnMinusNumbers(3,5))">3 - 5 = ?</button>
    <script>
        function fnSayHello(){
            document.querySelector('#clickme').innerHTML = '안녕하세요';
        }
        function fnPlusNumbers(pNum1, pNum2){
            return pNum1 + pNum2;
        }
        const fnMinusNumbers = function (pNum1, pNum2){
            return pNum1 - pNum2;
        }
    </script>
</body>
</html>

 - document.querySelector('#clickme').innerHTML = '안녕하세요';
  > id값이 #clickme 엘리먼트의 내용 설정

 - 덧샘결과 반환 함수의 선언식 표현 : fnSayHello

 - 뺄셈결과 반환 함수의 함수 표현식 : fnMinusNumbers

 

* 실행

* [눌러주세요!] 버튼클릭
 - 안녕하세요 표시문구 변경

* 3+5 버튼 클릭

* 3-5 버튼 클릭

 



02-2 변수 선언

var : 함수 스코프(function scope)만 지원, 블록 스코프(block scope) 지원 안함.

 - 스코프 : 유효범위

 

* 함수 스코프 예시

 - 함수에서 선언한 변수를 함수 밖(전역)에서 사용하면 오류발생

<script>
    fnMyFunction();
    function fnMyFunction(){
        var apple = 5;
        console.log(apple); // 5 출력
    }
    console.log(apple); //오류! Uncaught ReferenceError: apple is not defined
</script>

* 블록 스코프 예시

 - var 키워드는 블록스코프 지원하지 않음 : 블록내부 var 변수는 외부사용 가능

<script>
    var apple = 3;
    {
        var apple = 5;      // var 선언 변수는 블록 스코프가 아니어서 재선언 가능
        console.log(apple); // 5 출력
    }
    console.log(apple);     // 3 대신 5 출력
</script>

 - var 변수 : 전역변수 

 - 블록내 var 변수 : 동일한 이름으로 다른값 할당 (재할당)

 - 블록내에서 재할당한 변수는 블록에만 유효한 것이 아닌 전역변수 값을 변경함
  > var는 함수스코브에서만 유효성이 제한됨

* var 특징

  - 블록스코프 미지원 : 함수외부 선언 변수는 전역변수 역할

  - 같은 이름으로 중복선언 가능 : 기존에 선언한 변수를 덮어씀.

  > 블록으로 명시적인 스코프 적용을 의도하는 실수 등 코드 가독성을 저해하고, 디버그에 어려움 발생.

  : var 대안으로 let, const 사용

 

* let, const 키워드 : 블록 스코프 지원

  - 블록외부에서 사용 불가

  - 중복선언 제한

  > let : 스코프 적용한 변수선언 - 가변(mutable)

  > const : 스코프 적용한 상수선언 - 불변(immutable)

<script>
    {
        let apple = 3;
        console.log(apple);     // 3 출력
        apple = 5;              // let 변수 재할당 가능
        console.log(apple);     // 5 출력
        let apple = 7;          // let 변수 재선언 불가 - Identifier 'apple' has already been declared 

        const car;              // const 선언, 할당 동시 설정 필요
        const carname = "하이브리드카";
        console.log(carname);   // '하이브리드카' 출력
        carname = "디젤카";      // const 재할당 불가 - 불변성

    }
    console.log(apple);     // 블록내 let 변수 참조 불가
    console.log(carname);   // 블록내 const 변수 참조 불가
</script>

* 모던 자바스크립트에서 변수 사용 3원칙

 - const 우선 사용 : 변경대상이 아닌 변수

 - let 차선 사용 : 변경사용 변수

 - var 불가피한 경우 사용 : 전역변수 필요시 최상위 수준에서 사용 

 

* 하나만 더 - console.log() 함수와 템플릿 리터럴로 디버깅

 - 디버깅시 alert() 함수사용으로 브라우저에서 팝업창을 이용하여 결과 값 확인

 - 템플릿 리터럴 : 역따옴표 [`] - 문자열 안에 표현식 적용 가능  > 달러($), 중괄호({}) 를 이용하여 여러줄 사용

 - 디버그 시 브라우저 개발자도구의 콘솔 창 활용

<script>
    let apple = 3;
    const carname = "하이브리드카";
    console.log('사과: '+apple+', 자동차: '+carname);     // 이전 스타일
    console.log(`사과: ${apple}, 자동차: ${carname}`);  // ES6 스타일(템플릿 리터럴)
</script>




02-3 화살표 함수

* ES6 문법에서 추가된 새로운 함수표현
기존 : funtion(){ return ... }
개선 : function, return 키워드 생략, => (fat arrow) 기호로 직관적인 표현

 

* 화살표 함수 예

// 전통 함수 표현식
const fnPlusNumbers = function(pNum1, pNum2){
    return pNum1 + pNum2;
}
// 화살표함수 표현식
const fnPlusNumbers2 = (pNum1, pNum2) => {
    return pNum1 + pNum2;
}
// 화살표함수 표현식 - return 생략 (실행문 하나인 경우 불필요햔 중괄호도 함께 생략)
const fnPlusNumbers3 = (pNum1, pNum2) => pNum1+pNum2;
// 매개변수 1개인 경우 소괄호 생략
const fnPlusNumbers4 = pNum => pNum+1;
// 매개변수 0개인 경우 () 만 표시
const fnPlusNumbers5 = () => '안녕하세요.';

[DoIt!실습] 화살표 함수 실습하기

 - 0202. : Doit 실습 - 화살표 함수 실습하기

 - \0201\ex02-02\arrow_function.html

* 코드

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>arrow_function</title>
</head>
<body>
    <button onclick="
        console.log(fnSayHello());
        console.log(`1+2 = `, fnPlusNubers1(1,2));
        console.log(`2+3 = `, fnPlusNubers2(2,3));
        console.log(`3+4 = `, fnPlusNubers3(3,4));
        console.log(`4+1 = `, fnPlusNubers4(4));
    " id="clickme">화살표 함수 실행!</button>
    <script>
        const fnPlusNubers1 = function(pNum1, pNum2){
            return pNum1 + pNum2;
        }
        const fnPlusNubers2 = (pNum1, pNum2) => {
            return pNum1 + pNum2;
        }
        const fnPlusNubers3 = (pNum1, pNum2) => pNum1 + pNum2;
        const fnPlusNubers4 = (pNum1) => pNum1 + 1;
        const fnSayHello = () => '안녕하세요!';
    </script>
</body>
</html>

 -  버튼을 만들고 onclick 이벤트 핸들러에 각 함수 호츨문 등록.
 > onclick=" ~ "
 - 매개변수를 두 개 입력받아 덧셈 후 반환하는 함수 선언.
 > fnPlusNumbers1;
 - function 키워드를 생략한 화살표 함수 선언.
 > fnPlusNumbers2;

 - 화살표 함수에서 return 키워드 생략. (자동으로 결과값 반환) 한줄이므로 중괄호 {}도 생략.
 > fnPlusNumbers3;
 - 화살표 함수에서 매개변수가 하나일 때는 소괄호 ()도 생략.
 > fnPlusNumbers4;
 - 
화살표 함수에서 매개변수가 없을 때는 반드시 소괄호 ()를 사용.
 > fnSayHello();

 

* 실행결과



02-4 모듈 내보내기와 가져오기

모듈(module) : 코드를 관리하는 가장 작은 단위
 - 코드 관리와 재활용에 용이 :
 소스 복잡 > 변수, 함수 충돌 증가
 - ES6부터는 import, export 문 추가 : 모듈을 이용한 협업 개선
 - 모듈 내보내는 방식 
 > 여러 값을 공유하는 ‘이름으로
(named) 내보내기’

 > 기본값 하나만 공유하는 ‘기본으로(default) 내보내기’ 방식

 

* 이름으로 내보내고 가져오기
 - 소스 파일에 선언된 식별자를 복수로 선택 공유
 > export 키워드 작성 > 공유하고 싶은 식별자를 쉼표로 나열 : 중괄호 {}로 감싸기
 (식별자 : 변수, 상수, 함수, 클래스 등을 선언한 이름)

//외부와 공유할 conHello 상수 와 fnPlusNumbers 함수 선언
const conHello = '안녕하세요';
const fnPlusNubers = (pNum1, pNum2) => pNum1 + pNum2;

//외부 사용을 위해 내보내기
export {conHello, fnPlusNubers};

 - export 키워드 다음에 작성한 식별자 이름 : 모듈을 사용할 파일에서 import 키워드로 가져올 식 별자 이름과 일
 > {conHello, fnPlusNubers}

- 이름을 다르게 해서 내보내기 : 내보낼 식별자 이름 뒤에 as 키워드를 이용하 새 이름 지정

 > 외부 파일에서 새 이름으로 참조 가능

// js 파일에서 내보낸 식별자를 가져와 conHello, fnPlusNumbers 객체에 저장
import {conHello, fnPlusNubers} from './04-1_ibrary_named.js';
console.log("conHello : ", conHello);
console.log("fnPlusNubers : ", fnPlusNubers(1,2));

// js 파일에서 내보닌 모든 식별자를 가져와 myLibrary 객체에 저장
import * as myLibrary from './04-1_ibrary_named.js';
console.log("myLibrary.conHello : ", myLibrary.conHello);
console.log("myLibrary.fnPlusNubers : ", myLibrary.fnPlusNubers(1,2));

- 내보낸 모듈을 다른 파일에서 가져와 쓰려면 import 키워드를 사용

 > from 키워드 다음에 해당식별자 가 선언된 모듈. 즉 소스 파일의 경로 선언 : './04-1_ibrary_named.js'
- 모든 식별자 호출 : 별표(*) 선언

 > as 키워드와 함께 객체명지정 : as myLibrary

 > 객체에 점(.)을사용해서 식별자를사용 : myLibrary.conHello

 

* 기본으로 내보내고 가져오기

 - 소스 파일에 있는 식별자 중 하나를 대표로 지정
 > export 키워드 다음에 default 키워드를 추가

 - 모듈 하나 당 하나의 함수나 클래스만 공유
 > var, let, const는 사용 불가

/* HOST : 04-4_default.js*/
// 외부와 공유할 함수 : 기본(default) 내보내기는 모듈 하나에 하나의 함수나 클래스 만 가능 (var, let, const 불가)
const fnPlusNubers = (pNum1, pNum2) => pNum1 + pNum2;

// 기본 모듈 내보내기
export default fnPlusNubers;

/* GUEST */
//외부에서 기본 모듈로 내보내기 후 이름을 변경하여 사용
import fnMyFunction from './04-4_default.js';
console.log("fnMyFunction : ", fnMyFunction(1,2));

 - export default로 내보낸 식별자를 가져올 때 이름 변경가능
 >
library_default.js 소스에서 내보낸 함수 : fnPlusNumbers()
 > 가져올 때 : fnMyFunction() 이름변경

 

[DoIt!실습] 모듈 export, import 실습하기

 - 0203. : Doit 실습 - 화살표 함수 실습하기

* 코드

 - \0201\ex02-03\library_named.js

//외부와 공유할 conHello 상수 와 fnPlusNumbers 함수 선언
const conHello = '안녕하세요';
const fnPlusNubers = (pNum1, pNum2) => pNum1 + pNum2;

//외부 사용을 위해 내보내기
export {conHello, fnPlusNubers as fnPlusNumbers};

// 간소화 방법
// export const conHello = '안녕하세요!';
// export const fnPlusNumbers = (pNuml, pNum2) => pNuml + pNum2;

 - \0201\ex02-03\library_default.js

// 외부와 공유할 함수 : 기본(default) 내보내기는 모듈 하나에 하나의 함수나 클래스 만 가능 (var, let, const 불가)
const fnPlusNubers = (pNum1, pNum2) => pNum1 + pNum2;

// 기본 모듈 내보내기
export default fnPlusNubers;

 - \0201\ex02-03\main.js

// js 파일에서 내보낸 식별자를 가져와 conHello, fnPlusNumbers 객체에 저장
import {conHello, fnPlusNumbers} from './library_named.js';
console.log(conHello, "이름으로 내보내기입니다.");
console.log("[fnPlusNubers] 1 + 2 = : ", fnPlusNumbers(1,2));

// js 파일에서 내보닌 모든 식별자를 가져와 myLibrary 객체에 저장 : * 
import * as myLibrary from './library_named.js';
console.log(myLibrary.conHello, "*을 사용한 이름으로 내보내기 입니다.");
console.log("[myLibrary.fnPlusNubers] 3 + 3 = : ", myLibrary.fnPlusNumbers(3,4));

// default export를 이용한 기본 내보내기
import fnMyfunction from './library_default.js';
console.log("안녕하세요! 기본으로 내보내기입니다.");
console.log("[fnMyFunction] 5 + 6 = ", fnMyfunction(5,6));

 - \0201\ex02-03\main.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>module-import2</title>
</head>
<body>
    <p>콘솔 창을 열어서 결과를 확인하세요!</p>
    <!-- 모듈 사용 시 type 어트리뷰트값으로 "module"을 지정합니다. -->
    <script type="module" src="main.js"></script>
</body>
</html>

- HTML 문서에서 import, export 문을 사용한 모듈 파일을 가져올 때 : 가져온 파일을 모듈로 인식
 > <script> 엘리먼트의 type 어트리뷰트값을 반드시 "module"로 지정

 > 모듈이 되면 import, export 구문을 사용, 상수 선언은 모듈 스코프로 관리

 > 모듈 파일에 선언된 내용은 외부에서 사용할 수 없고 반드시 그 안에서 만 동작

 



02-5 콜백 함수와 비동기 처리 방식

Promise(ES6에 새롭게 추가) 이해를 위한 중간 개념정리

 - 동기(synchronous) 처리 방식 : 순서대로 실행 - 일렬

 - 비동기(asynchronous) 처리 방식 : 선행작업까지 기다리지 않고 실행 - 병렬


* 동기와 비동기 처리 개념 이해하기

구분 동기 처리 방식  비동기 처리 방식
실행 순서  • 모든 코드가 위에서 아래 순서로 실행   • 코드들이독립적으로실행
실행 대기 • 명령 요청 후 결과 응답시 까지 대기
 - 반환 결과를 계속 기다리므로 시간 지연이 큼
 • 명령을 요청 후 결과와 상관없이 다음작업 실행
 - 요청결과 응답시 별도 응답처리


* 콜백 함수로 비동기 처리 구현하기

 - 보통 함수는 값을 매개변수로 전달받는데
 > 자바스크립트에서 함수는 객체로 취급 - 함수의 매개 변수로 함수 전달 가능

// 콜백함수로 사용되는 함수
function fnFunctionA(pNum){
    return pNum;
}
// 콜백함수를 호출할 함수
function fnFunctionB(pFunc){
    console.log("fnFunctionB param fnFunctionA : "+pFunc(20));
}

fnFunctionB(fnFunctionA); // fnFunctionB 함수에 매개변수로 fnFunctionA 함수 전달

 - 매개변수로 전달된 함수 : 콜백함수 - fnFunctionA

 > 콜백함수는 다른 함수에 독립적으로 실행됨 : 비동기처리 구현시 사용

 - 두번째로 전달받은 fnFunctionA() 함수가 fnFunction() 함수에서 fnCallBack 매개변수에 담겨 실행딜 때 비동기로 실됨.

 

* 단순하게 표현한 콜백함수 구조 : 콜백함수 선언과 정의 함께 작성 > ES6 부터 Promise 방식으로 개

// 매개변수 전달 시 함수 선언과 정의 함께 작성 : 비동기처리의 완료 로직 적용
fnFunctionB("콜박함수실행!", function fnFunctionA(pNumA){
    console.log("pNumA : " + pNumA);
});

// 콜백함수를 호출할 함수
function fnFunctionB(pNumB, fnCallBack){
    fnCallBack(pNumB);
}

 

* 콜백으로 호출한 함수가 실행될때 비동기로 처리되는것이라고?

 - 함수 호출구조로 비동기처리가 된다?

 

* 콜백 비동기 호출 예
 -  비동기 처리 함수 : 독립적으로 실행되고 결과도 별도로 처리하는 함수

//콜백함수 실행
fnMsg(fnHello);

// 콜백함수 : 3 실행 후 실행
function fnMsg(fnCallback){
    console.log("1"); // first
    fnCallback(); // 매개변수로 전달받은 함수실행 : 비동기
    console.log("3"); // second
}

function fnHello(){
    setTimeout(() => console.log("2"), 1000); // third - 2초 후 실행에 따라 지연출력
}

 

[DoIt!실습] 콜백 함수의 비동기 처리 방식으로 상품 배송 서비스 구현하기

 - 0204. : Doit 실습 - 비동기 처리 방식 비스 구현하기

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>callback</title>
</head>
<body>
    <button onclick="
    /*콜백 함수를 순서대로 실행하면 콜백 지옥의 문제점 발생!*/
    fnProductReady(1, 2000, function(pRet){
        console.log(pRet);
        fnProductReady(2, 1000, function(pRet){
            console.log(pRet);
            fnProductReady(3, 500, function(pRet){
                console.log(pRet);
                console.log('가독성이 낮고 유지,보수하기 어려운 콜백 지옥 발생!');
            })
        })
    })
    ">콜백 함수 실행!</button>
    
    <script>
        //콜백 함수 생성
        function fnProductReady(pNum, pTime, fnCallback){
            setTimeout(() => {
                console.log(pNum);
                fnCallback("상품이 성공적으로 배송되었습니다");
            }, pTime); // 타이머로 가상의 네트워크 지연 상황 연출
        }
    </script>
</body>
</html>

- 버튼클릭 : 콜백함수를 매개변수로 갖는 함수를 호출하며 자신 함수를 콜백함수로 전달 (중첩선언)
 > 콜백함수 2초, 1초, 0.5초 소요메서드 호출

 > 지연시간 이후 다음 콜백함수 호출

- 콜백함수 : fnProductReady()

 > 매개변수 3개 : 실행번소, 타이머지연시간, 콜백함수

 > 실행번호, 메시지 표시

- 중첩 선언으로 콜백지옥 문제점 확인

- 타이머를 이용한 시간지연 효과 적용 : setTimeout(function, milliseconds);
 > function : 타이머 종료 후 실행될 함수

 > milliseconds : 타이머 동작시간 (ms - 1초 = 1000ms)

 

* 콜백 함수의 한계와 Promise

 - 콜백함수 : 유지보수, 가독성 저하

 > 콜백지옥 구성 : 중첩 코드 구성에서 발생

 > 반환값 처리 문제 : 콜백함수 종료 후 반환값 처리시점이 분리됨 - 부적응

 - 대안 : Promise



02-6 JSON과 Fetch API

* Fetch API를 이용해 서버에서 JSON 데이 터를 가져올 때 Promise를 사용하면 얼마나 편리한지 확인

 

* JSON 이해하기 - JSON(JavaScript object notation)

 

 - 자바스크립트에서 데이터를 저장하고 교환할 때 사용하는 정형화된 텍스트 형식
 > 대부분의 프로그래밍 언어에서 서버와 브라우저 간에 데이 터를 주고받는 형식으로 많이 사용

 - 시작과끝을중괄호({))로 지정하고, 각항목은 ‘키:값’ 형식으로 묶어서 표현, 각 항목은 콤마(,)로 구분
 >  JSON의 원본값은 텍스트 - 객체로 바꾸는 작업 : JSON.parse()
 > JSON 데이터가 담긴 자바스크립트 객체 - 텍스트로 변환 : JSON.stringify()

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>json</title>
</head>
<body>
    <script>
        // JSON.stringify()와 JSON.parse() 함수 사용예시
        let myObj = {"name":"홍길동", "age":35, "email":"test1@naver.com"};
        
        strJSON = JSON.stringify(myObj);
        console.log(strJSON);
        newObj = JSON.parse(strJSON);
        console.log(newObj);
        
    </script>
</body>
</html>

특정 환경에서만 발생하는 크롬 브라우저 확장프로그램 오류인것 같은데, 해결이 안된다.
 - 오류이후 처리는 정상 진행되니... 일단패스.
Uncaught TypeError: Cannot read properties of undefined (reading 'browserObject')
at webcontent.js:1:266
at webcontent.js:2:463
at webcontent.js:2:467
webcontent.js:1

실행결과

 - 텍스트 형태 출력  : {"name":"홍길동","age":35,"email":"test1@naver.com"}

 - 객체형태 출력 : Object - 확장하면 상세정보 확인 가능

 

* Fetch API 이해하기

 - API에서 제공 : 원격 서버에서 제공하는 데이터의 CRUD(create, read, update, delete) 작업 지원
 > HTTP Request, ResponsePost, Get, Put, Delete 메서드로관리 (셋째마당)
- 테스트 원격 웹 서비스 : JSONPlaceholder 웹사이트 이용 - https://jsonplaceholder.typicode.com/

 (JSON 형태의 더미 데이터 제공 : 포스트, 댓글, 사진 앨범, To-Do 리스트, 사용자 등)

 - fetch() 함수 : 매개변수 path에 주소 전달 - 서버 응답 정보를 Promise 객체로 반환

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>json</title>
</head>
<body>
    <script>
        // fetch 사용예시
        fetch('https://jsonplaceholder.typicode.com/users')
        .then(pResponse => pResponse.json())
        .then(pJSON => console.log(pJSON));
        
    </script>
</body>
</html>

 - jasonplaceholder 웹 사이트에서 테스트로 제공하는 사용자(users) 정보의 첫 번째값 조회

 - 서버에서 결과를 전송하면 Promise 객체에 서버가 응답한 값을 매개변수로 전달받아서 JSON 데이터로 변경한 후 출력

 

 

[DoIt!실습] 원격에서 정보를 Promise로 받기

 - 0205. : Doit 실습 - 원격에서 정보를 Promise로 받기

 > 콜 백 함수보다 Promise를 사용하면 훨씬 직관적이고 간결하다는 것 확인

# 0201/ex02-05/data.json

{
    "items":[
        {"name":"홍길동1", "age":35, "email":"test1@naver.com"},
        {"name":"홍길동2", "age":30, "email":"test2@naver.com"},
        {"name":"홍길동3", "age":45, "email":"test3@naver.com"}
    ]
}

# 0201/ex02-05/promise_getjson.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>promise</title>
</head>
<body>
    <button onclick="
        // JSON 로컬 텍스트 표시
        fetch('./data.json')
        .then(pResponse => pResponse.text())
        .then(pJSON => console.log(pJSON))
        ;
    ">JSON 로컬 읽기</button>

    <button onclick="
        // JSON 원격 텍스트 표시
        fetch('https://cors-anywhere.herokuapp.com/'
         + 'https://jsonplaceholder.typicode.com/posts/1')
        .then(pResponse => pResponse.text())
        .then(pJSON => console.log(pJSON));
    ">JSON 원격 읽기</button>
</body>
</html>

 - fetch() 함수로 로컬에 있는 data.json 파일을 읽어서 Promise 객체로 pResponse 매개변수에 저장
 > JSON값을 텍스트로 변경해 Promise로 반환하는 text() 함수 이용
 - <JSON 원격 읽기> 버튼를 클릭하면 원격(JSONPlaceholder 사이트)에서 제공하는 포스트 목록에서 첫 번째 항목 조회
 > fetch() 함수의 매개변수에 'https://jsonplaceholder.typicode.com/posts/1' 경로를 전달

 

*JSONPlaceholder를 fetch()함수로 바로 접근하면 CORS 오류가 발생
 - CORS(cross origin resource sharing) : ‘교차 줄처 리소스 공유’ - 보안을 위해 같은 도메인의 자료만 접근하도록 허용하는 정책
 > 테스트 목적 대응조치 : CORS 헤더 추가 
 : 접속할 주소 앞에 ‘https://cors-anywhere.herokuapp.com/’ 포함

GET https://cors-anywhere.herokuapp.com/https://jsonplaceholder.typicode.com/posts/1 403 (Forbidden)
 - promise_getjson.html:24 
onclick @ promise_getjson.html:24

See /corsdemo for more info
 - promise_getjson.html:27 

 - 최초 접속시 접속승인 버튼 클릭
 > 콜백 함수를 사용하지 않아도 Promise로 원격 데이터를 읽고 표시

 

 



02-7 Promise와 비동기 처리 방식

* Promise란?

 - 비동기 처리 방식으로 실행된 결과의 성공과실패를관리하는 객체

물건 거래를 예로 한 경우의 수
• 물건을 주는경우 - 약속이행(성공,resolved)
• 물건을 주지 못하는 경우 — 약속 불이행(실패,rejected)
• 물건을주지 못하고 지연된 경우- 약속 이행 지연(대기,pending)

 - Promise : 약속을 생성하는 과정과 최종 결과로 나누어 구성

• 실행 중 결과 기다림 (pending):약속은 아직 이행되거나 거절되지 않았고 지연 상태
 - 요청한 실행의 반환을 계속 대기 :  작성할 코드 없음
• 요청한 실행이 성공함 (resolved):약속을 지키기는 데 문제가 없는 경우
 - 요청 실행 성공한 경우 : 필요한 코드 작성
• 요청한 실행이 실패함 (rejected):약속을 지키는 데 문제가 생겨 거절하는 경우
 - 요청했던 실행이 실패한 경우 : 필요한 코드 작성

 - 약속의 실행 최종 결과 구분

• 약속 지킴 최종 성공(fulfilled):약속이 지켜져서 물건을 성공적으로 받은 경우
 - 코드상에서는 성공적으로 원하는 결과를 반환받은 경우
• 약속 못 지킴 최종 실패(unfulfilled):약속이 거절되어서 물건을 못 받게 되어 그다음 대책 실행
 - 코드상에서는 요청이 실패해서 오류 처리를 해야 하는 경우
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>promise</title>
</head>
<body>
    <script>
        // 가상의 서버 데이터 요청 및 그 결과 랜덤값 반환
        function RequestData(){
            return Math.random() > 0.5;
        }

        // 약속을 생성하는 부분
        const oProductReady = new Promise(function (fnResolve, fnReject){
            //실행 중 결과 기다림(pending)
            let bStatus = RequestData();

            if(bStatus){
                // 요청한 실행이 성공함(resolved)
                fnResolve('상품이 성공적으로 배송되었습니다.');
            }else{
                // 실행 중 결과 기다림(pending)
                fnReject('죄송합니다. 상품이 아직 준비되지 못했습니다.');
            }
        });

        // 약속의 실행 최종 결과
        oProductReady.then(function (pResult){
            // 약속 지킴 최종 성공(fulfilled)
            console.log(pResult);
        }, function (pErrMsg){
            // 약속 못 지킴 최종 실패(unfulfilled)
            console.log(pErrMsg);
        });
    </script>
</body>
</html>

 - 서버요청결과를 고려하여 랜덤함수의 결과로 응답결과를 분리하여 결과 확인
 > Math.random() > 0.5

 - 비동기 처리를 위한 Promise 생성부분 : const oProductReady

 > 상품 준비 요청 결과(RequestData())에 따라 fnResolve()fnReject() 함수 호출

 - Promise 실행결과에 따른 응답결과 처리

 > then() 메서드에서 콜백 함수와 비슷한기능 처리
  정상처리 : 콘솔결과 성공표시 - 첫번째 파라미터로 전달된 함수 실행
  실패처리 : 콘솔결과 실패표시 - 두번째 파라미터로 전달된 함수 실행

 

 

[DoIt!실습] 하나의 Promise 실습하기

 - 0206. : Doit 실습 - 하나의 Promise 실습하기

# 0201/ex02-06/promise_resolve_reject.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>Promise</title>
</head>
<body>
    <button onclick="
        // Promise 실행
        console.log('Promise 시작!');
        let bStatus = Math.random() > 0.5;
        fnCreatePromise(bStatus)
        // 비동기 실행으로 결과를 알려 줌
        .then(pResult => console.log(pResult))
        .catch(pErrMsg => console.error(pErrMsg));
        console.log('Promise 종료!');
    ">상품 배송 시작!</button>
    <script>
        // Promise 생성
        function fnCreatePromise(pStatus) {
            return new Promise((fnResolve, fnReject) => {
                // 상품 준비를 확인하는 비동기 함수를 실행했다고 가정함
                setTimeout(() => {
                    // 상품 준비 결과는 랜덤정보 true, false로 가정함
                    if(pStatus) fnResolve('상품이 성공적으로 배송되었습니다.');
                    else fnReject('죄송합니다. 상품이 아직 준비되지 못했습니다.');
                }, 3000);
            });
        }

    </script>
</body>
</html>

 - 외부 네트워크에 접속하진 않지만 비슷한상황을 연출하기 위해 타이머로 시간 지연
 > setTimeout(() => ...)

 - 결과의 성공 여부는 랜덤 함수로 예측할 수 없게 설정
 > let bStatus = Math.random() > 0.5;
 > Promise를 생성하는 fnCreatePromiseQ 함수 호출 때 전달

 - 시나리오 별 예상 응답 - 콘솔 메시지 순서

 > 동기실행 시 예상 시나리오 :   Promise 시작! - [결과] -Promise 종료!

 > 비동기실행 시 예상 시나리오 :  Promise 시작! -Promise 종료! - (3초 후)[결과]

 - Promise를 실행한 후

 > 성공하면 then() 메서드를 호출

 > 실패하면 catch() 메서드를 호출

 - fnCreatePromise() 함수에서 Promise를 생성하고 결과를 응답

 > pStatus 매개변수에 성공 여부를 판단 : (앞으로 일어날)  성공, 실패 별 처리함수 fnResolve()fnReject() 각각 작성


* Promise 여러 개 사용하기

 - Promise 연결 사용 장점

• 콜백 지옥 문제점 해결: 비동기 처리 순서대로 처리 시, (콜백 함수처럼) 중첩 불필요
 - 소스를 간결하고 직관적 으로 작성
 비동기 처리 완료 후 반환값 관리 쉬움 : 성공과 실패 모두
then()catch()에 전달된 함수를 통해 관리

 

[DoIt!실습] 여러 개의 Promise 실습하기

 - 0207. : Doit 실습 - 여러 개의 Promise 실습하기

# 0201/ex02-07/promise_multi.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>promise_multi</title>
</head>
<body>
    <button onclick="
        // Promise로 비동기 함수를 순서대로 실행
        fnProductReady(1, 2000)
        .then((pResult) => {
            console.log(pResult);
            return fnProductReady(2, 1000);
        })
        .then((pResult2) => {
            console.log(pResult2);
            return fnProductReady(3,500);
        })
        .then((pResult3) => console.log(pResult3));
    ">Promies : 상품배송시작!</button>
    
    <script>
        function fnProductReady(pNum, pTime){
            return new Promise((fnResolve) => {
                setTimeout(() => {
                    console.log(pNum);
                    fnResolve('상품이 성공적으로 배송되었습니다.');
                }, pTime);
            });
        }
    </script>
</body>
</html>

 - fnProductReady()는 가상으로 상품을 준비하는 비동기 처리 함수

 > 처리결과를 동기화 하여 동일한 함수를 2번 더 호출하며 3번의 비동기 호출을 진행 - 정상처리 시 then 처리

 - 버튼 클릭 시,  비동기 처리가 각각 2초, 1초, 0.5초로 지연되지만 1 > 2 > 3의 실행 순서 보장

* 비동기 실행의 Promise 결과가 (시간지연과 함께) 1 > 2 > 3 순서대로 콘솔 창에 표시
 - 코드보고 설명이 가능할 만큼 이해해보자. (78p)



02-8 await 연산자와 async 비동기 함수

* Promise 한계 : 비동기 처 리를 위해 then() 메서드 중첩 사용

 - ES8부터는await 연산자와async 함수 사용

 

* await 연산자 : 결과가 나올때 까지 기다리다.
 - await 연산자의 오른쪽 항을 동기로 처리

 >  Promise를 반환하는 함수를 대상으로 await 적용

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>await</title>
</head>
<body>
    <script>
        // Promise 비동기 기능 동기처리
        function fnProductReady(pNum, pTime){
            return new Promise((resolve) => {
                setTimeout(() => {
                    console.log(pNum);
                    resolve("상품이 성공적으로 배송되었습니다.");
                }, pTime);
            });
        }
        
        // strRet = await fnProductReady(1, 2000);
        strRet = fnProductReady(1, 2000);
        console.log(strRet);
    </script>
    
</body>
</html>
* 예제 코드 실행결과 오류발생 - async await 사용 방법에 이유가 있을듯...
Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules (at 08-1_await.html:20:18)
 - 08-1_await.html:20

* await 연산자 제거시 정상동작

 - 다음 예제의 async 구조가 되어야 정상 동작

* await만 사용하면 결과가 나오지 않을 때 무한루프 

 - 비동기 방식으로 처리하는 밍령이 있는함수는 반드시 async를 실행


* async 함수

 - 일반 함수를 선언할 때 앞에 async를 붙여서 비동기 처리 방식으로 선언

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>async</title>
</head>
<body>
    <script>
        // Promise 비동기 기능 동기처리
        function fnProductReady(pNum, pTime){
            return new Promise((resolve) => {
                setTimeout(() => {
                    console.log(pNum);
                    resolve("상품이 성공적으로 배송되었습니다.");
                }, pTime);
            });
        }
        async function fnDoAsyncFunc(){
            console.log(await fnProductReady(1, 2000)); // 2초 지연
            console.log(await fnProductReady(2, 1000)); // 1초 지연
            console.log(await fnProductReady(3, 500));  // 0.5초 지연
        }
        fnDoAsyncFunc();
    </script>
</body>
</html>

 - async 함수 사용방법 : 일반함수 사용과 동일
 > fnDoAsyncFunc();

 


[DoIt!실습] await 연산자와 async 비동기 함수 실습하기
- 0208. : Doit 실습 - await 연산자와 async 비동기 함수 실습하기
# 0201/ex02-06/promise_resolve_reject.html

* await 연산자와 async 비동기 함수를 사용하면 Promise를를 좀 더 유연하게 활용

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>async_await</title>
</head>
<body>
    <!-- async 함수 실행 -->
    <button onclick="fnDoAsyncFunc()">async, await : 상품 배송 시작!</button>

    <script>
        // await로 비동기 함수를 순서대로 실행
        // Promise 보다 소스가 간결하고 가동성 향상
        async function fnDoAsyncFunc(){
            console.log(await fnProductReady(1, 2000)); // 2초 지연
            console.log(await fnProductReady(2, 1000)); // 1초 지연
            console.log(await fnProductReady(3, 500)); // 0.5초 지연
        }
        //Promise로 비동기 함수 생성
        function fnProductReady(pNum, pTime){
            return new Promise((resolve) => {
                setTimeout(() => {
                    console.log(pNum);
                    resolve('상품이 성공적으로 배송되었습니다.');
                }, pTime);
            });
        }
    </script>
</body>
</html>

- fnProductReady() 함수 앞에 await 연산자 추가

 > async 함수 안에서 await 인산자가 사용된 함수 호출문이 하나씩 실행 
 > 완료될 때까지 다음 함수 호출하지 않고 대기
 > 처리순서 보장 :  1 > 2 >3 
- 무한 루프에 빠지지 않도록

 > async로 함수 전체를 감싸서 비동기로 처리

- fnProductReady() 함수 처리 시, 상품을 준비하는 동안 시간이 지 연되는 연출을 위해 

 > 매개변수로 번호, 지연시간 정보를 받아서 Promise를 생성하여 반환

 



미션 코딩! 입력된 숫자의 범주 판별하기

사용자가 숫자를 입력했을 때 메시지를 표시하는 프로그램 

 - 1~100 범위에 속하면 "성공적으로 입력하셨습니다!”라는 메시지 표시

 - 그렇지 않으면 "입력 범위가 맞지 않습니다!”라는 메시지 표시

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ex02-mission</title>
</head>
<body>
    <h1>1부터 100 범위 안의 숫자를 입력하세요.</h1>
    <input type="text" id="comIn" value="" />
    <button onclick="fnMeasure()">확인</button>
    <p>입력 결과 : </p>
    <textarea id="comOutPut" style="width:200px"></textarea>
    
    <script>
        function fnMeasure(){
            let iNumber, strResult;
            
            //입력한 숫자를 가져옴
            iNumber = document.querySelector("#comIn").value;

            //1부터 100까지 범위인지 확인
            if(iNumber < 1 || iNumber > 100) strResult = "입력 범위가 맞지 앖습니다.";
            else strResult = "성공적으로 입력하였습니다.";
            document.querySelector("#comOutPut").innerHTML = strResult;

        }
    </script>
</body>
</html>

 

 

 


* github에 작성한 실습파일 패키지경로 수정

 - 0104 > 0101/ex01-04

 - 0201 > 0102

Intellij

마우스 사용 최소화를 위해 방향키를 단축키로 사용할 수 있도록 적요해본다. 

 

좌 : alt+shift+H

우 : alt+shift+K

상 : alt+shift+Y

하 : alt+shift+U

 

기존 매핑된 것들을 피해서 적용해봤다.

 

 


eclipse

도 알아봤지만, 쉽지않다.

 

상 : ctrl+alt+shift+Y

하 : ctrl+alt+shift+U

좌, 우 는 바인딩 대상을 못찾았다. 억지로 previous word(좌), next word(우) 로 매핑할 수 있지만, 단어단위로 이동할거라 마음에 들지 않는다.

(shift left, shift right 도 있지만, tab, shift+tab 의 매핑인 것 같다)

 

좌, 우 도 ctrl+alt+shift+H, ctrl+alt+shift+K 로 매핑하고 싶은데, 방법이 없을까... 

이클립스통째로 전달받아서 개발환경 설정시 

이전사용자의 git user, email 이 적용되어 수정이 필요하다.

 

인터넷에 찾아보면 perferences 설정을 통해 수정한다고 되어 있는데, 

 - perferences > team > git > configuration

적용해보니 프로젝트 하나만 적용되고 나머지 2건의 프로젝트에는 반영이 되지 않았다. 

 

찾아보니 git repositories 에 설정된 레파지토리 별 속성에도 사용자를 설정할 수 있게 되어 있어서 

남은 프로젝트에도 user, email을 적용할 수 있었다. 

* 알면 상식, 모르면 기적

제목이 부끄러울 만큼 간단한 팁.

 

윈도우 탐색기에서 메뉴로 복사 > 붙혀넣기 하면 된다.

(마우스로 드래그하여 이동하면 안되기에 맨붕이었다가 발견? 했다.)

 

아래는 일기다. 더 안읽어도 된다. 내용없다.

더보기

폰 바꾸면 앱으로 자료를 한번에 옮기지 않고, 설치부터 하나하나 한땀한땀 설정하는 타입이다. 

 

앱설치하고 로그인하고 사용환경 맞추고, 은행앱, 인증서, 삼성페이, 페이북... 많다.

 

그 지난한 작업의 끝에 화룡점정. 카카오톡이 남았다. 

 

언제부턴가 메시지는 카톡 백업으로 하고, 

미디어는 아래 경로의 카톡 메시지 컨텐츠를 폴더이동하여 유지해왔다.

내 PC\Jk S23 Ultra\내장 메모리\Android\data\com.kakao.talk\contents

 

지난번에는 8기가가 넘었던 것으로 기억을 하는데, 

이번 확인해보니 17기가.. 

앞으로 512를 해야하나.. ㅋ

 

기존 폰에서 contents 폴더를 노트북에 옮겼다.

 

마지막으로 새폰에 옮기면 되는데... 드래그가 안됐다.

 

뭐지? 보안정책으로 이제 파일이동이 안되나?

 

폰투폰으로 usb선을 연결해서 앱으로  카카오톡 앱만 이동해 봤다.

contents 폴더는 이동이 안됐다.

 

궁여지책으로 설치된 파일관리앱을 다 시도해봤지만, 

이제 \Android\data\com.kakao.talk\contents 폴더로 접근이 안되는 것 같았다.

 

 

그러다가.. 우연히 성공했다.

 

복사 > 붙혀넣기.

 

마우스 드래그 이동은 안되는데, 복사하여 붙혀넣기를 하니 된다. 복사.

3시간.. 언제끝날까..

 

 

기본브라우저 설정을 안하면 발생하는 오류인가?

dbeaver의 브라우저 설정을 크롬으로 지정해 본다.

.. 다 실패

vdi 가상OS에 보안프로그램 영향으로 뭔가 안되는건지. 해결이 안된다.


dbeaver를 사용하며 이상한 오류가 발생하기 시작했다. 

가끔 발생을 하다가 프로시저 Declaration 조회시 항상 표시되기 시작했다.

프로그램 재실행이 필요한 오류라 더이상은 못참겠다.
싶어 대응방안을 찾아봤다.

 

 

참고 : https://stackoverflow.com/questions/15594590/eclipse-bug-unhandled-event-loop-exception-no-more-handles

 

Eclipse Bug: Unhandled event loop exception No more handles

I've built a GUI using Swing and the MigLayout. I am using Eclipse 4.2.2 (64-bit) on Windows 7 Ultimate. Every time I click back into the window to edit my code, a popup comes up, then I'm prompte...

stackoverflow.com

java 파일의 연결 에디터를 WindowBuilder 로 설정하라고 했지만, 

연결이 없어서 발생하는것인가 싶어 일반 편집기로 설정해보니 효과가 있는것 같다.

 

쓰다 문제있으면 WindowBuilder 로 다시 시도해봐야겠다.

 


 

* 2차 시도 : dbeaver 브라우저 연결 설정
  - 기본 브라우저 설정

  • 플러그인 : org.jkiss.dbeaver.model
  • 심각도 : 오류
  • 메시지 : No more handles
  • 예외스텍추적
    org.eclipse.swt.SWTError: No more handles
        at org.eclipse.swt.SWT.error(SWT.java:4944)
        at org.eclipse.swt.SWT.error(SWT.java:4833)
        at org.eclipse.swt.SWT.error(SWT.java:4804)
        at org.eclipse.swt.widgets.Widget.error(Widget.java:450)
        at org.eclipse.swt.widgets.Control.createHandle(Control.java:718)
        at org.eclipse.swt.widgets.Label.createHandle(Label.java:186)
        at org.eclipse.swt.widgets.Control.createWidget(Control.java:744)
        at org.eclipse.swt.widgets.Control.<init>(Control.java:116)
        at org.eclipse.swt.widgets.Label.<init>(Label.java:106)
        at org.jkiss.dbeaver.ui.controls.StatusLineContributionItemEx.fill(StatusLineContributionItemEx.java:52)
        at org.eclipse.jface.action.StatusLineManager.update(StatusLineManager.java:290)
        at org.eclipse.ui.internal.WorkbenchPage$E4PartListener.partDeactivated(WorkbenchPage.java:240)
        at org.eclipse.e4.ui.internal.workbench.PartServiceImpl$3.run(PartServiceImpl.java:266)
        at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
        at org.eclipse.e4.ui.internal.workbench.PartServiceImpl.firePartDeactivated(PartServiceImpl.java:263)
        at org.eclipse.e4.ui.internal.workbench.PartServiceImpl.activate(PartServiceImpl.java:750)
        at org.eclipse.e4.ui.internal.workbench.PartServiceImpl.activate(PartServiceImpl.java:683)
        at org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer.activate(AbstractPartRenderer.java:97)
        at org.eclipse.e4.ui.workbench.renderers.swt.ContributedPartRenderer.lambda$0(ContributedPartRenderer.java:63)
        at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
        at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4256)
        at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1066)
        at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1090)
        at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1075)
        at org.eclipse.swt.widgets.Shell.setActiveControl(Shell.java:1530)
        at org.eclipse.swt.widgets.Shell.WM_MOUSEACTIVATE(Shell.java:2441)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4787)
        at org.eclipse.swt.widgets.Canvas.windowProc(Canvas.java:340)
        at org.eclipse.swt.widgets.Decorations.windowProc(Decorations.java:1478)
        at org.eclipse.swt.widgets.Shell.windowProc(Shell.java:2284)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Canvas.windowProc(Canvas.java:340)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
        at org.eclipse.swt.widgets.Scrollable.callWindowProc(Scrollable.java:91)
        at org.eclipse.swt.widgets.Control.windowProc(Control.java:4844)
        at org.eclipse.swt.widgets.Canvas.windowProc(Canvas.java:340)
        at org.eclipse.swt.widgets.Display.windowProc(Display.java:5022)
        at org.eclipse.swt.internal.win32.OS.PeekMessage(Native Method)
        at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3637)
        at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1155)
        at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:338)
        at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1046)
        at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:155)
        at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:643)
        at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:338)
        at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:550)
        at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:171)
        at org.jkiss.dbeaver.ui.app.standalone.DBeaverApplication.start(DBeaverApplication.java:296)
        at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:203)
        at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:136)
        at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:402)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:255)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.base/java.lang.reflect.Method.invoke(Unknown Source)
        at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:659)
        at org.eclipse.equinox.launcher.Main.basicRun(Main.java:596)
        at org.eclipse.equinox.launcher.Main.run(Main.java:1467)
    
    
  • 세션 데이터
    eclipse.buildId=unknown
    java.version=11.0.12
    java.vendor=Eclipse Foundation
    BootLoader constants: OS=win32, ARCH=x86_64, WS=win32, NL=ko_KR
    Command-line arguments:  -os win32 -ws win32 -arch x86_64
    

윈도우 11을 설치하니 ubuntu를 설치할 수 있었다. 

 

내친김에 도커를 만져보려고 한다. 

 

하나하나 밟아보자

 

설치된 ubuntu 버전은?

jkoogi@JKASUS:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.3 LTS
Release:        20.04
Codename:       focal
jkoogi@JKASUS:~$

저장소 설정

 

* apt-get 업데이트 :  책 가이드
 - sudo apt-get update

더보기

jkoogi@JKASUS:~$ sudo apt-get update
[sudo] password for jkoogi:
Get:1 http://security.ubuntu.com/ubuntu focal-security InRelease [114 kB]
Get:2 http://security.ubuntu.com/ubuntu focal-security/main amd64 Packages [1993 kB]
Get:3 http://security.ubuntu.com/ubuntu focal-security/main Translation-en [326 kB]
Get:4 http://security.ubuntu.com/ubuntu focal-security/main amd64 c-n-f Metadata [12.2 kB]
Get:5 http://security.ubuntu.com/ubuntu focal-security/restricted amd64 Packages [1495 kB]
Get:6 http://security.ubuntu.com/ubuntu focal-security/restricted Translation-en [211 kB]
Get:7 http://security.ubuntu.com/ubuntu focal-security/restricted amd64 c-n-f Metadata [624 B]
Get:8 http://security.ubuntu.com/ubuntu focal-security/universe amd64 Packages [794 kB]
Get:9 http://security.ubuntu.com/ubuntu focal-security/universe Translation-en [154 kB]
Get:10 http://security.ubuntu.com/ubuntu focal-security/universe amd64 c-n-f Metadata [16.9 kB]
Get:11 http://security.ubuntu.com/ubuntu focal-security/multiverse amd64 Packages [22.9 kB]
Hit:12 http://archive.ubuntu.com/ubuntu focal InRelease
Get:13 http://security.ubuntu.com/ubuntu focal-security/multiverse Translation-en [5488 B]
Get:14 http://archive.ubuntu.com/ubuntu focal-updates InRelease [114 kB]
Get:15 http://security.ubuntu.com/ubuntu focal-security/multiverse amd64 c-n-f Metadata [528 B]
Get:16 http://archive.ubuntu.com/ubuntu focal-backports InRelease [108 kB]
Get:17 http://archive.ubuntu.com/ubuntu focal/universe amd64 Packages [8628 kB]
Get:18 http://archive.ubuntu.com/ubuntu focal/universe Translation-en [5124 kB]
Get:19 http://archive.ubuntu.com/ubuntu focal/universe amd64 c-n-f Metadata [265 kB]
Get:20 http://archive.ubuntu.com/ubuntu focal/multiverse amd64 Packages [144 kB]
Get:21 http://archive.ubuntu.com/ubuntu focal/multiverse Translation-en [104 kB]
Get:22 http://archive.ubuntu.com/ubuntu focal/multiverse amd64 c-n-f Metadata [9136 B]
Get:23 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages [2377 kB]
Get:24 http://archive.ubuntu.com/ubuntu focal-updates/main Translation-en [408 kB]
Get:25 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 c-n-f Metadata [16.3 kB]
Get:26 http://archive.ubuntu.com/ubuntu focal-updates/restricted amd64 Packages [1598 kB]
Get:27 http://archive.ubuntu.com/ubuntu focal-updates/restricted Translation-en [225 kB]
Get:28 http://archive.ubuntu.com/ubuntu focal-updates/restricted amd64 c-n-f Metadata [620 B]
Get:29 http://archive.ubuntu.com/ubuntu focal-updates/universe amd64 Packages [1024 kB]
Get:30 http://archive.ubuntu.com/ubuntu focal-updates/universe Translation-en [237 kB]
Get:31 http://archive.ubuntu.com/ubuntu focal-updates/universe amd64 c-n-f Metadata [23.5 kB]
Get:32 http://archive.ubuntu.com/ubuntu focal-updates/multiverse amd64 Packages [25.2 kB]
Get:33 http://archive.ubuntu.com/ubuntu focal-updates/multiverse Translation-en [7408 B]
Get:34 http://archive.ubuntu.com/ubuntu focal-updates/multiverse amd64 c-n-f Metadata [604 B]
Get:35 http://archive.ubuntu.com/ubuntu focal-backports/main amd64 Packages [45.7 kB]
Get:36 http://archive.ubuntu.com/ubuntu focal-backports/main Translation-en [16.3 kB]
Get:37 http://archive.ubuntu.com/ubuntu focal-backports/main amd64 c-n-f Metadata [1420 B]
Get:38 http://archive.ubuntu.com/ubuntu focal-backports/restricted amd64 c-n-f Metadata [116 B]
Get:39 http://archive.ubuntu.com/ubuntu focal-backports/universe amd64 Packages [24.9 kB]
Get:40 http://archive.ubuntu.com/ubuntu focal-backports/universe Translation-en [16.3 kB]
Get:41 http://archive.ubuntu.com/ubuntu focal-backports/universe amd64 c-n-f Metadata [880 B]
Get:42 http://archive.ubuntu.com/ubuntu focal-backports/multiverse amd64 c-n-f Metadata [116 B]
Fetched 25.7 MB in 15s (1769 kB/s)
Reading package lists... Done
jkoogi@JKASUS:~$

* 블로그 가이드
https://shanepark.tistory.com/237

 

Ubuntu 20.04 LTS ) Docker 설치하기

Intro Docker는 제가 회사에서 사용하는 노트북의 OS를 Windows 에서 Ubuntu 로 변경하게 된 트리거 였습니다. Docker를 사용하면 정말 편하게 격리된 컨테이너들을 구성해 가상화의 장점을 정말 잘 살릴

shanepark.tistory.com

도커 설치는 책, 블로그 무시하고 도커사이트를 참고하자

https://docs.docker.com/engine/install/ubuntu/

 

 

Install Docker Engine on Ubuntu

 

docs.docker.com

* sudo apt update

더보기

jkoogi@JKASUS:~$ sudo apt update
Hit:1 http://archive.ubuntu.com/ubuntu focal InRelease
Hit:2 http://archive.ubuntu.com/ubuntu focal-updates InRelease
Hit:3 http://archive.ubuntu.com/ubuntu focal-backports InRelease
Hit:4 http://security.ubuntu.com/ubuntu focal-security InRelease
Reading package lists... Done
Building dependency tree
Reading state information... Done
189 packages can be upgraded. Run 'apt list --upgradable' to see them.
jkoogi@JKASUS:~$

* repository 를 이용하기 위해 pakcage 설치

sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
    
* ca-certificates : ca-certificate는 certificate authority에서 발행되는 디지털 서명. 
  SSL 인증서의 PEM 파일이 포함되어 있어 SSL 기반 앱이 SSL 연결이 되어있는지 확인가능.
* curl : 특정 웹사이트에서 데이터를 다운로드 받을 때 사용.
* (apt-transport-https : 패키지 관리자가 https를 통해 데이터 및 패키지에 접근할 수 있도록 한다.)
* (software-properties-common : *PPA를 추가하거나 제거할 때 사용.)

 

더보기

sudo apt-get install \
>     ca-ceca-certificates \
>     curl \
>     gnupg \
>     lsb-release
Reading package lists... Done
Building dependency tree
Reading state information... Done
lsb-release is already the newest version (11.1.0ubuntu2).
lsb-release set to manually installed.
The following additional packages will be installed:
  dirmngr gnupg-l10n gnupg-utils gpg gpg-agent gpg-wks-client gpg-wks-server gpgconf gpgsm gpgv libcurl4
Suggested packages:
  pinentry-gnome3 tor parcimonie xloadimage scdaemon
The following packages will be upgraded:
  ca-certificates curl dirmngr gnupg gnupg-l10n gnupg-utils gpg gpg-agent gpg-wks-client gpg-wks-server gpgconf gpgsm gpgv
  libcurl4
14 upgraded, 0 newly installed, 0 to remove and 175 not upgraded.
Need to get 3100 kB of archives.
After this operation, 7168 B disk space will be freed.
Do you want to continue? [Y/n] y
Get:1 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 gpg-wks-client amd64 2.2.19-3ubuntu2.2 [97.4 kB]
Get:2 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 dirmngr amd64 2.2.19-3ubuntu2.2 [330 kB]
Get:3 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 gpg-wks-server amd64 2.2.19-3ubuntu2.2 [90.2 kB]
Get:4 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 gnupg-utils amd64 2.2.19-3ubuntu2.2 [481 kB]
Get:5 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 gpg-agent amd64 2.2.19-3ubuntu2.2 [232 kB]
Get:6 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 gpg amd64 2.2.19-3ubuntu2.2 [482 kB]
Get:7 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 gpgconf amd64 2.2.19-3ubuntu2.2 [124 kB]
Get:8 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 gnupg-l10n all 2.2.19-3ubuntu2.2 [51.7 kB]
Get:9 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 gnupg all 2.2.19-3ubuntu2.2 [259 kB]
Get:10 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 gpgsm amd64 2.2.19-3ubuntu2.2 [217 kB]
Get:11 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 gpgv amd64 2.2.19-3ubuntu2.2 [200 kB]
Get:12 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 ca-certificates all 20211016ubuntu0.20.04.1 [141 kB]
Get:13 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 curl amd64 7.68.0-1ubuntu2.15 [161 kB]
Get:14 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 libcurl4 amd64 7.68.0-1ubuntu2.15 [235 kB]
Fetched 3100 kB in 6s (554 kB/s)
Preconfiguring packages ...
(Reading database ... 32289 files and directories currently installed.)
Preparing to unpack .../00-gpg-wks-client_2.2.19-3ubuntu2.2_amd64.deb ...
Unpacking gpg-wks-client (2.2.19-3ubuntu2.2) over (2.2.19-3ubuntu2.1) ...
Preparing to unpack .../01-dirmngr_2.2.19-3ubuntu2.2_amd64.deb ...
Unpacking dirmngr (2.2.19-3ubuntu2.2) over (2.2.19-3ubuntu2.1) ...
Preparing to unpack .../02-gpg-wks-server_2.2.19-3ubuntu2.2_amd64.deb ...
Unpacking gpg-wks-server (2.2.19-3ubuntu2.2) over (2.2.19-3ubuntu2.1) ...
Preparing to unpack .../03-gnupg-utils_2.2.19-3ubuntu2.2_amd64.deb ...
Unpacking gnupg-utils (2.2.19-3ubuntu2.2) over (2.2.19-3ubuntu2.1) ...
Preparing to unpack .../04-gpg-agent_2.2.19-3ubuntu2.2_amd64.deb ...
Unpacking gpg-agent (2.2.19-3ubuntu2.2) over (2.2.19-3ubuntu2.1) ...
Preparing to unpack .../05-gpg_2.2.19-3ubuntu2.2_amd64.deb ...
Unpacking gpg (2.2.19-3ubuntu2.2) over (2.2.19-3ubuntu2.1) ...
Preparing to unpack .../06-gpgconf_2.2.19-3ubuntu2.2_amd64.deb ...
Unpacking gpgconf (2.2.19-3ubuntu2.2) over (2.2.19-3ubuntu2.1) ...
Preparing to unpack .../07-gnupg-l10n_2.2.19-3ubuntu2.2_all.deb ...
Unpacking gnupg-l10n (2.2.19-3ubuntu2.2) over (2.2.19-3ubuntu2.1) ...
Preparing to unpack .../08-gnupg_2.2.19-3ubuntu2.2_all.deb ...
Unpacking gnupg (2.2.19-3ubuntu2.2) over (2.2.19-3ubuntu2.1) ...
Preparing to unpack .../09-gpgsm_2.2.19-3ubuntu2.2_amd64.deb ...
Unpacking gpgsm (2.2.19-3ubuntu2.2) over (2.2.19-3ubuntu2.1) ...
Preparing to unpack .../10-gpgv_2.2.19-3ubuntu2.2_amd64.deb ...
Unpacking gpgv (2.2.19-3ubuntu2.2) over (2.2.19-3ubuntu2.1) ...
Setting up gpgv (2.2.19-3ubuntu2.2) ...
(Reading database ... 32289 files and directories currently installed.)
Preparing to unpack .../ca-certificates_20211016ubuntu0.20.04.1_all.deb ...
Unpacking ca-certificates (20211016ubuntu0.20.04.1) over (20210119~20.04.2) ...
Preparing to unpack .../curl_7.68.0-1ubuntu2.15_amd64.deb ...
Unpacking curl (7.68.0-1ubuntu2.15) over (7.68.0-1ubuntu2.7) ...
Preparing to unpack .../libcurl4_7.68.0-1ubuntu2.15_amd64.deb ...
Unpacking libcurl4:amd64 (7.68.0-1ubuntu2.15) over (7.68.0-1ubuntu2.7) ...
Setting up ca-certificates (20211016ubuntu0.20.04.1) ...
Updating certificates in /etc/ssl/certs...
rehash: warning: skipping ca-certificates.crt,it does not contain exactly one certificate or CRL
7 added, 11 removed; done.
Setting up gnupg-l10n (2.2.19-3ubuntu2.2) ...
Setting up gpgconf (2.2.19-3ubuntu2.2) ...
Setting up libcurl4:amd64 (7.68.0-1ubuntu2.15) ...
Setting up curl (7.68.0-1ubuntu2.15) ...
Setting up gpg (2.2.19-3ubuntu2.2) ...
Setting up gnupg-utils (2.2.19-3ubuntu2.2) ...
Setting up gpg-agent (2.2.19-3ubuntu2.2) ...
Setting up gpgsm (2.2.19-3ubuntu2.2) ...
Setting up dirmngr (2.2.19-3ubuntu2.2) ...
Setting up gpg-wks-server (2.2.19-3ubuntu2.2) ...
Setting up gpg-wks-client (2.2.19-3ubuntu2.2) ...
Setting up gnupg (2.2.19-3ubuntu2.2) ...
Processing triggers for libc-bin (2.31-0ubuntu9.2) ...
/sbin/ldconfig.real: /usr/lib/wsl/lib/libcuda.so.1 is not a symbolic link

Processing triggers for man-db (2.9.1-1) ...
Processing triggers for install-info (6.7.0.dfsg.2-5) ...
Processing triggers for ca-certificates (20211016ubuntu0.20.04.1) ...
Updating certificates in /etc/ssl/certs...
0 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
jkoogi@JKASUS:~$ sudo apt-get install     ca-certificates     curl     gnupg     lsb-release
Reading package lists... Done
Building dependency tree
Reading state information... Done
lsb-release is already the newest version (11.1.0ubuntu2).
ca-certificates is already the newest version (20211016ubuntu0.20.04.1).
ca-certificates set to manually installed.
curl is already the newest version (7.68.0-1ubuntu2.15).
gnupg is already the newest version (2.2.19-3ubuntu2.2).
0 upgraded, 0 newly installed, 0 to remove and 175 not upgraded.
jkoogi@JKASUS:~$jkoogi@JKASUS:~$

* Docker의 공식 GPG 키를 추가

jkoogi@JKASUS:~$ sudo mkdir -m 0755 -p /etc/apt/keyrings
jkoogi@JKASUS:~$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

* 리포지토리를 설정 : stable repository 등록

jkoogi@JKASUS:~$ echo \
>   "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
>   $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
jkoogi@JKASUS:~$
더보기

jkoogi@JKASUS:~$ sudo apt-key fingerprint
/etc/apt/trusted.gpg
--------------------
pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [ unknown] Docker Release (CE deb) <docker@docker.com>
sub   rsa4096 2017-02-22 [S]

/etc/apt/trusted.gpg.d/ubuntu-keyring-2012-archive.gpg
------------------------------------------------------
pub   rsa4096 2012-05-11 [SC]
      790B C727 7767 219C 42C8  6F93 3B4F E6AC C0B2 1F32
uid           [ unknown] Ubuntu Archive Automatic Signing Key (2012) <ftpmaster@ubuntu.com>

/etc/apt/trusted.gpg.d/ubuntu-keyring-2012-cdimage.gpg
------------------------------------------------------
pub   rsa4096 2012-05-11 [SC]
      8439 38DF 228D 22F7 B374  2BC0 D94A A3F0 EFE2 1092
uid           [ unknown] Ubuntu CD Image Automatic Signing Key (2012) <cdimage@ubuntu.com>

/etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg
------------------------------------------------------
pub   rsa4096 2018-09-17 [SC]
      F6EC B376 2474 EDA9 D21B  7022 8719 20D1 991B C93C
uid           [ unknown] Ubuntu Archive Automatic Signing Key (2018) <ftpmaster@ubuntu.com>

jkoogi@JKASUS:~$


* Docker Engine 설치

 - 오류?

jkoogi@JKASUS:~$ sudo apt-get update
Get:1 https://download.docker.com/linux/ubuntu focal InRelease [57.7 kB]
Err:1 https://download.docker.com/linux/ubuntu focal InRelease
  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 7EA0A9C3F273FCD8
Hit:2 http://security.ubuntu.com/ubuntu focal-security InRelease
Hit:3 http://archive.ubuntu.com/ubuntu focal InRelease
Hit:4 http://archive.ubuntu.com/ubuntu focal-updates InRelease
Hit:5 http://archive.ubuntu.com/ubuntu focal-backports InRelease
Reading package lists... Done
W: GPG error: https://download.docker.com/linux/ubuntu focal InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 7EA0A9C3F273FCD8
E: The repository 'https://download.docker.com/linux/ubuntu focal InRelease' is not signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
jkoogi@JKASUS:~$

> 메뉴얼 스크립트 진행

jkoogi@JKASUS:~$ echo \
arch=$(>   "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
>   $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
jkoogi@JKASUS:~$ sudo apt-get update
Get:1 https://download.docker.com/linux/ubuntu focal InRelease [57.7 kB]
Get:2 https://download.docker.com/linux/ubuntu focal/stable amd64 Packages [24.5 kB]
Hit:3 http://archive.ubuntu.com/ubuntu focal InRelease
Get:4 http://security.ubuntu.com/ubuntu focal-security InRelease [114 kB]
Get:5 http://archive.ubuntu.com/ubuntu focal-updates InRelease [114 kB]
Get:6 http://archive.ubuntu.com/ubuntu focal-backports InRelease [108 kB]
Fetched 418 kB in 2s (189 kB/s)
Reading package lists... Done
jkoogi@JKASUS:~$

 


 

* Docker Engine, containerd 및 Docker Compose를 설치

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
더보기

jkoogi@JKASUS:~$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  docker-ce-rootless-extras docker-scan-plugin pigz slirp4netns
Suggested packages:
  aufs-tools cgroupfs-mount | cgroup-lite
The following NEW packages will be installed:
  containerd.io docker-buildx-plugin docker-ce docker-ce-cli docker-ce-rootless-extras docker-compose-plugin
  docker-scan-plugin pigz slirp4netns
0 upgraded, 9 newly installed, 0 to remove and 175 not upgraded.
Need to get 111 MB of archives.
After this operation, 399 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 https://download.docker.com/linux/ubuntu focal/stable amd64 containerd.io amd64 1.6.16-1 [27.7 MB]
Get:2 http://archive.ubuntu.com/ubuntu focal/universe amd64 pigz amd64 2.4-1 [57.4 kB]
Get:3 http://archive.ubuntu.com/ubuntu focal/universe amd64 slirp4netns amd64 0.4.3-1 [74.3 kB]
Get:4 https://download.docker.com/linux/ubuntu focal/stable amd64 docker-buildx-plugin amd64 0.10.2-1~ubuntu.20.04~focal [25.9 MB]
Get:5 https://download.docker.com/linux/ubuntu focal/stable amd64 docker-ce-cli amd64 5:23.0.1-1~ubuntu.20.04~focal [13.2 MB]
Get:6 https://download.docker.com/linux/ubuntu focal/stable amd64 docker-ce amd64 5:23.0.1-1~ubuntu.20.04~focal [22.0 MB]
Get:7 https://download.docker.com/linux/ubuntu focal/stable amd64 docker-ce-rootless-extras amd64 5:23.0.1-1~ubuntu.20.04~focal [8765 kB]
Get:8 https://download.docker.com/linux/ubuntu focal/stable amd64 docker-compose-plugin amd64 2.16.0-1~ubuntu.20.04~focal [10.2 MB]
Get:9 https://download.docker.com/linux/ubuntu focal/stable amd64 docker-scan-plugin amd64 0.23.0~ubuntu-focal [3622 kB]
Fetched 111 MB in 12s (9444 kB/s)
Selecting previously unselected package pigz.
(Reading database ... 32285 files and directories currently installed.)
Preparing to unpack .../0-pigz_2.4-1_amd64.deb ...
Unpacking pigz (2.4-1) ...
Selecting previously unselected package containerd.io.
Preparing to unpack .../1-containerd.io_1.6.16-1_amd64.deb ...
Unpacking containerd.io (1.6.16-1) ...
Selecting previously unselected package docker-buildx-plugin.
Preparing to unpack .../2-docker-buildx-plugin_0.10.2-1~ubuntu.20.04~focal_amd64.deb ...
Unpacking docker-buildx-plugin (0.10.2-1~ubuntu.20.04~focal) ...
Selecting previously unselected package docker-ce-cli.
Preparing to unpack .../3-docker-ce-cli_5%3a23.0.1-1~ubuntu.20.04~focal_amd64.deb ...
Unpacking docker-ce-cli (5:23.0.1-1~ubuntu.20.04~focal) ...
Selecting previously unselected package docker-ce.
Preparing to unpack .../4-docker-ce_5%3a23.0.1-1~ubuntu.20.04~focal_amd64.deb ...
Unpacking docker-ce (5:23.0.1-1~ubuntu.20.04~focal) ...
Selecting previously unselected package docker-ce-rootless-extras.
Preparing to unpack .../5-docker-ce-rootless-extras_5%3a23.0.1-1~ubuntu.20.04~focal_amd64.deb ...
Unpacking docker-ce-rootless-extras (5:23.0.1-1~ubuntu.20.04~focal) ...
Selecting previously unselected package docker-compose-plugin.
Preparing to unpack .../6-docker-compose-plugin_2.16.0-1~ubuntu.20.04~focal_amd64.deb ...
Unpacking docker-compose-plugin (2.16.0-1~ubuntu.20.04~focal) ...
Selecting previously unselected package docker-scan-plugin.
Preparing to unpack .../7-docker-scan-plugin_0.23.0~ubuntu-focal_amd64.deb ...
Unpacking docker-scan-plugin (0.23.0~ubuntu-focal) ...
Selecting previously unselected package slirp4netns.
Preparing to unpack .../8-slirp4netns_0.4.3-1_amd64.deb ...
Unpacking slirp4netns (0.4.3-1) ...
Setting up slirp4netns (0.4.3-1) ...
Setting up docker-scan-plugin (0.23.0~ubuntu-focal) ...
Setting up docker-buildx-plugin (0.10.2-1~ubuntu.20.04~focal) ...
Setting up containerd.io (1.6.16-1) ...
Created symlink /etc/systemd/system/multi-user.target.wants/containerd.service → /lib/systemd/system/containerd.service.
Setting up docker-compose-plugin (2.16.0-1~ubuntu.20.04~focal) ...
Setting up docker-ce-cli (5:23.0.1-1~ubuntu.20.04~focal) ...
Setting up pigz (2.4-1) ...
Setting up docker-ce-rootless-extras (5:23.0.1-1~ubuntu.20.04~focal) ...
Setting up docker-ce (5:23.0.1-1~ubuntu.20.04~focal) ...
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /lib/systemd/system/docker.service.
Created symlink /etc/systemd/system/sockets.target.wants/docker.socket → /lib/systemd/system/docker.socket.
invoke-rc.d: could not determine current runlevel
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for systemd (245.4-4ubuntu3.15) ...
jkoogi@JKASUS:~$

* 도커 확인
 - docker version

더보기

 jkoogi@JKASUS:~$ docker version
Client: Docker Engine - Community
 Version:           23.0.1
 API version:       1.42
 Go version:        go1.19.5
 Git commit:        a5ee5b1
 Built:             Thu Feb  9 19:46:56 2023
 OS/Arch:           linux/amd64
 Context:           default
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
jkoogi@JKASUS:~$

* 오류 : 도커 실행이 안된다. WSL 우분투 환경에서 systemd 를 사용하지 않아서 발생하는 문제라고 한다.

jkoogi@JKASUS:/usr/sbin$ sudo apt-get install cgroupfs-mount
jkoogi@JKASUS:/usr/sbin$ sudo cgroupfs-mount
jkoogi@JKASUS:/usr/sbin$ sudo service docker start
더보기

jkoogi@JKASUS:/usr/sbin$ sudo apt-get install cgroupfs-mount
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
  cgroupfs-mount
0 upgraded, 1 newly installed, 0 to remove and 175 not upgraded.
Need to get 6320 B of archives.
After this operation, 32.8 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu focal/universe amd64 cgroupfs-mount all 1.4 [6320 B]
Fetched 6320 B in 0s (13.3 kB/s)
Selecting previously unselected package cgroupfs-mount.
(Reading database ... 32544 files and directories currently installed.)
Preparing to unpack .../cgroupfs-mount_1.4_all.deb ...
Unpacking cgroupfs-mount (1.4) ...
Setting up cgroupfs-mount (1.4) ...
invoke-rc.d: could not determine current runlevel
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for systemd (245.4-4ubuntu3.15) ...
jkoogi@JKASUS:/usr/sbin$ sudo cgroupfs-mount
jkoogi@JKASUS:/usr/sbin$ sudo service docker start
 * Starting Docker: docker                                                                                              [ OK ]
jkoogi@JKASUS:/usr/sbin$

참고 : https://otrodevym.tistory.com/entry/WSL-Docker-system-has-not-been-booted-with-systemd-as-init-system-pid-1-cant-operate

 

[WSL-Docker] system has not been booted with systemd as init system pid 1 cant operate

상황 WSL로 docker를 설치하고 실행하려고 했는데 에러가 발생했습니다. 문제 파악 /etc/init.d/docker로 실행하면 되지만 systemctl이나service로 실행하면 에러가 나는걸로 확인했고 블로그를 찾아보니 WSL

otrodevym.tistory.com

* 도커실행

 - sudo docker run hello-world

더보기

jkoogi@JKASUS:/usr/sbin$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:aa0cc8055b82dc2509bed2e19b275c8f463506616377219d9642221ab53cf9fe
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

jkoogi@JKASUS:/usr/sbin$

validation 체크하는 util class를 만들어봤다. 

값을 확인하려고 로그를 표시해봤는데, soniqube 에서 System.out.pirntln()을 막아놔서 logger로 출력할 필요가 생겼다. 

막상 해보니 로그가 안찍혔다.

 

로직은 돌아가는 것 같은데, 로그만 안찍힌다니.. 

 

메소드를 static으로 선언해서 동작을 안하는 것 같았다.

 

찾아보니 main()와 같이 static 선언된 경우 사용하는 로그 어노테이션(@Slf4j)이 있다는 것을 발견했다.
thanks to https://www.devkuma.com/docs/java/lombok/

 

Java Lombok 사용법

Lombok이란? 어노테이션을 선언하면, getter, setter, toString, equals등의 “반복적으로 작성하는 코드"를 컴파일시에 자동 생성해 준다. 하지만 Getter, Setter 자동 생성은 함부로 하게 되면, 객체 지향을

www.devkuma.com

 

별 기대없이 log 어노테이션을 바꿔줬는데.. 로그가 표시된다.

고맙다 lombok.

 

PS. Util 클래스를 만들면 static 메소드 사용시 객체를 생성해서 사용하는 오용의 소지가 있어서 생성자를 막기위해 

private 생성자를 선언해준다고 한다. (소나큐브가 뭐라고 했다.)

 

그래서 private 생성자를 선언해 줬는데, lombok이 또 이녀석을 해결해주고 있었다.

생성자 생성 대신 @UtilityClass 생성해주면 자동으로 private 생성자 메소드를 대응해준다고 한다.

 

dbeaver 사용시 줄바꿈을 하면 이전 줄의 첫문자의 아래칸으로 줄바꿈이 된다. 

쿼리작성에 편한 부분이 있지만, 

단락이 끝나면 줄앞 공백을 지우고 다시 써야하는 경우가 있다. 

이런 상황을 고려하여 단축키를 하나 추가했다. 

 - alt + backapace


줄바꿈 후 단축키를 이용하여 첫칸으로 이동한다.

01-1 프로그레시브 웹앱이 뭐예요?

 

PWA : progressive web app

 

네이티브앱 : SDK로 개발(안드로이드 스튜디오 : 자바 / 엑스코드 : 오브젝트C, 스위프트)
 - 운영체제 별 서비스 개발 : 안드로이드, IOS

 - 배포 : 앱스토어(애플), 플레이 스토어(구글)

 - 사용 : 스토어에서 다운로드하여 설치 (설치후 알림등의 다양한 기능 활용)

 > 네이티브앱 장단점 비교표

 

모바일 웹앱 : 모바일 베이스의 네이티브 앱

 - 웹 영역은 HTML5, CSS3, Javascript로 구현

 - 웹 영역은 스토어 배포 없이 서버의 컨텐츠 교체 만으로 최신기능 적용

 - 인터넷 속도 영향, 네이티브앱에 비해 제한된 기능

 > 모바일 웹앱 장단점 비교표

 

하이브리드 앱 : 네이티브앱과 모바일 웹앱의 장단점 활용 

 - 컨텐츠를 웹앱으로 제작 후 네이티브앱으로 변환하여 배포
 > 웹앱 방식의 개발, 네이트브 앱 방식의 배포
 - 제한적인 네이티브 앱 기능 사용
 - 크로스 플랫폼(아파치 코르도바 - 오픈소스)을 이용한 운영체제 별 네이트앱 배포

 > 하이브리드 앱 장단점 비교표

 

프로그래시브 웹(PWA) : 웹의 장점을 유지하며 네이티브 앱의 장점 활용 ? 하이브리드?
 - 하이브리드는 네이티브로 웹앱 컨텐츠를 패킹하고, 네이티브로 HW 기능을 구현하는 서비스

 - PWA는 네이티브가 아닌 API로 네이티브가 제공하는 HW 기능을 구현하는 서비스
 > 프로그래시브 웹앱 장단점 비교표 


01-2 프로그레시브 웹앱을 대표하는 6가지 핵심 기술

 - 필수 : 서비스워커, 웹앱 매니페스트, HTTPS
 - 확장 : 푸시알림, 홈화면 추가, 웹API

 

1. 서비스워커
 - 웹브라우저 내부에서 웹페이지와 독립적으로 백그라운드 실행
 - 브라우저와 서버 사이에서 상태 모니터링, 푸시알림 지원

 - 오프라인 동작 (인터넷 연결상태와 독립된 서비스 제공)

 

2. 웹앱 매니페스트
 - 앱 소개정보(메타데이터) 제공 (JSON) : manifest.json
 - 매니페스트 : 앱에서 사용하던 기능 - 브라우저에 정보제공

 

3. HTTPS (hypertext fransfer protocol over secure soket layer)
 - 보안을 강화한 웹 통신 규약 : 네트워크 영역에서 통신정보가 노출되어도 보안유지
  (전자상거래 등 보안이 중요한 서비스에 적합)
 > 서비스워커를 이용한 PWA 배포에 필수
 > PWA 성능평가 프로그램(라이트하우스 - lighthouse)에 인증받기위한 의무요소
 > 홈화면 추가 기능은 HTTPS에서만 지원

 

4. 푸시알림
 - 사용자에 알림정보 제공
 > PWA 푸시알림 동의 시 : 사이트 이탈 사용자, PWA가 종료된 백그라운드 상태에도 알림 가능

 

5. 홈화면 추가(add to home screen - 모바일) - 옴니박스(omnibox - 데스크톱) : 설치 (즐겨찾기, 바로가기 아님)

 - 웹 브라우저 사용 시 PWA 설치 안내
 > 운영체제에서 앱으로 인식
 - 홈화면 추가 제안 조건 :
 > HTTPS 접속 : PWA 호스팅 의무요소

 > 매니페스트 등록 : short_name, name, icons(192px X 512px), start_url, display( : fullscreen || standalone || minimal-ui)
 > 서비스 워커 설치 : 브라우저에 서비스워커 설치 의무

 > PWA 설치여부 : 해당 PWA 서비스가 이전에 설치되지 않은 상태
 - 설치된 아이콘은 네이티브 앱과 동일함

 

6. 웹 API

 - javascript api 사용 :  웹사이트, 웹앱, PWA 사용 (네이티브 기능을 지원하기 시작 : 위치정보, 카메라 등)

 

* 스타벅스의 PWA

 - 인터넷 접속 제한환경 극복 : 오프라인 지원

 - 멀티플렛폼 범용 POS(point of sale) 시스템 구축

 - 가볍고 빠른 반응속도

 

* PWA 사용자경험

 - 온라인, 오프라인을 아우르는 신뢰성

 - 네이티브 앱에 비해 쉬운 설치 지원
 - HTTPS를 의무 적용한 보안성
 - 알림을 통한 구독자 관리
 - 멀티 플랫폼 지원

 - 검색노출에 따른 확장성

 - 최신 서비스 제공이 가능 신속성

 - 네이티브 앱과 같이 HW 기능도 사용 가능

 - 네이티브 앱 대비 빠른 배포, 실행, 반응속도


01-3 비주얼 스튜디오 코드 설치하기

 

* 회사 보안 이슈로 VsCode 사용 불가

 - ecilpse로 대체해 보자.
 > 라이브서버 기능은 어떻게 대체하지... 

 

회사에서도 함께 진행했으면 하여 eclipse에서 live server를 실행해볼까 싶어 찾아봤지만,
관련 기능을 제공하는 플러그인이 없는 듯 하다.
eclipse 버전차이로 webclipse는 지원하지 않는 듯 하고, Tern Eclipse 로 대용하던게 있던것 같은데, javascirpt 관련 기능을 목적으로 쓰인 것이었던지...  codemix는 또 뭐냐... 어지럽다. 일단 그냥 집에서 vsCode로 해보자.
보안팀을 졸라볼까 ㅋ

01-4 '안녕하세요' 예제 만들기

 

index.html 파일만들고

코드생성기능으로 html 5 템플릿 코드를 생성한 뒤

 

언어 설정과 셈플텍스트 입력해주고

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>안녕하세요!</h1>
</body>
</html>

라이브서버를 실행해주면

엑세스허용 메시지를 확인하는 것으로 

크롬에 작성한 화면이 나온다.

디버그 모드에서 

디바이스 툴바 토글버튼으로 웹에서 모바일 모드로 전환하고

 

 

디바이스 목록에서 아이폰 6/7/8을 선택해 주면

show device frame 속성 선택시 프레임이 표시된다.

vscode의 상태 표시줄에 port:5500 영역을 클릭하면,

live server가 종료되면서 Go Live 버튼으로 변경된다.

다시 Go Live 버튼을 클릭하면 live server가 시작된다.

 

eclipse에서 live server 시도하다가 시간만 보냈.. ㅋ
어찌어찌하여 1장은 봤는데, 생각보다 시간이 좀 걸리네... 어쩌지...

 

 

 

AS : code-design.web.app@gmail.com / https://code-design.web.app/

* Do it! 스터디룸 카페 : https://cafe.naver.com/doitstudyroom

* Do it! 공부단 정보 :  https://cafe.naver.com/doitstudyroom/6325

 - 신청 : https://cafe.naver.com/doitstudyroom/43619

 

[Do it! 프로그레시브 웹앱 만들기] 공부단 신청합니다.

Do it! 프로그레시브 웹앱 만들기반응형 웹 개발부터 하이브리드 앱 배포까지 PWA 완전 정복! https://search.shopping.naver.com/book/cat...

cafe.naver.com

 

+ Recent posts