# 관악산 등산기 (신림역~관악산공원~연주대)

 

깨끗한 가을 날씨에 이끌려 오랜만에 등산을 하기로 마음을 먹고 관악산으로 향했다.

총 산행시간은 3시간이었으며

관악산입구 - 연주대 - 관악산입구로 다시 내려오는 루트를 이용하였다.

올라가는데 1시간 반

쉬는거 + 내려가는데 1시간 반이 소요되었다.

 

관악산은 신림역에서 버스를 타고 조금 들어가야 한다.

나는 신림역 4번출구에서 조금 걸어가서 나오는 버스정류장에서

5528번 버스를 타고 관악산 입구로 향했다.

 

큰 기와 입구가 관악산 공원의 시작을 알려준다.

코로나가 한창임에도 나처럼 등산온 사람들이 생각보다 많았다.

 

서울 둘레길 표지판이 있는데

둘레길을 이용하면 사당역에서 낙성대 ~ 서울대입구 ~ 석수역까지 갈 수 있다고 나온다.

물론 관심은 없다. 단지 블로그에 사진 하나라도 넣기 위해 찍어봤다.

 

관악산 공원 초입

깨끗한 하늘과 새소리, 맑은 공기가 자연을 느끼게 해준다.

너무 컴퓨터만 하면서 피폐해진 내 정신을 회복시켜주는 것 같았다.

 

가다보면 다음의 표지판이 나오는데

어디로 가도 상관이 없어보였다.

표지판이 낡아서 교체해야할듯;;

 

아무생각없이 쭉 올라가고 있었는데

뭔가 이상한 점이 느껴졌다.

아니나다를까 나는 관악산이 아닌

삼성산을 가고 있던 것이었다.

 

다시 내려가는 길 바닥에

떡하니 연주대는 옆으로 가라는 표시가 써있었다.

나처럼 올라가다 잘못된 방향인걸 깨닫고

다시 내려가는 사람이 좀 있었나보다.

내려가는 길에 표시를 해둔 것을 보니;;

 

다음의 정자가 보이면

관악산 연주대로 제대로 가고있는 것이 맞다는 걸 의미한다.

헷갈리지 말자.

 

올라가다보면 서울대 공대 표지판이 보인다.

서울대 공대에서 올라가면 헷갈리지 않고

더욱 쉽게 관악산에 올라갈 수 있을 듯하다.

 

아무 생각없이 올라가다보면 정상에 다다른다.

사실 난 연주암이 보이는 이곳이 연주대인 줄 알았지만

조금 더 가야했었다.

 

난 혼자 올라왔기에...

혼자서 내 그림자를 찍어줄 수 밖에 없었다느ㄴ..

다들 단체 혹은 같이 등산하러 왔길래

소심하게 혼자서 찍어봤다.

 

저 멀리 보이는 기상관측소 쪽으로 가야 연주대가 나온다.

 

연주대에서 쉬고 있는 사람들

마스크는 필수이다.

 

이제 왔던 길로 다시 돌아가야 할 시간이다.

아이스크림 장수도 연주대 정상에서 볼 수 있다.

 

나는 항상 내려가는게 너무 싫다.

무릎도 아프고 재미도 없기 때문이다.

그래서 그런가 항상 내려가는 길에는 딴 생각을 하곤 한다.

지금까지 어떻게 살아왔고

내가 어떤 사람이었는지

내 자신을 성찰하게 된다.

 

이런저런 생각을 하면서 반성도 하게 되고

내 생각을 정리할 시간이 된다.

그냥 집에만 있으면 여유시간이 있어도 내 자신을 되돌아보지 않는다.

게임을 하든가 잠을 자든가 사람을 만나지

나에 대한 생각은 하지 않는다.

 

저 멀리 다시 관악산 공원 기와입구가 보인다.

생각보다 빨리 올라가서 총 소요시간이 예상보다 적게 걸렸다.

하지만 북한산이나 다른 산에 비해 재미있지는 않았다.

그래도 가까운 산이니 자주 가지 않을까 싶다.

 

나에겐 등산이란

힘들게 올라가 정상에서의 기쁨을 만끽하기 위함이기도 하지만

나 자신에 대해서 다시한번 생각을 하게 해주는 시간인 것 같다.

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

 

 

Made by 꿩

'등산' 카테고리의 다른 글

[등산] 덕유산 등산기  (0) 2022.07.15
소백산 등산기 (희방사~연화봉~비로봉~삼가동)  (0) 2019.12.30

# 소백산 등산기 (희방사~연화봉~비로봉~삼가주차장)


