2023년 12월 18일 월요일

c# - BaseController (Authorization)

 

로그인을 해야지만 접속이 가능한 Controller에 상속한 BaseController를 만든다. 

 

1. BaseController.cs

    public class BaseController : Controller
    {
        public string actionName { get; protected set; }
        public string controllerName { get; protected set; }

        protected override void OnActionExecuting(ActionExecutingContext filter)
        {
            
            //로그인 체크
            LogonCheck(filter);

			//DoNotAuthorizeAttribute가 설정되어 있으면 접속권한 체크하지 않는다. 
            if (filter.ActionDescriptor.GetCustomAttributes(true).Any(x => x is DoNotAuthorizeAttribute))
            {
                return;
            }

			//Ajax 호출은 접속권한 체크하지 않는다. 
            if (filter.HttpContext.Request.IsAjaxRequest())
            {
                return;
            }

            //메뉴 권한체크 추가 
            CheckAccessAuth(filter);
        }

        private void LogonCheck(ActionExecutingContext filter)
        {

            if (!isLogin) //session or cookie로 로그인 여부 확인
            {

                var routeDictionary = new RouteValueDictionary { { "action", "Logout" }, { "controller", "Account" } };
                //강제 로그아웃 시킨다. 
                filter.Result = new RedirectToRouteResult(routeDictionary);

                return;
            }
        }

        private void CheckAccessAuth(ActionExecutingContext filter)
        {
            //컨트롤러, 액션
            actionName = filter.ActionDescriptor.ActionName;
            controllerName = filter.ActionDescriptor.ControllerDescriptor.ControllerName;
			
            //로그인 계정정보, controller, action 정보로 접속권한 db 체크 
            if (!CanAccessMenu(loginInfo, controllerName, actionName)) {

                //권한없을 경우는 로그인 말고 다른페이지로 이동
                var routeDictionary = new RouteValueDictionary() { { "action", "NotAuthorized" }, { "controller", "Account" } };
                filter.Result = new RedirectToRouteResult(routeDictionary);
                return;
            }
        }
    }

 

2. 권한체크 필요한 Controller에서 BaseController 상속받는다. 

 

    public class NoticeController : BaseController
    {
    
    }

 

출처 : https://bigexecution.tistory.com/78


C# - Dapper Helper Class #3 (DapperManager 예문)

 

1. Nuget 패키지 관리자에서 Dapper 설치

.NET Framework에 맞는 버전으로 설치

 

2. DapperManager.cs

    public class DapperManager
    {
        public string DBConn = "DBNAME";
        public SqlConnection con;

        public DapperManager(DB_StrName eDB)
        {
            DBConn = eDB.ToString();
        }

        private SqlConnection SqlConnection()
        {
            return new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[DBConn].ConnectionString);
        }

        /// <summary>
        /// Open new connection and return it for use
        /// </summary>
        /// <returns></returns>
        private IDbConnection CreateConnection()
        {
            var conn = SqlConnection();
            conn.Open();
            return conn;
        }

        public IEnumerable<T> GetAll<T>(string selectQuery)
        {
            using (var connection = CreateConnection())
            {
                return connection.Query<T>(selectQuery);
            }
        }

        public int GetCount(string selectQuery)
        {
            using (var connection = CreateConnection())
            {
                return connection.Query(selectQuery).Count();
            }
        }
        public T GetByIdx<T>(int idx, string tableName, string idxColumnName = null)
        {
            using (var connection = CreateConnection())
            {
                string columnName = string.IsNullOrEmpty(idxColumnName) ? "idx" : idxColumnName;
                return connection.QuerySingleOrDefault<T>($"SELECT * FROM {tableName} WHERE {columnName} = @Idx", new { Idx = idx });
            }
        }
        public T GetById<T>(string id, string tableName, string idColumnName)
        {
            using (var connection = CreateConnection())
            {
                return connection.QuerySingleOrDefault<T>($"SELECT * FROM {tableName} WHERE {idColumnName} = @Id", new { Id = id });
            }
        }

        public int AddRow<T>(string insertQuery, T entity)
        {
            using (var connection = CreateConnection())
            {
                int affectedRows = connection.Execute(insertQuery, entity);
                return affectedRows;
            }
        }

        public int UpdateRow<T>(string updateQuery, T entity)
        {
            using (var connection = CreateConnection())
            {
                int affectedRows = connection.Execute(updateQuery, entity);
                return affectedRows;
            }
        }

        public int DeleteRow(int idx, string tableName, string idxColumnName = null)
        {
            using (var connection = CreateConnection())
            {
                string columnName = string.IsNullOrEmpty(idxColumnName) ? "idx" : idxColumnName;
                int affectedRows = connection.Execute($"DELETE FROM {tableName} WHERE {columnName} = @Idx", new { Idx = idx });
                return affectedRows;
            }
        }

        public IEnumerable<T> ExecuteProcedure<T>(string storedProcedure, object parameters = null)
        {
            int commandTimeout = 180;

            using (var connection = CreateConnection())
            {
                if (parameters != null)
                {
                    return connection.Query<T>(storedProcedure, parameters,
                        commandType: CommandType.StoredProcedure, commandTimeout: commandTimeout);
                }
                else
                {
                    return connection.Query<T>(storedProcedure,
                        commandType: CommandType.StoredProcedure, commandTimeout: commandTimeout);
                }
            }
        }

    }

