간단하게 템플릿 에 대해 살펴보려고한다



<p>The sum of 1 + 1 is {{1 + 1}}</p>



HTML <P> 태그안에 1+1 값을 실행하면


결과는 2 를 도출할것이다



<p>The sum of 1 + 1 is not {{1 + 1 + getVal()}}</p>



함수 안의 값을 살펴보자


{{ 1 + 1 + getval() }}


무슨값이 나올까?? 


실행을 해보면 결과값으로 4가 나온다  getval() 값은 앞서 1+1 의 결과값인 2를 가져온다 


확인을 해보면 



TwoWayBinding


도대체 앵귤러가 양방향 바인딩바인딩하길레 궁금해서 도큐먼트를 찾아보고 공부한걸 적어보려한다


AppComponent.html

1
2
3
4
5
6
 
<div id="two-way-2">
  <h3>De-sugared two-way binding</h3>
  <my-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></my-sizer>
</div>
 
cs

Sizer-Component.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
  selector: 'my-sizer',
  template: `
  <div>
    <button (click)="dec()" title="smaller">-</button>
    <button (click)="inc()" title="bigger">+</button>
    <label [style.font-size.px]="size">FontSize: {{size}}px</label>
  </div>`
})
export class SizerComponent {
  @Input()  size: number | string;
  @Output() sizeChange = new EventEmitter<number>();
  dec() { this.resize(-1); }
  inc() { this.resize(+1); }
  resize(delta: number) {
    this.size = Math.min(40Math.max(8+this.size + delta));
    this.sizeChange.emit(this.size);
  }
}
cs


my-sizer  에 폰트 사이즈값을 입력받아준다 기본값 : 14px


14라는 값을 sizer-componenet 에서 받은후 fontsize 값을 변경해주는것이다


예로, bigger 버튼을 클릭하게되면 this.resize(+1) 함수가 실행되고


resize 함수에서 사이즈값을 맞춰주고


this.sizeChange.emit(this.size)  을 실행해준다


$event 라는 변수는 Sizer-Component.sizechange 을 포함한다 왜냐? 


변수 선언쪽을 확인해보자


  @Input()  size: number | string;                                             //입력받은값  ex) 12,14,16

   

  @Output() sizeChange = new EventEmitter<number>();     //size change 를 해주는 이벤트생성 


       <number>는 (this.size) 값 이다


앵귤러는 $event 값을 AppComponent.fontsizePx 에 값을 할당해준다


실행결과를 살펴보자 



첫번째 예제)  


AppComponent.html

1
(sizeChange)="$event"
cs



두번째 예제)


AppComponent.html

1
(sizeChange)="fontSizePx=$event"
cs








WRITTEN BY
내가달이다

,


1
2
3
4
5
6
7
8
9
10
11
12
13
@Component({
  selector: 'click-me',
  template: `
    <button (click)="onClickMe()">Click me!</button>
    {{clickMessage}}`
})
export class ClickMeComponent {
  clickMessage = '';
 
  onClickMe() {
    this.clickMessage = '클릭 이벤트 입니다';
  }
}
cs


단순 클릭 이벤트이다


돌아가는 사이클은 클릭 버튼을 누르면 {{clickMessage}} 를 보여준다 


결과

 




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Component({
  selector: 'key-up1',
  template: `
    <input (keyup)="onKey($event)">
    <p>{{values}}</p>
  `
})
export class KeyUpComponent_v1 {
  values = '';
 
 
  onKey(event:any) {
    this.values += event.target.value + ' | ';
  }
  
}
cs


유저입력값을 가져옵니다


돌아가는 사이클은 유저의 키입력을 $event 를 이용해 가져온후 event.target.value 를 통해 값을 가져온다


결과

 





1
2
3
4
5
6
7
8
9
10
import { Component } from '@angular/core';
@Component({
  selector: 'loop-back',
  template: `
    <input #box (keyup)="0">
    <p>{{box.value}}</p>
  `
})
export class LoopbackComponent { }
 
cs


위의 keyup 과의 차이점은 #box 라는 식별자를 주고 <p> 태그 안의 값을 #box 의 value 값을 보여준다

단, 빈값의 경우에는 값이 보여지지 않는데 이경우는 value 값을 가져와 | 넣어주면 동작한다


 결과

 