가끔씩 등산을 다니며 사진을 찍지만

휴대폰에 저장되어 있는 사진보다

블로그에 남겨두는 것이 더 의미가 있을 듯하여

앞으로 남겨두려고 한다.


총 산행시간은 약 6시간이었으며

희방사역 - 희방사 - 연화봉 - 제1연화봉 - 비로봉 - 삼가주차장

9시 14분 - 10시 15분 - 11시 50분 - 12시 30분 - 13시 24분 - 15시 20분

정도가 걸렸다.


이번에 간 산은 소백산으로 당일치기로 다녀왔다.

청량리 6시 40분 기차를 타고 달려 9시 14분 희방사 역에 도착하였다.


희방사 역은 매우 작았으며

등산객이 많아서 그런지

역 자체가 깔끔하고 옛날 건물은 아니었다.


몇몇 블로그 글을 보니

어떤 분들은 희방사역에서 택시를 타고

희방사 주차장까지 올라간다고 하던데

나는 걸어올라갔다.


시골길을 걷기도 했지만

아스팔트 길을 걸어올라가야 하기도 했다.


올라가다보면 연화봉 가는길 입구가 나온다.

참고로 희방사 등산로를 이용하기 위해서는

희방사 문화재 보존요금(?)을 내야하며 어른은 2000원이다.

물론, 희방사 구경은 전혀 하지 않았다ㅎ


시원한 폭포도 만나고 자연을 느끼며 올라가다보면

어느샌가 희방사에 도착하게 된다.


점차 눈이 많아지는 것을 느꼈다.

올 겨울은 매우 따뜻해서 눈을 제대로 보지 못했는데

제대로 쌓인 눈과 고드름을 보면서

겨울다운 겨울을 느꼈다.


위로 갈수록 눈이 많이 쌓였으며

나무에도 눈이 쌓여 나뭇가지가 하얗게 보였다.


위쪽은 완전히 겨울왕국

온 세상이 하얀 눈으로 뒤덮였다.

마치 한국이 아닌 다른 나라에 온 듯한 느낌이랄까...

눈을 구경하며 허기진 배를 채웠다.


드디어 연화봉 도착!

옆에 있던 할아버지에게 사진을 찍어달라 부탁했다는;; ㅎㅎ

물론 블로그에 내 사진을 올리진 않는다.


제1연화봉으로 가보기 전 앞으로 가야할 곳을 찍어보았다.

이때 능선을 타고 가므로

별로 힘들지 않을거라 생각했지만

이때부터 비로봉까지가 너무 힘들었다.

온통 눈으로 뒤덮인 산

여기는 어디 나는 누구..

올 한해 구경할 눈은 여기서 실컷 구경한 듯


사진으론 예쁘지만

눈이 저렇게 뭉쳐있다는 것은

엄청나게 추웠다는 것을 반증한다.

다행이도 겹겹이 입고와서 춥진 않았다.


제1연화봉은 정상이라는 느낌이기보다는

비로봉을 가기 위한 중간 도착지 느낌이다.

실제로 저게 끝이다.


저 멀리 보이는 비로봉을 위해 출발

비로봉이 거의 다왔다.

하지만 너무 힘들어서 정말 한발자국씩 겨우겨우 걸어갔다.

쉬고 싶은 마음이 간절했지만

바람이 너무 거세어서 빨리 걸음을 재촉할 수 밖에 없었다.


비로봉 정상에서 보이는 산줄기

이게 백두대간일까?


이제 삼가주차장으로 내려가려고 한다.

원래는 비로봉 말고 좀 더가서 국망봉에서 초암사쪽으로 내려오려고 했다.

힘들고 춥기도 하고....

무엇보다 기차타고 집에 다시오면 시간이 밤 00시가 될 듯 싶어

아쉽지만 도중에 내려가기로 결정했다.


내려오다가 발견한 버스 시간표!!!!

택시를 타고 기차역까지 갈 필요가 없어졌다.

국립공원은 인프라가 너무 잘되어있어서

참 좋은 것 같다는 생각이 ㅎㅎ


내려오는 길은 항상 무릎이 아프다.

그래도 거센 바람은 없어서 한결 편하고 즐거웠다.


다 내려오면 삼가주차장 화장실이 보인다.

네이버 지도로 찾아보니 여기가 아니라 좀 더 밑으로 내려가서

버스를 타라고 알려줬다.


그러나.. 마음씨 좋으신 할아버지가

풍기역까지 차를 태워주셔서

더 빠른 기차를 타고

생각보다 빨리 집에 도착할 수 있었다.


소백산은 눈이 내린 것도 예쁘지만

