반응형

■ Visual Studio 2010, SQL Server 2014 기준으로 개발

SQL 서버에 OpenAPI 호출하는 CLR을 등록하여, 거래처가 특정 조건을 만족하는지 검사하는 기능을 개발하게 되었는데 이 과정의 일부를 남깁니다.

CLR 프로젝트 생성

우선 Visual Studio에서 다음과 같이 SQL Server > Visual C# SQL CLR 데이터베이스 프로젝트를 시작합니다.

개발할 CLR이 SQL Sever에서 참조할 구성요소를 선택할 필요가 없으면 데이터베이스 참조는 취소해도 됩니다.

저의 경우 JSON을 처리하는 다른 DLL의 참조가 필요하여 DB 연결 정보를 입력하였습니다.
만약 연결된 DB 정보가 없이 참조 추가하려고 하면 다음과 같이 추가가 불가능합니다.

Visual Studio에서 기본적으로 생성되는 프로젝트 구성은 다음과 같습니다.

클래스 파일 추가

이제 실제 로직을 C#으로 구현하기 위하여 새로운 클래스 파일을 추가합니다 (이름은 NIMS.cs로 하였습니다).

추가된 빈 클래스 파일의 모습입니다.

API 스펙 확인

사용하려는 OpenAPI의 스펙은 다음과 같습니다.

JSON for. NET

위 OpenAPI의 호출 결과는 JSON으로 전달되기 때문에 JSON을 파싱 하기 위하여 JSON for. NET이라는 오픈 라이브러리를 사용합니다.

다음 사이트에서 파일을 내려받습니다.
sourceforge.net/projects/csjson/

내려받은 json-for-dotnet-1.2.zip 파일의 압축을 풀어서 System.Net.Json.dll 파일을 SQL 서버에 복사합니다.

제가 만든 CLR에서 이 System.Net.Json.dll을 참조해야 하므로 다음과 같이 SQL 서버에 어셈블리 등록을 합니다.

EXEC SP_CONFIGURE 'clr enabled', 1
RECONFIGURE WITH OVERRIDE 

ALTER DATABASE [MyDB] SET 
TRUSTWORTHY ON

CREATE ASSEMBLY Json
FROM 'D:\System.Net.Json.dll'    
WITH PERMISSION_SET = UNSAFE

그런데 JSON for. NET에서 제공해주는 기본 파서 기능이 좀 빈약하여, OpenAPI 결과를 처리할 수 있도록 기능 보완된 파서를 만들기 위하여 클래스 파일을 하나 더 추가합니다 (이름은 MyJsonParser.cs으로 했습니다).

그리고 다음과 같이 로직을 작성하였습니다.

MyJsonParser.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Json;

namespace NIMSAPI
{
    class MyJsonParser
    {
        private JsonTextParser parser;
        private JsonObjectCollection joc;

        public MyJsonParser(string planText = "")
        {
            parser = new JsonTextParser();
            if (!string.IsNullOrEmpty(planText))
            {
                joc = (JsonObjectCollection)parser.Parse(planText);
            }
        }

        // 생성자에서 주어진 초기 문자열 외에 추가적으로 파싱할 때 사용
        public void Parse(string planText)
        {
            planText = planText.Replace("\r", "").Replace("\n", "").Replace("\t", "");    // 파싱 오류방지를 위해 tab 및 개행문자열 제거

            joc = (JsonObjectCollection)parser.Parse(planText);
        }

        public object GetValue(string namePath, char split = '/', bool returnEmptyWhenNull = true)
        {
            string[] names = namePath.Split(split);
            JsonObjectCollection obj = null;

            if (names.Length == 1)
            {
                if (joc[namePath] is JsonObjectCollection)
                    obj = (JsonObjectCollection)joc[namePath];

                if (joc[namePath] is JsonArrayCollection)
                    obj = joc;
            }
            else
            {
                for (int i = 0; i < names.Length - 1; i++)
                {
                    if (i == 0)
                        obj = (JsonObjectCollection)joc[names[i]];
                    else
                        obj = (JsonObjectCollection)obj[names[i]];
                }
            }

            if (obj != null)
            {
                if (obj[names[names.Length - 1]] is JsonArrayCollection)
                    return obj[names[names.Length - 1]];
                else
                    return obj[names[names.Length - 1]].GetValue();
            }
            else
            {
                object retObj = null;

                if ((joc as JsonObjectCollection)[namePath] != null)
                {
                    retObj = (joc as JsonObjectCollection)[namePath].GetValue();
                }

                if (retObj == null && returnEmptyWhenNull)
                {
                    retObj = string.Empty;
                }

                return retObj;
            }
        }
    }
}

참조 추가

솔루션 탐색기에서 참조 추가를 눌러서 

앞에서 등록한 Json 어셈블리를 선택합니다.

정상적으로 추가되면 다음과 같이 참조 하위에 포함되게 됩니다.

이제 NIMS.cs에 OpenAPI를 호출하고 결과를 MyJsonParser로 파싱 처리하는 소스를 작성하였습니다.