3. NoticeDTO.cs

    public class Notice
    {
        public int idx_num { get; set; }
        public string title { get; set; }
        public string contents { get; set; }
        public string file1 { get; set; }
        public DateTime reg_date { get; set; }
        public DateTime mod_date { get; set; }
    }

 

4. NoticeDA.cs

        #region 공지사항 등록하기
        public static int Add_Notice(Notice notice)
        {
            DapperManager dm = new DapperManager("DBNAME");
            var insertQuery = "INSERT INTO NOTICE(title, contents, file1, reg_Date, mod_date, click_count) VALUES (@title, @contents, @file1, @reg_Date, @mod_date, 0)";
            return dm.AddRow<Notice>(insertQuery, notice);
        }
        #endregion

        #region 공지사항 수정하기
        public static int Update_Notice(Notice notice)
        {
            DapperManager dm = new DapperManager("DBNAME");
            var updateQuery = "UPDATE NOTICE SET title = @title, file1 = @file1, contents = @contents WHERE idx_num = @idx_num";
            return dm.UpdateRow<Notice>(updateQuery, notice);
        }
        #endregion
        
        #region 공지사항 삭제하기
        public static int Delete_Notice(int idx)
        {
            DapperManager dm = new DapperManager("DBNAME");
            return dm.DeleteRow(idx, "NOTICE", "idx_num");
        }
        #endregion
        
        #region 공지사항 가져오기
        public static Notice Get_Notice(int idx)
        {
            DapperManager dm = new DapperManager("DBNAME");
            return dm.GetByIdx<Notice>(idx, "NOTICE", "idx_num");
        }
        #endregion

 

출처 : https://bigexecution.tistory.com/79



2023년 12월 12일 화요일

MSSQL - 영업일 기준 날짜 만들기 (함수)



* 휴일만 임시 테이블로 관리
* 휴일을 수동으로 관리해야 하는 사항이지만 1년에 한번만 적용하면 끝
* startDate 기준으로 interval 값에 따라 (+)앞에 있는 날짜 (-)뒤에 있는 날짜 만들어짐
* 함수로 만들어 DB에서 호출하여 사용 가능



[기준일로 부터 영업일 수 만큼의 날짜 구하기]

-- select [dbo].[MFUNC_GetWorkDay](getdate(), -3)
-- select [dbo].[MFUNC_GetWorkDay]('20231111', 3)

CREATE FUNCTION [dbo].[MFUNC_GetWorkDay]
(
@startDate date,
@interval int
)
RETURNS INT
AS
BEGIN
--Declare @startDate date, @interval int
--SET @startDate = '20230607' --getdate()
--SET @interval = -3

DECLARE @holidayCalendar TABLE (CalendarDate date NULL)
DECLARE @AddDate date

if @interval is null set @interval = 0

-- 휴일만 등록 (23년, 24년)
insert into @holidayCalendar (CalendarDate)
values ('20230101'), ('20230121'), ('20230122'), ('20230123'), ('20230124')
, ('20230301')
, ('20230505'), ('20230527')
, ('20230606')
, ('20230815')
, ('20230928'), ('20230929'), ('20230930')
, ('20231003'), ('20231009')
, ('20231225')
, ('20240101')
, ('20240209'), ('20240210'), ('20240211'), ('20240212')
, ('20240301')
, ('20240410')
, ('20240505'), ('20240506'), ('20240515')
, ('20240606')
, ('20240815')
, ('20240916'), ('20240917'), ('20240918')
, ('20241003'), ('20241009')
, ('20241225')

--select * from @holidayCalendar

Declare @rCnt int, @cCnt int, @flag int
SET @rCnt = 0
SET @cCnt = 0

If @interval >= 0
set @flag = 1
else
set @flag = -1

set @AddDate = @startDate

while abs(@interval) > @rCnt
begin
set @cCnt = @cCnt + 1
set @AddDate = DateAdd(day,  @cCnt * @flag, @startDate)
if (datepart(dw, @AddDate) = 1) 
OR (datepart(dw, @AddDate) = 7)
OR exists(SELECT CalendarDate FROM @holidayCalendar WHERE CalendarDate = @AddDate)
begin
set @interval = @interval + (1 * @flag)
end
set @rCnt = @rCnt + 1
end