봄에 와서 꽃 구경하는 것도 좋을 것 같아보인다.

중간중간 식물 안내 표지판도 많았고

대부분 봄과 관련된 것 같았다.


나중에 잊혀질 때 쯤 다시오지 않을까싶다.

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




Made by

'등산' 카테고리의 다른 글

[등산] 덕유산 등산기  (0) 2022.07.15
관악산 등산기 (신림역~관악산공원~연주대)  (0) 2020.10.04

#ClickHouse 설치

 

 

ClickHouse는 오픈소스 DBMS로

일반적인 DBMS와 다르게 컬럼기반 DBMS이다.

 

컬럼기반 DBMS란?

데이터를 row 단위가 아닌 column 단위로 저장하고 관리하는 시스템을 말한다.

 

왜 기존의 DBMS를 변형한 컬럼기반 DBMS가 등장했을까?

데이터가 점점 많아지면서

 통계정보를 산출하고 자료를 분석을 하는데 시간이 많이 발생하게 되었다.

즉, 기존의 DBMS로 OLAP를 하는 경우 시간이 많이 발생하기 때문에

컬럼기반 DBMS가 등장하게 되었다.

 

컬럼기반 DBMS는 컬럼 단위로 저장이 되어있어서

동일한 컬럼 내에서 데이터를 갖고오는데 효율이 좋은 구조로

OLAP에 굉장히 잘 맞게 구성되어 있다.

 

ClickHouse는 컬럼기반 DBMS로 러시아 쪽에서 개발한 것으로 알고 있다.

이번 포스팅은 ClickHouse 설치하고

공식 문서에서 제공하는 샘플 데이터까지 설치하는 과정을 적으려 한다.

 

ClickHouse 설치

# yum install yum-utils
# rpm --import https://repo.yandex.ru/clickhouse/CLICKHOUSE-KEY.GPG
# yum-config-manager --add-repo https://repo.yandex.ru/clickhouse/rpm/stable/x86_64
# yum install clickhouse-server clickhouse-client
# /etc/init.d/clickhouse-server start
# clickhouse-client

설치는 매우 간단하다.

다음과 같이 ClickHouse 콘솔이 나오면 모두 설치가 된 것이다.

 

사용자 생성

# /etc/init.d/clickhouse-server stop
# vi /etc/clickhouse-server/user.xml

<user>
...

<사용자명>
    <password_sha256_hex> sha256 비밀번호 입력 </password_sha256_hex>
    <networks incl="networks" replace="replace">
            <ip>::1</ip>
            <ip>127.0.0.1</ip>
    </networks>
    <profile>default</profile>
    <quota>default</quota>
</사용자명>

</user>

 

서버를 잠시 멈추고

사용자 설정파일에서 사용자를 추가한다.

 

참고로 sha256 비밀번호를 생성하는 법은 다음을 참고한다.

# echo -n "비밀번호" | sha256sum | tr -d '-'
13a5c202e320d0bf9bb2c6e2c7cf380a6f7de5d392509fee260b809c893ff2f9

 

서버를 다시 시작하고 설정한 사용자로 클라이언트에 접속한다.

# /etc/init.d/clickhouse-server start
# clickhouse-client -h 127.0.0.1 -u 사용자이름 --password 비밀번호

 

SQL Editor - Tabix

ClickHouse 내부에는 SQL Editor인 Tabix가 있는데

Tabix로 ClickHouse를 실행해보자.

 

서버 설정파일에 Tabix 주석을 해제한 후 ip를 연다.

# vi /etc/clickhouse-server/config.xml
# 다음의 내용 주석 제거

<http_server_default_response><![CDATA[<html ng-app="SMI2"><head><base href="http://ui.tabix.io/"></head><body><div ui-view="" class="content-ui"></div><script src="http://loader.tabix.io/master.js"></script></body></html>]]></http_server_default_response>

<listen_host>::</listen_host>

 

서버를 재시작한 후

크롬 브라우저에서 http://ip주소:8123을 접속하면 Tabix 페이지가 나올 것이다.

사용자를 생성하지 않았다면 default로 하고 config.xml에 설정한 비밀번호를 입력한다.

 

ClickHouse 공식 홈페이지에 샘플 데이터가 있으므로

다운받아 테스트 해보는 것이 도움이 될 것이다.

 

만약 다른 DBMS와 비교를 하고 싶다면 클릭하우스 샘플 데이터를 마이그레이션해야 하는데

내 경험상 DBeaver로 쉽게 하려고 했지만 여러가지 문제로 데이터를 옮기지 못했다.

