6월 부터인가? 갑자기 카카오톡에 특정 사이트 URL을 전송하면 보여주던 이미지와 제목에서 이미지는 정상인데 제목이 문제가 되었다. 제목이 URL로만 보인다. 잘되는 것이 안되니 호기심이 생기네... 카카오톡은 어떤 것을 참조해서 제목을 가져오는 걸까?

일시적인 거지만 제목 대신 URL이 나오다가 다시 한글로 잘 나오더라.

카카오톡의 테스트 URL? 개발자 센터

일단 카카오톡 메시지로 전송이 되면 어떻게 되는지 미리 알수 있는 방법은 카카오톡 개발자 센터에 있다. 생뚱맞기는 하지만 카카오 스토리 > RESTAPI > 웹 페이지 스크롤링에서 테스트를 제공한다. [페이지 링크]

테스트 페이지

테스트는 간단하지만 개발자 센터에서 API 테스트기 때문에 액세스 토큰을 발급받아야 한다. 카카오톡 아이디만 있으면 되는 걸로 알고 있으니, 귀찮겠지만 테스트를 위해서 개발자센터에 등록 후 토큰을 발급 받으시면 된다.

테스트 결과. 정상으로 모두 나온다.

이제는 잘 나는 거 같다. 처음에 확인할때만 해도 title에 url이 나오고 있었는데... description은 공백이었고... 일찍 캡쳐해 놓을 껄...

여튼 저렇게 수집하는 기준은 어떤걸까? 바로 og (OpenGraph) 메타태그 이다.

카카오 개발자센터에 있는 웹 페이지 스크롤 관련 설명

이 페이지는 카카오톡 URL 전송이 정상적으로 안되는 경우 테스트하는 페이지라 og 관련 상세 설명은 생략한다. 페이스 북에서 시작을 했고 지금은 SEO(Search Engine Optimization, 검색엔진최적화)로 쓰이기 때문에 웹사이트에서는 매우 중요하다.

페이스 북이라고 했으니, 페이스북도 테스트URL이 있겠지? 당연히???? 있다. [페이지북 OG 테스트 페이지] 물론 여기도 개발자 센터이기 때문에 계정인증은 받아야 할 것이다.

해당 웹페이지에서 URL이 나온 이유와 해결 방안

카카오톡 수집기가 EUC-KR 문자셋을 지원하지 않거나 기본 UTF-8 세팅으로 변경이 된 것으로 보인다. 해당 사이트는 기본 EUC-KR 문자셋의 웹사이트 였는데, UTF-8로 바뀌었고, 웹 스크랩에서도 정상 동작을 하고 있으니, charset 이슈로 보인다.

아주 빠른 변경은 칭찬해~~

참조 URL

카카오톡 개발자 센터 > 웹 스크랩 테스트 : https://developers.kakao.com/tool/rest-api/open/v1/api/story/linkinfo/get

페이스북 개발자 센터 > 공유 디버거 : https://developers.facebook.com/tools/debug/?q=https%3A%2F%2Fbetanews.net%2Farticle%2F1184743


WRITTEN BY
비트센스
뷰파인더로 보는 프로그래머의 세상 페이스북 @bitsense 트위터 @picory 스카이프 picory MSN drawhalf@dreamwiz.com

트랙백  0 , 댓글  0개가 달렸습니다.
secret

개발 중 자주 쿼리를 확인하는 일이 있다. 그런데 ->toSql()로 하게 되면 바인딩 전 쿼리만 나와서 해당 값이 정상 들어갔는지 확인이 어려울 수 있다.

이번에는 mysql 4.x old 버전에 쿼리 질의를 할 일이 생겼는데, php 5.x 버전 부터 mysql 4.x 버전을 지원하지 않고, 어느 언어를 사용하더라도 4.x 버전을 미지원이라는 장벽을 맞이하게 되었다. 결국 원격으로 php 5.x 저 버전에 raw 쿼리를 던져서 질의 하도록 미들웨어 개념의 api를 만들었다. 기본 어드민 툴은 laravel에서 사용을 해야 하니 raw query를 생성해서 던지는 작업을 해야하는 경우가 생긴 것이다.