RETURN CONVERT(VARCHAR(10), @AddDate, 112)
END





[기간에 해당되는 영일 수 계산]

REATE FUNCTION [dbo].[fn_GetTotalWorkingDays]
(
    @DateFrom Date,
    @DateTo Date
)
RETURNS INT
AS
BEGIN
    DECLARE @TotDays INT = DATEDIFF(DAY, @DateFrom, @DateTo) + 1;
    DECLARE @TotWeeks INT = DATEDIFF(WEEK, @DateFrom, @DateTo) * 2;
    DECLARE @IsSunday INT = CASE WHEN DATENAME(WEEKDAY, @DateFrom) = 'Sunday' THEN 1 ELSE 0 END;
    DECLARE @IsSaturday INT = CASE WHEN DATENAME(WEEKDAY, @DateTo) = 'Saturday' THEN 1 ELSE 0 END;

    DECLARE @TotWorkingDays INT = @TotDays - @TotWeeks - @IsSunday + @IsSaturday;
    RETURN @TotWorkingDays;
END

GO

2023년 11월 29일 수요일

javascript - 전개 연산자 {...} [...] 문법 (비구조화 할당/구조분해 할당)

 

비구조화 할당 문법을 소개


  정의  

모질라 형님들의 문서에 의하면 '비구조화 할당(destructuring assignment) 구문은 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 자바스크립트 표현식(expression)'입니다.

간단하게 정리하면 배열 [], 혹은 객체 {} 안의 값을 편하게 꺼내 쓸 수 있는 문법입니다.


  기본 문법(배열)  

배열에서의 적용은 아래와 같습니다.

[a1, a2, ...rest_a] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(a1); // 1
console.log(a2); // 2
console.log(rest_a); // [3, 4, 5, 6, 7, 8, 9]

좌항이 호출될 변수명 집합, 우항이 할당할 값 입니다.

좌항의 각 요소에는 같은 index를 가지는 배열값이 할당됩니다.

또한 전개 연산자( ... )를 사용하여 좌항에서 명시적으로 할당되지 않은 나머지 배열 값들을 사용할 수 있습니다.


그리고 var, let, const를 사용해 변수들의 유효 범위를 명시적으로 선언할 수 있습니다.

var [b1, b2, ...rest_b] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let [c1, c2, ...rest_c] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const [d1, d2, ...rest_d] = [1, 2, 3, 4, 5, 6, 7, 8, 9];

전개 연산자 이후에 변수를 입력하거나, 좌 우항이 다른 속성일 경우 에러가 발생합니다.

[a1, a2, ...rest_a, a3] = [1, 2, 3, 4, 5, 6, 7, 8, 9]; // error
[a1, a2, ...rest_a] = {a1 : 10, a2: 20}; // error


  기본 문법(객체)  

객체에서의 적용은 아래와 같습니다.

var { a1, a2, ...rest_a } = { a1 : 10, a2 : 20, a3 : 30, a4 : 40 };
console.log(a1); // 10
console.log(a2); // 20
console.log(rest_a); // { a3: 30, a4: 40 }

객체의 경우에는 우항의 key 값이 좌항의 변수명과 매칭됩니다.

배열과 마찬가지로 var, let, const가 적용 가능합니다.


원래의 key 값과 다른 이름의 변수를 사용하는 방법은 아래와 같습니다.

var { a1 : awesome_name, a2 : dumb , ...rest_a } = { a1 : 10, a2 : 20, a3 : 30, a4 : 40 };
console.log(awesome_name); // 10
console.log(dumb); // 20

나머지 값을 뜻하는 전개 연산자는 우항의 key에 영향을 받지 않기 때문에 ...rest_a : blah 와 같은 표현식은 무의미하며, 실제로 에러가 발생합니다.


또한 우항의 key값에 변수명으로 사용 불가능한 문자열이 있을경우 아래와 같은 방식으로 비구조화 할 수 있습니다.

var key = 'it is key';
var { 'an-apple':an_apple, [key]:it_is_key } = { 'an-apple' : 10, 'it is key' : 20};
console.log(an_apple); // 10
console.log(it_is_key); // 20

다만 이 경우에는 'an-apple'과 매칭할 변수명(an_apple)을 작성하지 않으면 에러가 발생하게 됩니다.


마지막으로 객체 비구조화에서 주의해야 할 점은 변수 선언에 대한 명시(var, let, const)가 없을 경우 괄호를 사용하여 묶어주어야 한다는 것 입니다.