ClickHouse는 내부적으로 MySQL 엔진을 지원하고 있어서

해보진 않았지만 MySQL쪽으로 마이그레이션은 쉽지 않을까 싶다.

다른 DB로 해본다면

Tool을 사용하기보다 직접 컬럼을 수정해서 CSV나 JSON으로 하는 것이 더 빠를 것이라 생각한다.

 

클릭하우스 공식문서 - https://clickhouse.yandex/docs/en/

 

 

Made by 꿩

 

 

#Spring Boot와 JSP

 

 

우연히 Spring Boot를 https://start.spring.io/ 라는 사이트에서

프로젝트를 만들어 보았다.

 

평소같으면 기존 Spring Boot 프로젝트에서

틀이나 내용을 복붙해서 가져왔겠지만

 

새로운 스프링 부트 프로젝트를 만드는 연습을 한다고 생각하고

아무것도 복붙하지 않고 만들어 보았다.

 

그런데 왠걸...?

Hello World조차 화면에 나타내지 못했는데 5시간이 지났다.

아무리 설정파일을 고치고

기존 프로젝트를 참고해 똑같은 라이브러리를 깔고

톰캣을 8버전으로 낮춰도 보고

스프링 부트 버전을 여러번 바꿔도 보았지만

스프링 부트는

도무지 hello.jsp 파일을 찾지 못했다.

다른 점은 한가지 있긴 했다.

WEB-INF 폴더 밑이 아닌 templates 폴더 밑에 jsp 파일을 넣은 것이다.

 

templates 폴더 밑에 html파일은 읽히지만

jsp파일은 읽히지 않았다.

 

스프링 부트에서 jsp를 적용하려면

스프링 프로젝트처럼 webapp/WEB_INF/ 하위에 위치시키고

properties나 yml에서 경로를 설정해줘야 jsp파일을 사용할 수 있었다.

스프링 공식문서에 보면 내장된 서블릿 컨테이너에는 jsp 제한사항이 있다.

스프링 부트는 가능하다면 jsp를 피하고

Thymeleaf와 같은 템플릿 엔진을 사용하라고 권장한다.

국비교육에서 처음 스프링 부트를 배웠을 때

jsp로도 실습을 했었고

templates 폴더 안에 html 파일을 넣고 프로젝트까지 진행도 했었다.

 

원래는 강사님이 스프링 부트에서 jsp를 사용할 때

주의할 점이나 이유에 대해서 설명해 주셨었다.

그러나 시간이 지나면서

다 잊어버렸고

이제서야 희미하게 기억이 났다.

 

역시나

수업을 듣는다고 모든 내용을 흡수할 수 있는 것은 아니다.

이처럼

삽질도 하고 피부로 직접 느껴봐야

피가 되고 살이 되나보다.

스프링 공식문서 링크

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc-template-engines

 

 

Made by 꿩

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

추상클래스와 인터페이스  (0) 2018.11.11
다형성  (0) 2018.11.03
object vs instance vs class  (3) 2018.10.24

#[Spring] Google reCAPTCHA v3

 

 

오늘은 자동화 공격에 대한

구글이 제공하는 reCAPTCHA에 대해 소개하려 한다.

reCAPTCHA는 자동화 공격을 막기 위한 방법으로

흔히들 아는 "로봇이 아닙니다"를 떠올이면 된다.

자동화 공격은 사람이 아닌 기계로 공격을 하는 것으로

매크로를 만들어 불법적인 프로그램을 사용하거나

로그인을 할 때 비밀번호를 기계가 자동으로 입력하여

계정을 해킹하는 것 등을 말한다.

Google reCAPTCHA v2는

의심스러운 트래픽이 발생하면

'로봇이 아닙니다'를 증명하기 위해

사람만이 판단할 수 있는 이미지를 클릭하는 방식으로 방어하는 방식이다.

하지만 v2 방식은 이용자들에게 불편함을 주는 방식으로

이미지를 클릭해도 다른 이미지가 나와 여러번 클릭하거나

로그인할 때마다 로봇이 아니라는 것을 인증해야 해서

빡친 사람은 나뿐만이 아닐 것이다.

속사정은 모르지만

아마도 사용자를 방해한다는 피드백이 있어

reCAPTCHA v3가 나온 것이 아닐까 추측한다.

reCAPTCHA v3는 v2와 다르게 사용자를 방해하지 않는다.

사용자의 행동(action)을 보고 기계인지 사람인지 판단하는 방법이다.

reCAPTCHA v3는 0 ~ 1.0 까지의 점수를 서버에 보내주는데

0에 가까울수록 기계에 가깝다는 뜻이고

