안녕하세요.

오늘은 Node-Webkit에 대해 알아보도록 하겠습니다.


먼저 NWJS 즉 Node-Webkit.js에 대해 간단히 설명을 드리겠습니다.


 Node-Webkit.js 란?

노드웹킷JS는 기본으로 크로미움브라우저(Chromium) + Node.js를 합친 웹 어플리케이션(web application) 입니다.

Node.js 기반으로 크롬 브라우저의 축소판인 크로미움을 띄우면서 별도의 어플리케이션 역할을 합니다.


그렇다면, 왜 웹 어플리케이션을 사용할까요?


모든 사용자는 서로다른 브라우저를 사용하고있습니다.

예를들어서 사용자1은 인터넷 익스플로러를 사용하고 저는 크롬 브라우저를 사용합니다.

그리고 어떤 웹개발자가 인터넷익스플로러와 크롬브라우저 사용자 기준으로 웹페이지를 만들었어요.

그런데 사용자2가 파이어폭스 브라우저로 접속하였는데 이것을 고려하지 않은 웹페이지는 깨져 보이지 않는 상황이 됩니다.

그렇다면, 개발자가 또 수정작업과 업데이트를 해야겠죠.  수정작업을 통해서 기존 잘되던 브라우저도 번거로워질수도 있을뿐만 아니라 귀찮습니다.


하지만, 웹어플리케이션으로 제작될경우 별도의 브라우저를 설치할 필요없이 바로 실행을 할 수 있게 됩니다.

웹어플리케이션 종류는 여러가지(electron 등)가 있습니다. 그중하나가 노드웹킷(NWJS) 입니다.


그렇다면, 간단한 실행방법 및 소개를 진행하겠습니다.



노드웹킷 (NWJS) ?





노드웹킷은 많이 사용되고있는 웹어플리케이션 입니다.


지원은 3가지 OS(운영체제)에서 지원되고 있습니다.


Windows, Linux, MAC OS 3가지 모두 지원되고 있습니다. 

(추가적으로 테스트해본결과 라즈베리파이OS인 라즈비언(Raspbian)에서도 실행파일의 변형으로 실행가능합니다.)


위에서 간단히 설명을 드렸다싶이, 노드웹킷은 나의 웹페이지 혹은 특정 웹페이지를 어플리케이션(실팽파일) , 나만의 브라우저로 만들어줍니다.


간혹가다 CSS나 스크립트들이 인식이 잘 되지 않는 경우가 있으나 빠른 업데이트와 빠른 피드백으로 Fix되고 있습니다.


자세한 사항은 아래 NWJS 대표 홈페이지와 문서를 통해 확인하실수 있습니다.


Node-webkit 공식 홈페이지https://nwjs.io/


Node-webkit 개발 문서 : http://docs.nwjs.io/en/latest/For%20Users/Getting%20Started/


Node-webkit Github :  https://github.com/nwjs/nw.js



Windows에서 노드 웹킷 간단 사용하기 


윈도우10에서 노드웹킷(Node-webkit)에 대해 간단한 사용법을 알려드리고자 합니다.

디테일한 심화과정은 개발 문서에 자세히 기록되어있으며, 기능이 상당히 많기때문에 찾아서 진행하는 재미를 가지실 수 있을것입니다.

혹여나 도움이 필요하시다면 댓글을 달아주시면, 알고있는 선에서 답을 해드리도록 하겠습니다.



먼저 노드웹킷(NWJS) 공식홈페이지에서 SDK를 다운받습니다.

(노말버전과 차이점은 동일하게 빌드와 배포가 가능하지만, 노말에서는 기능이 빠졌습니다. 개발자모드등 용량도 당연히 더 적습니다.)



압축을 해제하시면 위의 파일들이 나타납니다.

해당파일 하나하나 설명을 드릴수는 없지만,

CSS 및 JS를 처리해주는 파일도 있고, 동영상, 플래시등 웹 환경에서 원활히 실행을 도와주는 파일들의 구성 그리고 배포를 도와주는 파일 구성 입니다.


배포할때 최대한 파일을 줄여보려고 하였으나, 배포하고나서는 거의 대부분이 필수파일 역할을 하였습니다.



1
2
3
4
{
  "name": "helloworld",
  "main": "http://google.com"
}
cs


** 이제 가장 중요한 작업 입니다. **

메모장(Notepad) 혹은 에디트플러스(EditPlus)에서 JSON파일을 하나 만들어줍니다.

위 사진과 스크립트는 최소 실행의 기본 스크립트 이며 필수 요소 입니다.


제가 작성한 스크립트는 일단 이름은 helloworld' 이며 노드웹킷을 실행하면 구글을 띄우게 하였습니다.

(자신이 제작한 html 파일이나 웹 주소를 입력하셔도 가능합니다)



그리고 설치한 노드웹킷 폴더안에 package.json 으로 저장하여 넣어주세요.

package.json 기준으로 노드웹킷이 실행 됩니다.



그리고 nw.exe를 실행하게되면, 구글을 주소를 입력해논 스크립트가 동작을하여 구글페이지가 나오게 되었습니다.

(사이즈 및 전체화면 툴바없애기 스크롤 없애기등 기능은 노드웹킷 문서를 살펴보시고 package.json에 해당 기능 스크립트를 추가하시면 됩니다.)


이렇게 노드웹킷의 간단실행기는 끝 입니다.

윈도우를 제외한, 리눅스, 맥에서도 동일한 형태의 구동이 가능합니다.


하지만 저렇게 설정을하게되면 설정값이 노출이되며 부가 파일들이 주렁주렁 많기때문에 사용자들에게 배포하기에는 문제가 많습니다.

그렇기때문에 노드웹킷에서 배포를하게된다면 파일을 확 줄어주게 됩니다.

(완전이 싱글 EXE로 줄어들진 않습니다.)



