#솔라리턴



얼마전 생일이 지나서

생일기념으로 친구가 점성술로 1년 운세를 봐주었다.


점성술에서는 1년 운세가 바뀌는 때가 바로 생일이다.

생일이 지나면서 프로펙션과 솔라리턴이 바뀌기 때문이다.



먼저 2018년을 되돌아보자면

참 되는 일이 없었다.


내가 무엇을 해야할지 몰라 우왕좌왕 했으며

정말 말도 안되는 것들에도 손을 담가도 보고 시도해보면서

소득도 없고 성과도 없었다.

1년이 텅 비어버린 것만 같다.


이럴 줄 알았으면

빡세게 알바라도 하면서 돈을 모아

여행이라도 갈껄이라는 후회가 남는다.


문제는 2018년보다 2019년이 더 안좋아보인다는 것이다.


뭐 친구는 조금.... 긍정적으로 얘기해주지만

친구 옆에서 점성학 이야기를 들은지 어언 3년째...

그동안 나도 궁금해서 몇몇 카페에도 가입하고 블로그 글도 자주 봤다.

서당개 3년이면 풍월을 읊는다고 했다.

상세히 보지는 못하지만

엄청 안좋거나 엄청 좋은 것 정도는 구분할 수 있다.


내년 프로펙션은 3하우스 사자자리로

태양이 부각되는 해이다.

사실 프로펙션 로드만 보면 내 태양이 나쁘지 않아 괜찮다고 볼 수도 있는데

솔라리턴에서 화성과 3도 차이로 스퀘어 각을 맺고 있고

내가 지금 피르다르 수성, 화성이라는 점도 걸린다.

더 큰 문제는 화성이 솔라리턴 앵글에 있다는 것....


나에겐 화성이란 마치 흉악범같은 존재로서

폴하고 항성 프로키온까지 더해져

마치 연쇄살인마를 보는 느낌이 든다.

어쨌든 단점이 가득했던 작년과는 다르게

올해에는 좋은 점이 있다는 한줄기 희망이 있지만

그 희망도 하자가 있다는 것이다.


안타깝고 슬픈 현실이다.


가끔씩

내 차트는 왜이리 안좋은 걸까?라는 생각을 한다.


뭐 어쩌겠어.

이렇게 태어났는데

이렇게 살아야지.

흑...



아무래도 주위에 운명학을 공부하는 친구가 있어서

나도 관심이 생겨

몇몇 술사들에게 내 생시로 운명을 점쳐보았다.


사주는 망가진 금수상관격이라

좋아지려다 말아먹은 사주란다.


사주 봐준 사람 말에 따르면

옛날 말로

굶지는 않고 살 팔자다

네?!

요즘은 굶는 사람들이 있나?

아니면

굶지 않는다는 것에 만족해야하나....?


예전에 점성술 봐준 사람 말에 따르면

만 29세즈음(토성리턴) 까지는 뭘 해도 안된다!!!

즈기요......

그럼 그때까지

손가락만 쪽쪽 빨고 있으라는 건가요...?


물론 내 인생도 잘 풀리는 때가 있다고 하지만

그건 참 머나먼 훗날..

과연 오기는 할까?


그냥 지금은 나의 시기가 아닌가보다하며

누가 돌을 던지면 조용히 맞고

누가 물을 뿌리면 샤워한다 생각하고

누가 욕을 하면 겸허하게 욕을 씹어주고

인생을 방관하며 살아야겠다.


올해와 마찬가지로

다음 2019년도

참 걱정되는 운세이긴 하지만

최대한 즐겁게 보내봐야겠다.

To be continued.........




Made by 꿩



'일상' 카테고리의 다른 글

[일상] 헬스장 창문 너머  (1) 2024.03.17
[일상] 청룡의 해가 들어오고 있어요!  (0) 2024.02.01
[일상] 나의 신(神)  (0) 2021.12.12
[일상] 명동성당 아침  (2) 2018.10.30
[일상] 북한산 3인방  (1) 2018.10.27

#[Firebase] FCM 푸시 메세지



이 글을 읽고 있는 당신!!!

FCM을 이용해 푸시 메세지를 보낸 적이 있는가?

완전 짱 신기함!!!!

쉽고

빠르게

대량 푸시를 하여

누군가에게 차단당할 수 있다!!!

ㅎㅎㅎ

장난이고

이번 주는 Firebase FCM 기능을 이용한 푸시 메세지를 포스팅하려 한다.


생각보다 간단하고 무료이므로

관심없는 이들도

재미삼아 만들어 보는 것도 좋을 듯하다.


작동원리를 간단히 설명하자면

당신의 컴퓨터에서 Firebase Cloud에 메세지를 보낸다.

당연히 메세지를 보낼 때

당신이 누구인지?, 누구에게 보낼 건지?, 메세지 내용 등

을 포함해서 보낸다.

그러면 Firebase가 해당 컴퓨터나 스마트폰에 푸시 메세지를 날려준다.


1. Firebase 계정만들기

Firebase FCM을 이용하므로 당연히 계정을 만들어야한다.

(무료 요금제 - Spark 요금제)


계정을 만들었으면 프로젝트를 추가한다.

위치는 대한민국이 있으니 설정하고 긍정적으로 체크하고 프로젝트를 만든다.


2. 푸시 메세지를 보내기 위한 정보 찾기

왼쪽 위의 설정버튼에서 프로젝트 설정을 클릭한다.



클라우드 메세징 탭을 보면

당신의 서버 키가 보일 것이다!!

이걸 복사하여 메모장에 잠시 가져다 놓자


다시 홈 화면으로 돌아오면

여기서 맨 오른쪽 거 </>라고 생긴 것을 클릭하자

이 버튼이 웹 앱에 Firebase를 추가하는 버튼이다.


그럼 다음과 같은 창이 뜰 것이다.