1에 가까울수록 사람에 가깝다고 알려준다.

간단하게 reCAPTCHA v3를 한번 구현해보자.

먼저, Google reCAPTCHA 사이트에 들어가 admin console 사이트를 등록한다.

https://www.google.com/recaptcha/intro/v3.html

 

v3 유형을 선택하고

도메인은 test용이니 localhost를 등록한다.

완료가 되면 사이트 키와 비밀 키를 받는데

설정에서 그 내용을 확인할 수 있다.

그 다음

Spring으로 간단한 maven 프로젝트를 생성한다.

recaptcha.jsp 파일은 다음과 같이 작성하였다.

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<html>

<head>
    <meta charset="UTF-8">
    <title>구글 리캡챠 테스트</title>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
    <script src="https://www.google.com/recaptcha/api.js?render=6Le-q6kUAAAAAFPDTU6lct7ZRRN7vK55hVF4Icp3"></script>
</head>

<body>
    <form action="/robot" method="get">
        <input type="text" name="name" />
        <input type="text" name="g-recaptcha-response" id="g-recaptcha-response" />
        <input type="submit" value="submit" />
    </form>

<script>
$(document).ready(function(){
    grecaptcha.ready(function() {
      grecaptcha.execute('reCAPTCHA_site_key', {action: 'login'}).then(function(token) {
         console.log(token)
         $.ajax({
            url: '${pageContext.servletContext.contextPath}/robot/token',
            type : 'POST',
            dataType: 'json',
            data : {'token': token},
            success : function(result){
                console.log(result);
            },
            fail: function(e){
                console.log("fail")
            }
          });// end ajax
      });
    });
});
</script>
</body>

</html>

Google DreCAPTCHA_site_key에 할당받은 사이트 키를 넣고

서버와 ajax 통신을 위해 jQuery를 이용했다.

일단 이 상태에서 토큰이 다음처럼 받아져야 한다.

이제 Controller에서 받아 Service 단에서 google reCAPTCHA와 통신을 한다.

통신 방법은 RestTemplate을 사용했으며

Post방식으로 토큰과 비밀키 값을 전송한다.

@Service
public class RecaptchaService {

    public RecaptchaDTO token(String token) {
        String url = "https://www.google.com/recaptcha/api/siteverify";

        RestTemplate restTemplate = new RestTemplate();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
        map.add("secret", "secret-key");
        map.add("response", token);

        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);

        RecaptchaDTO response = restTemplate.postForObject( url, request, RecaptchaDTO.class );

        return response;
    }

}

받은 자료를 콘솔에 뿌려주면 다음처럼 나오게 될 것이다.

여기서 score를 보면 0.9라는 것을 볼 수 있다.

이는 reCAPTCHA가 사람에 가깝다는 것을 판단한 것이며

이 score를 이용하여 서비스의 동작을 통제하면 될 것이다.

참고자료

https://developers-kr.googleblog.com/2019/01/introducing-recaptcha-v3-new-way-to.html

https://dany-it.tistory.com/302

https://developers.google.com/recaptcha/docs/v3?hl=ko

 

 

Made by 꿩

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

[방화벽] 인바운드 & 아웃바운드  (0) 2022.01.31
OAuth  (0) 2019.06.17
SSL인증서  (0) 2019.03.21
CSRF  (0) 2018.12.25
XSS 공격과 방어  (2) 2018.10.25

#OAuth

 

 

'당신의 비밀번호는 안녕하십니까?'

 

 

이메일, 비밀번호 유출은 매우 빈번하다.

어디 조금만 가입해도 이상한 스팸메일이 날라오며

잊을만 하면

유명한 사이트에서 고객정보 유출 사건이 한번씩 터진다.

 

유명한 사이트도 개인정보 유출과 관련해서 사건사고가 많은데

잘 알지도 못하는 사이트에 개인정보를 입력하고 싶은가???

 

몇몇 사람들은 비슷하거나 똑같은 비밀번호를 사용하고

이메일도 주로 하나 또는 두 개만을 사용한다.

그런데 보안이 제대로 지켜지는 지도 모르는 사이트에

덜컥 회원가입을 하고 로그인 한다면

당신의 이메일과 비밀번호는 안전하겠는가???

 

 

이런 문제를 방지할 수 있는 것이

바로 OAuth이다.

 

위키피디아에 따르면

OAuth는 인터넷 사용자들이 비밀번호를 제공하지 않고

다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나

애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로서 사용되는

접근 위임을 위한 개방형 표준이다.

 

내가 생각하는 OAuth란 쉽게 말해서