Windows에서 노드 웹킷 배포 하기



1. 먼저 package.json파일을 zip파일으로 압축을 해줍니다.

2. 그뒤 package.zip을 app.nw 로 변경해줍니다. (확장자까지 변경 입니다.)

3. 윈도우 명령어 프롬프트(cmd)를 실행합니다.



명령어 프롬포트를 실행후

1. 노드웹킷을 설치한 폴더로 cd(change dir) 이동합니다. 

2. copy /b nw.exe+app.nw app.exe 를 입력합니다.

3. app.exe가 생성됩니다. (배포완료)


app.exe와 함께 최소한의 파일들만으로도 package.json없이 실행이 가능 합니다.

(하지만 최소한이라고 해도 꾀 많습니다.)


여기까지 노드웹킷의 간단한 사용법과 배포방법을 마치겠습니다.

배포후에도 부수적으로 필요파일이 많기때문에 다음에 단일파일(Single-exe)로 줄이는 툴 사용방법은 아래링크로 다음 포스팅에서 확인할수 있습니다.


단일 실행 파일 만들기 (Enigma Virtual Box) : https://web-inf.tistory.com/29 



감사합니다.


반응형


안녕하세요.

새해 첫글 이네요.  2019년 다들 새해복 많이 받으시길 바랍니다. ^^


오늘은 간단하게 자바스크립트 '=>'로 된 문법에 대해 알아보도록 하겠습니다.


먼저 '=>' 해당 문법의 경우는 화살표 함수(Arrow function) 라고 부릅니다.


간단히 자바스크립트에 대해 이야기를 하고 가도록 하겠습니다.



자바스크립트? ECMAScript? 


넷스케이프사에서 만든 브라우저에서 동적인 요소를 구현을 위해 1995년에 개발된 스크립트가 '자바스크립트' 입니다.


그렇다면 여기서 왜 자바스크립트가 중요한지 말씀을 드리겠습니다.


자바스크립트를 다른 웹브라우저에서 지원을 받기 시작하면서, 표준 규약이 필요하였습니다. 그것을 ECMA국제기구에서 하였구요.


그렇게 됨으로써, ECMAScript가 탄생하게 되었습니다.


현재는 버전이 업그레이드 되면서 2015년에 'ECMAScript 6' 이 되었고 'ES6' 라고 부르고 있습니다.


화살표 함수는 ES6의 기능으로써 가끔 API나 예제를 살펴볼때 등장하여 당황스럽게 만들 수 도 있습니다.


그렇다면 '=>' 화살표함수(Arrow function)와 같은 뜻, 동작을 하게 되는 문법을 알아보겠습니다.



화살표 함수 (Arrow function) 


1
2
3
4
5
6
7
8
var materials = [
  'Hydrogen',
  'Helium',
  'Lithium',
  'Beryllium'
];
 
console.log(materials.map(material => material.length));
cs

모질라 문서에서 화살표 함수 예제를 가져왔습니다.


 예제 참고 링크https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Lexical_this


결론부터 말씀을 드리면 화살표 함수는 함수 표현식 function(meterial) 과 같습니다.


위의 예문의 결과문을 확인을 해본다면 



각 배열의 길이 값들이 재배열되어 아웃풋으로 출력이 됨을 확인할수 있습니다.


그럼 위 문장을 평소에 많이 보단 문장으로 변경을 해보겠습니다.


1
2
3
4
5
6
7
var materials = [
  'Hydrogen',
  'Helium',
  'Lithium',
  'Beryllium'
];
console.log(materials.map(function(material){ return material.length }));
cs

결과값은 동일하게 출력이 됩니다.

결론적으로, 화살표 함수는 function() { return value };를 간단하게 '=>' 로 표기할수도 있습니다.
더 추가적인내용은 위에 예제참고로 올려놓은 링크에서 확인 하실수 있습니다.

하지만, 지원되는 브라우저를 잘확인하시고 사용하셔야 합니다.

아래에 지원되는 브라우저 목록을 확인하시고 사용하시면 될것 같습니다.


지원하는 브라우저

  • Chrome (v. 45+)
  • Firefox (v. 22+)
  • Edge (v. 12+)
  • Opera (v. 32+)
  • Android Browser (v. 47+)
  • Opera Mobile (v. 33+)
  • Chrome for Android (v. 47+)
  • Firefox for Android (v. 44+)
  • Safari (v. 10+)
  • iOS Safari (v. 10.2+)
  • Samsung Internet (v. 5+)
  • Baidu Browser (v. 7.12+)

지원하지 않는 브라우저

  • IE (through v. 11)
  • Opera Mini (through v. 8.0)
  • Blackberry Browser (through v. 10)
  • IE Mobile (through v. 11)
  • UC Browser for Android (through v. 11.4)
  • QQ (through v. 1.2)


반응형


안녕하세요.


요즘은 JSTL 혹은 서버에서 페이지로 넘어올때 날짜변환이 이루어져 넘어오는경우가 많습니다.

하지만, 특수한 상황에는 꼭 자바스크립트에서만 처리를 해야 할 경우가 발생하는데요.


저도 자주 까먹어서 공유 및 기록차 포스팅을 하게되었습니다.


추가적으로 자바스크립트로 숫자형 3자리마다 콤마를 찍는 방법 또한 포스팅을 시작하겠습니다.


타임스탬프를 날짜로 변환하기 


먼저 샘플 타임스탬프 값을 가져왔습니다.


1545269785000


현재 시간을 샘플로 타임스탬프로 뽑아보았구요.

이 값을 이제 날짜형식으로 변경하는 샘플 입니다. 


1
2
3
var timestamp = 1545186677000;
var date = new Date(timestamp);
console.log(date);
cs


타임스탬프 값을 Date 내장함수에 넣어주면 됩니다.

간단 하죠? 결과값은 이렇게 출력이 됩니다.