머 이유가 어찌 됐건 일단 바인딩된 최종 raw query 획득을 위한 작업을 진행하기 위해서 설정 작업이 필요하다. Laravel에서 eloquent orm 이나 query builder로 쿼리를 실행하게 되면 QueryExecuted 이벤트가 발생을 한다. 해당 이벤트 발생시 실행된 쿼리를 수집하기 위해서는 AppServiceProvider.php에 추가를 한다.

Event 추가

// app/Provides/AppServiceProvider.php

use App\Http\Models\Query; // 추가한 Query class

    public function register()
    {
        //
        \Event::listen('Illuminate\Database\Events\QueryExecuted', function ($query) {
            Query::set($query);
        });
    }

 

Query Class 추가

class Query
{
    static $query;

    //
    static function get()
    {
        return self::debug_query();
    }

    static function set($query)
    {
        self::$query = $query;
    }
    
     /**
     * query build 내용을 raw query로 변경
     * @param $query
     * @return mixed|string
     */
    static function debug_query() {
        $queryRaw = self::$query;

        $query = vsprintf(str_replace('?', '%s', $queryRaw->sql), collect($queryRaw->bindings)->map(function ($binding) {
            return is_numeric($binding) ? $binding : "'{$binding}'";
        })->toArray());

        $double_linebreak_words = ['(', ')'];
        $double_linebreak_words_replace = array_map(function($str){ return PHP_EOL . $str . PHP_EOL; }, $double_linebreak_words);
        $query = str_replace($double_linebreak_words, $double_linebreak_words_replace, $query);


        $mysql_keywords = ['ADD', 'ALL', 'ALTER', 'ANALYZE', 'AND', 'AS', 'ASC', 'AUTO_INCREMENT', 'BDB', 'BERKELEYDB', 'BETWEEN', 'BIGINT', 'BINARY', 'BLOB', 'BOTH', 'BTREE', 'BY', 'CASCADE', 'CASE', 'CHANGE', 'CHAR', 'CHARACTER', 'CHECK', 'COLLATE', 'COLUMN', 'COLUMNS', 'CONSTRAINT', 'CREATE', 'CROSS', 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'DATABASE', 'DATABASES', 'DAY_HOUR', 'DAY_MINUTE', 'DAY_SECOND', 'DEC', 'DECIMAL', 'DEFAULT', 'DELAYED', 'DELETE', 'DESC', 'DESCRIBE', 'DISTINCT', 'DISTINCTROW', 'DIV', 'DOUBLE', 'DROP', 'ELSE', 'ENCLOSED', 'ERRORS', 'ESCAPED', 'EXISTS', 'EXPLAIN', 'FALSE', 'FIELDS', 'FLOAT', 'FOR', 'FORCE', 'FOREIGN', 'FROM', 'FULLTEXT', 'FUNCTION', 'GEOMETRY', 'GRANT', 'GROUP', 'HASH', 'HAVING', 'HELP', 'HIGH_PRIORITY', 'HOUR_MINUTE', 'HOUR_SECOND', 'IF', 'IGNORE', 'INDEX', 'INFILE', 'INNER', 'INNODB', 'INSERT', 'INTEGER', 'INTERVAL', 'INTO', 'JOIN', 'KEY', 'KEYS', 'KILL', 'LEADING', 'LEFT', 'LIKE', 'LIMIT', 'LINES', 'LOAD', 'LOCALTIME', 'LOCALTIMESTAMP', 'LOCK', 'LONG', 'LONGBLOB', 'LONGTEXT', 'LOW_PRIORITY', 'MASTER_SERVER_ID', 'MATCH', 'MEDIUMBLOB', 'MEDIUMINT', 'MEDIUMTEXT', 'MIDDLEINT', 'MINUTE_SECOND', 'MOD', 'MRG_MYISAM', 'NATURAL', 'NOT', 'NULL', 'NUMERIC', 'ON', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', 'ORDER', 'OUTER', 'OUTFILE', 'PRECISION', 'PRIMARY', 'PRIVILEGES', 'PROCEDURE', 'PURGE', 'READ', 'REAL', 'REFERENCES', 'REGEXP', 'RENAME', 'REPLACE', 'REQUIRE', 'RESTRICT', 'RETURNS', 'REVOKE', 'RIGHT', 'RLIKE', 'RTREE', 'SELECT', 'SET', 'SHOW', 'SMALLINT', 'SOME', 'SONAME', 'SPATIAL', 'SQL_BIG_RESULT', 'SQL_CALC_FOUND_ROWS', 'SQL_SMALL_RESULT', 'SSL', 'STARTING', 'STRAIGHT_JOIN', 'STRIPED', 'TABLE', 'TABLES', 'TERMINATED', 'THEN', 'TINYBLOB', 'TINYINT', 'TINYTEXT', 'TO', 'TRAILING', 'TRUE', 'TYPES', 'UNION', 'UNIQUE', 'UNLOCK', 'UNSIGNED', 'UPDATE', 'USAGE', 'USE', 'USER_RESOURCES', 'USING', 'VALUES', 'VARBINARY', 'VARCHAR', 'VARCHARACTER', 'VARYING', 'WARNINGS', 'WHEN', 'WHERE', 'WITH', 'WRITE', 'XOR', 'YEAR_MONTH', 'ZEROFILL', 'INT', 'OR', 'IS', 'IN'];
        $mysql_keywords = array_map(function($str){ return " $str "; }, $mysql_keywords);
        $mysql_keywords_lc = array_map(function($str){ return strtolower($str); }, $mysql_keywords);
        $query = str_replace($mysql_keywords_lc, $mysql_keywords, $query);


        $linebreak_before_words = ['INNER JOIN', 'LEFT JOIN', 'OUTER JOIN', 'RIGHT JOIN', 'WHERE', 'FROM', 'GROUP BY', 'SELECT'];
        $linebreak_before_words_replace = array_map(function($str){ return PHP_EOL . $str; }, $linebreak_before_words);
        $query = str_replace($linebreak_before_words, $linebreak_before_words_replace, $query);


        $linebreak_after_words = [','];
        $linebreak_after_words_replace = array_map(function($str){ return $str . PHP_EOL; }, $linebreak_after_words);
        $query = str_replace($linebreak_after_words, $linebreak_after_words_replace, $query);

        $query = str_replace('select ', 'SELECT ', $query);

        return $query;
    }
 }

사용 방법

namespace App\Http\Models;

use User;
use Illuminate\Database\Eloquent\Model;

class test extends Model
{
    public index()
    {
        $user = new User;
        
        $user->first();
        
        $query = Query::get();
        
        echo $query;
    }
}

결과

SELECT * FROM `users` LIMIT 1

 

 

 


WRITTEN BY
비트센스
뷰파인더로 보는 프로그래머의 세상 페이스북 @bitsense 트위터 @picory 스카이프 picory MSN drawhalf@dreamwiz.com

트랙백  0 , 댓글  0개가 달렸습니다.
secret

n일 이전 생성 파일 보기 및 삭제

# n일 이전 생성 파일 보기
find 폴더/ -mtime +n
find 폴더/ -mtime +n -print

# n일 이전 생성 파일 삭제
find 폴더/ -mtime +n -delete
find 폴더/ -mtime +n -exec rm {} \;

WRITTEN BY
비트센스
뷰파인더로 보는 프로그래머의 세상 페이스북 @bitsense 트위터 @picory 스카이프 picory MSN drawhalf@dreamwiz.com

트랙백  0 , 댓글  0개가 달렸습니다.
secret

요 근래 말이 많은 텔레그램입니다. 원격지 컴퓨터에 명령 실행할 방법을 찾다가, 메신저를 통해서 실행해 보자는 아이디어 차원에서 한번 챗봇을 보게 되었는데, 파이썬 + 텔레그램 봇 구성이 생각보다 쉬워 공유를 해봅니다.

telepot 모듈 설치

pip install telepot --upgrade

소스 샘플

import telepot

from telepot.loop import MessageLoop
import time

TOKEN_MAIN = 'BOT_TOKEN'
StartMsg = """
BOT 기본 명령어
1. /help : 도움말
2. 안녕
"""

# 특정 명령어가 입력할 때 반응
def execcommand(message, chat_id):
    args = message.split(' ')
    command = args[0]
    del args[0]