NIMS.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Collections.Specialized;
using System.Net.Json;

namespace NIMSAPI
{
    public class NIMS
    {
        // 상대 마약류취급자식별번호가 존재하는지 체크
        //      BizNo: 매출거래처의 사업자번호
        public static bool IsExistsBsshCode(string BizNo)
        {
            string Url = "https://www.nims.or.kr/api/bsshinfo.do";
            bool result = false;

            try
            {
                WebClient webClient = new WebClient();

                NameValueCollection formData = new NameValueCollection();
                formData["k"] = "XXXXXXXXX"; //인증키
                formData["fg"] = "1";
                formData["pg"] = "1";
                formData["bi"] = BizNo;

                byte[] responseBytes = webClient.UploadValues(Url, "POST", formData);
                string Result = Encoding.UTF8.GetString(responseBytes);

                MyJsonParser myParser = new MyJsonParser(Result);

                string ResultCode = myParser.GetValue("response/header/RESULT_CODE").ToString();
                int CustCount = int.Parse(myParser.GetValue("response/body/TOTAL_COUNT").ToString());

                JsonArrayCollection lists = (JsonArrayCollection)myParser.GetValue("response/body/list"); 

                int count = 0;
                foreach (JsonObjectCollection collection in lists)
                {
                    myParser.Parse(collection.ToString());  // 배열 요소를 다시 파싱 시킨다

                    string OppNarcoticManagerID = myParser.GetValue("BSSH_CD").ToString();        // 상대 마약류취급자식별번호
                    result = !string.IsNullOrEmpty(OppNarcoticManagerID);

                    if (++count == 1) break;    // 동일 거래처가 여러개 조회되는 경우가 있어서 한 번만 처리되게 함
                }
            }
            catch
            {
                result = false;
            }

            return result;
        }
    }

}

F6을 눌러서 빌드합니다.

빌드된 NIMSAPI.dll 파일을 SQL 서버에 복사하고 어셈블리 등록을 합니다.

CREATE ASSEMBLY NIMS
FROM 'D:\NIMSAPI.dll'    
WITH PERMISSION_SET = UNSAFE

참고로 다음과 같이 소유자 SID 문제로 어셈블리 등록이 되지 않는 경우 ALTER AUTHORIZATION로 해당 DB의 소유자를 변경해야 합니다.

/*
master 데이터베이스에 기록된 데이터베이스 소유자 SID가 데이터베이스 'MyDB'에 기록된 
데이터베이스 소유자 SID와 다릅니다. 
ALTER AUTHORIZATION 문을 사용하여 데이터베이스 'MyDB'의 소유자를 다시 설정하여 
이 문제를 해결해야 합니다.
*/

-- 현 소유자 확인
SELECT name AS [Database],
       SUSER_SNAME(owner_sid) AS [Owner]
FROM sys.databases
WHERE [name] = 'MyDB'

-- 소유자 변경
ALTER AUTHORIZATION ON DATABASE:: MyDB TO sa ;

사용자 함수 생성

등록된 CLR 어셈블리를 SQL 서버에서 함수 형태로 호출할 수 있도록 함수를 생성합니다.

CREATE FUNCTION FN_NIMS_CUST_EXISTS
(
    @p_BizNo NVARCHAR(20)
)
RETURNS BIT AS EXTERNAL NAME NIMS.[NIMSAPI.NIMS].IsExistsBsshCode


테스트

이 글이 도움이 되셨으면 공감(하트)과 댓글을 부탁 드려요!

반응형
반응형
  • BOX(container) 및 Item 들을 열과 행에 자유자재로 나타내기 위한 CSS 기술
  • 예전에는 layout을 위해 table, float tag를 사용 했으나 현재는 flexbox로 모두 대체 가능
  • 서로 다른 screen size 에서 HTML 요소들의 재배치를 통해서 반응형 웹 구현 가능

1. main axis, cross axis 개념

  • 횡(가로)을 중심축으로 하면 직각으로 대응되는 종(세로)이 반대축이 된다.

  • 종(세로)을 중심축으로 하면 직각으로 대응되는 횡(가로)이 반대축이 된다.

2. single line, multi line 개념

  • multi line은 flex-basis 값과 flex-wrap:wrap 속성에 의해 한 줄로 표현하기에 빈 공간이 모자라는 경우 발생

3. container에 적용되는 속성

  • display: flexbox를 쓰기 위하여 flex로 지정
  • flex-direction: main 축 기준으로 각 item이 놓여지는 방향 (row, column, row-reverse, column-reverse)
  • flex-wrap: 한 줄에 item이 지정된 크기를 유지할 수 없을만큼 꽉 찼을 떄 자동으로 행 분리 여부 (nowrap, wrap,wrap-reverse).
    default인 nowrap인 경우에는 item의 크기를 줄여서 한 행을 유지.
  • flex-flow: flex-direction 과 flex-wrap 속성값을 한꺼번에 지정 가능
  • justify-content: 중심축을 기준으로 각 item 사이의 간격 및 부모 box와의 간격 (flex-start, flex-end, center, space-around, space-evenly, space-between)