1
2
3
4
5
6
7
8
9
10
11
12
@Component({
  selector: 'key-up3',
  template: `
    <input #box (keyup.enter)="onEnter(box.value)">
    <p>{{value}}</p>
  `
})
export class KeyUpComponent_v3 {
  value = '';
  onEnter(value: string) { this.value = value; }
}
 
cs



값을 입력후 엔터키를 입력된 값을 가져오거나 보여줄수있다. 편한점은 별다른 이벤트없이 keyup.enter 만 이용하면 끝



 결과

 



여기에서 만약 엔터키를 입력하지않고 저장이 되게 하고싶다면  blur event 를 이용해보자

위의 예제에서  (blur)="update(box.value)" 이것만 추가시켜주면된다




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Component({
  selector: 'little-tour',
  template: `
    <input #newHero
      (keyup.enter)="addHero(newHero.value)"
      (blur)="addHero(newHero.value); newHero.value='' ">
 
    <button (click)=addHero(newHero.value)>Add</button>
    <ul><li *ngFor="let hero of heroes">{{hero}}</li></ul>
  `
})
export class LittleTourComponent {
  heroes = ['Windstorm''Bombasto''Magneta''Tornado'];
  addHero(newHero: string) {
    if (newHero) {
      this.heroes.push(newHero);
    }
  }
}
cs

이 예제는 위에서 배운것을 종합한예제이다 살펴보면 blur 이벤트를 살펴보면 자바스크립트는 2개의 동작을 하게된다

첫째로 addHero 이벤트를 동작시킨다

둘쨰로 <input #newHero> 인풋값을 클리어시켜준다


 결과

 






WRITTEN BY
내가달이다

,

MSSQL :: 0 CURSOR

ASP.NET MVC/SQL 2016. 12. 1. 22:54

포스팅하던중 친구가 이러한 쿼리가 가능하냐고 연락이와서 생각난김에 글을적어본다


친구의 요구사항은 테이블이 db_20161025,db_20161125,db_20161225 매달마다 백업하는 테이블이 있다고 가정을하고


'db_' 가 포함된 테이블을 전부 셀렉트 할수있냐는것이었다



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
--커서 시작
DECLARE UserTable_Cursor CURSOR
FOR
-- 테이블 중에 name 이 'db_'값 찾기
select name   from sysobjects where name like('db_%')
OPEN UserTable_Cursor
 