인증과 허가를 대신해주는 것이라 생각한다.

 

 

예를 들어,

쇼핑몰 홈페이지가 있다고 가정해보자.

이 쇼핑몰에서 옷을 구매하여 포인트를 적립하고 싶지만

로그인을 해야한다.

게다가 기억력이 안 좋아서

항상 동일한 비밀번호를 사용하기만 한다.

그렇다고 잘 알지도 모르는 사이트에

내 비밀번호를 입력하는 것도 망설여진다.

 

이때 소셜 로그인을 하면

굳이 잘 알지도 모르는 사이트에

비밀번호 입력을 하지 않아도 되고

로그인이 간편해진다.

 

OAuth를 이용한 인증방식에 대해 알아보자.

1. 고객이 카카오 로그인을 선택하면 쇼핑몰 서버는 카카오 로그인 페이지를 전송해준다.

2. 고객은 ID와 비밀번호를 입력해 본인을 인증한다.

3. 카카오 서버는 고객을 인증완료 페이지로 redirect 시킨다.

4. 카카오 서버는 redirect하면서 authorize_code 값을 포함시키고 쇼핑몰 서버는 이것을 수집한다.

5. 쇼핑몰 서버는 authorize_code로 카카오 서버에 access token을 요청한다.

6. 카카오 서버는 쇼핑몰 서버에 access token을 발급해준다.

7. 쇼핑몰 서버는 카카오 API 서버에 access token으로 사용자 정보를 불러온다.

 

정리하자면,

사용자는 카카오에서 로그인을 함으로써 본인을 인증하고

카카오는 인증을 확인하고 사용자 정보 접근을 허가하는 token 값을 발급한다.

token 값으로 쇼핑몰 서버는 사용자 정보를 카카오에서 갖고 오게 된다.

쉽게 말해 쇼핑몰과 사용자 사이에 카카오라는 중간자 역할을 둔 것이다.

 

 

참고자료

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

http://tech.devgear.co.kr/delphi_news/449506

https://d2.naver.com/helloworld/24942

 

 

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

 

 

Made by 꿩

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

[방화벽] 인바운드 & 아웃바운드  (0) 2022.01.31
[Spring] Google reCAPTCHA v3  (6) 2019.07.07
SSL인증서  (0) 2019.03.21
CSRF  (0) 2018.12.25
XSS 공격과 방어  (2) 2018.10.25

#Chain of Responsibility

 

 

1. 개념

 

Chain of Responsibility(책임 사슬)패턴

어떤 하나의 문제가 발생했을 경우

그 문제의 처리를 담당하는 여러개의 처리기를 두고

순서대로 처리해 나가는 패턴을 말한다.

 

자바에서 바로 try/catch/finally

책임 사슬 패턴을 적용한 예이다.

try{}블럭 안에서 예외가 발생했을 경우

catch{}블럭으로 이동하는데

어떤 예외인지에 따라 어떤 catch{}블럭이 실행되는지 결정되는 행위가

역할 사슬 패턴이라는 것이다.

 

 

2. Why? 왜 사용해야 할까?

 

프로젝트를 수행하다보면 무수히 많은 객체들을 생성하게 된다.

자신이 만든 모든 객체의 위치와 내용을 다시 기억해 내기란

실질적으로 힘든 경우가 있다.

이처럼

어떤 요청에 대해 처리해주는 객체의 위치를 파악하기 어려운 상황에 대비하여

이러한 요청을 처리해주는 객체들의 집합체나 계층화가 되어있으면

사용자는 굳이 객체의 위치를 알 필요없이

손쉽게 요청을 처리할 수 있다.

 

 

3. 장단점

 

책임 사슬 패턴을 사용하면 모든 후보 객체들을

다 알 필요없이 단순하게

자신과 연결된 단 하나의 후보 객체만 알면된다.

이처럼 객체들 간의 상호작용 과정을 단순화시키기에

객체 간의 결합도가 낮아지는 방법이 된다.

 

객체의 책임을 여러 객체에게 분산시키는 과정에서

상속을 이용하므로

객체의 기능을 추가, 삭제 및 수정하기 용이하다.

 

그러나 이 방식은 요청이 처리된다는 보장이 없다.

객체들 간의 연결고리가 잘 정의되어 있어야 하며

객체들 중 아무도 요청을 처리하지 못했을 경우

요청은 그냥 버려질 수 있다는 가능성이 있다.

이때 Exception을 던지는 방식 등으로 대처를 할 수 있다.

 

 

4. 클래스 다이어그램

 

5. 예제 코드

 