이것도 복사를 해 메모장에 일단 보관해놓자!


3. html 파일 만들기

html 파일을 만드는 이유는 토큰 값을 얻기 위해서다.

토큰 값은 쉽게 말해 바로 누구에게 보낼 지 알려주는 값이다.

나도 자세히는 모르지만

약간 주소 같은 느낌이 들었다.

주소를 알아야 택배 아저씨가 택배를 가져다 주니까...ㅎ


근데 스마트폰의 토큰 값은 바뀌지 않고

데스크 톱 토큰 값은 한번 껏다키니까 바뀌어 있었다.

이 부분에 대해서는 더 공부해야 할 듯 싶다(과연? ㅎ)


오늘 포스팅은 intellij로~

Web Application으로 프로젝트를 만든다.

아 !! 톰캣 꼭 설치되어 있어야 한다.


프로젝트를 만들고나면

아무 html 파일과 firebase-messaging-sw.js를 만들자!

(주의!) firebase-messaging-sw.js 이거 글자 틀리면 안된다!!


자바스크립트 파일(firebase-messaging-sw.js)은 다음과 같이 작성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js');
 
// Initialize Firebase
var config = {
  apiKey: "enter api key",
    authDomain: "test-4e9a6.firebaseapp.com",
    databaseURL: "https://test-4e9a6.firebaseio.com",
    projectId: "test-4e9a6",
    storageBucket: "test-4e9a6.appspot.com",
    messagingSenderId: "90275796882"
};
firebase.initializeApp(config);
 
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload){
 
    const title = "Hello World";
    const options = {
            body: payload.data.status
    };
 
    return self.registration.showNotification(title,options);
});
cs


html 파일도 다음과 같이 작성한다.

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
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
</head>
<body>
 
<h1 id="order"></h1>
 
<h1> 파이어 메세지</h1>
<script src="https://www.gstatic.com/firebasejs/5.5.9/firebase.js"></script>
<script>
    // Initialize Firebase
    var config = {
        apiKey: "API KEY를 넣어주세요~~~~~~~~~~~~~~~~~~~~~~~~",
        authDomain: "test-4e9a6.firebaseapp.com",
        databaseURL: "https://test-4e9a6.firebaseio.com",
        projectId: "test-4e9a6",
        storageBucket: "test-4e9a6.appspot.com",
        messagingSenderId: "90275796882"
    };
    firebase.initializeApp(config);
 
    const messaging = firebase.messaging();
 
    //token값 알아내기
    messaging.requestPermission()
        .then(function(){
            console.log("Have permission");
            return messaging.getToken();
        })
        .then(function(token){
            console.log(token);
        })
        .catch(function(arr){
            console.log("Error Occured");
        });
 
 
</script>
 
</body>
</html>
cs

apikey에 자신의 api key를 넣고

톰캣을 실행한다.

html 파일에 들어가면


다음과 같이 토큰값이 정상적으로 나오는 것을 확인할 수 있다.

이 토큰 값을 메모장에 옮겨놓는다.


4. 푸시 메세지 보내기

빨리 자고싶어서.....

메세지 보내는 html 파일 만들지는 않고

간단히 Restlet으로 해보려고 한다ㅎㅎ


Authorization에 서버 키를 넣고

"to" : 에는 토큰 값을 넣는다.


send 버튼을 누르면

겁나 빨리

푸시 메세지가 뜨는 것을 볼 수 있다.


친구에게 푸시 메세지를 보내고 싶다면

자신의 서버를 열어놔야 한다.


서버를 열어 해킹당할까봐 무섭다면

Firebase의 Hosting 서비스를 사용할 수 있다.


아까 만든 html과 js 파일을 hosting해놓고

친구가 호스팅 주소에 들어가 토큰 값을 알려준다면

당신은 그 친구에게 무한 푸시를 할 수 있다.


물론 차단하면 모든 노력은 물거품이 되지만... ㅎㅎ


안드로이드까지는 무리없이 웹으로 쉽게 푸시가 가능하다.

그러나 ios는 인증 과정을 거쳐야 해서 까다롭다.

역시 나는 안드로이드가 좋다.


언젠간...

Firebase FCM 푸시 메세지를 호스팅하는 글을 올려야 할 듯 싶다ㅎㅎ




To be continued.........




Made by 꿩












'Database > Firebase' 카테고리의 다른 글

[Firebase] FCM 푸시 메세지 - Notification  (2) 2019.01.06

#[Spring Boot] 카카오페이 API



생각보다 카카오페이 API에 대한 글이 적어서 포스팅을 해보려한다.


스프링 부트에서 카카오페이를 붙이는 데 도움이 되었으면 한다.

본 글은 단건결제 프로세스만 설명할 것이다.


먼저 Kakao Developers를 참고해야한다.

https://developers.kakao.com/docs/restapi/kakaopay-api

카카오페이 API가 어떤 데이터를 요청받고 주는지에 대해 쓰여있다.

----------------------------------------------------------------------------------------------------------------

먼저 결제준비 단계이다.

request는 카카오페이에서 요구하는 정보이다.

해석해보자면

POST방식으로 https://kapi.kakao.com + /v1/payment/approve란 호스트(url 주소)로

Authorization(권한)과 Content-Type을 보내라는 것이다.

이 부분이 header에 해당되는 내용이고

밑에 있는 키와 설명, 타입으로 되어있는 부분은 body로 보내면 된다.


권한은 어디서 얻을 수 있을까?

먼저, KakaoDevelopers에 로그인을 해야한다.

내 애플리케이션 -> 개요 -> 앱정보 -> 앱 키 표시를 눌렀을 때 나오는

admin 키가 바로 권한 키이다.


주의할 것은 바로 밑 플랫폼에서

다음과 같이 설정해야한다.


----------------------------------------------------------------------------------------------------------------

kakaoPay.html파일을 만들고 post방식으로 보내는 버튼을 만든다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
 