({ a, b } = { a : 10, b : 20});
console.log(a); // 10
console.log(b); // 20
{ c, d } = { c : 30, d : 40}; // error



  기본값 할당  

비구조화의 범위를 벗어나는 값 할당을 시도하면 undefined를 반환하게 됩니다.

[a, b] = [10];
console.log(a); // 10
console.log(b); // undefined
var {c, d} = { c : 20};
console.log(c); // 20
console.log(d); // undefined

이런 경우를 방어하기 위해 호출될 변수명들에 기본값 할당을 할 수 있습니다.

[a=10, b=20] = [10];
console.log(a); // 10
console.log(b); // 20
var {c = 30, d : new_name = 40} = { };
console.log(c); // 30
console.log(new_name); // 40

위와 같은 방법으로 변수명들에 할당 연산자(=)를 사용하여 기본값 할당을 할 수 있습니다.

5, 7번 줄처럼 객체에서 새로운 변수명에 할당하는 방식에도 기본값 할당을 사용할 수 있습니다.


  복사(copy)  

전개 연산자를 사용하여 배열, 객체의 깊은 복사를 할 수 있습니다.

var arr = [1,2,3];
var copy1 = arr;
var [...copy2] = arr;
var copy3 = [...arr];
arr[0] = 'String';
console.log(arr); // [ 'String', 2, 3 ]
console.log(copy1); // [ 'String', 2, 3 ]
console.log(copy2); // [ 1, 2, 3 ]
console.log(copy3); // [ 1, 2, 3 ]

얕은 복사인 copy1은 arr을 참조하기 때문에 0번 요소가 변경되었지만 전개 연산자를 사용한 copy2, copy3는 깊은 복사가 된 것을 볼 수 있습니다.


객체 역시 전개 연산자로 깊은 복사를 사용할 수 있습니다.

무엇보다도 강력한 점은 복사와 함께 새로운 값을 할당할 수 있다는 점 입니다.

var prevState = {
name: "yuddomack",
birth: "1996-11-01",
age: 22
};
var state = {
...prevState,
age: 23
};
console.log(state); // { name: 'yuddomack', birth: '1996-11-01', age: 23 }

위와 같이 ...prevState를 사용하여 기존 객체를 복사함과 동시에 age키에 새로운 값(23)을 할당할 수 있습니다.

리액트의 props나 state처럼 이전 정보를 이용하는 경우 유용하게 사용할 수 있습니다.



  함수에서의 사용  

함수의 파라미터 부분에서도 비구조화 할당을 사용할 수 있습니다.

이러한 문법은 특히 API 응답 값을 처리하는데에 유용하게 사용됩니다.

function renderUser({name, age, addr}){
console.log(name);
console.log(age);
console.log(addr);
}
const users = [
{name: 'kim', age: 10, addr:'kor'},
{name: 'joe', age: 20, addr:'usa'},
{name: 'miko', age: 30, addr:'jp'}
];
users.map((user) => {
renderUser(user);
});

마찬가지로 map함수의 파라미터에도 바로 사용할 수 있습니다.

const users = [
{name: 'kim', age: 10, addr:'kor'},
{name: 'joe', age: 20, addr:'usa'},
{name: 'miko', age: 30, addr:'jp'}
];
users.map(({name, age, addr}) => {
console.log(name);
console.log(age);
console.log(addr);
});



  for of 문  

뿐만 아니라 배열 내 객체들은 for of 문을 사용하여 비구조화 할 수 있습니다.

const users = [
{name: 'kim', age: 10, addr:'kor'},
{name: 'joe', age: 20, addr:'usa'},
{name: 'miko', age: 30, addr:'jp'}
];
for(var {name : n, age : a} of users){
console.log(n);
console.log(a);
}



  중첩된 객체 및 배열의 비구조화  

중첩된 객체 및 배열 역시 비구조화 할 수 있습니다.

const kim = {
name: 'kim',
age: 10,
addr: 'kor',
friends: [
{name: 'joe', age: 20, addr:'usa'},
{name: 'miko', age: 30, addr:'jp'}
]
};
var { name: userName, friends: [ ,{ name: jpFriend }] } = kim;
console.log(userName); // kim
console.log(jpFriend); // miko

friends 배열의 호출 변수를 명시하는 대신, 배열을 한번 더 비구조화한 모습이 시선을 강탈합니다.


출처 : https://yuddomack.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AC%B8%EB%B2%95-%EB%B9%84%EA%B5%AC%EC%A1%B0%ED%99%94-%ED%95%A0%EB%8B%B9


MSSQL - Cursor vs Temp Table

#테이블 변수사용의 예 use pubs go declare @tmptable table (     nid int identity(1,1) not null,     title varchar (80) not null ) -- 테이블 변수 선언 inse...