DECLARE @name varchar(20)           
DECLARE @strsql nvarchar(300

set @name = (select top 1 name   from sysobjects where name like('db_%'))
 
FETCH NEXT FROM UserTable_Cursor INTO @name
 
WHILE (@@FETCH_STATUS = 0)
 
BEGIN    
    SET @strsql =  ' SELECT * FROM ' + @name
       EXEC SP_EXECUTESQL @strsql  
    FETCH NEXT FROM UserTable_Cursor INTO @name       
END
 
CLOSE UserTable_Cursor
 
DEALLOCATE UserTable_Cursor
cs



4번 셀렉트문을 돌린값이다 ( 샘플 예제)


커서실행시 





'ASP.NET MVC > SQL' 카테고리의 다른 글

SQL :: 3 시도별 총회원 등급 카운트  (0) 2018.05.06
MSSQL :: 1 Join  (0) 2017.01.13

WRITTEN BY
내가달이다

,

지난 포스팅에 말했다 싶이 일정 시간마다 instagram,twitter 데이터를 크롤링 하는 스케쥴링을 구현해볼 생각이다


처음에는 간단하게 twitter api,instagram api 만을 이용해서 가져오면되지않을까? 


라는 별거아닌 생각으로 프로그램 작성을 했다.. 


트위터는 api 를 무난하게 사용해 작성을하였는데.. 아뿔사... 


인스타그램은 .. 정책이변경되서 권한이 얻기가 ... 드릅게 빡세다 ...  





어쩔수없이 페이지 자체를 크롤링 하는 방향으로 포커스를 맞췄다  아 내시간 ㅁ느아ㅣㅡㅁ니ㅏㅇ




#트위터 ,인스타그램 페이지 크롤링






트위터 홈페이지에서 #블랙베리 라는 태그를 가지고 검색을 한 화면 이다


트위터  나 인스타그램 같은경우는 화면을 최하단으로 스크롤 할경우  자동으로 다음페이지를 불러오게 되어있다


이런문제때문에 생각해볼게 좀많아서 이걸 어찌하나 했는데 


http://blog.nundefined.com 이 글의 도움을 많이 받았다



우선 크롤링을 하기위해서는 


 


PhantomJS,CasperJS,SpookyJS 가 필요하다 


설치하는 방법은 구글에 많이있으니 참고해서 설치하시기 바랍니다..


간단하게 설명하자면

 

PhantomJS/CasperJS 같은경우는 webkit 기반의 headless browser 이다 즉, 단독브라우저로 웹테스트 할떄 많이들 사용한다고 하더라


SpookyJS 위의 CasperJS,PhantomJs같은 경우는 node 와 관계없이동작하기때문에 이를 컨트롤 하기 위해서 사용을한다 



function.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
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
 scheduletwitter: function(count) {
 
            var searchquery = config.schedule.hashtag[count];    //앞서 저장되어있던 수집태그
            var id = config.schedule.name[count];                 //앞서 저장되어있던 id값    
            var encsearchquery = encodeURIComponent(searchquery);
            var url = 'https://twitter.com/search?f=tweets&vertical=default&q=%23'+encsearchquery+'&src=typd';
 
            var Spooky = require('spooky');
 
            var spooky = new Spooky({
                    casper: {
                          logLevel: 'debug',
                            verbose: false,
                            options: {
                                clientScripts: ['https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js']
                            },
                            viewportSize: {
                                        width: 1440, height: 768
                                    },
                               pageSettings: {
                                webSecurityEnabled: false
                                userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11" // Spoof being Chrome on a Mac (https://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx)
                            }
                            
                    }
                }, function (err) {
                    if (err) {
                        e = new Error('Failed to initialize SpookyJS');
                        e.details = err;
                        throw e;
                    }
 
             
                    spooky.start(url);
                         var twitter = function() {                            
                                spooky.then(function(){
                              this.scrollToBottom();
                                this.wait(1000);
                            var newScrolleds = this.evaluate(function() {
                                    return window.scrollY;
                                });
                            var newScrolled = this.evaluate(function() {
                                return window.document.body.scrollTop = document.body.scrollHeight;
                                });
                                    
                        });
                        spooky.then(function(){       
                        
                            this.scrollToBottom();
                            this.wait(1000);
                            var newScrolleds = this.evaluate(function() {
                                    return window.scrollY;
                                });
                                
                                this.emit('logs',newScrolleds)
                            var newScrolled = this.evaluate(function() {
                                return window.document.body.scrollTop = document.body.scrollHeight;
                                });
                                    this.emit('logs',newScrolled)
 
                            
                        });  
                    
                    }  
  
                        twitter()
               
 
                    }
 
                    spooky.run();
                             
                });
            spooky.on('logs'function (logs) {
                                        console.log(logs);
                                        });
 
  
 
 
}
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
//spookyJS URL 접속
spooky.start(url)              
            //spookyJS 다음 행동           
            spooky.then(function(){    
                            //스크롤을 맨아래로 이동                 
                             this.scrollToBottom();   
                             // 1초 wait  
                              this.wait(1000);          
                            var newScrolleds = this.evaluate(function() {
                                     //현재 윈도우 y값
                                    return window.scrollY;  
                                });
                            var newScrolled = this.evaluate(function() {
                                //현재 윈도우 x값
                                return window.document.body.scrollTop = document.body.scrollHeight; 
                                });
 
                            // logs 값 전송
                            this.emit('logs',logs)
   
 // logs 값 get
  spooky.on('logs'function (logs) {
    console.log(logs);
     });
cs



해당 코드를 실행하게되면 검색어가 입력된 페이지를 접속한후 맨아래로 이동후 그 좌표 로그값을 받는 것이다



이런식으로 찍히게 된다 (정상작동)


본격적으로 데이터를 가져와보자




가져 오게 되면

1
2
3
4
5
6
7
        Userid = this.evaluate(function() {
                                                var elements = __utils__.findAll('#stream-items-id > li > div > div > div > a > span.username.js-action-profile-name');
                                                return elements.map(function(e) {
                                                    return e.innerText
                                                });
                                        });
        this.emit('dbinsert', Userid)
cs


이런식으로 변수에 저장시켜주면된다


값까지 찾았으니 그후에는 db 에 입력시켜줍시다


this.emit 을 통해 node 으로 돌아와서


1
2
3
4
   spooky.on('dbinsert'function (data) {
                    db.dummy.save(data, function(){
                        });
                });
cs


디비로 전송시켜주면 끝


이제 이걸 내가원하는 시간마다 돌아가게 스케쥴링을 걸어주자 


server.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  var scheduler = new Scheduler(1);
 
 
            scheduler.add(8000function(done,res){
 
                
                setTimeout(function() {
                    for(var i = 0; i < config.schedule.hashtag.length; i++)
                    {
                        functions.scheduleinstagram(i)
                    }
                }, 3000);
 
                setTimeout(function() {
                    for(var i = 0; i < config.schedule.hashtag.length; i++)
                    {
                        functions.scheduletwitter(i)
                    }
                }, 3000);
            done();     
        });
cs



자이제 결과를 살펴보자




인스타그램도 이와 유사하다  궁금하신 부분이있으면 댓글달아주세여



WRITTEN BY
내가달이다

,

2 UI  에 이어서 마저 작성을한다



UI 에서 입력한값을 mongoDB로 입력할수있게해주려한다


2장에서 작성한 

collect.component.ts 추가 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   addinfo(
    email:string,
    name:string,
    hashtag:string,
    frcal:string,
    tocal:string,
     twitter:string,
    ){
      
      
       var query = {
                         "hashtag" : hashtag,
                          "email" :  email,
                          "frcal" : frcal,
                          "tocal" : tocal,
                          "twitter" : twitter,
                         "name"    : name
       }
       
        var headers = new Headers(); 
        headers.append('Content-Type''application/json')
        this.http.post('http://localhost:4100/dbUserinsert',query,{headers: headers}).subscribe((res) => {
        
    );
cs


server.js 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var express = require('express');
var request = require('request');
var bodyParser = require('body-parser');
var cors = require('cors');
var functions = require('./functions');
var dbsearch = require('./dbsearch');
var app = express();
var Scheduler = require('nschedule');
var config = require('./config');
var async = require('async');
 
 
 
 
           
         app.use(express.static(__dirname));
        app.post('/dbUserinsert',dbsearch.Userinsert);  //입력받은값 디비 저장
        app.listen(process.env.PORT || 4100);
        console.log("Server up on port 4100");
cs

MongoDB 설치

1
2
3
npm install mongojs -
//MongoDB 설치
 
cs


dbsearch.js 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var searchfunctions = require('./functions')
var mongojs = require('mongojs');
var db = mongojs('mongodb://''@''.mlab.com:63406/');
 
functions = {
 
 Userinsert : (req,res) => {
    var req = req.body;
    console.log(req)
     db.collect.save(req, function(err, result){
                if(err){
                    res.send(err); 
                    console.log(err);
                } else {
                    res.json(result);
                    console.log(result);
                }
            });
        
    }}  
cs




작성한 코드를 실행하게 되면


입력받은 값을  query 변수에 입력하고 JSON 으로 보내게 된다 


서버에서는 호출 된 URL http://localhost:4100/dbUserinsert app.post 시켜서  dbsearch.js 에 있는


Userinsert 함수를 실행시켜주게 된다 


완성이되면  이전페이지에서 보게된거처럼 그리드에 바인딩이 되어진다 




#입력된값을 DB 에 저장시키는 코드 까지 작성을 완료 했다

다음페이지에서는 일정시간마다 instagram,twitter 데이터를 크롤링 하는 스케쥴링을 포스팅할예정이다 




WRITTEN BY
내가달이다

,



마저 작성한다


첫번째  등록버튼을 클릭할때 위의 메뉴가 나오게 하고싶다

두번째  수집기간을 달력버튼이 말고 텍스트박스를 클릭할때 달력을 표시하게해주고싶다

세번째 수집된내용을 DB 에 저장시키고 목록을 그리드에 바인딩시켜준다

네번째 바인딩된 그리드 클릭후 엑셀출력 버튼을 클릭하면 수집된내용을 엑셀로 출력시켜준다



#첫번째

collect.component.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
45
46
<div class="row">
  <div class="large-6 columns">
    <button (click)="changeState('add')" class="btn btn-primary">신규등록</button>
  </div>  
</div>
<p></p>
<div *ngIf="appState == 'add'" class="row">
    <form class="form-horizontal"  [formGroup]="VailidateForm" (submit)="addinfo(
        email.value,
        name.value,
        hashtag.value,
        frcal.value,
        tocal.value,
        twitter.value
        )">
  <fieldset>
    <legend>신규 등록</legend>
    <div class="form-group" >
      <label for="inputEmail" class="col-md-1 control-label">이메일</label>
      <div class="col-md-5" [ngClass]="{'has-error':!VailidateForm.controls['email'].valid && VailidateForm.controls['email'].touched}">
        <input type="text" class="form-control" placeholder="@naver.com" #email [formControl]="VailidateForm.controls['email']" >
        <div *ngIf="VailidateForm.controls['email'].hasError('required') && VailidateForm.controls['email'].touched" class="alert alert-danger">이메일을 입력해주세요</div>
      </div>
    </div>
    <div class="form-group">
      <div class="col-md-1">
          <input type="submit"  class="btn btn-primary" value="등록" [disabled]="!VailidateForm.valid">
      </div>
        <div class="col-md-1">
          <button  class="btn btn-primary" (click) ="changeState('appState','default')" >
            취소
          </button>
         </div>
    </div>
  </fieldset>
</form>
</div>
<div style="width: 100%;">
    <ag-grid-ng2 #agGrid style="width: 100%; height: 200px;" class="ag-fresh"
                 [gridOptions]="gridOptions" (rowClicked)='onRowClicked($event)'
                 >   
    </ag-grid-ng2>
</div>
 
 
 
cs

collect.component.ts

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
import { Component,Input,OnInit,Injectable,OnDestroy,ViewChild } from '@angular/core';
import {Collect}  from '../collect';
import {GridOptions} from 'ag-grid/main';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
 
declare  var $:any;
 
 
@Component({
    moduleId:module.id,
    selector: 'collect',
    templateUrl: 'collect.component.html',
     styleUrls: ['collect.component.css']
 
})
@Injectable()
export class CollectComponent implements OnInit{
 
 VailidateForm : FormGroup;
 
 constructor(private http:Http,fb: FormBuilder){ 
 
        this.VailidateForm = fb.group({
        'email' : [null, Validators.required],
        'id' : [null, Validators.required],
        'hashtag' : [null , Validators.required],
        'date' : [null , Validators.required]
      })
 
      console.log(this.VailidateForm);
      this.VailidateForm.valueChanges.subscribe( (form: any) => {
        console.log('form changed to:'form);
      }
    );
cs

위 화면을 작성한 코드 예제이다


돌아가는 사이클은 신규등록을 클릭할시 밑에 form 들을 보여주게한다


위 코드에서 눈여겨 볼만한것은 *ngIf , [ngClass] ,[formControl] 이다


1.*ngIf


1
2
3
4
5
6
7
 
 
<div *ngIf="appState == 'add'" class="row">
    <!-- 변수의 값이 appState와 일치할 때 이 태그가보여진다 .-->
</div>
 
 
cs

2~3.[ngClass],[formControl]

1
2
3
4
5
[ngClass]="{'has-error':!VailidateForm.controls['email'].valid && VailidateForm.controls['email'].touched}"
//email 폼 값이 비어있거나 클릭이 되었을경우 발생한다
 
[formControl]="VailidateForm.controls['email']"
//form컨트롤값 지정
cs



collect.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
constructor(private http:Http,fb: FormBuilder){ 
 
        this.VailidateForm = fb.group({
        'email' : [null, Validators.required],
        'id' : [null, Validators.required],
        'hashtag' : [null , Validators.required],
        'date' : [null , Validators.required]
      })
 
      console.log(this.VailidateForm);
      this.VailidateForm.valueChanges.subscribe( (form: any) => {
        console.log('form changed to:'form);
      }
cs


코드를 살펴보자 vaildateForm 값을 넣어주고 


vaildateform 값이 변할때마다 log 를 찍어주도록하였다 





코드를 실행해보면





이러한 화면을 간단하게 만들어보았다


WRITTEN BY
내가달이다

,