    if command == '/help':
        send(chat_id, StartMsg)

# 메시지를 그대로 전송
def echoserver(message, chat_id, target):
    args = message.split(' ')
    command = args[0]

    if command == '안녕':
        send(chat_id, '안녕하세요~ %s 님!' % target['username'])

# 메시지 텔레그램으로 전송
def send(chat_id, message):
    bot.sendMessage(chat_id, message)

def handler(msg):
    content_type, chat_type, chat_id, msg_date, msg_id = telepot.glance(msg, long=True)

    print(msg)
    if content_type == 'text':
        _message = msg['text']
        if _message[0:1] == '/': # 명령어
            execcommand(_message, chat_id)
        else:
            echoserver(_message, chat_id, msg['from'])

bot = telepot.Bot(TOKEN_MAIN)
bot.message_loop(handler, run_forever=True)

버그 리포트

#1. ssl 접속 오류

urllib3 버전 이슈로 보입니다. 1.25 이상 버전에서 자체 서명된 인증서(self signed cert) 인 경우, SSL 인증서를 무시하는 부분을 거절하네요. 그래서 urllib3 버전을 강제로 다운그레이드 합니다.

# urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='api.telegram.org', port=443): 
pip install urllib3==1.24.3

참조 URL

https://telepot.readthedocs.io/en/latest/

 


WRITTEN BY
비트센스
뷰파인더로 보는 프로그래머의 세상 페이스북 @bitsense 트위터 @picory 스카이프 picory MSN drawhalf@dreamwiz.com

트랙백  0 , 댓글  0개가 달렸습니다.
secret

맥 팩키지 통합 관리 및 버전 변경을 쉽게 하기 위해서 홈브루(homebrew)를 사용합니다.

// 파이썬 설치
brew install python

// 버전 확인. 2020-05-15 현재 최신버전 3.8.22
python3
Python 3.8.2 (v3.8.2:7b3ab5921f, Feb 24 2020, 17:52:18) 
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

// python3 > python 명령으로 대체 방법
vi ~/.zprofile (macOS 카탈리나)

// 추가 내용
alias python='python3'

// 소스 적용
source ~/.zprofile

// python 실행
python

WRITTEN BY
비트센스
뷰파인더로 보는 프로그래머의 세상 페이스북 @bitsense 트위터 @picory 스카이프 picory MSN drawhalf@dreamwiz.com

트랙백  0 , 댓글  0개가 달렸습니다.
secret

2019년 하반기 부터 아이패드 프로 4세대 출시를 기다리는 사람들이 내 주위에 점점 늘어났습니다. 저도 딸아이가 필요하다는 말에 3세대를 구매하려고 했지만 곧 나올 4세대 말에.... 이왕이면... 신품을 사자는 생각으로 기다리고 있었습니다. 2020년 3월 출시설이 모락모락 올라왔지만, 1월 이후 강타한 "코로나19"는 기존 애플 제품군 생산차질로 인해 배송 지연이 발생하기 시작하면서, 하반기로 연길될 거라는 말이 3월 초까지만 해도 지배적이었습니다.

하지만 애플은 지난 3월 18일 아주 조용하게 출시를 했고, 4월 중순에는 한국 공홈 주문도 열렸습니다. 와~ 했더니, 내 손에 이렇게 아이패드가 와 있네요.

어쩌다 보니 예약판매는 아니지만 내손에 이녀석이 쥐여져 있었다.
역시나 심플하다. USB-C 가 인상적인네...
재미삼아 맥북프로 16인치로 연결을 했더니 충전표시가 뜨네요. 맥북프로 충전기 보다는 약하지만, 그래도 강하네요.
후면부가 좀더 각진 모양입니다. 두께는 전작과 비슷하네요.
맥북프로와 연결해서 사이드카를 실행합니다. 예전부터 해보고 싶었다는... 끊김이 없이 먼가 안정적인 느낌입니다. ^^
메신저 채팅을 위한 조그만 모니터가 하나 생겼네요.

현재 아이패드 프로4로 해본 것과 경험

1. 사이드카

기존 유선, 혹은 무선 모니터 공유기 앱보다 속도 뿐만 아니라 안정성도 뛰어 납니다. 사이드카를 실행 중에도 다른 앱을 실행할 수 있고, 그렇게 화면이 다른 앱으로 넘어가더라도, 화면 공유가 끊기질 않고 유지되고, 다시 돌아올 수 있습니다. 또한 연결이 끊긴 후 다시 연결이 되면 기존의 아이패드 위에서 실행 중이던 앱은 다시 아이패드 화면에서 노출이 됩니다.

무척 안정적인 느낌의 편안함이 느껴 집니다.

2. D-Diary, Notablilty

D-Diary는 그냥 평범한 다이어리? 앱이고 노타빌리티는 아주 유명한 필기 앱입니다. 필기 인식을 위해서 사용해 본 앱인데, D-Diary는 그냥 저냥 쓸만합니다. 노타빌리티는 들어온 명성에 비해 사용성이 복잡하고 기능이 너무 많습니다. 좀더 시간을 두고 익혀야할 것들이 있어 보입니다.

그런 의미에서 복잡해 보이고, 그래서 어려워 보입니다.

3. SchetchBook

제 아이패드 주 용도는 낙서 입니다. 글씨 낙서도 있지만 그림 낙서도 한번 어렸을적 마음을 담아서 끄적거려보려고 합니다. 지금은 인터넷 강의를 들으면서 낙서 중인데, 좀더 능력이 생기면 다른 앱으로 넘어갈 수도 있겠지만, 현재 제 수준에는 좋은 앱입니다. 일단 레이어가 지원되고, 다양한 펜들이 제공됩니다.

역시나 허들이 있습니다. 그래도 하고 싶은 거라 재미 있어 보입니다.

다른 앱들은 그리 중요하지 않아서 일단 이정도만 정리를 해봅니다. 시간을 두고 허들을 넘어야 할 것들이 있으니, 시간 대비 활용도가 높아지지 않을까 싶습니다.

총평

12.9인치는 상당히 큽니다. 이걸 들고 이동하면서 먼가 하겠다는 것은 좀 큰 용기가 필요하지 않을까 싶습니다. 그래도 서브 모니터로, 낙서장으로는 괜찮습니다. 어지간하면 11인치를 구매하는 것을 추천 드립니다.

이제는 나이가 먹어서 그런지 기능이 많으면 복잡해 보이고, 어려워 보입니다. ㅠ,.ㅠ;;

필기 입력을 하는 앱들은, 당연한 것이지만 펜 종류, 굻기, 색깔, 지우개 등등의 선택할 사항이 있습니다. 평평한 면의 더블 터치로 지우개와 펜 이동이 가능한 점이 장점이면서 단점입니다. 이제까지 몰랐던 제 습관 중에 펜을 돌리는 게 있나 봅니다. 애플 펜슬이 너무 민감해서 살짝 돌아가면서 더블 터치로 인식해서 펜이 갑자기 지우개가 되는 경우가 있습니다. 이제 좀 익숙해 졌지만, 기능의 장점이자 센서의 단점이네요.

공대생들에게 아이패드는 또하나의 노트북이 된 거 같습니다. 선배들이 아이패드는 거의 필수템으로 추천을 한다고 하네요.

딸래미 덕분에 저도 좋은 장난감 하나 마련을 해서 좋네요. 모두 하나씩 사세요. 맥북 있는 분은 꼭 사세요~~ ^^


WRITTEN BY
비트센스
뷰파인더로 보는 프로그래머의 세상 페이스북 @bitsense 트위터 @picory 스카이프 picory MSN drawhalf@dreamwiz.com

트랙백  0 , 댓글  0개가 달렸습니다.
secret

머신러닝 같은 강좌나 책을 읽다 보면 간혹 마주치는 단어가 시계열 혹은 시계열화 이란 것입니다. 말은 어려워 보이는데 영어로는 "time series" 라고 합니다. 한글은 어렵지만 영어는 어느 정도 뜻이 이해가 갑니다. 그냥 순차적으로 먼가 하는 거구나... 라는 센쑤~!

개발자들이 디비 등에서 추출한 정보는 보통 테이블 형식의 텍스트로 제공하는 경우가 많습니다. 이것을 보기 좋게 그래프 형태로 변형해서 보여주면, 직관적으로 이해하게 되고, 실시간 의사결정이 가능해 진다고 합니다. 예전부터 알고는 있었지만, 막상 그래프 표현은 좀 어렵기는 합니다.

vuejs에서는 되게 쉽습니다. 시계열의 대표적인 것이 Line Chart 일 것 같아서, 소스로 좀더 쉽게 만들어 보도록 하겠습니다. Line Charts 는 아래와 같은 형태 입니다.

설치

// 설치
npm i --save vue-chartjs chart.js

LineChart 템플릿 소스 샘플

// 공용 사용 가능성이 있어서 components/Charts 에 컴포넌트 형태로 저장하여 사용
// data = chartData 외부에서 가져옴
// chartData = {labels: ['전체 범주'], data: { label: '그래프 범주', data: []}
<script>
    import {Line} from 'vue-chartjs'