코드 예제는 java에서 Exception에서 아이디어가 떠올랐다.

실제 구동되는 동작은 다르지만 이해가 수월하길 바란다.

 

Exception 객체들은 모두 Problem 객체에 의해 관리되고 있으며

하위 클래스에서 자신이 처리할 수 있는 에러인지 확인하고

객체를 생성하는 코드를 구현해보았다.

public abstract class Problem {
	
	private static Problem[] list = {new SocketException(), new NullPointException(), new IOException()};
	protected static Integer num = 0;
	protected static String msg;
	
	public static Problem next(String error) {
		msg = error;
		
		if(num == list.length) {
			System.out.println("어떤 에러인지 확인 불가능");
			return null;
		}
		
		return list[num++].cause();
	}

	
	public abstract Problem cause();
}

 

하위 클래스 Exception객체들은 다음과 같이 구현되었다.

public class SocketException extends Problem{

	@Override
	public Problem cause() {
		if("socket".equals(msg)) {
			System.out.println("소켓 문제 발생! SocketException 객체 생성");
			num = 0;
			return this;
		}
		
		//다음 객체 ㄱㄱ
		return next(msg);
	}
}

public class NullPointException extends Problem{

	@Override
	public Problem cause() {
		
		if("null".equals(msg)) {
			System.out.println("객체에 Null 값이 들어감. NullPointException 객체 생성");
			num = 0;
			return this;
		}
		
		//다음 객체 ㄱㄱ
		return next(msg);
		
	}
}

public class IOException extends Problem{

	@Override
	public Problem cause() {
		
		if("IO".equals(msg)) {
			System.out.println("입력 값 오류 발생! IOException 객체 생성");
			num = 0;
			return this;
		}
		
		//다음 객체 ㄱㄱ
		return next(msg);
	}

}

 

클라이언트에서 에러가 발생해 Problem 객체를 호출하고

문제의 원인을 물어보는 코드를 구현했다.

public class Client {

	public static void main(String[] args) {
		
		System.out.println("에러 발생!");
		System.out.println("");
		
		
		//입력 오류로 에러가 발생한 경우
		System.out.println("입력 오류가 발생한 경우");
		Problem problem1 = Problem.next("IO");
		System.out.println("");
		
		//객체에 null값으로 에러가 발생한 경우
		System.out.println("null 값으로 에러가 난 경우");
		Problem problem2 = Problem.next("null");
			

	}

}

 

정리하자면 Client에서 오류가 발생하였고

Problem 객체를 이용하여 오류에 해당하는 객체를 생성하는 과정의 코드이다.

결과는 다음과 같이 나온다.

 

6. 참고

 

https://leetaehoon.tistory.com/64

https://ehclub.co.kr/2210

https://blog.naver.com/2feelus/220655715030

http://egloos.zum.com/iilii/v/3863886

GoF의 디자인 패턴

 

 

Made by 꿩

 

 

'스터디 > GoF의 디자인패턴' 카테고리의 다른 글

Strategy Pattern  (0) 2019.04.30
Template Method Pattern  (0) 2019.04.30
Decorator Pattern  (0) 2019.04.28
Factory Method Pattern  (0) 2019.04.23

#Strategy Pattern

 

 

1. 개념

 

전략 패턴(Strategy Pattern)이란 알고리즘 대체를 위해

동일한 목적을 지닌 알고리즘군을 인터페이스로 묶고

캡슐화하여 서로 대체가 가능하게 사용하는 것을 말한다.

 

예를 들어

종로에서 충무로를 가는 방법을 생각해보자

시간이 들더라도 걸어갈 수 있으며

택시를 타도 되고

버스나 지하철을 탈 수도 있다.

각각의 시간과 비용은 모두 다르지만

한 곳을 간다는 목적은 동일하다.

 

이처럼 비슷한 목적을 지닌 알고리즘을 묶어서

서로 상호교환이 가능하도록 만드는 패턴을

전략 패턴이라 한다.

 

 

2. Why? 왜 사용해야 할까?

 

구현된 알고리즘은 다르지만 동일한 목적을 지닌 클래스들이 존재할 때

전략 패턴을 사용하는 것이 좋다.

한 가지 알고리즘을 평소에 사용하더라도

참조하는 클래스의 변경이나 제거 등 여러가지 상황이 발생하거나

사용하는 시점에 따라서 알고리즘을 변경해야 하는 상황이 있을 수 있다.

이런 경우 언제든지 알고리즘을 쉽게 대체할 필요성이 있으며

전략 패턴을 사용하게 된다면

새로운 알고리즘을 추가하는 확장이 용이하기 때문이다.

 

 