숫자형 데이터 3자리 단위 콤마(,) 찍기 


먼저 숫자형 데이터가 필요 합니다.


문자가 섞여 있으면 되지 않습니다.


하지만 문자로 넘어온 숫자형 데이터라면 변환후 처리를 해주면 됩니다.


저는 샘플데이터로 날짜변환에서 사용한 타임스태프를 그대로 사용해보겠습니다.


1545269785000


저 숫자값을 문자라고 생각해고 Number()형으로 변환후 처리 해보겠습니다.


1
2
var money = Number(1545186677000).toLocaleString();
console.log(money);
cs


핵심은 .toLocaleString()입니다.

숫자값을 (,)로 3자리 단위로 처리 해줍니다.


간단합니다. 결과는 이렇게 출력이 됩니다.





감사합니다.


반응형


오늘은 FCM콘솔로 푸시를 보내지 않고, 자바 스프링MVC 웹서버(WAS)를 이용하여 이전에 구현했던 안드로이드 어플리케이션으로 푸시를 보내보겠습니다.


먼저 FCM 푸시를 수신받을 어플리케이션을 제작 및 FCM 콘솔에 프로젝트를 생성을 하셔야합니다.

(사전 준비가 되지 않으신분은 아래에 이전에 작성한 포스팅 자료의 링크를 참조해주시면 되겠습니다.)


FCM 프로젝트 생성 및 FCM 수신 어플리케이션 제작

https://web-inf.tistory.com/21


이번 과정에서는 스프링MVC 프로젝트를 만드는과정은 간단한 과정이기 때문에 생략하고 진행하도록 하겠습니다.


1. 시작하기 


먼저 이전 앱 서버로 푸시를 보내는 가이드 문서가 업데이트되어 HTTP v1 API로 변경이 되었습니다.

해당 문서는 FCM 프로젝트에서 비밀 KEY파일을 받아 Access Token을 발급 받은 뒤, Access Token과 함께 안드로이드의 해당 Device Token으로 푸시 요청을 보내는 과정입니다.


구글 FCM HTTP v1 API 가이드 문서

 https://firebase.google.com/docs/cloud-messaging/send-message?hl=ko


먼저 Access Token을 발급과정을 위해 key파일을 생성해보겠습니다.



FCM 콘솔에 접속을 합니다.

그리고 저번에 생성해뒀던 FCM TEST 프로젝트가 보이네요.

자신이 사용하는 FCM 프로젝트를 클릭해서 접속해주세요.

콘솔 링크 : https://console.firebase.google.com/u/0/project/_/settings/serviceaccounts/adminsdk?hl=ko



프로젝트에 접근한뒤, 설정에 서비스 계정 항목을 선택해서 들어가주세요.



오늘은 JAVA를 이용하여 작업을 진행하기 때문에, 자바를 선택하신뒤 비공개 키 생성 버튼을 눌러주세요.



한번더 경고창이 나오며 묻게 됩니다.

키 생성을 눌러 비밀키 JSON파일을 다운로드 받아주세요.

다운로드 하신 파일은 잘보관해주세요. 이후 작업에 사용됩니다.



2. SpringMVC 프로젝트에 API 구현하기




먼저 스프링MVC Maven, JAVA1.8 프로젝트와 톰캣을 준비하였습니다.

구현하는 용도에따라 다른분들은 구성이 달라질것이라 생각하여 프로젝트 생성 및 과정은 생략하였습니다.


또한 구글에서 제공하는 API에서는 자바환경에 Gradle 가이드만 제공되고 있어 Maven으로 동작시켜보았습니다.

세부적인 DB연결과 프로퍼티 저장등은 샘플환경만보시고 따로 작업해주시면 될 것 같습니다.





1. 준비과정 - 디바이스 토큰(Device Token)

먼저 이전에 만들어놓은 어플리케이션에서 디바이스 토큰을 가져 옵니다.

위 스크린샷에 MainActivity를 실행했을때 로그로 DeviceToken을 획득하게 설정해준후 에뮬레이터로 가져왔습니다.

(디바이스 토큰은 가끔 변경이 되므로 DB에 저장을 해두던가 별도의 방법으로 refresh받아 작업하시면될것같습니다.)





로그에 디바이스 토큰을 가져온 스크린샷 입니다.

디바이스토큰을 어디에 기록해두시면 됩니다.





2. 준비과정 - Firebase admin SDK 비밀키

먼저 사전에 생성해놓은 비밀키를 프로젝트 내에 복사해주세요.

저는 webapp > resources > google > json 경로에 복사해두었습니다.

(따로 키를 DB에 보관하시거나 저장하는 작업은 별도로 진행하시면 될 것 같습니다.)



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
        <dependency>
            <groupId>com.googlecode.json-simple</groupId>
            <artifactId>json-simple</artifactId>
            <version>1.1.1</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/com.google.api-client/google-api-client -->
        <dependency>
            <groupId>com.google.api-client</groupId>
            <artifactId>google-api-client</artifactId>
            <version>1.26.0</version>
        </dependency>
                        
        <!-- https://mvnrepository.com/artifact/com.google.oauth-client/google-oauth-client -->
        <dependency>
            <groupId>com.google.oauth-client</groupId>
            <artifactId>google-oauth-client</artifactId>
            <version>1.26.0</version>
        </dependency>
                
        <!-- https://mvnrepository.com/artifact/com.google.http-client/google-http-client -->
        <dependency>
            <groupId>com.google.http-client</groupId>
            <artifactId>google-http-client</artifactId>
            <version>1.26.0</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/com.google.http-client/google-http-client-jackson2 -->
        <dependency>
            <groupId>com.google.http-client</groupId>
            <artifactId>google-http-client-jackson2</artifactId>
            <version>1.26.0</version>
        </dependency>  
        
        <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>27.0.1-jre</version>
        </dependency>
 
cs