<h1> kakaoPay api 이용하기 </h1>
 
<form method="post" action="/kakaoPay">
    <button>카카오페이로 결제하기</button>
</form>
 
 
</body>
</html>
cs


----------------------------------------------------------------------------------------------------------------

이제  KakaoPay 클래스를 만들어본다.

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
package org.salem.service;
 
import java.net.URI;
import java.net.URISyntaxException;
 
import org.salem.domain.KakaoPayApprovalVO;
import org.salem.domain.KakaoPayReadyVO;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
 
import lombok.extern.java.Log;
 
@Service
@Log
public class KakaoPay {
 
    private static final String HOST = "https://kapi.kakao.com";
    
    private KakaoPayReadyVO kakaoPayReadyVO;
    
    public String kakaoPayReady() {
 
        RestTemplate restTemplate = new RestTemplate();
 
        // 서버로 요청할 Header
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization""KakaoAK " + "admin key를 넣어주세요~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!");
        headers.add("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);
        headers.add("Content-Type", MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8");
        
        // 서버로 요청할 Body
        MultiValueMap<StringString> params = new LinkedMultiValueMap<StringString>();
        params.add("cid""TC0ONETIME");
        params.add("partner_order_id""1001");
        params.add("partner_user_id""gorany");
        params.add("item_name""갤럭시S9");
        params.add("quantity""1");
        params.add("total_amount""2100");
        params.add("tax_free_amount""100");
        params.add("approval_url""http://localhost:8080/kakaoPaySuccess");
        params.add("cancel_url""http://localhost:8080/kakaoPayCancel");
        params.add("fail_url""http://localhost:8080/kakaoPaySuccessFail");
 
         HttpEntity<MultiValueMap<StringString>> body = new HttpEntity<MultiValueMap<StringString>>(params, headers);
 
        try {
            kakaoPayReadyVO = restTemplate.postForObject(new URI(HOST + "/v1/payment/ready"), body, KakaoPayReadyVO.class);
            
            log.info("" + kakaoPayReadyVO);
            
            return kakaoPayReadyVO.getNext_redirect_pc_url();
 
        } catch (RestClientException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (URISyntaxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        return "/pay";
        
    }
    
}
 
cs


1) cid는 가맹점 코드로 카카오페이에 연락해서 받아야 한다.

Test 코드이므로 TC0ONETIME를 넣었고

실결제를 하려면 카카오페이와 제휴 후 받은 cid 코드를 넣으면 된다.


2) Authorization에 위에서 설명한 admin 키를 넣어야 한다.


3)  body 부분에는 내가 결제로 지정할 데이터들을 넣는다.

kakao Developers에 필수라고 써있는 파라미터들은 꼭 넣어줘야한다.


4) HttpEntity<MultiValueMap<StringString>> body = new HttpEntity<MultiValueMap<StringString>>(params, headers);

hearder와 body를 붙이는 방법이다.


5) kakaoPayReadyVO = restTemplate.postForObject(new URI(HOST + "/v1/payment/ready"), body, KakaoPayReadyVO.class);

RestTemplate을 이용해 카카오페이에 데이터를 보내는 방법이다.

post방식으로 HOST + "/v1/payment/ready"에 body(header+body)정보를 보낸다.

정보를 보내고 요청이 성공적으로 이루어지면 카카오페이에서 응답정보를 보내준다.

KakaoPayReadyVO.class는 응답을 받는 객체를 설정한 것이다.

response로 위와 같은 데이터가 들어오므로 이를 객체로 받기 위한 자바 빈을 만들었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.salem.domain;
 
import java.util.Date;
 
import lombok.Data;
 
@Data
public class KakaoPayReadyVO {
    
    //response
    private String tid, next_redirect_pc_url;
    private Date created_at;
    
}
 
cs

안드로이드나 ios는 사용하지 않으므로 빼도 상관없다.


6) return kakaoPayReadyVO.getNext_redirect_pc_url();

마지막 return 값으로 redirect url을 불러와 결제가 완료되면 해당 주소로 가게끔 설정해 놓는다.

----------------------------------------------------------------------------------------------------------------

지금까지 만든 클래스가 잘 작동하도록 controller를 만든다.

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
package org.salem.controller;
 
import org.salem.service.KakaoPay;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
 
import lombok.Setter;
import lombok.extern.java.Log;
 
@Log
@Controller
public class SampleController {
    
    @Setter(onMethod_ = @Autowired)
    private KakaoPay kakaopay;
    
    
    @GetMapping("/kakaoPay")
    public void kakaoPayGet() {
        
    }
    
    @PostMapping("/kakaoPay")
    public String kakaoPay() {
        log.info("kakaoPay post............................................");
        
        return "redirect:" + kakaopay.kakaoPayReady();
 
    }
    
    @GetMapping("/kakaoPaySuccess")
    public void kakaoPaySuccess(@RequestParam("pg_token"String pg_token, Model model) {
        log.info("kakaoPaySuccess get............................................");
        log.info("kakaoPaySuccess pg_token : " + pg_token);
        
    }
    
}
 
cs

kakaoPaySuccess.html까지 만들어 놓으면

우선 카카오페이 결제가 정상적으로 작동이 될 것이다.

<url에 pg_token이 들어왔는지 확인하자!

ex) http://localhost:8080/kakaoPaySuccess?pg_token=8cf5a737f5fd9151f2ca>




지금까지는 카카오페이에 "갤럭시S9 제품 2100원 결제해주세요~"라고 요청했을때

카카오페이에서 알아서 결제하도록 만든 것이다.


결제가 완료되면 결제완료 창에

결제가 어떤 방식으로 이루어졌는지?

어떤 카드를 써서 결제를 했는지?

등등 결제정보를 카카오페이에서 받아와야하지 않겠는가?

----------------------------------------------------------------------------------------------------------------

