[BOJ] Python 백준 2447번 별 찍기-10 골드5

728x90

https://www.acmicpc.net/problem/2447

 

문제 풀이


해당 문제는 처음 반복문을 접할 때 풀어보는 별 찍기의 재귀버전이다.

 

3X3 크기의 한 패턴이 정해져 있고 크기가 증가할수록 같은 패턴이 반복되는 형태인데 처음엔 직관적으로 간단하게 생각해서 9 부분으로 나눠 각 Position에 대해 번호를 파라미터로 넘기고 해당 Position에 따라 별, 공백, 별 줄 바꿈 출력을 생각했으나 뜻대로 되지 않았다.

 

3X3 패턴이 출력되는 만큼 줄 바꿈도 같이 출력이 되었고 일정한 패턴의 확장이 아니라 그냥 패턴의 연속된 출력이었기 때문이다.

 

그래서 접근 방식을 다시 생각해봤다.

 

일단 3X3 패턴을 하나의 원소로 가정하고 3배씩 증가할 때마다 행과 열을 복사하는 방식이다.

 

패턴 복사 방법
패턴 복사 방법

 

위 사진처럼 직전의 패턴에 대해 증가할때마다 행을 3배로 복사하고 1,3번째 행은 열을 3배로, 2번째 행은 패턴의 길이만큼 공백을 넣어주면 된다.

 

파이썬은 리스트나 문자열의 복사가 상당히 쉬운 편이기 때문에 다행인 것 같다.

 

직전의 패턴에서 한 줄씩 문자열로 치환을 하면 나머진 구현에 어려움이 있을 것 같진 않다.

 