3. 준비과정 - Maven FCM전용 라이브러리 업데이트


프로젝트의 pom에 해당 dependecy를 붙여놓고 라이브러리를 다운받아주세요.

구글 가이드에서는 api-client라이브러리만 다운받으면 진행이 된다고 적혀있지만, 사실상 위에 기재된 라이브러리가 모두 필요하였습니다.

추가로 Spring의 RestTemplate을 사용하였으며, API로 파라미터를 넘길때는 JSON을 사용하였습니다.

(많은 삽질이 있었습니다.)




GOOGLE SEND API를 보시면 이제, 액세스 키 발급조건과, 디바이스토큰은 획득하였으며 POST방식으로 푸시를 보내주기만 하면됩니다.

(위 API 문서 링크에 있는 자료 입니다.)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
@RequestMapping(value="/fcmTest", method=RequestMethod.GET, produces="text/plain;charset=UTF-8")
    public void fcmTest() throws Exception {
        try {    
            
            String path = "C:/** .. **/webapp/resources/google/{fcm-test-*******************************.json}";           
            String MESSAGING_SCOPE = "https://www.googleapis.com/auth/firebase.messaging";
            String[] SCOPES = { MESSAGING_SCOPE };
            
            GoogleCredential googleCredential = GoogleCredential
                                .fromStream(new FileInputStream(path))
                                .createScoped(Arrays.asList(SCOPES));
            googleCredential.refreshToken();
                                
            HttpHeaders headers = new HttpHeaders();
            headers.add("content-type" , MediaType.APPLICATION_JSON_VALUE);
            headers.add("Authorization""Bearer " + googleCredential.getAccessToken());
            
            JSONObject notification = new JSONObject();
            notification.put("body""TEST");
            notification.put("title""TEST");
            
            JSONObject message = new JSONObject();
            message.put("token""fa_qIyte8d4:APA91bHOGnZulT059PyK3z_sb1dIkDXTiZUIuRksmS7TdK6XgXAS5kopeGIwUfyhad3X3iXMNknCUOZaF6_mgoj1ohG10CanRyJ_EW1d3xN2E-1DPiLdbMK4pdOgdhB1ztZClqB-25rC");
            message.put("notification", notification);
            
            JSONObject jsonParams = new JSONObject();
            jsonParams.put("message", message);
            
            HttpEntity<JSONObject> httpEntity = new HttpEntity<JSONObject>(jsonParams, headers);
            RestTemplate rt = new RestTemplate();            
            
            ResponseEntity<String> res = rt.exchange("https://fcm.googleapis.com/v1/projects/{프로젝트명}/messages:send"
                    , HttpMethod.POST
                    , httpEntity
                    , String.class);
        
            if (res.getStatusCode() != HttpStatus.OK) {
                log.debug("FCM-Exception");
                log.debug(res.getStatusCode().toString());
                log.debug(res.getHeaders().toString());
                log.debug(res.getBody().toString());
                
            } else {
                log.debug(res.getStatusCode().toString());
                log.debug(res.getHeaders().toString());
                log.debug(res.getBody().toLowerCase());
                
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
cs


먼저 풀소스 입니다.

테스트용으로 컨트롤러 단에 바로 호출하여 동작하도록 작성하였습니다.

'{ }' 부분은 자신의 조건에 맞춰 기입하셔야합니다.


구글 액세스키를 발급받은뒤 RestTemplate을 통하여 POST로 푸시를 발송하는 과정 입니다.

이제 중요포인트만 따로 뽑아서 설명을 드리고 마치겠습니다.




1. AccessKey 발급


먼저 AccessKey를 발급하기위해서는, 비밀키 경로를 InputStream으로 읽을수 있게 요구합니다.

절대경로로 작성되어야 하며, 차후에 프로퍼티에 기록 또는 DB 기록작업을 작업하시면 될 것 같습니다.





2. 푸시 내용 및 디바이스토큰으로 전송


발급된 액세스토큰을 HTTP헤더에 넣습니다. (빨간색 박스)

푸시내용을 JSON Object으로 API파라미터 조건에 맞게 담습니다. (초록색 박스)

앱에서 가져온 디바이스 토큰을 JSON Object로 API파라미터 조건에 맞게 담습니다. (노란색 박스)

마지막으로 요청할 주소를 넣습니다.

주의사항으로 자신의 프로젝트ID를 기입하여야 합니다. (파란색박스)

(프로젝트ID는 프로젝트 콘솔 -> 설정 -> 일반 에서 확인할수 있습니다.)


코드 작성을 마치셨으면 발송 후 로그를 확인 합니다.


요청을 통하여 '200' 으로 정상 요청이 되었다는것을 확인할수있습니다.



에뮬레이터 역시나 정상도착하여 아까 기입한 'TEST' 라는 푸시가 날라온걸 확인 할 수 있습니다.



이상으로 Spring MVC Maven 프로젝트를 통한 FCM 푸시 보내기를 마치겠습니다.



반응형


오랜만에 포스팅 입니다.

요즘 바쁜관계로 항상 포스팅해야지 하고선 키워드만 메모해놓고 포스팅을 못하고 있네요.


오늘은 구글 클라우드 메시징 서비스인 FCM 사용방법을 포스팅 하겠습니다.


클라우드 메시징 FCM 푸시는 서버 혹은 특정 요청발생시에 자신의 안드로이드 어플리케이션에서 수신을 받아 메시지를 받는 것을 말합니다.

(IOS에서도 사용가능합니다.)


프로젝트 생성 부터 푸시를 받는 예제까지 작업해보도록 하겠습니다.


1. 프로젝트 생성 및 기본 설정


먼저 자신의 구글 계정을 통하여 파이어베이스 콘솔사이트에 접속을 합니다.


파이어베이스 콘솔

https://console.firebase.google.com/u/0/?hl=ko&pli=1


그리고 다음 사진의 설명과 같이 진행하시면됩니다 



먼저 파이어베이스 콘솔사이트에 접속하여 프로젝트를 생성합니다.

프로젝트 추가를 누릅니다.



저는 테스트용도로 FCM TEST라고 프로젝트명을 지정하였습니다.

프로젝트 이름을 작성하고 약관에 동의후 프로젝트 만들기 하시면 됩니다.



생성된 프로젝트에 들어와서 Project Overview 항목에 '톱니바퀴' 모양을 눌러줍니다.



톱니바퀴를 누른뒤 '프로젝트 설정'에 들어가보시면 나의 프로젝트의 ID와 API키등을 확인할수 있습니다.



프로젝트 설정 하단에 오늘의 주제인 안드로이드 FCM구현을 위해 Android 앱에 Firebase 추가를 선택해줍니다.



안드로이드 추가를 선택하시면 Android 패키지 이름을 요구합니다.

해당 패키지이름은 안드로이드 프로젝트 패키지명을 의미합니다.



안드로이드로 넘어와서 프로젝트를 생성합니다.

프로젝트 이름 패키지명을 지정/생성후 하단 보이는 Package name 을 복사/붙여넣기 하시면됩니다.

(저는 테스트 용도로 'fcm'으로 생성하였습니다.)



다시 파이어베이스 콘솔로 돌아와서 안드로이드 스튜디오에서 생성한 패키지명을 입력해줍니다.

나머지 앱닉네임, 디버그 서명 인증서는 선택사항임으로 생략하겠습니다.



앱등록을 진행후에 'google-services.json' 파일을 제공합니다.

해당 파일은 나의 안드로이드 프로젝트와 파이어베이스를 동기화시키는 연결고리 역할을 합니다.

구글에서 인증 프로토콜로 구글에서 개발하여 하여 기존 RPC프로토콜과 다른 GRPC라고 명칭 합니다.



해당 프로젝트에 App폴더 및에 파일을 복사 해주시면 됩니다.



그리고 프로젝트에 build.gadle의 플러그인을 추가해줍니다.

(자세한 사항은 아래사진에 있습니다.)



먼저 App build.gradle 입니다.

가이드에는 최신버전 16.0.1을 권장하고 있지만, 저는 12.0.0 으로 진행하였습니다.

(보안적으로 업데이트를 하였지만, 안드로이드 스튜디오든 구글 플러그인은 항상 업데이트이후 말썽이 많아 기존 잘 유지되던 버전으로 사용하겠습니다.)


dependencies안에는  implementation 'com.google.firebase:firebase-messaging:12.0.0'


dependencies 밖에는 apply plugin: 'com.google.gms.google-services'


사진을 잘 참고해주시고 붙여넣어주세요!



Project build.gradle 입니다.

구글에서 권장하는 최신버전으로 붙여넣으셔도 문제없습니다.


dependencies안에  classpath 'com.google.gms:google-services:4.0.1' 를 붙여넣어주세요.



이로써 프로젝트 생성과 안드로이드 프로젝트 설정이 끝났습니다.



2.  안드로이드 프로젝트 소스코드 작성



Manifest 퍼미션 설정

FCM은 인터넷 환경에서 작동되는 서비스 입니다.

즉, 어플리케이션의 인터넷 퍼미션을 열어줘야합니다.


매니페스트 상단에 퍼미션 설정을 해주시면 됩니다.


 <uses-permission android:name="android.permission.INTERNET"></uses-permission>



Manifest 서비스 설정

FCM을 사용하기위해 어플을 설치한 기기장치의 디바이스 토큰값을 얻어오는 서비스와 푸시 메시지를 받았을때 동작하는 서비스를 등록해 주어야 합니다.


<application> 태그 안쪽에 붙여넣거나 작성해주시면됩니다.


<service

      android:name=".MyFirebaseMessagingService">

      <intent-filter>

           <action android:name="com.google.firebase.MESSAGING_EVENT"/>

      </intent-filter>

 </service>

 <service

      android:name=".MyFirebaseInstanceIDService">

      <intent-filter>

           <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>

       </intent-filter>

 </service>



메인 소스코드 작성

2가지의 자바 클래스파일을 자바 메인에 생성합니다.

(생성 위치는 다들 아실것이라 생각하지만 혹시나 모르시는분은 아래 사진을참고해주세요.)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
    @Override
    public void onTokenRefresh() {
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        Log.d("IDService""Refreshed token: " + refreshedToken);
 
        sendRegistrationToServer(refreshedToken);
    }
 
    private void sendRegistrationToServer(String token) {
 
    }
}
 
cs


MyFirebaseInstanceIDService

해당 클래스 파일은 어플리케이션 실행시 디바이스토큰이 생성 및 재생성 될시에 동작을 작성합니다.


sendRegistrationToServer는 어플리케이션을 실행후, 해당 어플리케이션을 실행한 Device 토큰을 서버로 전송하는 코드를 작성하시면 됩니다.

(앱으로 푸시를 보내기 위해서는 Device토큰이 필수값 입니다.)


오늘은 설정을 마친뒤 발송테스트를 파이어베이스 콘솔에서 진행할것 입니다.

혹시나 별도의 웹서버나 요청을할 서버가 있다면 코드를 작성하시면 될것입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public class MyFirebaseMessagingService extends FirebaseMessagingService {
    private static final String TAG = "MyFirebaseMsgService";
 
    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
 
        // TODO(developer): Handle FCM messages here.
        // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
        Log.d(TAG, "From: " + remoteMessage.getFrom());
 
        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
            Log.d(TAG, "Message data payload: " + remoteMessage.getData());
 
            if (/* Check if data needs to be processed by long running job */ true) {
                // For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
            } else {
                // Handle message within 10 seconds
                handleNow();
            }
 
        }
 
        // Check if message contains a notification payload.
        if (remoteMessage.getNotification() != null) {
            Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
            sendNotification(remoteMessage.getNotification().getBody());
        }
 
        // Also if you intend on generating your own notifications as a result of a received FCM
        // message, here is where that should be initiated. See sendNotification method below.
    }
    // [END receive_message]
 
    /**
     * Handle time allotted to BroadcastReceivers.
     */
    private void handleNow() {
        Log.d(TAG, "Short lived task is done.");
    }
 
    /**
     * Create and show a simple notification containing the received FCM message.
     *
     * @param messageBody FCM message body received.
     */
    private void sendNotification(String messageBody) {
 
        Intent intent = new Intent(this, MainActivity.class);
 
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 
        PendingIntent pendingIntent = PendingIntent.getActivity(this0, intent, PendingIntent.FLAG_ONE_SHOT);
 
        String channelId = getString(R.string.default_notification_channel_id);
        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
 
        NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(this, channelId)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setContentTitle("FCM Message")
                        .setContentText(messageBody)
                        .setAutoCancel(true)
                        .setSound(defaultSoundUri)
                        .setContentIntent(pendingIntent);
 
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String channelName = getString(R.string.default_notification_channel_name);
            NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
            notificationManager.createNotificationChannel(channel);
        }
        notificationManager.notify(0, notificationBuilder.build());
    }
}
cs


