GeoService-Xr의 SQL 실행 서비스

GeoService-Xr은 연결된 DBMS에 대해 SQL문 실행을 대신해 주고 그 결과를 클라이언트에게 JSON 형식으로 전송해 주는 기능을 제공합니다. 이를 위해서 실행할 SQL 문이 정의된 파일이 서버측에 필요한데요. 아래는 그 한가지 예입니다.

{
    "metadata": {
        "startToken": "{$",
        "endToken": "}"
    },
	
    "sql": {
        "getLayers": "SELECT layers FROM core_users LIMIT 1",
        "getBuildingsByRoadCode": "SELECT ST_AsText(the_geom) FROM buld_a WHERE rn_cd ='{$road_cd}' LIMIT 1",
        "addUseLog": "INSERT INTO core_uselog (systemname, username) VALUES('{$systemName}', '{$userName}')" 	
    }
}

위의 내용에 규칙이 존재하는데요. sql 문의 id가 get으로 시작하는 getLayers나 getBuildingsByRoadCode는 반드시 SELECT 문이여야 하고, add로 시작한다면 INSERT 문, del로 시작하면 DELETE 문, set으로 시작하면 UPDATE 문이어야 합니다. 위의 SQL 정의 파일의 이름이 SQL.json이라고 한다면, GeoService-Xr의 환경설정 파일인 XrConfig.xml에 다음처럼 기술되어져야 GeoService-Xr이 실행될때 SQL 문이 로딩되어 실행할 준비가 완료됩니다..


    ....

    d:/config/SQL.json

위와 같은 준비가 되면, 클라이언트 측에서 SQL 문을 호출할 수 있는데요. 아래는 javascript 문을 통해 실행한 내용의 예입니다.

var road_cd = this._CodeMap_Road[name];

$.ajax({
    url: url = ConfigValues.GIS_SERVER + "/Xr?rsql|getBuildingsByRoadCode|" + ConfigValues.DB_NAME,
    type: "POST",
    crossDomain: true,
    data: "road_cd:=" + road_cd + "\nparam2:=param2", // 파라메터의 구분은 \n 문자로 함
    dataType: "text",
    success: function (response) {
        // Java, C/C++ 등과 같은 언어의 편의성을 위해 결과의 끝에 \0이 붙음
        // javascript에서 json으로 파싱하기 위해 response 문자열 끝에 \0 문자를 제거해야 함
        response = response.substr(0, response.length - 1); 
        response = JSON.parse(response);
        
        ...
    },

    error: function (xhr, status) {
        alert("ERROR");
    }
});

MySQL, MariaDB의 INSERT INTO … ON DUPLICATE KEY UPDATE …

MySQL(MariaDB)에서 동일한 Key 값이 이미 존재한다면 UPDATE 문을 호출하여 기존의 Row의 값을 변경하고, 동일한 Key 값을 가진 Row가 없다면 INSERT를 호출하는 SQL 문의 예입니다.

INSERT INTO 
    current_load_powerfactor 
    (ref_mRID, update_timeStamp, value) 
VALUES
    ("_1e1ccab5-250a-44a3-89d8-177e2d53e071", NOW(), 99) 
ON DUPLICATE KEY UPDATE 
    update_timeStamp=NOW(), value=99

위의 SQL은 current_load_powerfactor라는 테이블에 대해서, Primary Key로 잡힌 ref_mRID가 중복된 이미 존재하는 Row가 있다면, 중복된 Row의 값을 변경(UPDATE 문 실행)하고, 중복된 Row가 없다면 새로운 Row를 추가(INSERT)하라는 내용입니다.

웹서버에 대한 Cross Domain 허용하기

개발 시에 다양한 웹서버에 대한 자원에 접근하기 위해 일시적인 방안으로 Cross Domain 접근을 허용할 필요가 있습니다. 이에 대해 각 웹서버에서의 방법이 상이한데요. 이에 대해 정리해 봅니다.

IE Express

IE Express가 실치된 Program Files(x86)/IIS Express/AppServer 폴더 안에 존재하는 applicationhost.config 파일에서 <customHeaders/> 부분에 <add name=”Access-Control-Allow-Origin” value=”*” />와 <add name=”Access-Control-Allow-Headers” value=”Content-Type” />를 추가합니다. 예를 들어 아래와 같습니다.

<httpProtocol>
    <customHeaders>
        <clear/>
        <add name="X-Powered-By" value="ASP.NET"/>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
    </customHeaders>
    <redirectHeaders>
        <clear/>
    </redirectHeaders>
</httpProtocol>

NGINX

NGINX가 설치된 폴더 안에 conf/nginx.conf 파일에서 ‘location /’ 부분의 블럭에 ‘add_header ‘Access-Control-Allow-Origin’ ‘*’;’ 추가합니다. 예를 들어 아래와 같습니다.

location / {
    #root   html;
    root e:/;
    add_header 'Access-Control-Allow-Origin' '*';
    index  index.html index.htm;
}

JavaScript 새로운 문법 정리

자바스크립트에서 var로 정의된 변수의 유효범위는 함수입니다. 일반적인 프로그래밍 언어에서 변수의 유효범위는 블럭(Block)인데요. 자바스크립트에서 블럭의 범위 지정을 위한 시작은 ‘{‘이며 끝은 ‘}’입니다. let을 통한 변수의 정의는 바로 이러한 블럭 범위에서만 유효한 변수를 정의할 수 있도록 합니다.