    export default {
        name: 'LineChart',
        extends: Line,
        props: ['chartData'],
        data: () => ({
                colorSets: [ // 여러 그래프 사용을 위해서 색상표 예약
                    {fore: '#EF9A9A', back: '#B71C1C'},
                    {fore: '#F48FB1', back: '#880E4F'},
                    {fore: '#CE93D8', back: '#4A148C'},
                    {fore: '#B39DDB', back: '#311B92'},
                    {fore: '#9FA8DA', back: '#1A237E'},
                    {fore: '#64B5F6', back: '#0D47A1'},
                    {fore: '#4FC3F7', back: '#01579B'},
                    {fore: '#0097A7', back: '#006064'},
                    {fore: '#00897B', back: '#004D40'},
                    {fore: '#81C784', back: '#1B5E20'},
                ],
                datacollection: { // 데이터 샘플
                    // 전체 범주
                    labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
                    datasets: [
                        {
                        	// 그래프별 범주
                            label: 'Data One',
                            backgroundColor: '#f87979',
                            pointBackgroundColor: 'white',
                            borderWidth: 1,
                            pointBorderColor: '#249EBF',
                            // 실제 데이터. labels와 배열 순서가 맞아야 함. 빈곳은 0으로 보정이 필요
                            data: [40, 20, 30, 50, 90, 10, 20, 40, 50, 70, 90, 100]
                        }
                    ]
                },
                options: {
                    scales: {
                        yAxes: [{
                            ticks: {
                                beginAtZero: true
                            },
                            gridLines: {
                                display: true
                            }
                        }],
                        xAxes: [{
                            gridLines: {
                                display: false
                            }
                        }]
                    },
                    legend: {
                        display: true
                    },
                    responsive: true,
                    maintainAspectRatio: false
                }
            }
        ),
        mounted() {
            this.init()
        },
        methods: {
            init() {
                let data = this.chartData.chartData

                let datasets = []
                let pos = 0
                data.forEach((site) => {
                    let colors = this.colorSets[pos]

                    datasets.push({
                        label: site.label,
                        borderWidth: 2,
                        borderColor: colors.back,
                        backgroundColor: colors.back,
                        pointBorderColor: colors.fore,
                        pointBackgroundColor: colors.fore,
                        fill: false,
                        data: site.data
                    })

                    pos++
                })

                this.datacollection = {
                    labels: this.chartData.labels,
                    datasets: datasets
                }

                this.render()
            },
            render() {
                this.renderChart(this.datacollection, this.options)
            }

        }
    }
</script>

<style scoped>

</style>

vuejs 샘플 소스

<template>
    <v-container fluid>
        <v-row>
          <v-col>
            <div class="text-lg-center pa-5" style="width: 100%;" v-if="chartLoading">
              <v-progress-circular
                  width="7"
                  size="70"
                  indeterminate
                  color="red"
              ></v-progress-circular>
            </div>
            <line-chart :chartData="chartData" v-if="!chartLoading"/>
          </v-col>
        </v-row>
    </v-container>
</template>

<script>
    // '@/components/Charts/LineChart' 사용 가능하면 대체를 해도 된다.
    import LineChart from '../Charts/LineChart'