MyFirebaseMessagingService

해당 클래스파일은 메시지를 수신하여 알림으로 보여주는 클래스 입니다.


어플리케이션이 실행되면서 해당 클래스가 서비스로 돌고 있다가 메시지가 수신이된다면 Notification으로 알림을 해주는 코드 입니다.

만약 알림을 수신하지않고 별도의 작업을 하고싶게 작성하고싶으면 onMessageReceived 메소드를 수정하시면 될것 같습니다.



strings.xml 설정

간혹 혹시나, MyFirebaseMessagingService 소스코드를 작성하였을때 Strings.xml에서 없는 String값이라고 에러가 나올수도있습니다.

해당 오류에 맞는 태그 스트링 값입니다.

(에러가 안발생하시는분은 선택사항입니다.)


<string name="default_notification_channel_id">Channel ID</string>

 <string name="default_notification_channel_name" translatable="true">Test</string>


이제 모든 설정이 끝이 났습니다.

작성한 코드가 정상적으로 동작 실행하는지 확인해보겠습니다.


3. 동작 확인



다시 콘솔로 돌아옵니다.

그후 성장 메뉴에 Cloud Messaging메뉴로 들어갑니다.



'Send your first message' 혹은 기존에 메시지를 보내보셨던분은 '알림 생성'으로 메시지 작성을 시작합니다.