이러한 let 키워드를 통해 보다 분명한 의미로 변수를 정의해, 필요한 시점에서만 메모리에 적재되어 사용되고 필요하지 않은 시점에서는 메모리에서 제거되도록 할 수 있는데요. 아래의 예는 배열에 대한 각 요소를 저장하기 위해 i라는 변수를 let으로 선언하고 있습니다.

let a = [1, 2, 3];
for (let i of a) {
    alert(i);
}

let 키워드는 IE나 Chrome 모두에서 지원되지만, 위의 for 문은 IE(v11)에서 지원하지 않습니다.

아래의 코드는 배열에 대한 각 소요를 순회하며 처리할 수 있는 함수를 지정할 수 있는 배열의 forEach 매서드에 대한 예제 코드입니다.

function logArrayElements(element, index, array) {
    alert("a[" + index + "] = " + element);
}

[2, 5, 9].forEach(logArrayElements);

아래의 코드는 C++, Java, C#의 람다 함수와 매우 유사한 Javascript의 문법입니다. IE(v11)에서는 지원하지 않으며 Chrome에서만 지원합니다.

// Case 1 Start
sayHello = name => alert("Hello, " + name);
sayHello("Dip2K");
// Case 1 End

// Case 2 Start
setTimeout(() => alert("timeout!"), 2000);
// Case 2 End

// Case 3 Start
[2, 4, 8].forEach(item => alert(item));
// Case 3 End  
      
// Case 4 Start
calcCircumference = diameter => {
    return Math.PI * diameter;
}

alert(calcCircumference(10));
// Case 4 End

Javascript에서 함수를 정의시에 인자에 기본값을 지정할 수 있는데요. 아래의 코드에서 그 예를 명확히 살펴볼 수 있습니다.

function volume(l = 10, w, h = 10) {
    alert(l + " " + w + " " + h);
}

volume();

volume2 = (l = 10, w, h = 10) => {
    alert(l + " " + w + " " + h);
};

volume2();

Javascript에서는 C나 C#에서처럼 변수를 활용한 형식화된 문자열을 쉽게 구성할 수 있는 문법을 제공합니다. 아래는 first와 last라는 변수를 문자열을 구성하기 위해서 ${} 사용하고 있습니다. 문자열 구성을 위해 외따움표(‘)나 쌍따움표(“)가 아닌 `를 사용해야 한다는 점에 유의해야 합니다.

let first = "Kim";
let last = "Hyoung Jun";

const welcome = `You have logged in as ${first} ${last}`;

alert(welcome);

아래의 문법은 IE(v11)에서는 지원하지 않지만, 매우 유용한 것으로서 배열을 합치거나 복제하는데 유용하게 사용될 수 있습니다.

// Case 1 Start
const odd = [1, 3, 5];
const nums = [2, 4, 6, ...odd];
alert(nums);
// Case 1 End

// Case 2 Start
const odd2 = [...odd];
alert(odd2);
// Case 2 End

// Case 3 Start
const { a, b, ...z } = { a: 1, b: 2, c: 3, d: 4 };
alert(a);
alert(b);
alert(z);
// Case 3 End

Case 1은 odd 배열과 nums 배열을 합치는 것이고, Case 2는 odd 배열을 odd2 배열로 복제(참조가 아닌)하는 것입니다. Case 3는 다소 그 성격이 다른데 a는 1, b는 2, z는 {c:3, d:4} 객체가 됩니다.

아래의 문법은 Javascript의 람다 함수(명확히 람다 함수라고 불르는 것이 맞는지는 확실치 않으나)를 사용해 코드를 간결하게 표현한 것으로써, 배열의 요소 중 특정 조건에 일치하는 요소를 검색하는 것으로, 특정 조건을 람다 함수로 정의해 표현하고 있습니다.

const pets = [
    { type: 'Dog', name: 'Max' },
    { type: 'Cat', name: 'Karl' },
    { type: 'Dog', name: 'Tommy' }
];

pet = pets.find(pet => pet.name === 'Tommy');
alert(pet.type);

FingerEyes-Xr for HTML5의 DeferableLabelText 추상 클래스 사용하기

FingerEyes-Xr에서 제공하는 DeferableLabelText 클래스는 이원화된 DBMS로부터 데이터와 공간 데이터를 연계해 라벨의 텍스트로 표현할 수 있는 기능을 제공합니다. 이 글은 DeferableLabelText 클래스의 활용예에 대해서 최대한 간략하게 정리한 글입니다.

먼저 DeferableLabelText를 상속받은 예는 아래와 같습니다.

MyDeferableLabelText = Xr.Class({
    name: "MyDeferableLabelText",
    extend: Xr.theme.DeferableLabelText,

    construct: function () {
        this.superclass();
    },

    methods: {
        /* void */ requestLabelText: function (fid) {
            var that = this;

            // 이 부분은 DBMS로부터 데이터를 가져오는 AJAX 코드로 대체되어야 할 부분  
            setTimeout(function () {
                that.setText(fid, "HELLO");
            }, 1000);
        }
    }
});

이렇게 정의한 MyDeferableLabelText 클래스는 수치지도 레이어에 지정되며 아래의 예와 같습니다.

var lyr = new Xr.layers.ShapeMapLayer(layerId, ...);
lyr.deferableLabelText(new MyDeferableLabelText());