justify-content

  • align-items: 반대축에서 item을 어떻게 정렬할 지 (stretch, flex-start, flex-end, center, baseline, stretch)

align-items

  • align-content: 반대축에서 item을 어떻게 배치할 지 (stretch, flex-start, flex-end, center, space-around, space-evenly, space-between)

align-content

4. item에 적용되는 속성

  • order: HTML tag가 나오는 순서와 관계 없이 item이 나열되는 순서를  임의로 변경할 때 숫자 지정
  • flex-grow: container가 늘어날 때 width 크기에 맞춰서 한 줄을 꽉 채우도록 item의 크기를 늘릴 비례값(숫자) 지정(기본값 0)

flex-grow

  • flex-shrink: flex-grow와 반대로 container가 줄어들 때 width 크기에 맞춰서 item의 크기를 줄일 비례값(숫자) 지정(기본값 1)
  • flex-basis: 기본 값 auto(grow, shrink에 지정된 값 이용). grow, shrink 없이 basis에 비율('%')로 값을 지정
  • flex: grow, shrink, basis를 한꺼번에 지정
  • align-self: container 지정값(justify-content, align-items, align-content)을 벗어나 item 독자적으로 배치 (center, flex-start, flex-end)

align-self

* 본문 내 이미지 일부는 css-tricks.com/snippets/css/a-guide-to-flexbox/ 에서 capture 함.
 
반응형
반응형

javascript에서는 함수를 3가지 방법으로 정의할 수 있습니다.

1. Function 생성자 함수 이용

let add = Function('a', 'b', 'return a + b;');

console.log(add(10, 20));

가장 일반적이지 않은 방법으로서 실무적으로는 사용할 일이 거의 없을 것 같습니다. 다만 다른 함수정의 방식으로 함수를 생성하더라도 내부적으로는 생성자 함수를 통해서 함수가 만들어지게 됩니다. 때문에 javascript에서 모든 함수는 그 자체로 객체 입니다.

2. 함수 선언문 이용

function add(a, b)
{
  return a + b;
}

console.log(add(10, 20));

function 다음에 함수명을 반드시 포함해야 하며, 이 이름으로 함수를 호출할 수 있습니다. 함수 선언문을 이용해 함수를 정의하면 함수 호이스팅(function hoisting)이 일어납니다. 함수 호이스팅은 함수 정의를 소스 유효범위 내 가장 위로 끌어 올리는 것을 말합니다.
그래서 다음과 같이 함수 정의를 하기 전에 함수를 사용하더라도 오류가 발생하지 않습니다.

console.log(add(10, 20));

function add(a, b)
{
  return a + b;
}

3. 함수 표현식 이용

let add = function (a, b)
{
  return a + b;
}

console.log(add(10, 20));

function 다음에 함수명이 없는 익명 함수 리터럴을 사용할 수 있으며 이를 변수에 할당하여 함수를 생성 합니다.
할당된 변수이름 뒤에 괄호를 붙여서 함수 호출을 할 수 있습니다.
이 경우에는 함수 호이스팅이 일어나지 않아서 만약 함수 정의 전에 함수를 사용하면 오류가 발생 합니다.

일반적으로는 익명 함수 형태로 사용하며 함수 내에서 재귀 호출이 필요한 경우에는 다음과 같이 함수명을 사용할 수도 있습니다. 다만 이때의 함수명은 함수 정의 밖에서는 사용할 수 없습니다.

let factorial = function _factorial (num)
{
  if (num > 1)
  {
    return num * _factorial(num - 1);
  }
  else
  {
    return 1;
  }
}

console.log(factorial(5));  // 120
console.log(_factorial(5)); // not defined 에러

 

반응형
반응형

자바스크립트에는 !를 두 개 붙인 !! 연산자가 있는데 !! 다음의 값(피연산자)에 대하여 불린값을 반환한다.

console.log(!!0);
console.log(!!1);
console.log(!!'');
console.log(!!'hello');
console.log(!!false);
console.log(!!true);
console.log(!!null);
console.log(!!undefined);
console.log(!!{});
console.log(!![]);

null 과 undefined는 모두 false 이고, 빈 배열 및 빈 객체는 모두 true 인 점을 주의할 필요가 있다.

당연하겠지만 not 연산자인 !와 함께 !!!를 사용하면 반대되는 불린값을 얻게 된다.

console.log(!!!0);
console.log(!!!1);
console.log(!!!'');
console.log(!!!'hello');
console.log(!!!false);
console.log(!!!true);
console.log(!!!null);
console.log(!!!undefined);
console.log(!!!{});
console.log(!!![]);

false를 다음과 같이 Boolean 객체로 만들면

console.log(!!(new Boolean(false)));

값(valueOf())이 false 라도 객체이기 때문에 true가 된다.

 

반응형

+ Recent posts