어플리케이션에게 발송한 푸시 메시지 제목, 메시지 내용을 작성하였습니다.

(임의로 Test, Fcm Test 라고 작성 테스트 하였습니다.)




푸시 메시지를 받을 타겟을 생성한 앱을 선택해줍니다.

이렇게 된다면 해당 어플리케이션이 설치된 모든 디바이스에게 푸시를 전달합니다.



예약항목에서는 메시지를 언제 발송할것인지 스케쥴링 합니다.

(저는 테스트 목적으로 'Now' 바로 보내기를 설정후 발송하겠습니다.)



나머지 전환 이벤트 및 추가항목은 선택사항임으로 생략하겠습니다.

그리고 게시를 누르고 '발송'을 합니다.


4. 결과 



안드로이드 에뮬레이터로 실행하였습니다.

어플리케이션이 잘 실행되어 메시징 서비스로 메시지를 잘전달받은것을 확인 할 수 있습니다.


이로써 FCM 푸시 서비스 구현을 마치겠습니다.


*추가 푸시메시지 발송 후 확인이 안될시*

모두 정상적으로 작성하였는데도 푸시메시지가 확인이 되지않는다면

매니페스트의 'Messaging서비스'에 'enabled'와 'exported'를 'true' 설정후 다시 실행해보세요.



감사합니다.


반응형

'IT > Android' 카테고리의 다른 글

Android NDK&JNI(C/C++) 사용하기 (JNI-Hello, World)  (8) 2021.03.26
WebView 안드로이드 웹뷰 생성하기  (5) 2019.02.19


평상시 Restful 방식으로 Json 혹은 Text를 주고 받던중에 또 다른 웹서비스 방식중인 Soap 방식을 자바로 요청응답을 주고 받아야 하는일이 생겼습니다.

우선 Soap방식의 경우 XML을 요청 하고 응답을 받는데요.


오늘은 SOAPMessage를 이용한 XML을 요청 -> XML을 응답을 자바(Java)로 받는 과정을 포스팅을 하겠습니다.


SOAP (Simple Object Access Protocol) 이란?


SOAP은 HTTP, HTTPS, SMTP등을 사용하여 XML 기반의 메시지를 컴퓨터 네트워크 상에서 교환하는 형태의 프로토콜로써 웹 서비스(Web Service)의 기본적인 메시지 전송 수단이며 XML-RPC와 WDDX에서 envelope/header/body로 이루어진 구조와 전송(transport)과 상호 중립성(interaction neutrality)의 개념을 도입하였다. 

-> 쉽게말해 HTTP, HTTPS등 통신프로토콜 위에서 XML 메시지를 요청응답 받는것 입니다.



자바로 SOAP 요청/응답 하기 


먼저 부분 부분소스 분석을 한 뒤 하단에 풀소스를 첨부하겠습니다.

(급하신분들은 미리 맨하단 샘플소스를 참조해주시면되겠습니다.)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();        
factory.setNamespaceAware(true);             
DocumentBuilder parser = factory.newDocumentBuilder();
 
//request SOAP message DOMSource create
String sendMessage = 
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
        "<root> " +
        "     <body>" +
        "         <record>" +
        "               ... " +
        "           ... " +
        "           ... " +
        "        </record>" + 
        "    <body>" +
        "</root> "
        