3. 장단점

 

전략 패턴은 알고리즘의 변경 부분만을 따로 빼내어 구현한 것이므로

알고리즘마다 사용되는 코드 중복을 방지할 수 있으며

알고리즘을 쉽게 대체할 수 있고

확장성이 용이하여 다양한 알고리즘을 쉽게 추가할 수도 있다.

클라이언트와 독립적이기 때문에 알고리즘 변경에 대해서도 강하다.

 

그러나

알고리즘이 늘어날수록 객체도 무한정 늘어나며

클라이언트가 사용할 객체를 직접 결정해야 하기 때문에

많은 알고리즘에 대한 성능과 효율을 알고 있어야 하고

서로간의 차이를 알아야 하는데

직접 만든 것이 아니라면 부담스러울 수 있다.

 

 

4. 추가내용

 

앞서 템플릿 메소드 패턴에서 언급했듯이

보통 전략 패턴은 템플릿 메소드 패턴과 비교가 된다.

전략 패턴은 템플릿 메소드 패턴과 구성은 동일하지만 사용목적이 다르다고 볼 수 있다.

템플릿 메소드 패턴 공통된 메소드를 통해서 코드의 중복없이 사용하는 것이고

전략 패턴 상황에 맞는 필요한 전략을 선택하기 위해 사용하는 패턴이다.

 

그리고

객체의 행위를 유연하게 확장하고 구조가 데코레이터 패턴과 유사하지만

전략 패턴코드 내부의 알고리즘을 변화시키고

데코레이터 패턴코드 외부의 리턴 값을 변화시킨다는 점에서 차이가 있다.

 

 

5. 클래스 다이어그램

 

 

6. 예제 코드

 

포켓몬을 잡는 코드를 보며 전략 패턴에 대해서 알아보자

당신은 포켓몬 게임을 시작하며 스타팅 포켓몬으로 치코리타를 받았다.

당신에겐 절실히 다른 포켓몬이 필요하여 잠만보를 잡으려 한다.

당신에겐 몬스터볼, 하이퍼볼, 마스터볼이 있다.

세 개의 몬스터볼을 전략 1,2,3으로 구현하였고 몬스터볼 인터페이스로 묶어봤다.

public interface MonsterBall {
	
	public int throwBall();

}

public class Strategy1 implements MonsterBall{

	@Override
	public int throwBall() {
		System.out.println("몬스터 볼을 던진다.(확률:20%, 가격: 천원)");
		return 1;
	}
}

public class Strategy2 implements MonsterBall{

	@Override
	public int throwBall() {
		System.out.println("하이퍼볼을 던진다.(확률:50%, 가격: 삼천원)");
		return 4;
	}
}

public class Strategy3 implements MonsterBall{

	@Override
	public int throwBall() {
		System.out.println("마스터볼을 던진다.(확률:100%, 가격: 백만원)");
		return 9;
	}
}

 

Player1 캐릭터는 포켓몬을 잡기 위해 몬스터볼을 던질 수 있게 만들었고

전략을 파라미터로 받는다.

public class Player1 {
	
	public int getPokemon(MonsterBall monsterBall) {
		
		return monsterBall.throwBall();
		
	}
}

 

당신은 나중을 위해 하이퍼볼과 마스터볼을 아껴놓기로 하고

일반 몬스터볼(전략1)을 던져보기로 결정했다.

import java.util.Random;

public class PokemonGame {

	public static void main(String[] args) {
		
		Player1 player1 = new Player1();
		
		System.out.println("야생의 잠만보가 출현했습니다.");
		Random random = new Random();
		
		int ran = random.nextInt(10);
		int prob = player1.getPokemon(new Strategy1());
		
		if(ran <= prob) {
			System.out.println("잠만보를 잡았습니다!");
		} else {
			System.out.println("아쉽게 놓쳤다, 잠만보가 도망쳤다.");
		}

	}
}

 

결과는 다음과 같다.

 

 

7. 참고

 

https://rearrangingall.blogspot.com/2017/01/01-strategy-pattern.html

https://niceman.tistory.com/133

https://kimsunzun.tistory.com/entry/Strategy%EC%A0%84%EB%9E%B5-%ED%8C%A8%ED%84%B4

GoF의 디자인 패턴

 

 

Made by 꿩

'스터디 > GoF의 디자인패턴' 카테고리의 다른 글

Chain of Responsibility  (0) 2019.05.06
Template Method Pattern  (0) 2019.04.30
Decorator Pattern  (0) 2019.04.28
Factory Method Pattern  (0) 2019.04.23

+ Recent posts