    export default {
        name: 'List',
        components: { LineChart },
        data: () => ({
            chartLoading: false, // 데이터를 불러오기 전까지는 progress circle을 사용
            chartData: []
        }),
        mounted() {
            this.init()
        },
        methods: {
            init() {
                let item = '{"labels":["01","02","03","04","05","06","07","08","09","10","11"],"chartData":[{"label":"다음","data":["65","13","22","125","41","142","156","121","24","29","151"]},{"label":"다우존스","data":["1","1","0","6","1","3","6","8","0","0","6"]},{"label":"네이버","data":["65","13","22","119","41","139","150","119","20","28","147"]},{"label":"뉴스원","data":["61","7","17","105","28","128","138","108","10","20","137"]},{"label":"다나와","data":["0","0","0","1","0","0","1","0","0","0","0"]}]}'
            	let data = JSON.parse(item)
                
                this.chartData = {
                    labels: data.labels,
                    chartData: data.chartData
                }

                // 차트 보이기
                this.chartLoading = false
            }
    }
</script>

<style scoped>
 
</style>

 

소스 샘플 결과


WRITTEN BY
비트센스
뷰파인더로 보는 프로그래머의 세상 페이스북 @bitsense 트위터 @picory 스카이프 picory MSN drawhalf@dreamwiz.com

트랙백  0 , 댓글  0개가 달렸습니다.
secret

관련 세미나 동영상: https://www.youtube.com/watch?v=BlEzbGTQ9Zs

우아한테크세미나 동영상 자료

2020년 5월 7일 개최한 "우아한테크세미나" 발표 내용은 아래와 같습니다.

발표자료

1부 - 엔티티 클래스 설계와 퍼시스턴스 프레임워크의 활용
* 발표자료 (원페이지뷰) :
https://bit.ly/2YNxlV7
* 발표자료 (슬라이드) :
https://benelog.github.io/entity-dev/

2부 - Spring Data JDBC Advanced
* 발표자료 :
https://bit.ly/3fCkRpg
* 참고코드 :
https://bit.ly/2SFjwE8www.bit.ly/2YNxlV7

참 멋지네요.

 


WRITTEN BY
비트센스
뷰파인더로 보는 프로그래머의 세상 페이스북 @bitsense 트위터 @picory 스카이프 picory MSN drawhalf@dreamwiz.com

트랙백  0 , 댓글  0개가 달렸습니다.
secret