StringReader reader = new StringReader(sendMessage);
InputSource is = new InputSource(reader);
Document document = parser.parse(is);
DOMSource requestSource = new DOMSource(document);
 
//SOAPMessage create
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage requestSoapMessage = messageFactory.createMessage(); 
SOAPPart requestSoapPart = requestSoapMessage.getSOAPPart(); 
requestSoapPart.setContent(requestSource);
cs


세세한 설명보단 큰흐름만 집고 넘어가도록하겠습니다.

먼저 보낼(요청할) SOAP XML을 String으로 담고 MessageFactory, SOAPMessage등으로 요청할 XML로 파싱합니다.



1
2
3
4
5
6
//SOAPConnection create instance
SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance();
SOAPConnection connection = scf.createConnection();
 
//SOAP SEND MESSAGE
SOAPMessage responseSoapMessage = connection.call(requestSoapMessage, "요청보낼 URL");
cs

요청할 SOAP XML을 생성한후, SOAPMessage를 요청할 연결준비를 합니다.

새로운 커넥션을 맺고 요청보낼 URL을 입력합니다.



1
2
3
4
5
6
7
8
9
10
11
12
ByteArrayOutputStream out = new ByteArrayOutputStream();
responseSoapMessage.writeTo(out);
                
SOAPBody soapBody = responseSoapMessage.getSOAPBody();  
Iterator i = soapBody.getChildElements();  
Node node = (Node) i.next();
          
JSONParser jsonParser = new JSONParser();
JSONObject soapResult = (JSONObject) jsonParser.parse(node.getChildNodes().item(0).getChildNodes().item(0).getNodeValue());
            
log.debug(soapResult.toString());
 
cs


*응답 XML안에 JSON값이 있을경우*

요청에 성공하였다면 responseSoapMessage 응답값을 OutputStream에 담고 만약 응답 SOAP XML내부에 JSON형식의 String이 있다면,

내부 Body노드를 찾아 JSON으로 파싱후 결과값을 출력 하면 됩니다.



1
2
3
4
5
6
ByteArrayOutputStream out = new ByteArrayOutputStream();
responseSoapMessage.writeTo(out);
 
String soapResult = new String(out.toByteArray(), "UTF-8");
 
log.debug(soapResult);
cs

*응답 XML을 찍어내고 싶은경우*

만약, JSON String이 아니라면 단순 응답값을 String으로 찍어낸후 확인하는 방법이 있습니다.


SAMPLE 소스 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.util.Iterator;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.Node;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
 
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.dom.DOMSource;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; 