N=int(input())
# 하나의 별표에서 시작한다 가정
res=["*"]
def func(n):
    global res
    if n>3:
        func(n//3)
    # 행 X3
    res=res*3

    # 열 X3
    for i in range(len(res)//3):
        res[i]=res[i]*3
    # 열 + 공백 + 열
    for i in range(len(res)//3,len(res)*2//3):
        res[i]=res[i]+" "*len(res[i])+res[i]
    # 열 X3
    for i in range(len(res)*2//3,len(res)):
        res[i]=res[i]*3

func(N)
for i in range(len(res)):
    print(res[i])

 

재귀를 타면서 문자열 리스트를 공유해야 하기 때문에 결과 리스트를 전역변수로 공유하는 global을 사용했다.

 

필자는 이게 직관적이기에 사용했는데 각자 파라미터로 직접 데이터를 보내는 방식과 비교하여 본인이 편한 방식대로 구현하면 된다.

 

문제에서 입력 조건이 3 이상이기 때문에 조건문에 3 초과인 경우 재귀를 타도록 구현하였는데 제출하고 생각해 보니 애초에 res 리스트는 빈 리스트로 초기화하고 n == 1인 경우에 res 리스트를 별표 문자열 하나로 초기화 하는 방식이 다소 깔끔하지 않을까 생각이 든다.  

 

결과 화면

 

문제를 맞긴 했지만 처음에 다소 접근 방식에서 헤맸던 문제이다.

 

함수를 실행시켰을 때와 재귀를 타고 다시 실행했을 때의 실행결과를 고려하다 보니 스스로 발목을 잡는 것처럼 복잡하고 헷갈려서 재귀 문제는 최대한 같은 부분을 단순화시켜서 함수 그 자체가 실행하는 과정에 집중하는 연습과 경험이 필요한 것 같다.

728x90

댓글()

데이터 전처리를 위한 파이썬 Pandas 사용하기

취업 후 학습|2024. 2. 8. 11:51
728x90

데이터 분석을 하기 위해선 수집된 데이터(Raw Data)를 목적에 맞게끔 가공하는 작업이 필요하다.
 
순금을 뽑기 위해 불순물을 제거하는 것처럼 분석하고자 하는 목적에 맞는 데이터를 추출해야 보다 정확한 분석이 가능하기 때문이다.
 
Raw Data를 분석에 적합한 형태로 가공하는 작업을 전처리 작업이라고 하는데 이 전처리 작업에 유용한 라이브러리인 Pandas에 대해 데이터 분석과 시각화 관련된 공부를 하는 김에 정리하려고 한다.
 

Pandas란


Pandas는 데이터 조작과 분석을 위한 Python의 라이브러리이다.
 
데이터 구조는 Series와 DataFrame으로 구성되어 있다.

  • 시리즈(Series): 시리즈는 1차원 배열과 같은 데이터 구조로, 각각의 데이터에 인덱스가 부여되어 있다.
    예를 들어, 날씨 정보를 담은 시리즈에서는 날짜가 인덱스로 사용되고, 각 날짜에 해당하는 온도가 시리즈의 값으로 들어갈 수 있다.
  • 데이터프레임(DataFrame): 데이터프레임은 연속된 여러 시리즈로 엑셀과 같은 표 형식의 2차원 배열 데이터 구조다.
    예를 들어, 여러 날짜에 대한 온도, 습도, 강수량 정보를 담은 여러 시리즈를 합쳐서 데이터프레임으로 만들 수 있다.

Pandas를 이용하여 Data를 쉽게 로딩하고 정리, 분석, 시각화할 수 있으며 DB와 유사한 연산을 지원하기 때문에 Data를 편리하게 처리할 수 있다.
 
따라서 Pandas는 데이터 분석, 머신러닝, 통계 등 다양한 분야에서 사용된다.
 

Pandas 사용하기


Pandas를 설치하는 명령어는 다음과 같다.

pip install pandas
설치 완료 메시지
설치 완료 메시지

위 사진처럼 뜬다면 설치가 완료된 것이다.
 
각 함수를 사용한 결과를 보면서 어떤 상황엔 어떤 함수를 써야 하는지 알아보자.
 
1. 데이터 읽어오기
 
크게 엑셀에서 읽어오거나 직접 데이터를 입력하는 두 가지 방법이 있다.
 

user_data.xlsx
user_data.xlsx

위 사진과 같은 데이터가 있을 때 Pandas에서 사용하는 코드와 출력 결과는 다음과 같다.
 

import pandas as pd

# 엑셀 파일에서 데이터 읽어오기
excel_file_path = 'user_data.xlsx'

# csv파일일 경우
# df = pd.read_csv(excel_file_path, encoding='utf-8-sig')

# excel파일일 경우
df = pd.read_excel(excel_file_path)

# 읽어온 데이터 출력
print(df)

# 직접 데이터 입력
data = {'이름': ['홍길동', '김철수', '이영희','고길동'],
        '나이': [25, 30, 22, None],
        '직업': ['학생', None, '디자이너','개발자']}

# 데이터프레임 생성
df = pd.DataFrame(data)

# 생성한 데이터프레임 출력
print(df)

# 데이터 일부 확인
print("df.head(2)")
print(df.head(2))
print("df.tail(1)")
print(df.tail(1))

 

전체 데이터, 상단 2행, 하단 1행
전체 데이터, 상단 2행, 하단 1행

 
출력 결과를 보면 알 수 있듯이 엑셀처럼 2차원 배열 형태를 확인할 수 있고 첫 번째 행이 컬럼 명, 두 번째 행부터는 자동으로 인덱스가 붙어있다.
 
직접 데이터를 넣을 경우엔 딕셔너리의 키를 컬럼 명으로, 값을 데이터 리스트로 만든 후 DataFrame 함수의 파라미터로 넣으면 된다.
 
또한 데이터가 많을 경우 전체 출력을 하기 어렵기 때문에 데이터 구조나 예시 데이터를 확인하기 위해 head(), tail() 함수를 사용하면 된다.
 
Default는 5줄이고 파라미터에 넣은 숫자만큼의 행을 가져오기 때문에 SQL의 LIMIT과 같은 기능이다.
 

print("컬럼 명")
print(df.columns)

print("행, 열 크기")
print(df.shape)

print("데이터 정보 확인")
print(df.info())

print("요약 통계 확인")
print(df.describe())

 
각각의 출력 결과는 다음과 같다.
 

출력 결과

 
컬럼명과 행열의 크기, 데이터들의 대략적인 요약, 숫자 데이터들의 통계를 확인할 수 있다.
 
이를 이용해 행렬의 크기와 non-null의 Count를 비교해서 데이터가 없는(Null 값인) 부분이 있다면 차후에 계측값 제거를 통해 가공해야겠다는 생각을 할 수 있다.
 
Data Frame에서 특정 컬럼을 선택하여 Series를 추출할 수 있는데 컬럼 하나를 추출할 때와 여러 개를 추출할 때의 파라미터 값을 잘 확인해야 한다.
 

print("열 선택")
selected_column = df['나이']
print(selected_column.head())
print(selected_column.size, selected_column.count())
selected_columns = df[['이름', '나이']]
print(selected_columns.head())
print(selected_columns.size)
print(selected_columns.count())
print(selected_columns.value_counts())
출력 결과

 
단일 컬럼 선택 시 문자열 하나만 들어가지만 복수 컬럼 선택 시 리스트 형태의 컬럼명을 파라미터로 보내며 Count 관련 함수는 Null 값이 들어간 행을 제외하고 세기 때문에 Law Data에서 자신에게 필요한 데이터만 추출하면 유용하게 사용할 수 있다.
 

print('조건식을 이용한 열 선택')
selected_column = df[df['이름'] == "홍길동"]
print(selected_column.head())
출력 결과

 
특히 특정 조건에 해당하는 데이터를 추출하려면 컬럼 선택 값으로 추출하고자 하는 조건식을 사용하면 된다.
 
이를 이용하면 특정 나이대, 특정 지역에 해당하는 데이터를 추출할 수 있다.
 

print("Null 값이 있는 데이터 갯수")
print(df.isnull().sum())
print("Null값을 제거한 데이터")
print(df.dropna())
print("직업의 Null값을 제거한 데이터")
print(df.dropna(subset=['직업']))
출력 결과

 
isnull() 함수는 데이터가 Null인 경우 True를 반환하는데 Sum()을 통해 합계를 구함으로써 Null값을 카운트하는 효과를 낼 수 있다.
 
또한 dropna()는 데이터가 Null인 행을 제거한 데이터를 반환하며 파라미터로 특정 컬럼의 Null 값만 제거할 수 있기 때문에 항상 Law Data를 다루기 전 dropna()를 사용하여 빈 값이 있으면 안 되는 컬럼의 데이터를 제거하는 게 좋을 것 같다.
 

print("Null값 채우기")
print(df.fillna({'나이' : 0 , '직업' : '없음'}))
출력 결과

 
반대로 Null 값을 일괄적으로 채워야 할 때가 있는데 fillna() 함수를 사용하면 된다.
 
한 가지 값으로 채울 수 있다면 해당 값만 파라미터로 보내면 되지만 컬럼마다 초기화해야 하는 값이 다르다면 딕셔너리 형태로 Key는 컬럼명, Value는 Data 값으로 설정하면 위 사진처럼 채워진다.

728x90

댓글()

MSSQL 테이블 변수, 임시 테이블 사용하기

취업 후 학습|2023. 12. 4. 17:49
728x90

실무에서 파트너사 알림톡 발송을 위해 대량의 데이터를 반복 Insert 할 일이 생겼는데 초기에 생각보다 시간이 너무 오래 걸려 효율적인 방법을 찾던 중 테이블 변수와 임시 테이블에 대해 알게 되어 정리할 겸 작성하기로 했다.

 

Join으로 조회한 데이터들을 While문을 통해 Row 접근으로 Update, Insert를 반복하는 작업인데 테이블 변수와 임시 테이블을 모르고 비효율적인 쿼리로 실행했을 땐 필요한 Data를 While문 안에서 계속 Join 하며 Select 했더니 아래 표처럼 기하급수적으로 시간이 늘어났다.

 

발송 Data Row 수 톡 발송 완료시간
50개 18초
100개 1분 10초
200개 4분 10초
300개 9분 20초
600개 37분 40초

 

시작한 직후엔 1초당 3개씩 발송하더니 시간이 갈수록 1초에 1개, 2초에 1개.... 이런 식으로 점점 딜레이가 됐었다.

 

운영계 DB에 불필요한 테이블을 만들지 않으려다 보니 이러한 결과가 나왔는데 테이블 변수나 임시 테이블을 사용하니 시간은 획기적으로 줄어들었다.

 

여담이지만 필요한 데이터를 파이썬으로 생성했더니 참 편한 것 같다.

 

테이블 변수


테이블 변수는 조회한 테이블 형태의 값들을 변수에 저장하는 것을 뜻한다.

 

변수이기 때문에 일반 변수와 동일하게 DECLARE로 "@"를 붙여 선언하고 메모리에 생성되기 때문에 쿼리가 실행되는 함수, 프로시저 안에서만 일시적으로 유효하다.

 

-- 테이블 변수 선언
DECLARE @TEMP_TABLE_NAME TABLE(
    -- 컬럼 선언
    COL1 VARCHAR(10),
    COL2 INT
)

-- 기존 테이블 전체 테이블 변수로 복사
INSERT INTO @TEMP_TABLE_NAME
SELECT * FROM ORIGIN_TABLE;

-- Join한 결과에서 특정 컬럼만 테이블 변수로 복사
INSERT INTO @TEMP_TABLE_NAME
SELECT A.COL1, A.COL2, B.COL1, B.COL2 FROM ORIGIN_TABLE_1 AS A
INNER JOIN ORIGIN_TABLE_2 AS B
ON A.COL1 = B.COL1;

-- 조회 예시
SELECT * FROM @TEMP_TABLE_NAME;

 

장점

  • 임시 테이블보다 빠르게 작동하며, 디스크 I/O를 줄일 수 있다.
  • 트랜잭션 로그에 기록되지 않으므로 롤백이 필요하지 않다.
  • 저장 프로시저, 함수, 트리거 등에서 사용할 수 있다.
  • 컴파일 시점에 결정되므로, 재컴파일을 유발하지 않는다.

단점

  • 통계를 생성하지 않아, 쿼리 최적화에 영향을 줄 수 있다.
  • 인덱스를 생성할 수 없으므로, 대량의 데이터를 처리하는 데는 부적합하다. (100건 이상의 데이터 사용 시 성능 저하)
  • 세션 간에 공유할 수 없다.
  • ALTER TABLE 명령을 사용하여 구조를 변경할 수 없다.

 

임시 테이블


임시 테이블은 일시적으로 데이터를 저장하고 조작하는 데 사용하는 테이블이며 시스템 DB인 tempdb에 저장된다.

 

테이블이기 때문에 CREATE을 사용하고 "#"을 붙여 임시 테이블을 선언한다.

 

이때 "#"지역 임시 테이블을 뜻하고 테이블 변수와는 다르게 "##"을 통한 전역 임시 테이블 선언이 가능하다.

 

즉, 전역 선언을 통해 사용자 본인의 다른 Session에서도 접근이 가능하다.

 

명시적으로 삭제하지 않더라도 DB와 연결된 Session이 종료되면 자동으로 삭제되며 전역 임시 테이블의 경우 마지막 Session이 종료되면 삭제되기 때문에 실무에서 테이블 조작하기 편하게 해주는 것 같다.

 

주로 복잡한 쿼리를 단순화하거나 중간 결과를 저장하고 여러 프로시저에서 결과를 공유하는 용도로 사용한다.

 

-- 지역 임시 테이블 선언 ('#' 한 개)
CREATE TABLE #TEMP_TABLE_NAME (
    -- 컬럼 선언
    COL1 VARCHAR(10),
    COL2 INT
)

-- 전역 임시 테이블 선언 ('#' 두 개)
CREATE TABLE ##TEMP_TABLE_NAME (
    -- 컬럼 선언
    COL1 VARCHAR(10),
    COL2 INT
)
-- 기존 테이블 전체 테이블 변수로 복사
INSERT INTO #TEMP_TABLE_NAME
SELECT * FROM ORIGIN_TABLE;

-- Join한 결과에서 특정 컬럼만 테이블 변수로 복사
INSERT INTO #TEMP_TABLE_NAME
SELECT A.COL1, A.COL2, B.COL1, B.COL2 FROM ORIGIN_TABLE_1 AS A
INNER JOIN ORIGIN_TABLE_2 AS B
ON A.COL1 = B.COL1;

-- 조회 예시
SELECT * FROM #TEMP_TABLE_NAME;

 

장점

  • 복잡한 쿼리를 단순화하고, 중간 결과를 저장하여 데이터 처리를 더 효율적으로 만들 수 있다.
  • 큰 데이터 세트를 작은 부분으로 분할하여 처리하면 성능이 향상될 수 있다.
  • 쿼리의 중간 결과를 확인하고 문제를 디버깅하는 데 도움이 된다.
  • 사용자 세션별로 생성되므로 다른 사용자가 접근할 수 없어 보안에 좋다.

단점

  • 트랜잭션 로그에 기록되므로, 많은 양의 데이터를 처리하면 로그 크기가 커질 수 있다.
  • 디스크 I/O 작업에 대한 Overhead가 존재한다.
  • 저장 프로시저 내부에서 실행할 때마다 재 컴파일이 발생한다.

 

적은 데이터(100건 이하)는 테이블 변수가 더 빠를 수 있지만 많은 데이터(100건 이상)는 임시 테이블이 성능적으로 유리하다.

 

필자는 애초에 비효율적인 쿼리였기 때문에 저장 프로시저 수정, 임시 테이블 적용, Update 필요 없는 행 로직 수행 제외 등 여러 차례에 걸쳐 튜닝한 결과 상당한 시간 단축을 이루었다.

 

다음은 데이터 1000건 기준의 테이블 변수와 임시 테이블 적용 후 알림톡 발송 실행 시간이다.

 

테이블 변수 실행 시간
테이블 변수 실행 시간 (24초)
임시 테이블 실행 시간
임시 테이블 실행 시간 (18초)

 

단일 Insert로는 최대 1000행이 가능하기 때문에 1000행을 기준으로 잡았으며 임시 테이블이 테이블 변수보다 25%가량 시간 단축 된 것을 확인할 수 있었다.

 

여태까진 쿼리에 대한 큰 고민을 하지 않은 것 같아 이번 경험을 계기로 끊임없이 고민하고 개선시키려 노력해야겠다.

728x90

댓글()

[PDF 전자책] 파이썬을 이용한 업무 자동화 프로그램 만들기

728x90
파이썬을 이용한 업무 자동화
Thumbnail

일을 하다 보면 생각보다 자주 단순 반복작업을 하게 되는 경우가 있습니다.
 
때에 따라서 많은 데이터를 수집해야 할 수도 있고 주기적으로 메일을 보낸다거나 엑셀 파일의 수많은 데이터를 수정해야 할 수도 있습니다.
 
사람이 동시에 할 수 있는 일의 양과 그에 따른 시간은 한정적이기 때문에 단순 반복 작업을 자동화시킨다면 그만큼 낭비되는 시간을 아껴 업무 효율화를 추구할 수 있습니다.
 
마치 공장에서 일련의 프로세스들을 자동화 기계를 통해 비용과 시간 대비 생산량을 극대화시키듯, 정해진 패턴이 있고 비교적 많은 시간을 요구하는 작업이라면 컴퓨터를 통해 빠르고 효과적으로 처리할 수 있습니다.
 
물론 기본적으로 특정 기능을 하는 프로그램이 아니라 직접 프로그래밍을 통해 자신이 원하는 기능을 구현하는 것이기 때문에 Python 혹은 최소한 하나의 프로그래밍 언어에 익숙하고 자신의 생각을 코드로 나타낼 수 있는 역량이 필요합니다.
 
만약 코드를 직접 구현할 자신이 없다면 언어와 관련된 학습은 구글링을 통해 쉽게 집약된 자료를 찾을 수 있고 자신의 생각을 코드로 나타내는 부분은 알고리즘 연습을 통해 충분히 독학 가능하다고 생각합니다.
 
https://kmong.com/knowhow/gig/290286

전문가가 필요한 순간, 프리랜서 마켓 No.1 크몽

마케팅·디자인·IT프로그래밍·영상 등 다양한 비즈니스 분야의 전문가를 만나보세요!

kmong.com

 
알고리즘 같은 경우, 집약된 자료를 찾기 힘들어 정리할 겸 과외 경험을 살려 최대한 이해하기 쉽게 작성했으며 반응도 좋았기에 충분히 도움 될 것이라 생각합니다.
 
자동화 프로그램을 작성하는데 자신의 상황에 맞게 로직을 구성하고 해당 논리를 그대로 코드로 구현할 수준이면 되기 때문에 굳이 어려운 알고리즘을 학습할 필요가 없어 부담 갖지 않으셔도 됩니다.
 
이를 통해 기본적인 프로그래밍에 대한 역량을 갖췄다면 이젠 실 생활에 적용하여 소위 말하는 "일잘러"로 거듭나는 일만 남았습니다.
 
실제로 저도 취준생 때 재밌을 것 같아 직접 구현해 보고 이를 프로젝트에 적용하여 팀원들에게 좋은 평가를 받았었고 면접에서도 강점으로 어필하였으며 실무에서도 효율적인 업무가 가능했습니다.
 
또한 전자책을 완성한 직후 평가를 위해 지인과 직장 선배들에게 공유했었는데 일관되게 긍정적인 피드백을 받았습니다.
 
아무래도 소비자분들께 판매를 하는 전자책이기 때문에 저 스스로가 완벽하다고 생각하지 않으면 서비스를 올려두지 않습니다.
 
관심 있으신 분들은 아래 링크를 통해 어떤 내용들이 있는지 확인해 보고 고민해 보시는 것을 추천드립니다.
 
https://kmong.com/knowhow/gig/490311

전문가가 필요한 순간, 프리랜서 마켓 No.1 크몽

마케팅·디자인·IT프로그래밍·영상 등 다양한 비즈니스 분야의 전문가를 만나보세요!

kmong.com

 
만약 구매하신 분들 중에서 날카로운 피드백을 크몽을 통해서나 블로그 댓글로 남겨주신다면 적극 수용, 반영하고 수정된 내용들을 다시 드리도록 하겠습니다.

728x90

댓글()

스프링 Annotation(어노테이션) 정리

취업 후 학습|2023. 6. 28. 16:01
728x90

업무를 하면서 다양하고 많은 Annotation에 대한 이해가 부족해 정리하고자 작성하기로 했다.

 

Lombok Annotation


@Setter

Class의 모든 필드에 해당하는 Setter 메서드 생성

 

@Getter

Class의 모든 필드에 해당하는 Getter 메서드 생성

 

@ToString

Class의 모든 필드에 해당하는 ToString 메서드 생성

 

@NoArgsConstructor

Class의 기본 생성자 추가

 

@RequiredArgsConstructor

Final이나 @NonNull인 필드만 파라미터로 받는 생성자 추가

 

@AllArgsConstructor

Class의 모든 필드 값을 파라미터로 받는 생성자 추가

 

@EqualsAndHashCode

Equals와 HashCode 메서드를 오버라이딩 하는 어노테이션

 

@Data

@Setter, @Getter, @ToString, @NoArgsConstructor 등 Lombok에서 제공하는 필드와 관련된 모든 코드 추가 (모든 기능 사용 가능하므로 Risk 존재해서 사용하지 않는 게 좋음)

 

JPA Annotation


@Entity

실제 DB 테이블과 매핑될 Class

 

@Table(name = "")

실제 DB의 name에 해당하는 테이블과 매핑(생략할 경우 Class명과 테이블명 매핑)

 

@Id

해당 테이블의 PK 필드

 

@Column(name = "")

name에 해당하는 컬럼과 매핑(생략할 경우 필드명과 컬럼명 매핑)

 

Spring Annotation 


@Controller

해당 Class는 Controller란 것을 명시하고 Spring에서 Bean으로 등록 (Bean이란 Spring에서 관리하는 자바 객체)

 

@Service

해당 Class는 비즈니스 로직을 수행하는 Service란 것을 명시하고 Spring에서 Bean으로 등록

 

@Repository

해당 Class는 DAO인 것을 명시하고 Spring에서 Bean으로 등록 (Spring에서 지원하지 않는 Exception을 Spring Exception으로 전환)

 

@Component

해당 Class는 Component란 것을 명시하고 Spring에서 Bean으로 등록 (@Controller, @Service, @Repository의 상위 어노테이션이므로 3가지 전부 @Component으로 대체 가능)

 

@Bean

개발자가 제어 불가능한 외부 라이브러리 등을 Bean으로 등록

 

@ComponentScan

@Component, @Controller, @Service, @Repository 가 부여된 Class 들을 검색해서 Bean으로 등록

 

@RequestMapping(value = "")

URI의 요청이 value와 일치할 경우 해당 클래스나 메서드 실행

 

@RequestParam(value = "", required = false)

메서드 파라미터 앞에 쓰며 Http 요청의 파라미터 값(value)을 메서드 파라미터로 받음

required 옵션의 Default는 true이며 true일 경우 해당 파라미터가 없을 때 400 에러 발생

 

@RequestBody

메서드 파라미터 앞에 쓰며 Http 요청의 Body를 자바 객체로 변환해서 매핑된 메서드 파라미터로 전달

 

@RequestHeader(value = "")

메서드 파라미터 앞에 쓰며 Request의 Header값을 메서드의 파라미터로 받는 어노테이션

 

@ResponseBody

자바 객체를 Http 요청의 Body로 변환(content-type을 application/json으로 설정 필요)

 

@RestController

@Controller와 @ResponseBody를 합친 어노테이션

 

@ModelAttribute

View단에서 전달하는 파라미터를 메서드의 파라미터로 변환해 주는 어노테이션(태그의 name과 클래스의 멤버 변수명, Set 메서드명 일치)

 

@GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping

각 Get, Post, Put, Delete, Patch 요청에 대한 Annotation

 

@Valid

파라미터 객체 앞에 쓰며 유효한 객체인지 검사

 

@CookieValue(value = "", required = false)

쿠키의 value 값을 받아오며 required의 Default는 true

required = false를 사용하지 않은 상태에서 해당 쿠키값이 존재하지 않다면 500 에러를 발생시키고 사용하면 존재하지 않을 때 null로 받음

 

@Lazy

Class가 실제 사용될 때 Spring에서 Bean등록을 하게 되는 지연 로딩

 

@Autowired

Field, Setter, Constructor 3가지에 사용하며 Type에 따라 Bean을 주입

 

@Qualifier("id")

@Autowired와 같이 쓰며 같은 타입의 Bean 객체가 있을 경우 명시된 ID로 원하는 Bean을 주입하는 어노테이션

 

@PathVariable

메서드 파라미터 앞에 쓰며 URI에서 특정 값을 메서드 파라미터로 받아오는 어노테이션

특정 값은 URI에서 {}로 감싸고 파라미터 명과 같음

 

@Transactional

메서드 내부의 DB 트랜잭션 설정하는 어노테이션

 

@Scheduled(cron = "")

Cron 표현식에 의한 정해진 시간에 메서드를 실행시키는 어노테이션

 

@Test

Junit에서 테스트할 대상으로 지정

728x90

댓글()

스프링이란? 스프링과 스프링 부트의 차이점은?

취업 후 학습|2023. 6. 20. 14:26
728x90

이미 Spring Boot를 이용한 웹 업무를 하고 있지만 유지보수 수준이기 때문에 구체적인 이해가 부족한 듯싶어 처음부터 정리할 겸 작성하기로 했다.

 

Spring 이란?


Spring은 Java 개발을 편하게 해주는 프레임워크이며 웹 MVC 모듈을 제공하여 동적인 웹을 효과적으로 제작할 수 있다.

 

또한 ORM(JPA, Mybatis)과 같은 모듈들을 보다 편하게 사용할 수 있다는 장점이 있다.

 

이때 ORM은 Object Relational Mapping의 약자로 객체와 관계형 데이터 베이스의 데이터를 자동으로 Mapping 해주는 것을 뜻한다.

 

추가적으로 https://start.spring.io/ 해당 사이트에서 초기 프로젝트를 생성하는 서비스를 제공하기도 한다.

 

Spring은 자바 객체의 생명 주기를 관리하기 때문에 사용자는 컨테이너에서 필요한 객체를 가져와 사용만 하면 된다는 편리함이 있으며 대표적인 특징으로는 DI, IOC가 있다. 

 

DI는 Dependency Injection(의존성 주입)의 약자로 어떤 객체를 사용하는 주체가 객체를 직접 생성하는 것이 아니라 Spring에서 생성한 객체를 주체에게 주입시켜 주는 방식을 뜻한다.

 

객체를 직접 생성하게 되면 수정 사항이 생길 때마다 수정할 부분이 많아지는데(의존성이 높아지는데) Spring에서 생성하게 되면 Interface를 기반으로 관리하기 때문에 수정할 부분이 줄어든다(의존성이 낮아진다).

 

이때 Interface를 사용하는 이유는 Controller 단에서 직접 Service를 바라보는 게 아닌 Interface를 바라보고 있는데 Interface에 대한 실제 구현체가 Service단에 있으므로 Runtime 직전까지는 실제 구현체를 알지 못한다.

 

따라서  Controller 단에서는 실제 비즈니스 로직에 대해 알 필요가 없고 Interface의 메서드로만 로직을 구성하면 된다.

 

반대로 Service 단에서는 Interface의 규칙만 잘 지킨다면 언제든 로직 변경이 가능하고 새로운 클래스로 대체도 가능하기 때문에 의존성이 낮아져 확장성이 높다는 장점이 있다.

 

IOC는 Inversion Of Control(제어의 역전)의 약자로 간단하게 말하자면 사용자의 제어권을 Spring에게 넘기는 것을 뜻한다.

 

일반적인 Java Programming의 흐름은 사용자가 직접 객체를 생성하고 메서드를 호출하는 방식이었지만 Spring에서는 Spring이 객체를 생성하고 주입하여 객체의 메서드를 호출하는 방식이다.

 

따라서 Spring이 실행될 때 모든 의존성 객체를 생성하고 필요한 곳에 주입해 준다.

 

Spring과 Spring Boot의 차이점


결론부터 말하자면 Spring Boot는 Spring의 복잡성을 줄인 업그레이드 버전이라고 생각하면 된다.

 

Spring은 Dependency 설정을 위해 https://mvnrepository.com/ 같은 곳에서 일일이 찾아야 하고 버전 관리도 직접 해야 해서 번거롭고 복잡하지만 Spring Boot는 spring-boot-starter를 통해 자동으로 설정할 수 있어 훨씬 더 짧은 시간에 비교적 간단하게 실행할 수 있다.

 

또한 Spring은 주로 maven 기반의 Java Application을 만드는 데 사용하지만 Spring Boot는 Gradle 기반의 REST API 개발에 사용하며 톰캣 같은 WAS가 내장되어 있어 쉽게 Web Application 구동이 가능하며 실행 가능한 JAR 파일 생성도 가능하여 자바 옵션만으로 쉽게 배포가 가능하다.

 

정리하자면 Spring은 프레임워크를 보다 세밀하게 제어하는 경우, Spring Boot는 빠르게 간단하게 Application 개발을 하는 경우에 적합하다.

 

 

728x90

댓글()

리액트 data.map is not a function 에러 해결

취업 후 학습|2023. 5. 3. 10:49
728x90

리액트에서는 return 문에서 JSX를 사용하기 때문에 직접적으로 for문과 같은 반복문을 사용하지 못한다.

 

굳이 사용하자면 JSX를 반환하는 함수를 선언하고 그 안에 반복문을 사용할 순 있겠지만 코드가 짧아질수록 편의성이 증가하므로 주로 map을 쓰는 편이다.

 

map 함수 에러
map 함수 에러

하지만 종종 위와 같이 map is not a function 에러가 나타나는 경우가 있다.

 

문제는 두 가지 경우로 나눌 수 있는데 첫 번째는 data 부분이 배열이 아닌 경우고, 두 번째는 data 변수가 배열로 데이터를 받기 전 렌더링이 되었을 경우다.

 

map 함수는 배열에 접근하기 위한 자바스크립트의 내장 함수이기 때문에 배열이 아닌 데이터(특히 객체)에 map을 사용할 경우 문제가 발생한다.

 

따라서 콘솔에 해당 변수를 찍어보면 배열이 아닌 경우가 대다수일 것이다.

 

하지만 간혹 가다 분명히 배열이 맞는데 위와 같은 에러가 나오는 경우가 있다.

 

이것은 두 번째 케이스인 변수가 배열의 데이터를 받기 전에 렌더링 되었을 경우다.

 

물론 useState([])처럼 빈 배열로 초기화하면 되지만 상황에 따라 불가능한 경우도 있을 것이다.

 

그럴 땐 데이터를 받아왔을 때만 컴포넌트를 렌더링 하면 된다.

 

즉, 문제 되는 변수가 data 라면 {data && data.map()}처럼 data 변수에 값을 받아왔을 때만 map 함수를 실행시키도록 변경하면 문제는 해결된다.

 

이때 중괄호({})로 감싸주는 것을 잊으면 안 된다.

 

 

=====  리액트를 처음으로 접해서 공부할 겸 정리한 것이라 적극적인 피드백 환영합니다!! =====

728x90

댓글()

파이썬 Pyautogui로 매크로 만들기

취업 후 학습|2023. 2. 26. 18:54
728x90

파이썬은 인터프리터 언어라 컴파일 언어에 비해 비록 느리지만 사용자 친화적으로 쉬운 구문과 광범위한 응용 프로그램에 사용할 수 있단 장점이 있다.

 

특히 강력한 라이브러리로 데이터 분석, AI, 자동화 등에 강점을 보이는데 이번에는 자동화(매크로)에 자주 쓰이는 Pyautogui에 대해 알아보자.

 

시작 전에 처음 들어봤거나 확실하게 알지 못하는 사람들을 위해 매크로가 무엇인지 알아보자.

 

매크로란 컴퓨터 과학 분야에서 정해진 순서에 따라 특정한 입력 시퀀스가 출력 시퀀스를 정의하는 규칙이나 패턴을 말한다. (출처 : 위키백과)

 

즉, 쉽게 풀어서 말하자면 정해진 반복 작업을 컴퓨터가 수행하는 것이다.

 

특히 게임이나 티켓팅, 수강신청 등에서 매크로란 단어를 많이 접했을 텐데 이들의 공통점이 정해진 위치를 반복적으로 이동, 클릭, 입력한다는 점이다.

 

로직만 잘 구성한다면 불필요한 반복 작업을 컴퓨터에게 대신시킬 수 있기 때문에 아주 유용한 스킬이다.

 

Pyautogui 사용하기


그럼 Pyautogui를 설치해 보자.

 

필자는 윈도우 환경이며 Visual Studio Code를 사용하기 때문에 터미널에 바로 입력하면 된다.

 

Pyautogui 설치 로그
Pyautogui 설치 로그

 

명령어는 pip install pyautogui이고 위 사진처럼 Successfully installed 로그가 찍힌다면 설치가 완료된 것이다.

 

이제 Pyautogui를 설치했으니 관련 함수들을 알아보자.

 

함수들은 크게 마우스, 키보드, 이미지 관련 함수로 나눌 수 있는데 상당히 함수가 많기 때문에 그중에서도 자주 쓰일만한 함수들만 정리했다. 

 

특히 빨간 표시는 생략 가능한 옵션을 뜻한다.

 

 마우스 관련 함수
 position()  마우스의 현재 위치 좌표 출력
 mouseInfo()  마우스의 죄표, RGB Color 등 관련 정보
 moveTo(x, y, n)  좌표 (x, y)로 n 초 동안 이동
 dragTo(x, y, n)  좌표 (x, y)로 n 초 동안 드래그
 click(button=’right’)  왼쪽 클릭 (오른쪽 클릭)
 click(clicks=n, interval=t)  왼쪽 클릭 (t초 간격으로 n번 클릭)
 doubleClick()  왼쪽 더블 클릭
 scroll(x)  x만큼 스크롤 이동(양수면 위, 음수면 아래)
 키보드 관련 함수
 write(‘String’, interval=n)  영어 문자열을 n초 마다 입력 (한글 지원 X)
 keyDown(‘key’)  key에 해당하는 키를 누름
 keyUp(‘key’)  key에 해당하는 키를 뗌
 press([‘key’], presses=n, interval=t)  리스트에 있는 키를 t초에 한 번씩 n 입력
 hotkey(‘key1’, ’ key2’)  key1, key2 입력
 KEYBOARD_KEYS  입력 가능한 키 리스트
 이미지 관련 함수
 screenshot(‘test.png’, region=(x1, y1, x2, y2))  스크린샷 이미지 객체 반환, test.png 명으로 파일 저장, (x1, y1) 부터  (x2, y2)까지의 영역
 locateOnScreen(‘test.png’)  test.png 와 일치하는 영역 반환(left, top, width, height)
 locateAllOnScreen(‘test.png’)  test.png 와 일치하는 모든 영역 반환(left, top, width, height)
 locateCenterOnScreen(‘test.png’)  test.png 와 일치하는 영역의 중앙 좌표 반환
 기타 함수
 size()  주 모니터 크기 반환(width, height)
 countdown(n)  n초 동안 카운트 다운하며 각 숫자를 출력
 PAUSE = t  각 함수별 t초 딜레이(Default = 0.1초)

 

특히 매크로는 정해진 좌표를 반복 클릭하기 때문에 구현 단계에서 좌표를 얻을 수 있는 mouseInfo()가 상당히 유용한 함수다.

 

주의해야 할 점은 키보드 관련 함수에서 알파벳키를 입력하고 실제 입력 상황에서 한글로 되어 있다면 상관없지만 write로 직접 한글 입력은 지원하지 않기 때문에 한글 입력을 위해선 편법을 위한 추가 사항이 조금 필요하다.

 

바로 pyperclip을 설치해서 클립보드에 한글을 복사 후 붙여 넣기 하는 방식이다.

 

명령어는 pip install pyperclip이며 pyautogui를 설치할 때처럼 동일하게 하면 된다.

 

import pyperclip, pyautogui

# 클립보드에 한글 문자열 복사
pyperclip.copy('한글 입력 테스트')

# ctrl + v 로 붙여넣기
pyautogui.hotkey('ctrl', 'v')

 

설치 후 위 코드처럼 작성하면 한글을 입력하는 듯한 효과를 볼 수 있다.

 

모든 함수를 사용한 예제를 보기엔 너무 방대하므로 간단하게 특정 위치를 반복 클릭하는 매크로와 임시 비밀번호를 생성해서 저장하는 예제를 살펴보자.

 

반복 클릭 매크로


import pyautogui

# 첫 시작 위치로 이동
pyautogui.moveTo(334, 351)

# 시작 위치에서 마우스가 벗어나면 반복 중지
while pyautogui.position().x == 334 and pyautogui.position().y == 351:
    pyautogui.click()
    pyautogui.moveTo(320, 446)
    pyautogui.click()
    pyautogui.moveTo(334, 351)

 

위 코드는 특정 위치를 무한 반복 클릭하는 코드다.

 

이때 주의해야 할 점은 마우스를 다루기 때문에 딜레이나 무한 루프를 탈출할 조건을 사용하지 않을 경우 이도저도 못하는 난감한 상황이 발생할 수 있다.

 

해당 예제에서는 시작 위치를 정하고 마우스가 위치를 벗어날 경우 프로그램을 종료하도록 작성했다.

 

위와 같은 로직으로 미리 mouseInfo() 함수를 이용해서 좌표 정보를 얻고 작성하면 빠르게 반복 클릭할 수 있다.

 

임시 비밀번호 생성 후 저장


import pyautogui, random, time

# 길이가 8인 소문자 임시 비밀번호 생성
def temp_pw():
    pw = ''
    for i in range(8):
        pw += chr(random.randrange(97,123))
    return pw

# 메모장 위치
pyautogui.moveTo(496, 423)
pyautogui.doubleClick()

# 메모장이 켜질때까지 대기
time.sleep(1)

# 메모장에 커서 생성
pyautogui.moveTo(604, 713)
pyautogui.click()

# 5개의 임시 비밀번호 생성
for i in range(5):
    pyautogui.write(temp_pw()+'\n')

# 저장
pyautogui.hotkey('ctrl', 's')

# 메모장 종료
pyautogui.hotkey('alt', 'f4')

 

필자는 임시 비밀번호를 저장하기 위한 메모장을 생성했었고 해당 위치 좌표로 이동 후 더블 클릭으로 켰다.

 

너무 속도가 빨라 엉뚱한 곳을 클릭하는 것을 방지하기 위해 메모장이 켜질 때까지 대기하려 time.sleep(1)을 했다.

 

메모장이 켜지면 커서를 생성하기 위해 한번 클릭을 했고 소문자로 이루어진 8자리 임시 비밀번호를 저장 후 종료하는 로직이다.

 

이처럼 파이썬의 자동화 도구를 잘 사용하면 불필요한 반복 작업을 컴퓨터에게 시킬 수 있어 상당히 편리하고 개인에게 강력한 무기가 될 수 있다고 생각한다.

 

필자도 종종 필요한 경우 자동화 코드를 작성해서 편리했고 이를 본 주위 사람들이 신기해했던 경험이 있기 때문이다.

 

차후에 단순한 마우스, 키보드 자동화 말고도 엑셀 파일처럼 업무 자동화에 대해서도 가능한 자세히 포스팅하도록 하겠다.

728x90

'취업 후 학습' 카테고리의 다른 글

스프링이란? 스프링과 스프링 부트의 차이점은?  (0) 2023.06.20
리액트 data.map is not a function 에러 해결  (0) 2023.05.03
jQuery로 요소 찾기  (0) 2023.01.03
SAP ERP란  (0) 2022.09.29
Git Branch 전략  (0) 2022.08.17

댓글()