이제 결제승인 단계로 가본다.

매커니즘은 결제준비 단계와 크게 다르지 않지만

결제완료 후 받아오는 pg_token과 tid가 필수적으로 있어야 한다.


동일하게 KakaoPay 클래스에 kakaoPayInfo메소드를 추가했다.

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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package org.salem.service;
 
import java.net.URI;
import java.net.URISyntaxException;
 
import org.salem.domain.KakaoPayApprovalVO;
import org.salem.domain.KakaoPayReadyVO;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
 
import lombok.extern.java.Log;
 
@Service
@Log
public class KakaoPay {
 
    private static final String HOST = "https://kapi.kakao.com";
    
    private KakaoPayReadyVO kakaoPayReadyVO;
    private KakaoPayApprovalVO kakaoPayApprovalVO;
    
    public String kakaoPayReady() {
 
        RestTemplate restTemplate = new RestTemplate();
 
        // 서버로 요청할 Header
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization""KakaoAK " + "admin key를 넣어주세요~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!");
        headers.add("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);
        headers.add("Content-Type", MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8");
        
        // 서버로 요청할 Body
        MultiValueMap<StringString> params = new LinkedMultiValueMap<StringString>();
        params.add("cid""TC0ONETIME");
        params.add("partner_order_id""1001");
        params.add("partner_user_id""gorany");
        params.add("item_name""갤럭시S9");
        params.add("quantity""1");
        params.add("total_amount""2100");
        params.add("tax_free_amount""100");
        params.add("approval_url""http://localhost:8080/kakaoPaySuccess");
        params.add("cancel_url""http://localhost:8080/kakaoPayCancel");
        params.add("fail_url""http://localhost:8080/kakaoPaySuccessFail");
 
         HttpEntity<MultiValueMap<StringString>> body = new HttpEntity<MultiValueMap<StringString>>(params, headers);
 
        try {
            kakaoPayReadyVO = restTemplate.postForObject(new URI(HOST + "/v1/payment/ready"), body, KakaoPayReadyVO.class);
            
            log.info("" + kakaoPayReadyVO);
            
            return kakaoPayReadyVO.getNext_redirect_pc_url();
 
        } catch (RestClientException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (URISyntaxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        return "/pay";
        
    }
    
    public KakaoPayApprovalVO kakaoPayInfo(String pg_token) {
 
        log.info("KakaoPayInfoVO............................................");
        log.info("-----------------------------");
        
        RestTemplate restTemplate = new RestTemplate();
 
        // 서버로 요청할 Header
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization""KakaoAK " + "admin key를 넣어주세요~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!");
        headers.add("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);
        headers.add("Content-Type", MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8");
 
        // 서버로 요청할 Body
        MultiValueMap<StringString> params = new LinkedMultiValueMap<StringString>();
        params.add("cid""TC0ONETIME");
        params.add("tid", kakaoPayReadyVO.getTid());
        params.add("partner_order_id""1001");
        params.add("partner_user_id""gorany");
        params.add("pg_token", pg_token);
        params.add("total_amount""2100");
        
        HttpEntity<MultiValueMap<StringString>> body = new HttpEntity<MultiValueMap<StringString>>(params, headers);
        
        try {
            kakaoPayApprovalVO = restTemplate.postForObject(new URI(HOST + "/v1/payment/approve"), body, KakaoPayApprovalVO.class);
            log.info("" + kakaoPayApprovalVO);
          
            return kakaoPayApprovalVO;
        
        } catch (RestClientException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (URISyntaxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        return null;
    }
    
}
 
cs


1) kakaoPayApprovalVO = restTemplate.postForObject(new URI(HOST + "/v1/payment/approve"), body, KakaoPayApprovalVO.class);

응답정보를 받기 위해 KakaoPayApprovalVO 클래스를 만든다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package org.salem.domain;
 
import java.util.Date;
 
import lombok.Data;
 
@Data
public class KakaoPayApprovalVO {
    
    //response
    private String aid, tid, cid, sid;
    private String partner_order_id, partner_user_id, payment_method_type;
    private AmountVO amount;
    private CardVO card_info;
    private String item_name, item_code, payload;
    private Integer quantity, tax_free_amount, vat_amount;
    private Date created_at, approved_at;
    
    
}
 
cs

여기서 amount 와 card_info는 JSONObject로 전송받기 때문에

따로 AmountVO, CardVO라는 객체를 만들어 준다.

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
package org.salem.domain;
 
import lombok.Data;
 
@Data
public class AmountVO {
 
    private Integer total, tax_free, vat, point, discount;
}
 
package org.salem.domain;
 
import lombok.Data;
 
@Data
public class CardVO {
    
    private String purchase_corp, purchase_corp_code;
    private String issuer_corp, issuer_corp_code;
    private String bin, card_type, install_month, approved_id, card_mid;
    private String interest_free_install, card_item_code;
    
 
}
 
cs

----------------------------------------------------------------------------------------------------------------

Controller에서 model.addAttribute를 이용하여

화면 쪽에 정보를 전송한다.

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
package org.salem.controller;
 
import org.salem.service.KakaoPay;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
 
import lombok.Setter;
import lombok.extern.java.Log;
 
@Log
@Controller
public class SampleController {
    
    @Setter(onMethod_ = @Autowired)
    private KakaoPay kakaopay;
    
    
    @GetMapping("/kakaoPay")
    public void kakaoPayGet() {
        
    }
    
    @PostMapping("/kakaoPay")
    public String kakaoPay() {
        log.info("kakaoPay post............................................");
        
        return "redirect:" + kakaopay.kakaoPayReady();
 
    }
    
    @GetMapping("/kakaoPaySuccess")
    public void kakaoPaySuccess(@RequestParam("pg_token"String pg_token, Model model) {
        log.info("kakaoPaySuccess get............................................");
        log.info("kakaoPaySuccess pg_token : " + pg_token);
        
        model.addAttribute("info", kakaopay.kakaoPayInfo(pg_token));
        
    }
    
}
 
cs


----------------------------------------------------------------------------------------------------------------

이제 kakaoPaySuccess.html에 결제승인된 정보를 나타내보자.

Controller에서 보내온 데이터를 Thymeleaf를 이용해 표현했다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
 
카카오페이 결제가 정상적으로 완료되었습니다.
 
결제일시:     [[${info.approved_at}]]<br/>
주문번호:    [[${info.partner_order_id}]]<br/>
상품명:    [[${info.item_name}]]<br/>
상품수량:    [[${info.quantity}]]<br/>
결제금액:    [[${info.amount.total}]]<br/>
결제방법:    [[${info.payment_method_type}]]<br/>
 
 
 
<h2>[[${info}]]</h2>
 
</body>
</html>
cs


결제가 완료되면 화면은 다음과 같이 나올 것이다.




To be continued.........




Made by 꿩






# 추상클래스와 인터페이스



추상화란 형태를 잡는 것이다.

미술에서 추상화는 구체적인 형상을 나타내는 것이 아니라

점, 선, 면, 색과 같은 순수한 조형 요소로 표현한 것이다.

프로그래밍에서 추상화도 마찬가지이다.

구체적인 코드를 짜는 것이 아니라

기본 틀을 잡고 가는 것이다.


추상클래스와 인터페이스는 모두 추상화에 포함된다.

추상클래스는 메소드의 내용을 구현할 수 있는 것과 달리

인터페이스는 명시만 되어있다.

인터페이스가 추상클래스보다 더 추상화된 형태라고 보면 된다.


그렇다면 왜 추상화란 개념이 프로그래밍에 적용이 될까?

바로 다른 사람과의 커뮤니케이션 때문이다.


같이 프로그램 코드를 짜고 있는 상황에서

다른 사람이 어떤 이름의 객체, 메소드를 만드는 지 모른다면

다른 사람의 만든 객체를 내가 쓸 수 없다.

혹은 다른 사람의 일이 다 끝나야 내가 코드를 완성시킬 수 있다.


그러나 인터페이스를 이용하여 먼저 약속을 해놓으면

상대방의 코드 내용을 알지 못해도

나는 내 코드를 완성시킬 수 있다.

일반적으로는

인터페이스 -> 추상클래스 -> 구현클래스

이 3단계로 프로그램 코드를 완성했다.

그러나

자바 8버전 부터는 인터페이스에 디폴트 메소드가 생겼다.

인터페이스도 제한적이지만 메소드를 구현할 수 있게 되면서

추상클래스를 꼭 만들 필요성이 없어졌다.

그렇다면 추상클래스를 이제 쓸 필요가 없어졌는가?

아니다.

인터페이스가 추상클래스의 역할 전부를 대체할 수 없다.

인터페이스는 여전히 상수변수만을 쓸 수 있다.

그렇기에 객체변수를 선언할 필요가 있는 경우엔

추상클래스가 필요하다.


참고로 자바 8버전부터 디폴트 메소드로 인해

스프링에서 몇몇 추상클래스가 Deprecated 되었다.

한마디로 더이상 못쓴다는 것이다.


예를 들어,

WebMvcConfigurerAdapter라는 추상클래스가 있다.


자바 8버전을 베이스로 만든 스프링 5버전 부터는 쓸 수 없다고 나온다.

이 추상클래스가 Deprecated 된 이유는

앞서 말했듯이 바로 디폴트 메소드의 추가로 인해 생겼다.

혹여나 옛날 코드를 참고해 코드를 짜면 에러가 생길 수 있으므로 참고하길 바란다.


To be continued.........




Made by 꿩



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

Spring Boot와 JSP  (0) 2019.08.02
다형성  (0) 2018.11.03
object vs instance vs class  (3) 2018.10.24

# 다형성


나는 게임을 못한다.

가끔씩 LOL을 하는데

너무나 쉽게 내 행동을 간파당해서

라인전이 망하고 한타에서도 진다.

그렇다고 오버워치를 하면 

딜러가 힐러보다 딜을 못하는 상황을 만들어낸다.

네 그렇습니다.

LOL, 오버워치 모두 실버유저입니다.

ㅠㅠ

그래서 가끔 게임이 하기 싫어질 때가 있는데

그럴때마다 하는 게임이 있다.

바로!!!!

추억의 게임인 포켓몬스터 골드버전!!!!



이 게임의 두가지 특징이 얘기해보려 한다.


첫번째

포켓몬은 몬스터볼로 잡을 수 있어서

컴퓨터와 싸움을 하면

포켓몬들은 모두 몬스터볼에서 나온다.


두번째

골드버전은 이전버전과 다르게

포켓몬에게 아이템을 소지할 수 있다.

아이템에 따라 포켓몬에게 적용되는 효과가 달라진다.



이 두가지 특징이 다형성과 연결된다.

다형성다양한 형태를 가질 수 있는 특징을 말한다.


어디서 많이 들어봤던

오버라이딩과 오버로딩이 바로 다형성의 예이다.


<오버라이딩>


먼저, 오버라이딩은 상위 클래스가 가지고 있는 메소드를

하위 클래스가 재정의 해서 사용한다는 것이다.


몬스터볼이라는 상위 클래스를 상속받아

모든 포켓몬스터를 몬스터볼로 꺼내고 돌아오게 할 수 있다.

 예를 들어 다음의 코드와 같다.


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
public class PocketMonster {
 
    public static void main(String[] args){
 
        //포켓몬 만들기?!
        MonsterBall pikachu = new Pikachu();
        MonsterBall yadon = new Yadon();
 
        //피카츄 꺼내기
        pikachu.getout();
        //피카츄 불러들이기
        pikachu.comeback();
 
        //야돈 꺼내기
        yadon.getout();
        //야돈 불러들이기
        yadon.comeback();
 
    }
 
    static class MonsterBall{
 
        public void getout(){
            System.out.println("포켓몬 꺼내기");
        }
 
        public void comeback(){
            System.out.println("포켓몬 불러들이기");
        }
 
    }
 
    static class Pikachu extends MonsterBall {
 
        @Override
        public void getout() {
            System.out.println("피카츄 꺼내기");
        }
 
        @Override
        public void comeback() {
            System.out.println("피카츄 불러들이기");
        }
    }
 
    static class Yadon extends MonsterBall{
 
        @Override
        public void getout() {
            System.out.println("야돈 꺼내기");
        }
 
        @Override
        public void comeback() {
            System.out.println("야돈 불러들이기");
        }
    }
 
}
 
cs


피카츄와 야돈은 모두 몬스터볼(부모 클래스)를 상속받는다.

둘 모두 몬스터볼의 메소드를 사용할 수 있고

각자에 맞게 바꿀 수도 있다.


몬스터볼을 가지고

피카츄를 내보낼 수 있고

야돈을 내보낼 수 있다.


겉모습은 몬스터볼인데

피카츄, 야돈을 모두 생성(?!)할 수 있는

다형성의 예이다.


<오버로딩>


오버로딩은 하나의 클래스에서 같은 이름의 메소드가 있지만

파라미터에 따라 다르게 동작한다.


포켓몬에게 아이템을 소지할 수 있는데

아이템에 따라 다른 효과를 적용할 수 있다.

 예를 들어 다음의 코드와 같다.


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
public class PocketMonster {
 
    public static void main(String[] args) {
        
        //꼬부기 생성?!
        Kkobugi kkobugi = new Kkobugi();
 
        kkobugi.item(new HappyEgg());
        kkobugi.item(new LearningDevice());
    }
 
    public static class Kkobugi{
 
        public void item(HappyEgg happyEgg){
            System.out.println("지닌 포켓몬이 받는 경험치의 양을 1.5배로 상승시킵니다.");
        }
 
        public void item(LearningDevice learningDevice){
            System.out.println("배틀에 나간 포켓몬과 경험치를 나눠 받을 수 있습니다.");
        }
    }
 
    //행복의알
    public static class HappyEgg{ }
    //학습장치
    public static class LearningDevice{ }
 
}
 
cs


아이템이라는 메소드 이름은 동일하지만

꼬부기에게 어떤 아이템을 주느냐에 따라

효과가 달라지는 것을 볼 수 있다.


같은 이름의 메소드에서

어떤 파라미터를 주느냐에 따라

다른 결과를 나타낼 수 있는 다형성의 예이다.



다형성이 있다면 코드를 편하게 짤 수 있다.

새로운 포켓몬을 등록할 때

몬스터볼의 기능인 넣었다 뺐다하는 기능을

포켓몬에게 일일히 다 써줄 필요가 없고

그냥 몬스터볼을 상속만 시켜주면

몬스터볼의 기능을 사용할 수 있다.


이처럼 다형성을 이용한다면 개발의 효율성을 높일 수 있다.


To be continued.........




Made by 꿩

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

Spring Boot와 JSP  (0) 2019.08.02
추상클래스와 인터페이스  (0) 2018.11.11
object vs instance vs class  (3) 2018.10.24

# 명동성당 아침


요즘 새벽 6시에 운동을 하는데

생각보다 일찍 끝나 아침에 여유가 있었다.


문득 오랜만에 가고싶은 곳이 생각나

종각역으로 가지 않고 을지로3가역에서 내렸다.


이른 아침

출근을 하는 회사원들의 서두름 속에서

나는 여유로움을 느끼며 명동성당으로 천천히 걸어갔다.




주말이나 가끔 평일미사를 보러 갈 때는

관광객 + 미사를 보러 오는 사람들로 항상 북적이는 곳이다.


오전 8시 10분 명동성당에는

평소와 다르게

주위 상점이나 건물들 속에서

혼자 고요함을 지키고 있었다.


맑고 맑은 가을 하늘 아래

나 홀로 명동성당 앞에 서있는 기분이란....


내 목적지는 바로 명동성당 뒷편!

바로 촛불을 키고 성모 마리아께 기도를 드리는 곳이다.



예전부터 가끔 의지할 곳이 필요할 때 이곳에 와서 기도를 드렸었다.


사실 성모마리아님께 기도드리는 곳은 두 곳이다.

명동성당 입구에 하나

명동성당 뒤편에 하나

입구쪽은 사람들이 많이 다녀가고

관광객들도 들락날락 거리기에 좋아하지 않는다.


개인적으로 사람이 많은 곳에서 기도하는 것을 좋아하는 편이 아니라서

평일 밤이나 아침에 명동성당 뒤편에 있는 마리아님께 기도를 가끔 한다.



이른 아침이라고 생각했는데도

성모 마리아 상 옆 켜진 촛불은 꽤 있었다.


아침이 아닌 새벽부터 많은 사람들이 저마다

자신만의 기도를 품은채 이곳에 온 듯하다.


나도 초 1개를 키고 취업과 건강을 위해 기도를 드렸다.


항상 기도를 할 때

내 기도를 꼭 이뤄주리라고 생각하진 않는다.


내가 보기에 좋은 일이 훗날엔 좋지 않게 발현이 될 수 있고

지금 불행한 일이 훗날 나에게 큰 도움이 될 수 있기 때문이다.


인생사 새옹지마란 말도 있지 않은가?


그저 내가 힘든 상황을 잘 이겨내고

좋은 결과를 얻기를 바랄 뿐이다.



요즘 날씨가 꽤 쌀쌀해졌다.

winter is coming

겨울이 오나보다.


따뜻한 이불 밖에 나가기가 힘들지만

가끔씩 일찍 이곳에 와서

종종 기도를 하며 나만의 시간을 갖는 것도 좋을 것 같다.




To be continued.........




Made by 꿩



'일상' 카테고리의 다른 글

[일상] 헬스장 창문 너머  (1) 2024.03.17
[일상] 청룡의 해가 들어오고 있어요!  (0) 2024.02.01
[일상] 나의 신(神)  (0) 2021.12.12
[일상] 솔라리턴  (0) 2018.12.19
[일상] 북한산 3인방  (1) 2018.10.27

# MIME 타입



내 PC에는 무수히 많은 종류의 파일들이 있다.

이 파일을 구분하는 것은 바로 확장자이다.

.jpg .txt .pdf .mp4 .avi 등의 확장자로 파일이 구분되어 있고

 해당 확장자에 맞는 프로그램으로 파일을 열 수 있다.


그렇다면 웹에서는 어떨까?

웹에서는 확장자로 파일을 구분하지는 못한다.

그 대신 MIME 타입을 알려주면 어떤 종류의 파일인지 인식할 수 있다.

그래서 웹에서 데이터를 전송하는 경우

꼭 MIME 타입을 명시해야 한다.


MIME은 Multipurpose Internet Mail Extension으로

다목적 전자우편 확장이라 한다.

전자우편으로 다양한 파일을 보낸다고 생각할 수 있다.


기존의 인코딩 방식으로는 파일의 종류를 알 수 없었지만

문서, 이미지, 동영상 등의 파일도 전송하기 위해

새로운 인코딩 방식인 MIME이 생겼다.

(전자우편에 사용하기 위해 등장했지만 HTTP 통신간 전송 데이터 종류를 알리는 용도로도 쓰인다)


MIME 타입은 여러가지 형태가 있다.

MIME 타입의 형식은 가운데 슬래시(/)가 있고

슬래시 앞에는 파일 종류가 뒤에는 파일 포맷으로 되어있다.



MIME 타입의 종류는 다음과 같다.


파일종류

설명 

MIME 타입

text

텍스트

 text/plain, text/html, text/css, text/javascript

image

이미지

 image/gif, image/png, image/jpeg, image/bmp

video

동영상

video/mp4, video/ogg, video/webm

 audio

오디오

 audio/midi, audio/mpeg, audio/webm, audio/ogg, audio/wav

 application

이진 데이터

 application/octet-stream, application/vnd.mspowerpoint, application/xml,  application/pdf, application/json

multi-data

동시전송

multipart/form-data, multipart/byteranges 



(참고)

https://ko.wikipedia.org/wiki/MIME

https://dololak.tistory.com/130 

https://www.iana.org/assignments/media-types/media-types.xhtml

http://www.emh.co.kr/content.pl?mime

      


To be continued.........




Made by 꿩

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

URI? URL? URN?  (0) 2018.10.27

# 북한산 3인방


오랜만에 혼자 북한산에 가봤다.

산에 가볼때가 됐는데라고 생각만 했고

이런저런 핑계로 미루고만 있었다.


그러다 단풍이 다지고 앙상한 나무만이 남아있는 북한산에 가게될까봐

이불 밖을 벗어나 북한산으로 향했다.



북한산을 올라가면서 20대 초반으로 보이는 3명과 나란히 가게 되었다.

별 생각없이 올라가다 문득 저 3명에게 뒤쳐지기 싫은 생각이 들었다.

조금 속도를 높여 앞으로 나아갔고

쉬고 싶었지만 꾹 참고 힘을 쥐어짜냈다.


열심히 올라가다가 도저히 남은 힘이 나오지 않길래

경쟁심을 잠시 내려놓고 중간에 결국 쉬었다.

근데!!!

그 3명도 같이 쉬는게 아닌가...

쉬는 장소도 아닌데..

그리고 힐끗 나를 보는 시선이 느껴졌다.


뭐지?

한번 해보자는 건가?ㅋㅋ

20대 중반을 대표해서 20대 초반과 등산 시합을 하기로 마음먹고 걸음을 옮겼다.

내가 다시 올라가자 그 3인방도 올라가기 시작했다.

자연의 적막함 속에 불타오르는 무언의 경쟁이 시작되었다.


1차전 시작....

내가 앞장서 가고 있었다.

내 앞을 막는 사람들을 요리조리 피해가며

길이 아닌 곳으로 추월해가며 잘가고 있었다.

그러나 역시 나이차이로 내 발걸음은 무거워졌고

3인방의 숨소리가 내 바로 뒤까지 느껴졌다.

'안돼! 이대로 포기할 순 없어!'

내 안의 숨은 힘을 이끌어 내며 허벅지를 불태웠지만

오랫동안 컴퓨터 앞에서 잠자고 있었던 허벅지는 이미 기절한지 오래....

기절한 허벅지를 손으로 열심히 달래며 한걸음 한걸음 떼었지만

20대 초반의 건강한 허벅지를 이길 수 없었다.

결국 나는 추월당했고 나의 패배로 끝났다.


패배의 설움을 달래며 물을 한 켭 들이키고 좀 쉬다가 올라가다보니

조금 위쪽에 그 3인방이 쉬고 있던게 아닌가?!

그래... 너희도 힘들었지? 나만 힘든게 아니었어...

내게 쏟아지는 시선을 모른채

힘들지 않은 척 ㅎㅎ

시크하게 머리카락을 휘날리며 3인방을 지나갔다.



역시나!!!

그 3인방이 곧바로 뒤를 따라오는게 아닌가!!!


2차전 시작의 경종이 울리며

다시 산속은 소리없는 경쟁이 시작되었다.

이번에도 내가 먼저 앞장서가고 있었다.


시작은 좋았다.

허벅지에게 물이라는 에너지 드링크를 부어넣어서 그런지

허벅지 상태는 좋았다.

1차전의 설욕을 앙갚음할 수 있을 것 같았다.

그러나 나이는 무시할 수 없었다.

20대 초반과 중반은 내 생각보다 꽤 큰 차이가 있었다.


이젠 영혼이 반쯤 떠난 허벅지를 되살리기 위해

앞에 사람 많아 빠르게 갈 수 없을 때

조금씩 쉬며 체력을 보충했고

최단거리 전략을 쓰면서

부족한 피지컬을 전략을 쓰며 보충하려고 했었다.


허벅지는 초죽음 상태가 되었고

종아리마저 조금씩 쥐가 올듯 말듯하는게 느껴졌다.


'하 이게 내 마지막이구나'

2차전도 결말이 다가오는 걸 느꼈다.

나는 KO패를 당했고 3인방의 뒷모습을 씁쓸히 바라볼 수 밖에 없었다.


1,2차전 모두 졌기에 깔끔하게 승부를 인정하고

느긋하게 올라가기 시작했다.


등산 시합에 신경쓰느라 몰랐지만

꽤 올라온 것을 알 수 있었다.


주위의 풍경이 보이기 시작하며

폐쇄된 공간에서 눅눅한 공기로 오염된 마음이 정화되는 것을 느꼈다.


가을이라 그런지 백운대 정상에는 사람이 바글바글 했다.

옆에는 낭떠러지라 다른 길로 추월할 수도 없었고

고생한 허벅지도 쉬는겸 쉬엄쉬엄 올라갔다.


오늘 날씨가 좋아 백운대 정상에서 한강에서 이어지는 바다까지 보였다.

그러나 너무 추웠다.

땀도 마르고 바람도 거세어 정상에 오래 있을 수는 없었다.


소심하게 인증샷을 찍고 정상에서 내려갔다.

내려가다보니 올라오면서 보지 못한 것들이 보였다.


바닥에 무수히 흩어진 낙엽들

나무를 감싸고 있는 이끼

나무 사이사이 존재감을 알리는 햇빛

졸졸졸 흘러내리는 물소리까지

산이 내뿜고 있는 숨이 느껴졌다.


시간도 많이 남았고 해서

내려가다 풍경을 보며 가만히 멍도 때려보고

풍경사진도 여러각도로 찍어보며 천천히 내려왔다.


겨울이 벌써 찾아온 정상과 다르게 밑쪽은 아직 가을 분위기를 내뿜고 있었다.

빨갛게 익은 단풍나무와 노랗게 물든 은행나무가 아직 겨울은 아니라고 말해주는 듯했다.


어릴 적 가을마다 단풍잎과 은행잎을 사전에 넣었던 생각이 나서

갑자기 혼자 잘 물들고 모양이 예쁜 잎을 찾기 시작했다.



단풍잎은 많기도 하고 단풍나무가 높게 자라지 않아

단풍잎을 수집하기는 좀 쉬웠지만

은행잎은 나무가 너무 높았고

떨어진 잎은 이미 거무스름해서

내 마음에 드는 잎을 찾기란 여간 쉽지 않았다.



고심 끝에 나에게 채택된 잎파리들을 책 속에 고이 모셔놓고

집으로 왔다.


그래... 난 가방에 책을 넣고 등산을 했었다.

물도 0.7리터가 들어있었다.

혹시나 배고파지면 먹을 떡도 들어있었다.

그에 반해 그 3인방은 가방도 물도 없이 맨 몸이었다.

처음부터 내가 불리한 게임이었다.

내가 운동선수가 아닌 이상 건장한 20대 초반 남성을 이길 수는 없었다.

그래도 그정도까지 게임을 끌고 갈 수 있었던 것도 대단한 것이다.

라고 위안을 삼고 있다.ㅎㅎ


* * *


산을 올라가다보면 당연히 힘이 든다.

나보다 빨리 올라가는 사람도 있고

나보다 느려 내가 추월하는 사람도 있다.

힘이 너무 들면 적당히 올라왔으니 내려갈까?라는 생각도 들 수 있다.


누군가는 나처럼 다른 사람들을 신경쓰며 열심히 올라가는 사람도 있을 것이고

누군가는 주위 사람 신경쓰지 않고 자신만의 페이스대로 올라가는 사람도 있다.


다른 사람들을 신경쓰며 올라가다보면 어느샌가 많이 올라왔다는 것을 알 수 있다.

그러나 주위의 풍경은 보지 않고

오직 목표만을 바라보고 앞으로 나아간다.


너무 목표만을 향해서 가는 것도 좋지 않고

너무 느긋하게 자신만의 페이스대로 가는 것도 좋지 않다고 생각한다.


어떤 시기엔 열심히 목표를 향해 나아가고

또다른 시기엔 쉬엄쉬엄 자신만의 페이스대로 나아가는 게 올바른 길이라 생각한다.


그러나 중간에 포기하고 내려가는 것은 싫다.

길을 다른 방향으로 돌릴지언정

중간에 내려가면

결코 정상에서의 행복을 느낄 순 없다.


아무리 힘이 들어도

한 발자국씩이라도 올라가자.


* * *


산을 올라가면 당연히 내려도 와야한다.

정상에 언제까지 있을 수는 없다.


나는 인생에 내리막길로 접어들었을 때

오늘과 같이 내려가는 길을 즐기며 내려가고 싶다.


올라올 때 보지 못했던 것들을 보고

소소한 행복을 느끼며

가벼운 마음으로 내리막길을 즐기고 싶다.




To be continued.........




Made by 꿩


'일상' 카테고리의 다른 글

[일상] 헬스장 창문 너머  (1) 2024.03.17
[일상] 청룡의 해가 들어오고 있어요!  (0) 2024.02.01
[일상] 나의 신(神)  (0) 2021.12.12
[일상] 솔라리턴  (0) 2018.12.19
[일상] 명동성당 아침  (2) 2018.10.30

+ Recent posts