try {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();        
        factory.setNamespaceAware(true);             
        DocumentBuilder parser = factory.newDocumentBuilder();
 
        //request SOAP message DOMSource create
        String sendMessage = 
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
            "<root> " +
            "     <body>" +
            "         <record>" +
            "               ... " +
            "           ... " +
            "           ... " +
            "        </record>" + 
            "    <body>" +
            "</root> "
            
        StringReader reader = new StringReader(sendMessage);
        InputSource is = new InputSource(reader);
        Document document = parser.parse(is);
        DOMSource requestSource = new DOMSource(document);
 
        //SOAPMessage create
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage requestSoapMessage = messageFactory.createMessage(); 
        SOAPPart requestSoapPart = requestSoapMessage.getSOAPPart(); 
        requestSoapPart.setContent(requestSource);
 
        //SOAPConnection create instance
        SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance();
        SOAPConnection connection = scf.createConnection();
 
        //SOAP SEND MESSAGE
        SOAPMessage responseSoapMessage = connection.call(requestSoapMessage, "요청보낼 URL");
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        responseSoapMessage.writeTo(out);
        //String soapResult = new String(out.toByteArray(), "UTF-8");
 
        SOAPBody soapBody = responseSoapMessage.getSOAPBody();  
 
        Iterator i = soapBody.getChildElements();  
        Node node = (Node) i.next();
          
        JSONParser jsonParser = new JSONParser();
        JSONObject soapResult = (JSONObject) jsonParser.parse(node.getChildNodes().item(0).getChildNodes().item(0).getNodeValue());
            
        log.debug(soapResult.toString());
 
catch (Exception e) {
    e.printStackTrace();
}       
cs

단순 import한 라이브러리, 클래스와 try/catch문 안의 핵심 소스만 첨부하였습니다.

샘플로만으로도 충분히 구현 할 수 있을 것입니다.


반응형


안녕하세요.


MySQL 5.1 버전이상의 정기적인 예약 작업 수행을 할수있는 이벤트 스케줄러에 대해 포스팅해보겠습니다.


이벤트 스케줄러는 말그대로 특정 이벤트를 자동으로 정기적으로 수행시킬수 있습니다.


예를들어 '특정 UPDATE문을 2018년 11월 2일 15시 36분 03초에 시켜줘' 라고 등록을 해놓으면 DB가 자동으로 일을 수행하게됩니다.


이벤트 스케줄러 생성 하기 


먼저 기본 문법에 대해 보겠습니다.


1
2
3
4
5
6
7
8
9
CREATE EVENT IF NOT EXISTS [이벤트 이름]
    ON SCHEDULE
        [수행, 반복 할 시간]
    ON COMPLETION NOT PRESERVE
    ENABLE
    COMMENT [코멘트]
    DO 
    [수행할 명령]
END
cs


[이벤트 이름]  : 해당 이벤트 스케줄의 이름을 정해주어야 합니다.

[수행, 반복 할 시간] : 해당 명령을 수행하거나 반복할 시간 및 기간을 정해주면 됩니다.

[코멘트] : 해당 이벤트의 내용을 입력해주시면 됩니다.

[수행할 명령] : 해당 이벤트의 시간의 수행할 명령을 입력하면 됩니다.





[수행, 반복 할 시간] 설정하기

 


1
2
3
4
5
6
7
8
9
CREATE EVENT IF NOT EXISTS [이벤트 이름]
    ON SCHEDULE
       AT '2018-11-02 13:40:13' -- 특정 시간에 1회 실행
    ON COMPLETION NOT PRESERVE
    ENABLE
    COMMENT [코멘트]
    DO 
    [수행할 명령]
END
cs

특정 시간에 1회 명령을 실행 하려면 'AT [시간]'을 사용해줍니다.

1
2
3
4
5
6
7
8
9
10
CREATE EVENT IF NOT EXISTS [이벤트 이름]
    ON SCHEDULE
       EVERY 1 DAY -- 하루 한번 반복
    ON COMPLETION NOT PRESERVE
    ENABLE
    COMMENT [코멘트]
    DO 
    [수행할 명령]
END
 

cs


특정 날짜 기간에 명령을 반복 실행 하려면 'EVERY [기간, 시간]'을 사용해줍니다.

(기간, 시간은 YEAR, QUATER, MONTH, DAY, HOUR, MINUTE, WEEK, SECOND 등 사용 할 수 있습니다.)


1
2
3
4
5
6
7
8
9
10
11
CREATE EVENT IF NOT EXISTS [이벤트 이름]
    ON SCHEDULE
           EVERY 1 DAY STARTS '2018-11-02 13:32:55' ENDS '2018-11-03 13:32:55'
           -- 하루 한번 11월 2일 13:32:55 부터 11월 3일 13:32:55까지만 실행
    ON COMPLETION NOT PRESERVE
    ENABLE
    COMMENT [코멘트]
    DO 
    [수행할 명령]
END
 
cs


특정 날짜 기간에 시작일 종료일을 지정 할 수 있습니다.

(하루 한번 반복하는것을 [언제 시작할것인가, 언제 끝낼것인가])

언제 시작하는지 알리는 STARTS구문만 사용하여도 문제가 없습니다.





ON COMPLETION NOT PRESERVE ENABLE



해당 설정은 이벤트를 수행후 삭제 여부를 설정합니다.


만약, 이벤트를 수행후 이벤트를 삭제하지 않는다면 'NOT'을 제거 해주시면 됩니다.

(ON COMPLETION PRESERVE ENABLE)




샘플 (SAMPLE) 



1
2
3
4
5
6
7
8
9
CREATE EVENT IF NOT EXISTS '테스트'
    ON SCHEDULE
           EVERY 1 DAY
    ON COMPLETION NOT PRESERVE
    ENABLE
    COMMENT '테스트 입니다.'
    DO 
    INSERT INTO TEST_TABLE ('TEST1''TEST2'VALUES ('테스트', NOW())
END
cs

샘플 구문을 해석 해보겠습니다.

'테스트' 라는 이벤트를 생성하며 내용은 '테스트 입니다.' 입니다.

실행완료시 해당 이벤트를 삭제를 진행하며, 매일 1회 INSERT 문으로 TEST데이터를 집어넣습니다.

(실행 되는 시간은 이벤트 생성 즉시 생성되는 시간 입니다.)


반응형


안녕하세요. 오늘은 MySQL 이벤트 스케줄러 기능활성화에 대해 알아보겠습니다.

이벤트 스케줄러에대해 간단하게 설명을 드린다면, MySQL에서 정기적으로 일을 수행시켜야할때가 있습니다.

그때 반복적 혹은 1회성으로 DBMS를 제어를 도와주는것이 이벤트 스케줄러(Event Scheduler) 입니다.


해당 기능은 MySQL 5.16부터 추가되었습니다.


이벤트 스케줄러를 사용하기전, MySQL에서 활성화 작업을 진행해야합니다.

그작업을 포스팅하였습니다.


MySQL버전 : 5.6.41

Linux : CentOS


이벤트 스케줄러 활성화 하기 



MySQL에 로그인 합니다.




MySQL에 접속한뒤 이벤트 스케줄러가활성화 되어있는지 확인해보는 명령어를 입력합니다.



show variables like 'event%';



만약 결과가 OFF라면 비활성화 되어있는상태이며 이벤트 스케줄러가 있어도 동작을 하지 않습니다.




해당 이벤트스케줄 활성 옵션을 ON으로 변경해줍니다.



 SET GLOBAL event_scheduler = ON;



다시 활성화 여부를 SELECT해보면 ON으로 바뀐것을 확인할수있습니다.


이제 MySQL의 이벤트 스케줄러를 생성후 사용하시면 동작이 가능합니다.



이벤트 스케줄러 초기화 문제 


MySQL을 재시작시에 이벤트 스케줄러 활성화 옵션이 다시 OFF로 전환되는것을 확인할수 있습니다.

이는 MySQL설정에서 변경하여 재시작시에도 계속해서 ON으로 활성화되게 설정해보는 작업을 해보겠습니다.





먼저 MySQL 부팅시 설정파일인 my.cnf 경로를 찾아 줍니다.


 주의!! CentOS기준으로 작업을 진행중 입니다.


mysqld --verbose --help | grep -A 1 'Default options'



Linux에서 해당 명령어를 입력하시면 MySQL의 my.cnf 위치를 알수있습니다.

(사진의 빨간색 네모를 확인해주세요.)



위치된 경로의 설정파일을 vi에디터로 실행시켜줍니다.



[mysqld] 안에 event_scheduler = ON을 입력해주시고 저장을 해주세요.

(저는 하단에 설정하였습니다. 사진 하단 빨간색 네모를 확인해주세요.)



그후 MySQL을 재시작합니다.

service mysqld restart

(centOS기준 재시작 명령어 입니다.)



다시 MySQL접속후에도 Value값이 ON이 되어있는것을 확인 할 수 있습니다.


이제 정상적으로 이벤트 스케줄러를 사용할수 있게 되었습니다.



반응형

+ Recent posts