TortoiseSVN 을 사용할 경우.

Tortoise SVN을 사용할 경우 
 
command로 실행하는 방법은 크게 2가지 이다.
 
1.svn.exe를 이용하는 방법
2.TortoiseProc.exe를 이용하는 방법
 
 

1. SVN Command

 

svnadmin dump

   - 저장소 백업

   - svnadmin dump [저장소 폴더명] > [덤프 파일명]

   - ex) svnadmin dump project_sample > dump_project_sanmple_20010131

 

svnadmin load

   - 저장소 복원

   - svnadmin load [저장소 폴더명] < [덤프 파일명]

   - ex) svnadmin create project_sample

           svnadmin load project_sample < dump_project_sanmple_20010131

 

svn checkout

   - svn 서버에서 소스 내려받기

   - svn checkout svn://192.168.2.2/App App

   - svn checkout -r 100 svn://192.168.2.2/App App   (revision 100번 소스 받기)

   - svn checkout -r HEAD svn://192.168.9.128/sample_repos sample_HEAD     (마지막 리비전 받기)

   - 자세한 것은 svn checkout --help 참고

 

svn export

    - 버전관리 정보 없는 깨끗한 사본을 받아옴
    - svn export --help
    - svn export -r 1 svn://192.168.0.12/sample_repos sample_pos
 

svn commit 파일명 or 폴더명 or ./

   - svn commit 했을 때 소스 파일에서 out of date 에러 날 때는 그 사이에 svn에 소스가 업데이트 됬다는 의미이다. 따라서, out of date 에러났을 때는 svn update을 실행해서 동기화를 한 후에 commit을 하면 된다.

   - commit 하기전에는 update를 실행하여 out of date 에러를 막자.

   - 예)

      # svn commit

      # svn commit ./test/test.h

 

svn resolved -R ./
   - 소스 충돌 날 때 이놈으로 풀면 됨.


svn cleanup
   - 소스가 lock 되 있을 경우 이 명령으로 해제 한다. lock 되는 원인은 알아서 찾는다.

 

svn update

   - 서버와 소스 동기화.

      A  Added

      D  Deleted

      U  Updated

      C  Conflict

      G  Merged

      E  Existed

   - commit 하기전에는 소스 충돌을 막기 위해 update를 실행해야 한다.

   - update를 했는데 에러가 났을 경우에는 각각의 revision을 따로 update 해본다. 경험상 한번에 할 경우에 드물게 에러가 나는 경우가 있다.

      #svn update -r 100   --> 100은 revision number

      #svn update -r 101

 

svn log

   - svn user가 commit한 로그 볼 때 사용한다.

      # svn log svn://192.168.9.128/sample_repos     ==> 주의) svn path를 안주면 마지막 로그를 빼먹는다.

        # svn log -l 10   (상위 10개의 로그만 보기)       ==> 주의) svn path를 안주면 마지막 로그를 빼먹는다.

      # svn log -l 10 svn://192.168.9.128/sample_repos

    

   - commit log 수정하기

      # svn propset --revprop -r [리비전번호] svn:log “수정할 메세지”

       참고: http://altistory.net/929

      # TortoiseSVN 사용할 때 show log 선택 후에 로그 패널에서 마우스 오른쪽 버튼 클릭하면 "Edit log message" 나온다.

 

svn mkdir

   repository에 folder 생성한다.

    - # svn mkdir svn://192.168.163.11/TEST_repo/test_folder

 

svn import

   - 처음으로 repository에 파일 추가하기. 

    - 주의할점은 *.a 같은 파일은 추가 안될 수 있으니 --no-ignore 옵션 사용하기.

    - # svn import import_path svn://192.168.163.11/TEST_repo/import_path --no-ignore

 

svn add

   - 새로 만든 파일 추가 하기. import와 똑같이 사용 가능하다.

   - # svn add --no-ignore [path]

 

svn delete (or del, remove)

   - 파일, 폴더 삭제

   - # svn del [FILE_NAME] or [DIR]

   - # svn del svn://192.168.16.11/TEST_repo/test_dir

      --> commit도 동시에 된다. help 참고.

 

svn switch(or sw)

   - 저장소 이름 변경할 때

    # mv sample_repo1 sample_repo2 (su 로그인 후 저장소 이름을 직접 변경)

    # svn switch --relocate svn:/192.168.9.128/sample_repo1 svn:/192.168.9.128/sample_repo2

       --> repository에서 다운받은 곳에서 명령을 실행한다.

 

    "svn: E155007: 작업 사본이 아닙니다.(Not a working copy)" 이 에러는 .svn 없는 곳에서 svn 명령을 실행

     했을 때 발생한다.

    

   - 저장소 IP 변경할 때

    # svn switch --relocate svn:/192.168.30.198/sample_repo1 svn:/192.168.30.122/sample_repo1

 

svn diff

  - 두 revision 비교 또는 file 비교

  - 참고: http://pokute.tistory.com/201

변경된 파일만 출력

svn diff | awk '/^Index/ {print $NF}'

 

두 리비전 비교

# svn diff -r 100:101

 

두 리비전의 파일비교

#svn diff -r 100:101 file_path

 

참고 링크 : http://blog.daum.net/rayolla/251

 

2.거북이 SVN을 이용해서 실행하기

 

ex) TortoiseProc.exe /command:update /path:"경로" /closeonend:0

 

참고링크 : http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-automation.html

1.1 데이터 사이언스란?

1.1.1 데이터 사이언스의 정의

데이터 사이언스(Data Science)는 데이터를 수집, 처리, 분석, 모델링하여 가치 있는 인사이트(통찰력)를 도출하고 의사 결정을 지원하는 학문이자 기술 분야이다.

데이터 사이언스는 단순한 데이터 분석을 넘어 빅데이터, 인공지능(AI), 머신러닝(ML) 등과 결합하여 더욱 정교한 의사 결정을 가능하게 한다. 현대 사회에서는 방대한 양의 데이터를 효과적으로 처리하고 활용하는 것이 중요해졌으며, 데이터 사이언스는 이를 최적화하는 데 핵심적인 역할을 한다.

데이터 사이언스를 구성하는 주요 요소

  • 통계학(Statistics): 데이터를 요약하고 패턴을 분석하여 의미를 도출
  • 데이터 분석(Data Analysis): 데이터를 정리, 시각화, 해석하여 유용한 정보 제공
  • 머신러닝(Machine Learning): 데이터를 학습하여 패턴을 찾고 예측 모델 구축
  • 데이터 엔지니어링(Data Engineering): 대규모 데이터를 저장, 관리, 처리하는 기술
  • 데이터 시각화(Data Visualization): 데이터를 직관적으로 표현하여 쉽게 이해하도록 지원
  • 도메인 지식(Domain Knowledge): 특정 산업(의료, 금융, 마케팅 등)에 대한 이해를 바탕으로 분석 수행

데이터 사이언스의 핵심 목표

  • 데이터에서 의미 있는 인사이트(통찰력)를 도출하여 문제 해결
  • 데이터 기반의 의사 결정을 자동화하여 효율성 증대
  • 미래를 예측하는 모델을 구축하여 비즈니스 및 연구 분야에 활용

데이터 사이언스는 기업의 성과 개선, 연구 혁신, 정책 결정 등 다양한 영역에서 중요한 역할을 하며, 데이터를 활용하는 모든 분야에서 필수적인 요소로 자리 잡고 있다.


1.1.2 데이터 분석과 머신러닝의 차이

데이터 분석(Data Analysis)과 머신러닝(Machine Learning)은 데이터 사이언스의 핵심 요소이지만, 목적과 방법론이 다르다.

데이터 분석 (Data Analysis)

  • 과거 및 현재 데이터를 분석하여 패턴과 인사이트(통찰력)를 도출
  • 주요 기법: 통계 분석, 탐색적 데이터 분석(EDA), 데이터 시각화, 가설 검정
  • 결과: 데이터에 대한 해석과 설명

머신러닝 (Machine Learning)

  • 데이터에서 자동으로 패턴을 학습하고 예측하는 모델을 구축
  • 주요 기법: 지도 학습(Regression, Classification), 비지도 학습(Clustering, Dimensionality Reduction)
  • 결과: 예측 모델, 자동화된 의사 결정 시스템

데이터 분석 vs 머신러닝 비교 표

비교 항목 데이터 분석 (Data Analysis) 머신러닝 (Machine Learning)
목적 데이터의 의미와 패턴을 찾음 패턴을 학습하여 미래를 예측
방법론 통계 분석, EDA, 데이터 시각화 지도학습, 비지도학습, 강화학습
출력 결과 데이터의 해석 및 설명 자동화된 예측 및 의사 결정
활용 사례 고객 구매 패턴 분석, A/B 테스트 추천 시스템, 이미지 인식, 자율주행

데이터 분석은 데이터를 탐색하고 해석하여 의미를 도출하는 과정이며, 머신러닝은 데이터를 학습하여 자동으로 패턴을 찾고 미래를 예측하는 방법론이다.

데이터 분석은 머신러닝을 포함할 수도 있지만, 머신러닝은 분석보다 예측 및 자동화에 초점을 맞춘다는 점에서 차이가 있다.


1.1.3 데이터 사이언스가 활용되는 분야

데이터 사이언스는 다양한 산업에서 비즈니스 가치 창출과 문제 해결을 위해 활용되며, 기업과 연구 기관뿐만 아니라 공공 분야에서도 중요한 역할을 한다.

금융(Finance)

  • 사기 탐지(Fraud Detection): 신용카드 결제 및 금융 거래 데이터를 분석하여 이상 패턴 감지
  • 투자 및 리스크 관리(Investment & Risk Management): 주식시장 데이터 분석 및 알고리즘 트레이딩
  • 고객 맞춤 금융 서비스: 개인 맞춤형 금융 상품 추천

의료(Healthcare)

  • 질병 예측 및 진단(Disease Prediction & Diagnosis): 의료 데이터를 분석하여 질병 발병 가능성 예측
  • 의료 영상 분석(Medical Image Analysis): 딥러닝을 활용한 CT, MRI, X-ray 진단 자동화
  • 병원 운영 최적화(Hospital Management Optimization): 환자 대기 시간 예측 및 병상 관리

마케팅 및 고객 분석(Marketing & Customer Analytics)

  • 추천 시스템(Recommendation System): 고객의 소비 패턴을 분석하여 맞춤형 제품 추천
  • 고객 세분화(Customer Segmentation): K-Means 클러스터링을 활용한 고객 그룹화
  • 광고 최적화(Ad Optimization): A/B 테스트 및 데이터 기반 광고 성과 분석

자율주행 및 스마트 모빌리티(Autonomous Vehicles & Smart Mobility)

  • 자율주행 자동차(Autonomous Vehicles): 딥러닝을 활용한 객체 탐지 및 실시간 주행 예측
  • 교통 흐름 예측(Traffic Flow Prediction): 실시간 도로 데이터 분석을 통한 교통 체증 예측
  • 공유 모빌리티 최적화(Shared Mobility Optimization): 차량 이용 패턴 분석을 통한 최적 배차 모델 구축

결론

데이터 사이언스는 금융, 의료, 마케팅, 자율주행 등 다양한 산업에서 활용되며, 데이터 기반의 혁신을 가능하게 하는 핵심 기술이다.

데이터를 효과적으로 분석하고 모델링하여 비즈니스 가치와 효율성을 극대화하는 역할을 하며, 점점 더 많은 기업과 연구 기관에서 필수적인 요소로 자리 잡고 있다.

좋아요2
 

출처: https://gangdonggil.tistory.com/1382 [개발_노트:티스토리]

11.2 시계열 모델링 (Time Series Modeling)

시계열 모델링은 시간에 따라 변하는 데이터를 분석하고 미래를 예측하는 기법이다.
전통적인 통계 모델인 ARIMA, SARIMA와 딥러닝을 활용한 LSTM 모델이 대표적인 방법이다.

이 장에서는 ARIMA, SARIMA 모델과 LSTM을 활용한 시계열 예측 기법을 다룬다.


11.2.1 ARIMA 모델 (AutoRegressive Integrated Moving Average)

1) ARIMA란?

ARIMA(자기회귀 누적 이동 평균)는 시계열 데이터를 기반으로 미래 값을 예측하는 대표적인 통계적 모델이다.
이 모델은 자기회귀(AR), 차분(I), 이동 평균(MA)의 조합으로 시계열 데이터를 분석한다.

ARIMA 모델 구성 요소

  • AR (AutoRegressive, 자기회귀): 과거 값(시간 t 이전 값들)을 사용하여 현재 값을 예측
  • I (Integrated, 차분): 데이터의 안정성을 확보하기 위해 차분 연산 수행
  • MA (Moving Average, 이동 평균): 과거의 예측 오차를 사용하여 현재 값을 예측

📌 ARIMA 모델 수식

Y_t = c + φ_1 * Y_{t-1} + φ_2 * Y_{t-2} + ... + θ_1 * e_{t-1} + θ_2 * e_{t-2} + ... + e_t
  • Y_t: 현재 값
  • φ: 자기회귀 계수
  • θ: 이동 평균 계수
  • e_t: 예측 오차

2) ARIMA 모델 적용 (Python 코드 예제)

📌 Python 코드 예제 (ARIMA 모델을 활용한 시계열 예측)

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.arima.model import ARIMA

# 가상의 시계열 데이터 생성
date_range = pd.date_range(start="2023-01-01", periods=100, freq="D")
np.random.seed(42)
data = np.cumsum(np.random.normal(loc=0, scale=2, size=100)) + 100
df = pd.DataFrame({"Date": date_range, "Value": data})
df.set_index("Date", inplace=True)

# ARIMA 모델 학습 (p=2, d=1, q=2 설정)
model = ARIMA(df["Value"], order=(2, 1, 2))
model_fit = model.fit()

# 예측 수행 (향후 10일)
forecast = model_fit.forecast(steps=10)

# 결과 시각화
plt.figure(figsize=(10, 5))
plt.plot(df, label="Actual Data")
plt.plot(pd.date_range(start=df.index[-1], periods=11, freq="D")[1:], forecast, label="ARIMA Forecast", linestyle="dashed", color="red")
plt.xlabel("Date")
plt.ylabel("Value")
plt.title("ARIMA 모델 예측 결과")
plt.legend()
plt.show()

ARIMA 모델 활용

  • order=(p, d, q)에서
    • p: 자기회귀 차수
    • d: 차분 차수
    • q: 이동 평균 차수
  • model_fit.forecast(steps=n)을 사용해 미래 n일 예측 가능

11.2.2 SARIMA 모델 (Seasonal ARIMA, 계절성 ARIMA)

1) SARIMA란?

SARIMA는 ARIMA 모델에 계절성(Seasonality) 요소를 추가한 모델이다.
계절성을 포함하는 시계열 데이터(예: 월별 판매량, 계절별 온도 변화)에서는 ARIMA보다 SARIMA가 더 적합하다.

SARIMA 모델 구성 요소

  • ARIMA(p, d, q) 모델을 기반으로 계절성 요소 추가
  • 계절성 차수(P, D, Q, m)가 추가됨
    • P: 계절성 자기회귀 차수
    • D: 계절성 차분 차수
    • Q: 계절성 이동 평균 차수
    • m: 계절 주기 (예: 월별 데이터라면 m=12)

📌 SARIMA 모델 수식

SARIMA(p, d, q) × (P, D, Q, m)
  • 일반 ARIMA(p, d, q) 모델에 계절성 요소 (P, D, Q, m)를 포함

2) SARIMA 모델 적용 (Python 코드 예제)

📌 Python 코드 예제 (SARIMA 모델을 활용한 시계열 예측)

from statsmodels.tsa.statespace.sarimax import SARIMAX

# SARIMA 모델 학습 (p=1, d=1, q=1) × (P=1, D=1, Q=1, m=12)
sarima_model = SARIMAX(df["Value"], order=(1, 1, 1), seasonal_order=(1, 1, 1, 12))
sarima_fit = sarima_model.fit()

# 예측 수행 (향후 10일)
sarima_forecast = sarima_fit.forecast(steps=10)

# 결과 시각화
plt.figure(figsize=(10, 5))
plt.plot(df, label="Actual Data")
plt.plot(pd.date_range(start=df.index[-1], periods=11, freq="D")[1:], sarima_forecast, label="SARIMA Forecast", linestyle="dashed", color="red")
plt.xlabel("Date")
plt.ylabel("Value")
plt.title("SARIMA 모델 예측 결과")
plt.legend()
plt.show()

SARIMA 모델 활용

  • seasonal_order=(P, D, Q, m)를 설정하여 계절성 반영 가능
  • 주기적 변동이 있는 데이터에서 강력한 성능 발휘

11.2.3 LSTM을 활용한 시계열 예측

1) LSTM이란?

LSTM(Long Short-Term Memory)은 딥러닝 기반의 시계열 예측 모델로,
장기적인 패턴을 학습할 수 있어 ARIMA, SARIMA보다 더 복잡한 데이터 패턴을 예측하는 데 유리하다.

LSTM의 특징

  • 장기 의존성(Long-Term Dependency) 학습 가능
  • 비선형 관계를 학습할 수 있어 복잡한 시계열 데이터에 적합
  • 대량의 데이터에서 강력한 성능 발휘

2) LSTM을 활용한 시계열 예측 (Python 코드 예제)

📌 Python 코드 예제 (LSTM 기반 시계열 예측 모델 구현)

import tensorflow as tf
from tensorflow.keras import layers
from sklearn.preprocessing import MinMaxScaler

# 데이터 정규화 (LSTM은 데이터 정규화 필요)
scaler = MinMaxScaler()
df["Scaled_Value"] = scaler.fit_transform(df[["Value"]])

# 입력 데이터 생성 (과거 10일 데이터를 기반으로 예측)
sequence_length = 10
X, y = [], []
for i in range(len(df) - sequence_length):
    X.append(df["Scaled_Value"].values[i:i+sequence_length])
    y.append(df["Scaled_Value"].values[i+sequence_length])

X, y = np.array(X), np.array(y)

# LSTM 모델 생성
model = tf.keras.Sequential([
    layers.LSTM(50, return_sequences=True, input_shape=(sequence_length, 1)),
    layers.LSTM(50, return_sequences=False),
    layers.Dense(1)
])

# 모델 컴파일 및 학습
model.compile(optimizer="adam", loss="mse")
model.fit(X, y, epochs=20, batch_size=16)

# 예측 수행
y_pred = model.predict(X)

# 결과 시각화
plt.figure(figsize=(10, 5))
plt.plot(df.index[sequence_length:], y, label="Actual Data", alpha=0.5)
plt.plot(df.index[sequence_length:], y_pred, label="LSTM Prediction", linestyle="dashed", color="red")
plt.xlabel("Date")
plt.ylabel("Value")
plt.title("LSTM 모델 예측 결과")
plt.legend()
plt.show()

LSTM 활용

  • 데이터 정규화 필요 (MinMaxScaler)
  • 과거 데이터를 기반으로 미래 값 예측 가능

결론

ARIMA → 단기적인 예측에 강점, 간단한 시계열 분석에 적합
SARIMA → 계절성을 반영한 시계열 분석에 적합
LSTM → 복잡한 패턴을 학습하고 장기 예측에 강력한 성능 발휘

적절한 시계열 모델을 선택하면 데이터 패턴을 분석하고 미래를 효과적으로 예측할 수 있다.

출처: https://gangdonggil.tistory.com/1411 [개발_노트:티스토리]

 

아래는 요청하신 PPTA 웹진 2022년 11월호 “딥러닝 기반 시계열 예측(Time Series Forecasting) 모델 동향” 페이지 내용을 공적이고 전문적인 스타일간결하게 정리한 것입니다.


📌 개요

  • 주제: 금융, 기후, 의료, 교통 등 다양한 분야에서 활용되는 시계열 데이터 예측의 최근 딥러닝 모델 동향. 전통적 통계모델(ARIMA, VAR)과 대비해 RNN 계열, Neural ODE/CDE, Transformer 계열, GCN 계열 모델을 중심으로 소개. 정부조달기술진흥협회
  • 저자: 임선규 과장 (금융결제원), 개인 의견임을 명시. 정부조달기술진흥협회

I. 서론

  • 시계열 데이터 예측은 오랜 전통의 연구 분야로,
    • ARIMAVAR 같은 통계 기반 모델에 더해
    • RNN, GRU, LSTM 등 딥러닝 기반 모델 연구가 활발히 이루어짐 정부조달기술진흥협회
  • 논문 구조: RNN 계열(II장), ODE/CDE 기반(III장), Transformer 기반(IV장), 공간-시간 정보 활용 GCN 계열(V장), 적용 환경(VI장) 순.

II. RNN 계열 모델

  • RNN은 순환적 구조로 시계열 데이터를 다루지만, 장기 의존성 문제(long‑term dependency)가 존재 정부조달기술진흥협회
  • 이를 보완한 LSTM, GRU
    • LSTM: forget/input/output 게이트 구조로 장기 패턴 학습 가능
    • GRU: reset/update 게이트, 파라미터 수 적고 학습 속도 빠름 정부조달기술진흥협회

III. ODE / CDE 기반 모델

  • 기존 RNN·LSTM·GRU는 불연속 데이터 기반이며, Neural ODENeural CDE
    • 연속적 hidden state dynamics를 미분 방정식 개념으로 모델링
    • Neural ODE: 연속 모델링과 메모리 효율성을 동시에 확보 (역전파 시 ODE solver 사용) 정부조달기술진흥협회
    • ODE‑RNN: 불규칙 시계열 처리에 적합
    • Neural CDE: controlled differential equations 기반으로 irregular time series에 특화 정부조달기술진흥협회

IV. Transformer 계열 모델

  • Transformer는 자연어처리 기반 기술이나,
    • Seq2Seq + Attention 구조를 통해 장기 의존성 문제 개선
    • Transformer 계열은 시계열 예측에 더 최적화된 구조로 발전 중 정부조달기술진흥협회

V. GCN 계열 모델


VI. 모델 활용 환경

  • 대부분 모델은 PyTorch 등 개발 프레임워크 패키지GitHub 오픈 소스 코드 형태로 제공됨
  • 실험 환경 구축 시 접근성과 활용 사례가 풍부하며, 실제 데이터 분석 및 예측 실험에 바로 적용 가능 정부조달기술진흥협회

✅ 요약 정리

모델 계열특징 요약
RNN·LSTM·GRU 순차적 예측, 장기 의존성 문제 존재 → 게이트 방식으로 보완
Neural ODE/CDE continuous hidden state modeling, 메모리 효율성과 irregular data 처리 우수
Transformer Attention 기반, 장기 의존성 문제 해결, NLP에서 시계열 예측으로 확장
GCN 공간+시간 정보 함께 활용, 교통 등 그래프 특성 데이터 예측에 강점
 

💡 추천 학습 방향

  • 직접 코딩 실험 또는 Kaggle 등 예측 대회 데이터 사용하여,
    • 실습 중심으로 LSTM, Transformer, GCN 기반 시계열 모델을 비교해 보는 것 권장합니다.
  • 논문이나 모델별 GitHub 구현 코드 확인 후, 적용 사례 중심으로 분석해보시면 이해가 훨씬 수월하실 것입니다.

추가적으로 알고 싶은 부분이나, 예제 코드·모델 추천 요청 있으면 언제든지 말씀해 주세요.

'study' 카테고리의 다른 글

문제점: Tomcat 버전 정보 노출  (0) 2025.05.09
Mac 내장 Apache로 웹서버 운영하기  (0) 2025.01.23
jquery formData();  (0) 2023.09.25
SVN CLEANUP 옵션설명  (0) 2023.04.14
jar 압축 / 해제  (0) 2023.03.09
IT 이야기/JBoss EAP

[JBoss EAP 7] JBoss EAP 7.3 주요 설정 내용

by 찬찬이 아빠 2023. 4. 11.
반응형
 
  1. JBoss EAP 7 버전 정보
버전 출시일
JBoss EAP 7.3.7 2021.05

 

  2. JBoss EAP 7 주요 실행 스크립트

1) /JBOSS/domains/노드명/bin/env.sh

#!/bin/sh

DATE=`date +%Y%m%d%H%M%S`

##### JBoss EAP Directory Setup #####
export JBOSS_HOME=/JBOSS/jboss-eap-7.3
export JAVA_HOME=/usr/lib/jvm/java-1.8.0
export DOMAIN_BASE=/JBOSS/domains
export SERVER_NAME=AP_name10
export HOST_NAME=`hostname`

##### Configuration File #####
export CONFIG_FILE=standalone-ha.xml
export PORT_OFFSET=0
export JBOSS_USER=jboss

##### Bind Address #####
export BIND_ADDR=`hostname -i`
export MGMT_ADDR=$BIND_ADDR
export CONTROLLER_IP=$MGMT_ADDR
let CONTROLLER_PORT=9991+$PORT_OFFSET
export CONTROLLER_PORT

export LAUNCH_JBOSS_IN_BACKGROUND=true

##### Multicast IP for standalone-ha.xml #####
##### MIP, Change Please #####
export MULTICAST_ADDR=230.20.61.1
export JMS_MULTICAST_ADDR=231.20.61.1
export MODCLUSTER_MULTICAST_ADDR=224.20.61.100

export JAVA_OPTS=" $JAVA_OPTS -Djboss.default.multicast.address=$MULTICAST_ADDR"
export JAVA_OPTS=" $JAVA_OPTS -Djboss.messaging.group.address=$JMS_MULTICAST_ADDR"
export JAVA_OPTS=" $JAVA_OPTS -Djboss.modcluster.multicast.address=$MODCLUSTER_MULTICAST_ADDR"

##### TCP mode can be used when multicast is not preferable or allowed by security policies.
#### https://access,redhat.com/solutions/3021711
#export TCP_MULTICAST_ADDR=was1[7600],was2[7600]

#export JAVA_OPTS=" $JAVA_OPTS -Djboss.jgroups.transport.machine=$SERVER_NAME"
#export JAVA_OPTS=" $JAVA_OPTS -Djboss.cluster.tcp.initial_hosts=$TCP_MULTICAST_ADDR"

export JAVA_OPTS=" $JAVA_OPTS -Djboss.tx.node.id=$SERVER_NAME"
export JAVA_OPTS=" $JAVA_OPTS -Djboss.as.management.blocking.timeout=600"
export LOG_HOME=/CLOUD/JBOSS/LOG/$SERVER_NAME

##### JBoss EAP System module and User module directory #####
export JBOSS_MODULEPATH=$JBOSS_HOME/modules

# JVM Options : Server
export JAVA_OPTS="-server $JAVA_OPTS"

# JVM Options : Memory
export JAVA_OPTS=" $JAVA_OPTS -Xss2m -Xms1024m -Xmx2048m -XX:MaxMetaspaceSize=512m"

export JAVA_OPTS=" $JAVA_OPTS -XX:+PrintGCTimeStamps"
export JAVA_OPTS=" $JAVA_OPTS -XX:+PrintGCDetails"
export JAVA_OPTS=" $JAVA_OPTS -Xloggc:$LOG_HOME/gclog/gc_$DATE.log"
export JAVA_OPTS=" $JAVA_OPTS -XX:+UseParallelGC"
export JAVA_OPTS=" $JAVA_OPTS -XX:+ExplicitGCInvokesConcurrent"
export JAVA_OPTS=" $JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError"
export JAVA_OPTS=" $JAVA_OPTS -XX:HeapDumpPath=$LOG_HOME/gclog/java_pid_$DATE.hprof"

# Linux Large Page Setting
#export JAVA_OPTS=" $JAVA_OPTS -XX:+UseLargePages"

export JAVA_OPTS=" $JAVA_OPTS -verbose:gc"
export JAVA_OPTS=" $JAVA_OPTS -Djava.net.preferIPv4Stack=true"
export JAVA_OPTS=" $JAVA_OPTS -Dorg.jboss.resolver.warning=true"
export JAVA_OPTS=" $JAVA_OPTS -Dsun.rmi.dgc.client.gcInterval=3600000 "
export JAVA_OPTS=" $JAVA_OPTS -Dsun.rmi.dgc.server.gcInterval=3600000"
export JAVA_OPTS=" $JAVA_OPTS -Djboss.modules.system.pkgs=org.jboss.byteman"
export JAVA_OPTS=" $JAVA_OPTS -Djava.awt.headless=true"

export JAVA_OPTS=" $JAVA_OPTS -Djboss.server.base.dir=$DOMAIN_BASE/$SERVER_NAME"
export JAVA_OPTS=" $JAVA_OPTS -Djboss.socket.binding.port-offset=$PORT_OFFSET"
export JAVA_OPTS=" $JAVA_OPTS -Djboss.node.name=${SERVER_NAME}"
export JAVA_OPTS=" $JAVA_OPTS -Djboss.bind.address.management=$MGMT_ADDR"
export JAVA_OPTS=" $JAVA_OPTS -Djboss.bind.address=$BIND_ADDR"

export JAVA_OPTS=" $JAVA_OPTS -Dserver.mode=local"

# Use log4j in application
export JAVA_OPTS=" $JAVA_OPTS -Djboss.server.log.dir=$LOG_HOME "

echo "================================================="
echo "JBOSS_HOME=$JBOSS_HOME"
echo "DOMAIN_BASE=$DOMAIN_BASE"
echo "SERVER_NAME=$SERVER_NAME"
echo "CONFIG_FILE=$CONFIG_FILE"
echo "BIND_ADDR=$BIND_ADDR"
echo "PORT_OFFSET=$PORT_OFFSET"
echo "CONTROLLER=$CONTROLLER_IP:$CONTROLLER_PORT"
echo "jboss.node.name=${SERVER_NAME}"
echo "================================================="

##### SCOUTER Setting
#SCOUTER_OPT="-javaagent:/scouter/agent.java_6_7/scouter.agent.jar -Dscouter.config=/scouter/agent.java_6_7/conf/AP_anme10.conf"
#export JAVA_OPTS=" $JAVA_OPTS $SCOUTER_OPT"
#export JAVA_OPTS=" $JAVA_OPTS -Djboss.modules.system.pkgs=org.jboss.byteman,scouter"

 

2) /JBOSS/domains/노드명/bin/env.properties

org.apache.catalina.connector.URI_ENCODING=UTF-8
org.apache.catalina.connector.USE_BODY_ENCODING_FOR_QUERY_STRING=true
org.apache.coyote.http11.Http11Protocol.MAX_HEADER_SIZE=8192
org.apache.coyote.ajp.DEFAULT_CONNECTION_TIME=60000
org.apache.coyote.http11.DEFAULT_CONNECTION_TIMEOUT=60000
org.apache.tomcat.util.http.Parameters.MAX_COUNT=10000
file.encoding=UTF-8
#jvmRoute=AP_name10
UseJK=true

 

3) /JBOSS/domains/노드명/bin/add-user.sh

#!/bin/sh

. ./env.sh

# JAVA_OPTS="$JAVA_OPTS -Djboss.domain.config.user.dir=../domain/configuration"
JAVA_OPTS="$JAVA_OPTS -Djboss.server.config.user.dir=$DOMAIN_BASE/$SERVER_NAME/configuration"

$JBOSS_HOME/bin/add-user.sh $@

 

4) /JBOSS/domains/노드명/bin/dbms-encryption-password.sh

#!/bin/sh

JAVA_HOME=/usr/lib/jvm/jre-1.8.0/bin
JBOSS_HOME=/JBOSS/jboss-eap-7.3

picketbox=`find ${JBOSS_HOME}/ -type f -name "picketbox*" | sort | head -n 1`
jboss_logging=`find ${JBOSS_HOME}/ -type f -name "jboss-logging*"`
module_name=org.picketbox.datasource.security.SecureIdentityLoginModule

export CLASSPATH=${picketbox}:${jboss_logging}

if [ -d $JAVA_HOME ]; then
	read -p "Input Database Password : " dbpassword
    ${JAVA_HOME}/java -cp $CLASSPATH ${module_name} ${dbpassword}
else
	echo "JAVA 1.8 is not installed. Please install and try again."
fi

 

5) /JBOSS/domains/노드명/bin/dump.sh

#!/bin/sh

. ./env.sh

for count in 1 2 3; do
	echo "Thread Dump : $count"
    for i in `ps -ef | grep java |grep "SERVER=$SERVER_NAME " | awk '{priont $2}'`;do
    echo "+kill -3 $i"
    kill -3 $i
    echo "sleep 1 sec"
    sleep 1
    done
    echo "done"
    sleep 3
done

 

6) /JBOSS/domains/노드명/bin/jboss-cli.sh

#!/bin/sh

. ./env.sh

export JAVA_OPTS=" -Djava.awt.headless=false $JAVA_OPTS"

$JBOSS_HOME/bin/jboss-cli.sh --controller=$CONTROLLER_IP:$CONTROLLER_PORT --connect $@

 

 

7) /JBOSS/domains/노드명/bin/jconsole.sh

#!/bin/sh

. ./env.sh

echo "================================================================"
echo "   JXM URL : service:jmx:remoting-jmx://$MGMT_ADDR:$CONTROLLER_PORT"
echo "================================================================"
$JBOSS_HOME/bin/jconsole.sh

 

 

8) /JBOSS/domains/노드명/bin/jdr.sh

#!/bin/sh

. ./env.sh

$JBOSS_HOME/bin/jdr.sh $@

 

9) /JBOSS/domains/노드명/bin/kill.sh

#!/bin/sh

. ./env.sh

ps -ef | grep java | grep "SERVER=$SERVER_NAME " | awk {'print "kill -9 " $2'} | sh -x
ps -ef | grep "tail" | grep "$SERVER_NAME" | awk {'print "kill -9 " $2'} | sh -x

 

10) /JBOSS/domains/노드명/bin/shutdown.sh

#!/bin/sh

. ./env.sh

$JBOSS_HOME/bin/jboss-cli.sh --connect --controller=$CONTROLLER_IP:$CONTROLLER_PORT --command=:shutdown

tail -f $LOG_HOME/nohup/$SERVER_NAME.out

 

 

11) /JBOSS/domains/노드명/bin/start.sh

#!/bin/sh

DATE=`date +%Y%m%d%H%M%S`

. ./env.sh

PID=`ps -ef | grep java | grep "=$SERVER_NAME " | awk '{print $2}'`
echo $PID

if [ e$PID != "e" ]
then
	echo "JBoss SERVER - $SERVER_NAME is already Running..."
    exit;
fi

UNAME=`id -u -n`
if [ e$UNAME != "e$JBOSS_USER" ]
then
	echo "Use $JBOSS_USER account to start JBoss SERVER - $SERVER_NAME..."
    exit;
fi

echo $JAVA_OPTS

if [ ! -f $LOG_HOME/server.log ]; then
	touch $LOG_HOME/server.log
fi

nohup $JBOSS_HOME/bin/standalone.sh -DSERVER=$SERVER_NAME -P=$DOMAIN_BASE/$SERVER_NAME/bin/env.properties -c $CONFIG_FILE >> $LOG_HOME/nohup/${SERVER_NAME}_${date}.out &

if [ e$1 = "enotail" ]
then
	echo "Starting... $SERVER_NAME"
    exit;
fi

tail -f $LOG_HOME/server.log &
tail $LOG_HOME/server.log -n0 -F | while read line; do
	if [[ $line =~ ' started in ' ]] && [[ $line =~ ' - Started ' ]] || [[ $line =~ ' ERROR ' ]]; then
    	pkill -9 -P $$ tail
    fi
done

 

 

12) /JBOSS/domains/노드명/bin/status.sh

#!/bin/sh

. ./env.sh

ps -ef | grep java | grep "SERVER=$SERVER_NAME "

 

13) /JBOSS/domains/노드명/bin/stop.sh

#!/bin/sh

. ./env.sh

ps -ef | grep java | grep "SERVER=$SERVER_NAME " | awk {'print "kill -15 " $2'} sh -x
ps -ef | grep "tail" | grep "$SERVER_NAME" | awk {'print "kill -15 " $2'} | sh -x

 

14) /JBOSS/domains/노드명/bin/tail.sh

#!/bin/sh

. ./env.sh

tail -f $LOG_HOME/server.log

 

 

15) /JBOSS/domains/노드명/bin/scripts/jboss_start.sh

#!/bin/sh

JBOSS_DIR="/JBOSS/domains"

unset JBOSS_NODE DATE JBOSS_BIN_DIR PNODE_NAME UNAME JBOSS_HOME JAVA_HOME DOMAIN_BASE SERVER_NAME HOST_NAME CONFIG_FILE PORT_OFFSET JBOSS_USER BIND_ADDR CONTROLLER_IP CONTROLLER_PORT MULTICAST_ADDR JMS_MULTICAST_ADDR MODCLUSTER_MULTICAST_ADDR JAVA_OPTS LOG_HOME JBOSS_MODULEPATH

if [ `ls -F $JBOSS_DIR | grep / | wc -l` -eq 1 ]; then
	node_list=`ls -F $JBOSS_DIR | grep / | cut -d/ -f1`
	JBOSS_BIN_DIR=$JBOSS_DIR/${node_list}/bin
    
	if [ ! -d $JBOSS_BIN_DIR ]; then
		JBOSS_BIN_DIR=$JBOSS_DIR/${node_list}
	fi
    
    DATE=`date +%Y%m%d%H%M%S`
    if [ -f ${JBOSS_BIN_DIR}/env.sh ]; then
    	. ${JBOSS_BIN_DIR}/env.sh
    else
    	echo -e "\n======================================"
        echo -e "${node_list} node are env.sh file not found\n"
        echo -e "\n======================================"
        echo -e "Rerun script after node name resolution\n"
        exit;
    fi
    
    PID=`ps -ef | grep java | grep "=$SERVER_NAME " | awk '{print $2}'`    
    echo $PID
    
    if [ e$PID != "e" ]; then
		echo "JBoss SERVER - $SERVER_NAME is already Running..."
        exit;
	fi
    
    UNAME=`id -u -n`
	if [ e$UNAME != "e$JBOSS_USER" ]; then
		echo "Use $JBOSS_USER account to start JBoss SERVER - $SERVER_NAME..."
		exit;
	fi
    
	echo $JAVA_OPTS
    if [ ! -f $LOG_HOME/server.log ]; then
    	touch $LOG_HOME/server.log
    fi
    
	nohup $JBOSS_HOME/bin/standalone.sh -DSERVER=$SERVER_NAME -P=$JBOSS_BIN_DIR/env.properties -c $CONFIG_FILE >> $LOG_HOME/nohup/${SERVER_NAME}_${DATE}.out &

	if [ e$1 = "enotail" ]; then
		echo "Starting... $SERVER_NAME"
		exit;
	fi

	tail -f $LOG_HOME/server.log &
    tail $LOG_HOME/server.log -n0 -F | while read line; do
    	if [[ $line =~ ' started in ' ]] && [[ &line =~ ' - Started ' ]] || [[ $line =~ ' ERROR ' ]]; then
        	pkill -9 -P $$ tail
        fi
    done
else
	node_check=`ps ax | grep jboss | grep "DSERVER" | grep "standalone.sh" | egrep -v "java|grep" | awk -F= '{print $2}' | awk '{print $1}' | sort -u`
    node_name=`echo ${node_check} | grep -v -e '^$' | tr " " "|"`
    if [[ ${node_name} == "" ]]; then
    	NODE_LIST=`ls -F $JBOSS_DIR | grep / | cut -d/ -f1 | grep -v -e '^$' | tr "\n" "\t"`
    else
    	NODE_LIST=`ls -F $JBOSS_DIR | grep / | cut -d/ -f1 | egrep -v "${node_name}" | grep -v -e '^$' | tr "\n" "\t"`
    fi
    
    if [ `echo ${NODE_LIST} | grep -v -e '^$' | wc -l` -eq 1 ]; then
    	echo -e "\nInput JBoss Node Name."
        echo -e "\\033[0;31mNode List : \\033[0;32m ${NODE_LIST} \\033[0;39m\n"
        read -p " [ JBoss Node Name ] : " ID
        
        JBOSS_NODE=$JBOSS_DIR/${ID}
        
        if [[ $ID == "" ]]; then
        	echo -e "\nSpace or Enter is not allowed.."
            echo -e "\\033[0;31mNode List : \\033[0;32m ${NODE_LIST} \\033[0;39m\n"
            echo -e "Rerun script after node name resolution\n"
            exit;
        elif [ -d $JBOSS_NODE ]; then
        	JBOSS_BIN_DOR=$JBOSS_NODE/bin
            if [ ! -d $JBOSS_BIN_DIR ]; then
            	JBOSS_BIN_DIR=$JBOSS_NODE
            fi
            
            DATE=`date +%Y%m%d%H%M%S`
            if [ -f ${JBOSS_BIN_DIR}/env.sh ]; then
    			. ${JBOSS_BIN_DIR}/env.sh
            else
               	echo -e "\n======================================"
                echo -e "${node_list} node are env.sh file not found\n"
                echo -e "\n======================================"
                echo -e "Rerun script after node name resolution\n"
                exit;
            fi
            
            PID=`ps -ef | grep java | grep "=$SERVER_NAME " | awk '{print $2}'`    
            echo $PID
            if [ e$PID != "e" ]; then
            	echo "JBoss SERVER - $SERVER_NAME is already Running..."
                exit;
            fi
            
            UNAME=`id -u -n`
            if [ e$UNAME != "e$JBOSS_USER" ]; then
            	echo "Use $JBOSS_USER account to start JBoss SERVER - $SERVER_NAME..."
               exit;
            fi
            
            echo $JAVA_OPTS
            nohup $JBOSS_HOME/bin/standalone.sh -DSERVER=$SERVER_NAME -P=$JBOSS_BIN_DIR/env.properties -c $CONFIG_FILE >> $LOG_HOME/nohup/${SERVER_NAME}_${DATE}.out &
			
            if [ e$1 = "enotail" ]; then
            	echo "Starting... $SERVER_NAME"
                exit;
            fi
            
            tail -f $LOG_HOME/server.log &
            tail $LOG_HOME/server.log -n0 -F | while read line; do
            	if [[ $line =~ ' started in ' ]] && [[ &line =~ ' - Started ' ]] || [[ $line =~ ' ERROR ' ]]; then
        			pkill -9 -P $$ tail
        		fi
            done
        else
        	echo -e "\nNo Search Node Name : ${ID}"
            echo -e "\\033[0;31mNode List : \\033[0;32m ${NODE_LIST} \\033[0;39m\n"
            echo -e "Rerun script after node name resolution\n"
            exit;
        fi
    else
    	echo -e "\nAll JBoss Nodes are Running!!\n"
    if
fi

 

 

16) /JBOSS/domains/노드명/bin/scripts/jboss_stop.sh

#!/bin/sh

JBOSS_DIR=`ps ax | grep jboss | grep "DSERVER" | grep "standalone.sh" | egrep -v "grep" | awk -F-P= '{print $2}' | awk -F/ '{print "/" $2, $3, $4}' | sort -u | tr " " "/"`

node_check=`ps ax | grep jboss | grep "DSERVER" | grep "standalone.sh" | egrep -v "grep" | awk -F= '{print $2}' awk '{print $1}' | sort -u`

unset JBOSS_NODE DATE JBOSS_BIN_DIR PNODE_NAME UNAME JBOSS_HOME JAVA_HOME DOMAIN_BASE SERVER_NAME HOST_NAME CONFIG_FILE PORT_OFFSET JBOSS_USER BIND_ADDR CONTROLLER_IP CONTROLLER_PORT MULTICAST_ADDR JMS_MULTICAST_ADDR MODCLUSTER_MULTICAST_ADDR JAVA_OPTS LOG_HOME JBOSS_MODULEPATH

if [ `echo ${node_check} | grep -v -e '^$' | tr " " "\n" | wc -l` -ge 1 ]; then
	for ID in ${node_check[@]}
    do
    	JBOSS_NODE=$JBOSS_DIR/${ID}
        echo -e "\n Do you want ot stop the\\033]0;32m ${ID}\\033[0;39m Node?"
        JBOSS_BIN_DIR=${JBOSS_NODE}/bin
        if [ ! -d ${JBOSS_BIN_DIR} ]; then
        	JBOSS_BIN_DIR=${JBOSS_NODE}
        fi
        
        DATE=`date +%Y%m%d%H%M%S`
        if [ -f ${JBOSS_BIN_DIR/env.sh ]; then
        	. ${JBOSS_BIN_DIR}/env.sh
        else
        	echo -e "\n===================================="
            echo -e "${ID} are env.sh file not found"
            echo -e "\n===================================="
            continue;
        fi
        echo -e "\n"
        read -p " [ Input Yes or No  : ] " answer
        	case $answer in
            	[yY]* )
                	ps -ef | grep "java" | grep "${JBOSS_NODE}" | awk {'print "kill -15 " $2'} | sh -x && \
                    ps -ef | grep "tail" | grep "${ID}" | awk {'print "kill -15 " $2'} | sh -x;;
                [nN]* )
                	continue;;
                * )
                	echo -e "\n You must enter Yes or No. Rerun the shell. ";
            esac
        echo -e "\n"
    done
else
	echo -e "JBoss Service is not Running!!\n"
fi

 

17) /JBOSS/domains/노드명/bin/scripts/jboss_kill.sh

#!/bin/sh

JBOSS_DIR=`ps ax | grep jboss | grep "DSERVER" | grep "standalone.sh" | egrep -v "grep" | awk -F-P= '{print $2}' | awk -F/ '{print "/" $2, $3, $4}' | sort -u | tr " " "/"`

node_check=`ps ax | grep jboss | grep "DSERVER" | grep "standalone.sh" | egrep -v "grep" | awk -F= '{print $2}' awk '{print $1}' | sort -u`

unset JBOSS_NODE DATE JBOSS_BIN_DIR PNODE_NAME UNAME JBOSS_HOME JAVA_HOME DOMAIN_BASE SERVER_NAME HOST_NAME CONFIG_FILE PORT_OFFSET JBOSS_USER BIND_ADDR CONTROLLER_IP CONTROLLER_PORT MULTICAST_ADDR JMS_MULTICAST_ADDR MODCLUSTER_MULTICAST_ADDR JAVA_OPTS LOG_HOME JBOSS_MODULEPATH

if [ `echo ${node_check} | grep -v -e '^$' | tr " " "\n" | wc -l` -ge 1 ]; then
	for ID in ${node_check[@]}
    do
    	JBOSS_NODE=$JBOSS_DIR/${ID}
        echo -e "\n Do you want ot stop the\\033]0;32m ${ID}\\033[0;39m Node?"
        JBOSS_BIN_DIR=${JBOSS_NODE}/bin
        if [ ! -d ${JBOSS_BIN_DIR} ]; then
        	JBOSS_BIN_DIR=${JBOSS_NODE}
        fi
        
        DATE=`date +%Y%m%d%H%M%S`
        if [ -f ${JBOSS_BIN_DIR/env.sh ]; then
        	. ${JBOSS_BIN_DIR}/env.sh
        else
        	echo -e "\n===================================="
            echo -e "${ID} are env.sh file not found"
            echo -e "\n===================================="
            continue;
        fi
        echo -e "\n"
        read -p " [ Input Yes or No  : ] " answer
        	case $answer in
            	[yY]* )
                	ps -ef | grep "java" | grep "${JBOSS_NODE}" | awk {'print "kill -9 " $2'} | sh -x && \
                    ps -ef | grep "tail" | grep "${ID}" | awk {'print "kill -9 " $2'} | sh -x;;
                [nN]* )
                	continue;;
                * )
                	echo -e "\n You must enter Yes or No. Rerun the shell. ";
            esac
        echo -e "\n"
    done
else
	echo -e "JBoss Service is not Running!!\n"
fi

 

 

  3. JBoss EAP 7 주요 설정 내용

1) /JBOSS/domains/노드명/configuration/logging.properties

# Note this file has been generated and will be overwritten if a
# logging subsystem has been defined in the XML configuration.

# Additional loggers to configure (the root logger is always configured)
loggers=sun.rmi,org.jboss.as.config,io.jaegertracing.Configuration,com.arjuna

logger.level=INFO
logger.handlers=FILE,CONSOLE

logger.sun.rmi.level=WARN
logger.sun.rmi.useParentHandlers=true

logger.org.jboss.as.config.level=DEBUG
logger.org.jboss.as.config.useParentHandlers=true

logger.io.jaegertracing.Configuration.level=WARN
logger.io.jaegertracing.Configuration.useParentHandlers=true

logger.org.apache.tomcat.util.modeler.level=WARN
logger.org.apache.tomcat.util.modeler.useParentHandlers=true

logger.com.arjuna.level=WARN
logger.com.arjuna.useParentHandlers=true

handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
handler.CONSOLE.level=WARN
handler.CONSOLE.formatter=COLOR-PATTERN
handler.CONSOLE.properties=enabled,autoFlush,target
handler.CONSOLE.enabled=true
handler.CONSOLE.autoFlush=true
handler.CONSOLE.target=SYSTEM_OUT

handler.FILE=org.jboss.logmanager.handlers.PeriodicRotatingFileHandler
handler.FILE.level=ALL
handler.FILE.formatter=PATTERN
handler.FILE.properties=append,autoFlush,enabled,suffix,fileName
handler.FILE.append=true
handler.FILE.autoFlush=true
handler.FILE.enabled=true
handler.FILE.suffix=.yyyy-mm-dd
handler.FILE.fileName=/JBOSS/LOG/AP_name10/server.log

formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
formatter.PATTERN.properties=pattern
formatter.PATTERN.pattern=%d{yyyy-mm-dd HH\:mm\:ss,SSS} %-5p [%c] (t) %s%E%n

formatter.COLOR-PATTERN=org.jboss.logmanager.formatters.PatternFormatter
formatter.COLOR-PATTERN.properties=pattern
formatter.COLOR-PATTERN.pattern=%K{level}%d{HH\:mm\:ss,SSS} %-5p [%c] (%t) %s%E%n

 

 

2) /JBOSS/domains/노드명/configuration/standalone.xml

<?xml version='1.0' encoding='UTF-8'?>

<server xmlns="urn:jboss:domain:11.0">
	<extensions>
    	<extension module="org.jboss.as.clustering.infinispan"/>
        <extension module="org.jboss.as.connector"/>
        <extension module="org.jboss.as.deployment-scanner"/>
        <extension module="org.jboss.as.ee"/>
        <extension module="org.jboss.as.ejb3"/>
        <extension module="org.jboss.as.jaxrs"/>
        <extension module="org.jboss.as.jdr"/>
        <extension module="org.jboss.as.jmx"/>
        <extension module="org.jboss.as.jpa"/>
        <extension module="org.jboss.as.jsf"/>
        <extension module="org.jboss.as.logging"/>
        <extension module="org.jboss.as.mail"/>
        <extension module="org.jboss.as.naming"/>
        <extension module="org.jboss.as.pojo"/>
        <extension module="org.jboss.as.remoting"/>
        <extension module="org.jboss.as.sar"/>
        <extension module="org.jboss.as.security"/>
        <extension module="org.jboss.as.transactions"/>
        <extension module="org.jboss.as.webservices"/>
        <extension module="org.jboss.as.weld"/>
        <extension module="org.wildfly.extension.batch.jberet"/>
        <extension module="org.wildfly.extension.bean-validation"/>
        <extension module="org.wildfly.extension.clustering.web"/>
        <extension module="org.wildfly.extension.core-management"/>
        <extension module="org.wildfly.extension.discovery"/>
        <extension module="org.wildfly.extension.ee-security"/>
        <extension module="org.wildfly.extension.elytron"/>
        <extension module="org.wildfly.extension.io"/>
        <extension module="org.wildfly.extension.microprofile.config-smallrye"/>
        <extension module="org.wildfly.extension.microprofile.health-smallrye"/>
        <extension module="org.wildfly.extension.microprofile.metrics-smallrye"/>
        <extension module="org.wildfly.extension.microprofile.opentracing-smallrye"/>
        <extension module="org.wildfly.extension.request-controller"/>
        <extension module="org.wildfly.extension.security.manager"/>
        <extension module="org.wildfly.extension.undertow"/>
	</extensions>
    <management>
    	<security-realms>
        	<security-realm name="ManagementRealm">
            	<authentication>
                	<local default-user="$local" skip-group-loading="true"/>
                    <properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
                </authentication>
                <authorization map-groups-to-roles="false">
                	<properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
                </authorization>
            </security-realm>
            <security-realm name="ApplicationRealm">
            	<server-identities>
                	<ssl>
                    <!--	<keystore path="application.keystore" relative-to="jboss.server.config.dir" keystore-password="password" alias="server" key-password="password" generate-self-signed-certificate-host="localhost"/> -->
                    </ssl>
                </server-identities>
                <authentication>
                	<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
                    <properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
                </authentication>>
                <authorization>
                	<properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
                </authorization>
            </security-realm>
        </security-realms>
        <audit-log>
        	<formatters>
            	<json-formatter name="json-formatter"/>
            </formatters>
            <handlers>
            	<file-handler name="file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
            </handlers>
            <logger log-boot="true" log-read-only="false" enabled="false">
            	<handlers>
                	<handler name="file"/>
                </handlers>
            </logger>
        </audit-log>
        <management-interfaces>
        	<http-interface security-realm="ManagementRealm">
            	<http-upgrade enabled="true"/>
            	<socket-binding native="management-http"/>
            </http-interface>            
       </management-interfaces>
       <access-contorl provider="simple">
           <role-mapping>
               <role name="SuperUser">
                   <include>
                       <user name="$local"/>
                   </include>
               </role>
           </role-mapping>
       </access-control>
   </management>
   <profile>
       <subsystem xmlns="urn:jboss:domain:logging:8.0">
           <console-handler name="CONSOLE">
               <level name="ERROR"/>
               <formatter>
                   <named-formatter name="COLOR-PATTERN"/>
               </formatter>
           </console-handler>
           <periodic-rotating-file-handler name="FILE" autoflush="true">
               <formatter>
                   <named-formatter name="PATTERN"/>
               </formatter>
               <file relative-to="jboss.server.log.dir" path="server.log"/>
               <suffix value=".yyyy-MM-dd"/>
               <append value="true"/>
           </periodic-rotating-file-handler>
           <logger category="com.arjuna">
               <level name="WARN"/>
           </logger>
           <logger category="io.jaegertracing.Configuration">
               <level name="WARN"/>
           </logger>
           <logger category="org.jboss.as.config">
               <level name="DEBUG"/>
           </logger>
           <logger category="sun.rmi">
               <level name="WARN"/>
           </logger>
           <root-logger>
               <level name="INFO"/>
               <handlers>
                   <handler name="CONSOLE"/>
                   <handler name="FILE"/>
               </handlers>
           </root-logger>
           <formatter name="PATTERN">
               <pattern-formatter pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
           </formatter>
           <formatter name="COLOR-PATTERN">
               <pattern-formatter pattern="%K{level}%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
           </formatter>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:batch-jberet:2.0">
           <default-job-repository name="in-memory"/>
           <default-thread-pool name="batch"/>
           <job-repository name="in-menory">
               <in-memory/>
           </job-repository>
           <thread-pool name="batch">
               <max-threads count="10"/>
               <keepalive-time time="30" unit="seconds"/>
           </thread-pool>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:bean-validation:1.0"/>
       <subsystem xmlns="urn:jboss:domain:core-management:1.0"/>
       <subsystem xmlns="urn:jboss:domain:datasources:5.0">
           <datasources>
               <datasource jndi-name="java:jboss/cubridDS" pool-name="cubridDS" enabled="true">
                   <connection-url>jdbc:cubrid:dbmshost1:33000:db명:::?hold_cursor=no&amp;charset=utf-8</connection-url>
                   <driver-class>cubrid.jdbc.dirver.CUBRIDDriver</driver-class>
                   <driver>cubrid</driver>
                   <pool>
                       <min-pool-size>5</min-pool-size>
                       <max-pool-size>50</max-pool-size>
                       <prefill>false</prefill>
                       <use-strict-min>true</use-strict-min>
                   </pool>
                   <timeout>
                       <blocking-timeout-millis>300000</blocking-timeout-millis>
                       <idle-timeout-minutes>10</idle-timeout-minutes>
                   </timeout>
                   <security>
                       <security-domain>cubrid-password</security-domain>                       
                   </security>
                   <validation>
                       <check-valid-connection-sql>select 1</check-valid-connection-sql>
                       <validate-on-match>true</validate-on-match>
                       <background-validation>false</background-validation>
                   </validation>
                   <statement>
                       <share-prepared-statements>false</share-prepared-statements>
                   </statement>
               </datasource>
               <datasource jndi-name="java:jboss/postgresDS" pool-name="postgresDS" enabled="false">
                   <connection-url>jdbc:postgresql://dbmshost1:5432/postgres</connection-url>
                   <driver-class>org.postgresql.Driver</driver-class>
                   <driver>postgres</driver>
                   <pool>
                       <min-pool-size>5</min-pool-size>
                       <max-pool-size>50</max-pool-size>
                       <prefill>false</prefill>
                       <use-strict-min>true</use-strict-min>
                   </pool>
                   <timeout>
                       <blocking-timeout-millis>300000</blocking-timeout-millis>
                       <idle-timeout-minutes>10</idle-timeout-minutes>
                   </timeout>
                   <security>
                       <security-domanin>cubrid-password</security-domain>
                   </security>                  
                   <validation>
                       <check-valid-connection-sql>select 1</check-valid-connection-sql>
                       <validate-on-match>true</validate-on-match>
                       <background-validation>false</background-validation>
                       <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.etensions.postgres.PostgreSQLValidConnectionChecker"></valid-connection-checker>
                       <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter"></exception-sorter>
                   </validation>
                   <statement>
                       <share-prepared-statements>false</share-prepared-statements>
                   </statement>
               </datasource>
               <drivers>
                   <driver name="cubrid" module="cubrid">
                       <driver-class>cubrid.jdbc.driver.CUBRIDDriver</driver-class>
                   </driver>
                   <driver name="postgres" module="postgres">
                       <driver-class>org.postgresql.Driver</dirver-class>
                   </driver>
               </drivers>
           </datasources>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:deployment-scanner:2.0">
           <deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="0" scan-enabled="false" runtime-failure-causes-rollback="${jboss.deployment.scanner.rollback.on.failure:false}"/>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:discovery:1.0"/>
       <subsystem xmlns="urn:jboss:domain:distributable-web:2.0" default-session-management="default" dafault-single-sign-on-management="default">
           <infinispan-session-management name="default" cache-container="web" granularity="SESSION">
               <primary-owner-affinity/>
           </infinispan-session-management>
           <infinispan-single-sign-on-management name="default" cache-container="web" cache="sso"/>
           <infinispan-routing cache-container="web" cache="routing"/>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:ee:4.0">
           <spec-descriptor-property-replacement>false</spec-descriptor-property-replacement>
           <concurrent>
               <context-services>
                   <context-service name="default" jnid-name="java:jboss/ee/concurrency/context/default" use-transaction-setup-provider="true"/>
               </context-services>
               <managed-thread-factories>
                   <managed-thread-factory name="default" jndi-name="java:jboss/ee/concurrency/factory/default" context-service="default"/>
               </managed-thread-factories>
               <managed-executor-services>
                   <managed-executor-service name="default" jndi-name="java:jboss/ee/concurrency/executor/default" context-service="default" hung-task-threshold="60000" keepalive-time="5000"/>
               </managed-executor-services>
               <managed-scheduled-executor-services>
                   <managed-scheduled-executor-service name="default" jndi-name="java:jboss/ee/concurrency/scheduler/default" context-service="default" hung-task-threshold="60000" keepalive-time="3000"/>
               </managed-scheduled-executor-services>
           </concurrent>
           <default-bindings context-service="java:jboss/ee/concurrency/context/default" datasource="java:/jboss/cubridDS" managed-executor-service="java:jboss/ee/concurrency/scheduler/default" managed-thread-factory="java:jboss/ee/concurrency/factory/default"/>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:ee-security:1.0"/>
       <subsystem xmlns="urn:jboss:domain:ejb3:6.0">       
           <session-bean>
               <stateless>
                   <bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
               </stateless>
               <stateful default-access-timeout="5000" cache-ref="simple" passivation-disabled-cache-ref="simple"/>
               <singleton default-access-timeout="5000"/>
           </session-bean>
           <pools>
               <bean-instance-pools>
                   <strict-max-pool name="mdb-strict-max-pool" derive-size="from-cpu-count" instance-acquisition-timeout="5" instance-acquisition-time-unit="MINUTES"/>
                   <strict-max-pool name="slsb-strict-max-pool" derive-size="from-worker-pools" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
               </bean-instance-pools>
           </pools>
           <caches>
               <cache name="simple"/>
               <cache name="distributable" passivation-store-ref="infinispan" aliases="passivating clustered"/>
           </caches>
           <passivation-stores>
               <passivation-store name="infinispan" cache-container="ejb" max-size="10000"/>
           </pasivation-stores>
           <async thread-pool-name="default"/>
           <timer-service thread-pool-name="default" default-data-store="default-file-store">
               <data-stores>
                   <file-data-store name="default-file-store" path="timer-service-data" relative-to="jboss.server.data.dir"/>
               </data-stores>
           </timer-service>
           <remote connector-ref="http-remoting-connector" thread-pool-name="default">
               <chnnel-creation-options>
                   <option name="MAX_OUTBOUND-MESSAGES" value="1234" type="remoting"/>
               </chnnel-creation-options>
           </remote>
           <thread-pools>
               <thread-pool name="default">
                   <max-threads count="10"/>
                   <keepalive-time time="60" unit="seconds"/>
               </thread-pool>
           </thread-pools>
           <default-security-domain value="other"/>
           <default-missing-method-permissions-deny-access value="true"/>
           <statistics enabled="${wildfly.ejb3.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
           <log-system-exceptions value="true"/>
       </subsystem>
       <subsystem xmlns="urn:wildfly:elytron:8.0" final-providers="combinde-providers" disallowed-providers="OracleUcrypto">
           <providers>
               <aggregate-providers name="combined-providers">
                   <providers name="elytron"/>
                   <providers name="openssl"/>
               </aggregate-providers>
               <provider-loader name="elytron" module="org.wildfly.security.elytron"/>
               <provider-loader name="openssl" module="org.wildfly.openssl"/>
           </providers>
           <audit-logging>
               <file-audit-log name="local-audit" path="audit.log" relative-to="jboss.server.log.dir" format="JSON"/>
           </audit-logging>
           <security-domains>
               <security-domain name="ApplicationDomain" default-realm="ApplicationRealm" permission-mapper="default-permission-mapper">
                   <realm name="ApplicationRealm" role-decoder="groups-to-roles"/>
                   <realm name="local"/>
               </security-domain>
               <security-domain name="ManagementDomain" default-realm="ManagementRealm" permission-mapper="default-permission-mapper">
                   <realm name="ManagementRealm" role-decoder="groups-to-roles"/>
                   <realm name="local" role-mapper="super-user-mapper"/>
               </security-domain>
           </security-domains>
           <security-realms>
               <identity-realm name="local" identity="$local"/>
               <properties-realm name="ApplicationRealm">
                   <users-properties path="application-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ApplicationRealm"/>
                   <groups-properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
               </properties-realm>
               <properties-realm name="ManagementRealm">
                   <users-properties path="mgmt-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ManagementRealm"/>
                   <groups-properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
               </properties-realm>
           </security-realms>
           <mappers>
               <simple-permission-mapper name="default-permission-mapper" mapping-mode="first">
                   <permission-mapping>
                       <principal name="anonymous"/>
                       <permission-set name="default-permissions"/>
                   </permission-mapping>
                   <permission-mapping match-all="true">
                       <permission-set name="login-permission"/>
                       <permission-set name="default-permissions"/>
                   </permission-mapping>
               </simple-permission-mapper>
               <constant-realm-mapper name="local" realm-name="local"/>
               <simple-role-decoder name="groups-to-roles" attribute="groups"/>
               <constant-role-mapper name="super-user-mapper">
                   <role name="SuperUser"/>
               </constant-role-mapper>
           </mappers>
           <permission-sets>
               <permission-set name="login-permission">
                   <permission class-name="org.wildfly.security.auth.permission.LoginPermission"/>
               </permission-set>
               <permission-set name="default-permissions">
                   <permission class-name="org.wildfly.extension.batch.jberet.deployment.BatchPermission" module="org.wildfly.extension.batch.jberet" target-name="*"/>
                   <permission class-name="org.wildfly.transaction.client.RemoteTransactionPermission" module="org.wildfly.transaction.client"/>
                   <permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/>
               </permission-set>
           </permission-sets>
           <http>
               <http-authentication-factory name="management-http-authentication" security-domain="ManagementDomain" http-server-mechanism-factory="global">
                   <mechanism-configuration>
                       <mechanism mechanism-name="DIGEST">
                           <mechanism-realm realm-name="ManagementRealm"/>
                       </mechanism>
                   </mechanism-configuration>
               </http-authentication-factory>
               <provider-http-server-mechanism-factory name="global"/>
           </http>
           <sasl>
               <sasl-authentication-factory name="application-sasl-authentication" sasl-server-factory="configured" security-domain="ApplicationDomain">
                   <mechanism-configuration>
                       <mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
                       <mechanism mechanism-name="DIGEST-MD5">
                           <mechanism-realm realm-name="ApplicationRealm"/>
                       </mechanism>
                   </mechanism-configuration>
               </sasl-authentication-factory>
               <sasl-authentication-factory name="management-sasl-authentication" sasl-server-factory="configured" security-domain="ManagementDomain">
                   <mechanism-configuration>
                       <mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
                       <mechanism mechanism-name="DIGEST-MD5">
                           <mechanism-realm realm-name="ManagementRealm"/>
                       </mechanism>
                   </mechanism-configuration>
               </sasl-authentication-factory>
               <configurable-sasl-server-factory name="configured" sasl-server-factory="elytron">
                   <properties>
                       <property name="wildfily.sasl.local-user.default-user" value="$local"/>
                   </properties>
               </configurable-sasl-server-factory>
               <mechanism-provider-filtering-sasl-server-factory name="elytron" sasl-server-factory="global">
                   <filters>
                       <filter provider-name="WildFlyElytron"/>
                   </filters>
               </mechanism-provider-filtering-sasl-server-factory>
               <provider-sasl-server-factory name="global"/>
           </sasl>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:infinispan:9.0">
           <cache-container name="web" default-cache="passivation" module="org.wildfly.clustering.web.infinispan">
               <local-cache name="passivation">
                   <locking isolation="REPEATABLE_READ"/>
                   <transaction mode="BATCH"/>
                   <file-store passivation="true" purge="false"/>
               </local-cache>
               <local-cache name="sso">
                   <locking isolation="REPEATABLE_READ"/>
                   <transaction mode="BATCH"/>
               </local-cache>
               <local-cache name="routing"/>
           </cache-container>
           <cache-container name="server" default-cache="default" module="org.wildfly.clustering.server">
               <local-cache name="default">
                   <transaction mode="BATCH"/>
               </local-cache>
           <cache-container>
           <cache-container name="ejb" aliases="sfsb" default-cache="passivation" module="org.wildfly.clustering.ejb.infinispan">
               <local-cache name="passivation">
                   <locking isolation="REPEATABLE_READ"/>
                   <transaction mode="BATCH"/>
                   <file-store passivation="true" purge="false"/>
               </local-cache>
           <cache-container>    
           <cache-container name="hibernate" module="org.infinispan.hibernate-cache">
               <local-cache name="entity">
                   <object-memory size="10000"/>
                   <expiration max-idle="100000"/>
               </local-cache>
               <local-cache name="local-query"/>
                   <object-memory size="10000"/>
                   <expiration max-idle="100000"/>
               </local-cache>
               <local-cache name="timestamps"/>
           </cache-container>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:io:3.0">
           <worker name="default"/>
           <buffer-pool name="default"/>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:jaxrs:1.0"/>
       <subsystem xmlns="urn:jboss:domain:jca:5.0">
           <archive-validation enabled="true" fail-on-error="true" fail-on-warn="false"/>
           <bean-validation enabled="true"/>
           <default-workmanager>
               <short-running-threads>
                   <core-threads count="50"/>
                   <queue-length count="50"/>
                   <max-threads count="50"/>
                   <keepalive-time time="10" unit="seconds"/>
               </short-running-threads>
               <long-running-threads>
                   <core-threads count="50"/>
                   <queue-length count="50"/>
                   <max-threads count="50"/>
                   <keepalive-time time="10" unit="seconds"/>
               </short-running-threads>
          </default-workmanager>
          <cached-connection-manager/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:jdr:1.0"/>
      <subsystem xmlns="urn:jboss:domain:jmx:1.3">
          <expose-resolved-model/>
          <expose-expression-model/>
          <remoting-connector/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:jpa:1.1">
          <jpa default-datasource="" default-extended-persistence-inheritance="DEEP"/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:jsf:1.1"/>
      <subsystem xmlns="urn:jboss:domain:mail:3.0">
          <mail-session name="default" jndi-name="java:jboss/mail/Default">
              <smtp-server outbound-socket-binding-ref="mail-smtp"/>
          </mail-session>
      </subsystem>
      <subsystem xmlns="urn:wildfly:microprofile-config-smallrye:1.0"/>
      <subsystem xmlns="urn:wildfly:microprofile-health-smallrye:2.0" security-enabled="false" empty-liveness-checks-status="${env.MP_HEALTH_EMPTY_LIVENESS_CHECKS_STATUS:UP}" empty-readiness-checks-status="${env.MP_HEALTH_EMPTY_READINESS_CHECKS_STATUS:UP}"/>
      <subsystem xmlns="urn:wildfly:microprofile-metrics-smallrye:2.0" security-enabled="false" exposed-subsystems="*" prefix="${wildfly.metrics.prefix:jboss}"/>
      <subsystem xmlns="urn:wildfly:microprofile-opentracing-smallrye:1.0"/>
      <subsystem xmlns="urn:jboss:domain:naming:2.0">
          <remote-naming/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:pojo:1.0"/>
      <subsystem xmlns="urn:jboss:domain:remoting:4.0">
          <connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm"/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:request-controller:1.0"/>
      <subsystem xmlns="urn:jboss:domain:resource-adapters:5.0"/>
      <subsystem xmlns="urn:jboss:domain:sar:1.0"/>
      <subsystem xmlns="urn:jboss:domain:security:2.0">
          <security-domains>
              <security-domain name="cubrid-password" cache-type="default">
                  <authentication>
                      <login-module code="org.picketbox.datasource.security.SecureIdentityLoginModule" flag="required">
                          <module-option name="username" value="public"/>
                          <module-option name="password" value="2d6219b35e931895a11f65ce06a77a33c"/>
                          <module-option name="managedConnectionFactoryName" value="jbossjca:service=LocalTxCM,name=cubridDS"/>
                      </login-module>
                  </authentication>
              </security-domain>
              <security-domain name="other" cache-type="default">
                  <authentication>
                      <login-module code="Remoting" flag="optional">
                          <module-option name="password-stacking" value="useFirstPass"/>
                      </login-module>
                      <login-module code="RealmDirect" flag="required">
                          <module-option name="password-stacking" value="useFirstPass"/>
                      </login-module>
                  </authentication>
              </security-domain>
              <security-domain name="jboss-web-policy" cache-type="default">
                  <authorization>
                      <policy-module code="Delegating" flag="required"/>
                  </authorization>
              </security-domain>
              <security-domain name="jaspitest" cache-type="default">
                  <authentication-jaspi>
                      <login-module-stack name="dummy">
                          <login-module code="Dummy" flag="optional"/>
                      </login-module-stack>
                      <auth-module code="Dummy"/>
                  </authentication-jaspi>
              </security-domain>
              <security-domain name="jboss-ejb-policy" cache-type="default">
                  <authorization>
                      <policy-module code="Delegating" flag="required"/>
                  </authrization>
              </security-domain>
          </security-domains>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:security-manager:1.0">
          <deployment-permissions>
              <maximum-set>
                  <permission class="java.security.AllPermission"/>
              </maximum-set>
          </deployment-permissions>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:transaction:5.0">
          <core-environment node-identifier="${jboss.tx.node.id:1}">
              <process-id>
                  <uuid/>
              </process-id>
          </core-environment>
          <recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
          <coordinator-environment statistics-enabled="${wildfly.transactions.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
          <object-store path="tx-object-store" relative-to="jboss.server.data.dir"/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:undertow:10.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
          <buffer-cache name="default"/>
          <server name="default-server">
              <ajp-listener name="ajp" max-post-size="524288000" socket-binding="ajp" max-connections="1024"/>
              <http-listener name="default" max-post-size="524288000" socket-binding="http" redirect-socket="https" enable-http2="true"/>
              <http-listener name="https" max-post-size="524288000" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true"/>
              <host name="default-host" alias="localhost">
                  <location name="/" handler="welcom-content"/>
                  <http-invoker security-realm="ApplicationRealm"/>
                  <filter-ref name="secret-checker" predicate="equals(%p,${jboss.ajp.port:8009})"/>
              </host>
          </server>
          <servlet-container name="default">
              <jsp-config x-powered-by="false" development="false" check-interval="60"/>
              <websockets/>
          </servlet-container>
          <filters>
              <expression-filter name="secret-checker" expression="not equals(%{r,secret}, 'Q2xvdWQxMjMj') -> response-code(403)"/>
          </filters>
          <handlers>
              <file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
          </handlers>
      </subsystem>                 
      <subsystem xmlns="urn:jboss:domain:webservices:2.0" statistics-enabled="${wildfly.webservices.statistics-enabled:${wildfly.statistics-enabled:false}}">
          <wsdl-host>${jboss.bind.address:127.0.0.1}</wsdl-host>
          <endpoint-config name="Standard-Endpoint-Config"/>
          <endpoint-config name="Recording-Endpoint-Config">
              <pre-handler-chain name="recording-handlers" protocol-bindings="##SOAP11_HTTP ##SOAP11_HTTP_MTOM ##SOAP12_HTTP ##SOAP12_HTTP_MTOM">
                  <handler name="RecordingHandler" class="org.jboss.ws.common.invocation.RecordingServerHandler"/>
              </pre-handler-chain>
          </endpoint-config>
          <client-config name="Standard-Client-Config"/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:weld:4.0"/>
   </profile>
   <interfaces>
       <interface name="management">
           <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
       </interface>
       <interface name="public">
           <inet-address value="${jboss.bind.address:127.0.0.1}"/>
       </interface>       
   </interfaces>
   <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
       <socket-binding name="ajp" port="8009"/>
       <socket-binding name="http" port="8081"/>
       <socket-binding name="https" port="8443"/>
       <socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9991}"/>
       <socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
       <socket-binding name="txn-recovery-environment" port="4712"/>
       <socket-binding name="txn-status-manager" port="4713"/>
       <outbound-socket-binding name="mail-smtp">
           <remote-destination host="localhost" port="25"/>
       </outbound-socket-binding>
   </socket-binding-group>
   <deployments>
       <deployment name="sample.war" runtime-name="sample.war" enabled="false">
           <fs-exploded path="/WebApp/deploy/sample.war"/>
       </deployment>
   </deployments>
</server>

 

 

3) /JBOSS/domains/노드명/configuration/standalone-ha.xml

<?xml version='1.0' encoding='UTF-8'?>

<server xmlns="urn:jboss:domain:11.0">
	<extensions>
    	<extension module="org.jboss.as.clustering.infinispan"/>
        <extension module="org.jboss.as.clustering.jgroups"/>
        <extension module="org.jboss.as.connector"/>
        <extension module="org.jboss.as.deployment-scanner"/>
        <extension module="org.jboss.as.ee"/>
        <extension module="org.jboss.as.ejb3"/>
        <extension module="org.jboss.as.jaxrs"/>
        <extension module="org.jboss.as.jdr"/>
        <extension module="org.jboss.as.jmx"/>
        <extension module="org.jboss.as.jpa"/>
        <extension module="org.jboss.as.jsf"/>
        <extension module="org.jboss.as.logging"/>
        <extension module="org.jboss.as.mail"/>
        <extension module="org.jboss.as.modcluster"/>
        <extension module="org.jboss.as.naming"/>
        <extension module="org.jboss.as.pojo"/>
        <extension module="org.jboss.as.remoting"/>
        <extension module="org.jboss.as.sar"/>
        <extension module="org.jboss.as.security"/>
        <extension module="org.jboss.as.transactions"/>
        <extension module="org.jboss.as.webservices"/>
        <extension module="org.jboss.as.weld"/>
        <extension module="org.wildfly.extension.batch.jberet"/>
        <extension module="org.wildfly.extension.bean-validation"/>
        <extension module="org.wildfly.extension.clustering.web"/>
        <extension module="org.wildfly.extension.core-management"/>
        <extension module="org.wildfly.extension.discovery"/>
        <extension module="org.wildfly.extension.ee-security"/>
        <extension module="org.wildfly.extension.elytron"/>
        <extension module="org.wildfly.extension.io"/>
        <extension module="org.wildfly.extension.microprofile.config-smallrye"/>
        <extension module="org.wildfly.extension.microprofile.health-smallrye"/>
        <extension module="org.wildfly.extension.microprofile.metrics-smallrye"/>
        <extension module="org.wildfly.extension.microprofile.opentracing-smallrye"/>
        <extension module="org.wildfly.extension.request-controller"/>
        <extension module="org.wildfly.extension.security.manager"/>
        <extension module="org.wildfly.extension.undertow"/>
	</extensions>
    <management>
    	<security-realms>
        	<security-realm name="ManagementRealm">
            	<authentication>
                	<local default-user="$local" skip-group-loading="true"/>
                    <properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
                </authentication>
                <authorization map-groups-to-roles="false">
                	<properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
                </authorization>
            </security-realm>
            <security-realm name="ApplicationRealm">
            	<server-identities>
                	<ssl>
                    <!--	<keystore path="application.keystore" relative-to="jboss.server.config.dir" keystore-password="password" alias="server" key-password="password" generate-self-signed-certificate-host="localhost"/> -->
                    </ssl>
                </server-identities>
                <authentication>
                	<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
                    <properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
                </authentication>>
                <authorization>
                	<properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
                </authorization>
            </security-realm>
        </security-realms>
        <audit-log>
        	<formatters>
            	<json-formatter name="json-formatter"/>
            </formatters>
            <handlers>
            	<file-handler name="file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
            </handlers>
            <logger log-boot="true" log-read-only="false" enabled="false">
            	<handlers>
                	<handler name="file"/>
                </handlers>
            </logger>
        </audit-log>
        <management-interfaces>
        	<http-interface security-realm="ManagementRealm">
            	<http-upgrade enabled="true"/>
            	<socket-binding native="management-http"/>
            </http-interface>            
       </management-interfaces>
       <access-contorl provider="simple">
           <role-mapping>
               <role name="SuperUser">
                   <include>
                       <user name="$local"/>
                   </include>
               </role>
           </role-mapping>
       </access-control>
   </management>
   <profile>
       <subsystem xmlns="urn:jboss:domain:logging:8.0">
           <console-handler name="CONSOLE">
               <level name="ERROR"/>
               <formatter>
                   <named-formatter name="COLOR-PATTERN"/>
               </formatter>
           </console-handler>
           <periodic-rotating-file-handler name="FILE" autoflush="true">
               <formatter>
                   <named-formatter name="PATTERN"/>
               </formatter>
               <file relative-to="jboss.server.log.dir" path="server.log"/>
               <suffix value=".yyyy-MM-dd"/>
               <append value="true"/>
           </periodic-rotating-file-handler>
           <logger category="com.arjuna">
               <level name="WARN"/>
           </logger>
           <logger category="io.jaegertracing.Configuration">
               <level name="WARN"/>
           </logger>
           <logger category="org.jboss.as.config">
               <level name="DEBUG"/>
           </logger>
           <logger category="sun.rmi">
               <level name="WARN"/>
           </logger>
           <root-logger>
               <level name="INFO"/>
               <handlers>
                   <handler name="CONSOLE"/>
                   <handler name="FILE"/>
               </handlers>
           </root-logger>
           <formatter name="PATTERN">
               <pattern-formatter pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
           </formatter>
           <formatter name="COLOR-PATTERN">
               <pattern-formatter pattern="%K{level}%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
           </formatter>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:batch-jberet:2.0">
           <default-job-repository name="in-memory"/>
           <default-thread-pool name="batch"/>
           <job-repository name="in-menory">
               <in-memory/>
           </job-repository>
           <thread-pool name="batch">
               <max-threads count="10"/>
               <keepalive-time time="30" unit="seconds"/>
           </thread-pool>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:bean-validation:1.0"/>
       <subsystem xmlns="urn:jboss:domain:core-management:1.0"/>
       <subsystem xmlns="urn:jboss:domain:datasources:5.0">
           <datasources>
               <datasource jndi-name="java:jboss/cubridDS" pool-name="cubridDS" enabled="true">
                   <connection-url>jdbc:cubrid:dbmshost1:33000:db명:::?altHosts=dbmshost2:33000&amp;hold_cursor=no&amp;charset=utf-8</connection-url>
                   <driver-class>cubrid.jdbc.dirver.CUBRIDDriver</driver-class>
                   <driver>cubrid</driver>
                   <pool>
                       <min-pool-size>5</min-pool-size>
                       <max-pool-size>50</max-pool-size>
                       <prefill>false</prefill>
                       <use-strict-min>true</use-strict-min>
                   </pool>
                   <timeout>
                       <blocking-timeout-millis>300000</blocking-timeout-millis>
                       <idle-timeout-minutes>10</idle-timeout-minutes>
                   </timeout>
                   <security>
                       <security-domain>cubrid-password</security-domain>                       
                   </security>
                   <validation>
                       <check-valid-connection-sql>select 1</check-valid-connection-sql>
                       <validate-on-match>true</validate-on-match>
                       <background-validation>false</background-validation>
                   </validation>
                   <statement>
                       <share-prepared-statements>false</share-prepared-statements>
                   </statement>
               </datasource>
               <datasource jndi-name="java:jboss/postgresDS" pool-name="postgresDS" enabled="false">
                   <connection-url>jdbc:postgresql://dbmshost1:5432,dbmshost2:5432/postgres</connection-url>
                   <driver-class>org.postgresql.Driver</driver-class>
                   <driver>postgres</driver>
                   <pool>
                       <min-pool-size>5</min-pool-size>
                       <max-pool-size>50</max-pool-size>
                       <prefill>false</prefill>
                       <use-strict-min>true</use-strict-min>
                   </pool>
                   <timeout>
                       <blocking-timeout-millis>300000</blocking-timeout-millis>
                       <idle-timeout-minutes>10</idle-timeout-minutes>
                   </timeout>
                   <security>
                       <security-domanin>cubrid-password</security-domain>
                   </security>                  
                   <validation>
                       <check-valid-connection-sql>select 1</check-valid-connection-sql>
                       <validate-on-match>true</validate-on-match>
                       <background-validation>false</background-validation>
                       <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.etensions.postgres.PostgreSQLValidConnectionChecker"></valid-connection-checker>
                       <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter"></exception-sorter>
                   </validation>
                   <statement>
                       <share-prepared-statements>false</share-prepared-statements>
                   </statement>
               </datasource>
               <drivers>
                   <driver name="cubrid" module="cubrid">
                       <driver-class>cubrid.jdbc.driver.CUBRIDDriver</driver-class>
                   </driver>
                   <driver name="postgres" module="postgres">
                       <driver-class>org.postgresql.Driver</dirver-class>
                   </driver>
               </drivers>
           </datasources>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:deployment-scanner:2.0">
           <deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="0" scan-enabled="false" runtime-failure-causes-rollback="${jboss.deployment.scanner.rollback.on.failure:false}"/>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:discovery:1.0"/>
       <subsystem xmlns="urn:jboss:domain:distributable-web:2.0" default-session-management="default" dafault-single-sign-on-management="default">
           <infinispan-session-management name="default" cache-container="web" granularity="SESSION">
               <primary-owner-affinity/>
           </infinispan-session-management>
           <infinispan-single-sign-on-management name="default" cache-container="web" cache="sso"/>
           <infinispan-routing cache-container="web" cache="routing"/>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:ee:4.0">
           <spec-descriptor-property-replacement>false</spec-descriptor-property-replacement>
           <concurrent>
               <context-services>
                   <context-service name="default" jnid-name="java:jboss/ee/concurrency/context/default" use-transaction-setup-provider="true"/>
               </context-services>
               <managed-thread-factories>
                   <managed-thread-factory name="default" jndi-name="java:jboss/ee/concurrency/factory/default" context-service="default"/>
               </managed-thread-factories>
               <managed-executor-services>
                   <managed-executor-service name="default" jndi-name="java:jboss/ee/concurrency/executor/default" context-service="default" hung-task-threshold="60000" keepalive-time="5000"/>
               </managed-executor-services>
               <managed-scheduled-executor-services>
                   <managed-scheduled-executor-service name="default" jndi-name="java:jboss/ee/concurrency/scheduler/default" context-service="default" hung-task-threshold="60000" keepalive-time="3000"/>
               </managed-scheduled-executor-services>
           </concurrent>
           <default-bindings context-service="java:jboss/ee/concurrency/context/default" datasource="java:/jboss/cubridDS" managed-executor-service="java:jboss/ee/concurrency/scheduler/default" managed-thread-factory="java:jboss/ee/concurrency/factory/default"/>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:ee-security:1.0"/>
       <subsystem xmlns="urn:jboss:domain:ejb3:6.0">       
           <session-bean>
               <stateless>
                   <bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
               </stateless>
               <stateful default-access-timeout="5000" cache-ref="simple" passivation-disabled-cache-ref="simple"/>
               <singleton default-access-timeout="5000"/>
           </session-bean>
           <pools>
               <bean-instance-pools>
                   <strict-max-pool name="mdb-strict-max-pool" derive-size="from-cpu-count" instance-acquisition-timeout="5" instance-acquisition-time-unit="MINUTES"/>
                   <strict-max-pool name="slsb-strict-max-pool" derive-size="from-worker-pools" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
               </bean-instance-pools>
           </pools>
           <caches>
               <cache name="simple"/>
               <cache name="distributable" passivation-store-ref="infinispan" aliases="passivating clustered"/>
           </caches>
           <passivation-stores>
               <passivation-store name="infinispan" cache-container="ejb" max-size="10000"/>
           </pasivation-stores>
           <async thread-pool-name="default"/>
           <timer-service thread-pool-name="default" default-data-store="default-file-store">
               <data-stores>
                   <file-data-store name="default-file-store" path="timer-service-data" relative-to="jboss.server.data.dir"/>
               </data-stores>
           </timer-service>
           <remote connector-ref="http-remoting-connector" thread-pool-name="default">
               <chnnel-creation-options>
                   <option name="MAX_OUTBOUND-MESSAGES" value="1234" type="remoting"/>
               </chnnel-creation-options>
           </remote>
           <thread-pools>
               <thread-pool name="default">
                   <max-threads count="10"/>
                   <keepalive-time time="60" unit="seconds"/>
               </thread-pool>
           </thread-pools>
           <default-security-domain value="other"/>
           <default-missing-method-permissions-deny-access value="true"/>
           <statistics enabled="${wildfly.ejb3.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
           <log-system-exceptions value="true"/>
       </subsystem>
       <subsystem xmlns="urn:wildfly:elytron:8.0" final-providers="combinde-providers" disallowed-providers="OracleUcrypto">
           <providers>
               <aggregate-providers name="combined-providers">
                   <providers name="elytron"/>
                   <providers name="openssl"/>
               </aggregate-providers>
               <provider-loader name="elytron" module="org.wildfly.security.elytron"/>
               <provider-loader name="openssl" module="org.wildfly.openssl"/>
           </providers>
           <audit-logging>
               <file-audit-log name="local-audit" path="audit.log" relative-to="jboss.server.log.dir" format="JSON"/>
           </audit-logging>
           <security-domains>
               <security-domain name="ApplicationDomain" default-realm="ApplicationRealm" permission-mapper="default-permission-mapper">
                   <realm name="ApplicationRealm" role-decoder="groups-to-roles"/>
                   <realm name="local"/>
               </security-domain>
               <security-domain name="ManagementDomain" default-realm="ManagementRealm" permission-mapper="default-permission-mapper">
                   <realm name="ManagementRealm" role-decoder="groups-to-roles"/>
                   <realm name="local" role-mapper="super-user-mapper"/>
               </security-domain>
           </security-domains>
           <security-realms>
               <identity-realm name="local" identity="$local"/>
               <properties-realm name="ApplicationRealm">
                   <users-properties path="application-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ApplicationRealm"/>
                   <groups-properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
               </properties-realm>
               <properties-realm name="ManagementRealm">
                   <users-properties path="mgmt-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ManagementRealm"/>
                   <groups-properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
               </properties-realm>
           </security-realms>
           <mappers>
               <simple-permission-mapper name="default-permission-mapper" mapping-mode="first">
                   <permission-mapping>
                       <principal name="anonymous"/>
                       <permission-set name="default-permissions"/>
                   </permission-mapping>
                   <permission-mapping match-all="true">
                       <permission-set name="login-permission"/>
                       <permission-set name="default-permissions"/>
                   </permission-mapping>
               </simple-permission-mapper>
               <constant-realm-mapper name="local" realm-name="local"/>
               <simple-role-decoder name="groups-to-roles" attribute="groups"/>
               <constant-role-mapper name="super-user-mapper">
                   <role name="SuperUser"/>
               </constant-role-mapper>
           </mappers>
           <permission-sets>
               <permission-set name="login-permission">
                   <permission class-name="org.wildfly.security.auth.permission.LoginPermission"/>
               </permission-set>
               <permission-set name="default-permissions">
                   <permission class-name="org.wildfly.extension.batch.jberet.deployment.BatchPermission" module="org.wildfly.extension.batch.jberet" target-name="*"/>
                   <permission class-name="org.wildfly.transaction.client.RemoteTransactionPermission" module="org.wildfly.transaction.client"/>
                   <permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/>
               </permission-set>
           </permission-sets>
           <http>
               <http-authentication-factory name="management-http-authentication" security-domain="ManagementDomain" http-server-mechanism-factory="global">
                   <mechanism-configuration>
                       <mechanism mechanism-name="DIGEST">
                           <mechanism-realm realm-name="ManagementRealm"/>
                       </mechanism>
                   </mechanism-configuration>
               </http-authentication-factory>
               <provider-http-server-mechanism-factory name="global"/>
           </http>
           <sasl>
               <sasl-authentication-factory name="application-sasl-authentication" sasl-server-factory="configured" security-domain="ApplicationDomain">
                   <mechanism-configuration>
                       <mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
                       <mechanism mechanism-name="DIGEST-MD5">
                           <mechanism-realm realm-name="ApplicationRealm"/>
                       </mechanism>
                   </mechanism-configuration>
               </sasl-authentication-factory>
               <sasl-authentication-factory name="management-sasl-authentication" sasl-server-factory="configured" security-domain="ManagementDomain">
                   <mechanism-configuration>
                       <mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
                       <mechanism mechanism-name="DIGEST-MD5">
                           <mechanism-realm realm-name="ManagementRealm"/>
                       </mechanism>
                   </mechanism-configuration>
               </sasl-authentication-factory>
               <configurable-sasl-server-factory name="configured" sasl-server-factory="elytron">
                   <properties>
                       <property name="wildfily.sasl.local-user.default-user" value="$local"/>
                   </properties>
               </configurable-sasl-server-factory>
               <mechanism-provider-filtering-sasl-server-factory name="elytron" sasl-server-factory="global">
                   <filters>
                       <filter provider-name="WildFlyElytron"/>
                   </filters>
               </mechanism-provider-filtering-sasl-server-factory>
               <provider-sasl-server-factory name="global"/>
           </sasl>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:infinispan:9.0">
           <cache-container name="web" default-cache="dist" module="org.wildfly.clustering.web.infinispan">
               <transport lock-timeout="60000"/>
               <replicated-cache name="sso">
                   <locking isolation="REPEATABLE_READ"/>
                   <transaction mode="BATCH"/>
               </replicated-cache>
               <replicated-cache name="routing"/>
               <distributed-cache name="dist">
                   <locking isolation="REPEATABLE_READ"/>
                   <transaction mode="BATCH"/>
                   <file-store/>
               </distributed-cache>               
           </cache-container>
           <cache-container name="server" aliases="singleton cluster" default-cache="default" module="org.wildfly.clustering.server">
               <transport lock-timeout="60000"/>
                   <transaction mode="BATCH"/>
               </replicated-cache>               
           <cache-container>
           <cache-container name="ejb" aliases="sfsb" default-cache="dist" module="org.wildfly.clustering.ejb.infinispan">
               <transport lock-timeout="60000"/>
               <distributed-cache name="dist">
                   <locking isolation="REPEATABLE_READ"/>
                   <transaction mode="BATCH"/>
                   <file-store/>
               </distributed-cache>               
           <cache-container>    
           <cache-container name="hibernate" module="org.infinispan.hibernate-cache">
               <transport lock-timeout="60000"/>
               <local-cache name="local-query">
                   <object-memory size="10000"/>
                   <expiration max-idle="100000"/>
               </local-cache>
               <invalidation-cache name="entity"/>
                   <object-memory size="10000"/>
                   <expiration max-idle="100000"/>
               </invalidation-cache>
               <replicated-cache name="timestamps"/>
           </cache-container>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:io:3.0">
           <worker name="default"/>
           <buffer-pool name="default"/>
       </subsystem>
       <subsystem xmlns="urn:jboss:domain:jaxrs:1.0"/>
       <subsystem xmlns="urn:jboss:domain:jca:5.0">
           <archive-validation enabled="true" fail-on-error="true" fail-on-warn="false"/>
           <bean-validation enabled="true"/>
           <default-workmanager>
               <short-running-threads>
                   <core-threads count="50"/>
                   <queue-length count="50"/>
                   <max-threads count="50"/>
                   <keepalive-time time="10" unit="seconds"/>
               </short-running-threads>
               <long-running-threads>
                   <core-threads count="50"/>
                   <queue-length count="50"/>
                   <max-threads count="50"/>
                   <keepalive-time time="10" unit="seconds"/>
               </short-running-threads>
          </default-workmanager>
          <cached-connection-manager/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:jdr:1.0"/>
      <subsystem xmlns="urn:jboss:domain:jgroups:7.0">
          <channels default="ee">
              <channel name="ee" stack"udp" cluster="ejb"/>
          </channels>
          <stacks>
              <stack name="udp">
                  <transport type="UDP" socket-binding="jgroups-udp"/>
                  <protocol type="PING"/>
                  <protocol type="MERGE3"/>
                  <socket-protocol type="FD_SOCK" socket-binding="jgroups-udp-fd"/>
                  <protocol type="FD_ALL"/>
                  <protocol type="VERIFY_SUSPECT"/>
                  <protocol type="pbcast.NAKACK2"/>
                  <protocol type="UNICAST3"/>
                  <protocol type="pbcast.STABLE"/>
                  <protocol type="pbcast.GMS"/>
                  <protocol type="UFC"/>
                  <protocol type="MFC"/>
                  <protocol type="FRAG3"/>
              </stack>
              <stack name="tcp">
                  <transport type="TCP" socket-binding="jgroups-tcp"/>
                  <!-- <protocol type="TCPPING"/>
                      <property name="initial_hosts">${jboss.cluster.tcp.initial_hosts}</property>
                      <property name="port_range">0</property>
                  </protocol> -->
                  <!-- <socket-protocol type="MPING" socket-binding="jgroups-mping"/> -->
                  <protocol type="MERGE3"/>
                  <socket-protocol type="FD_SOCK" socket-binding="jgroups-tcp-fd"/>
                  <protocol type="FD_ALL"/>
                  <protocol type="VERIFY_SUSPECT"/>
                  <protocol type="pbcast.NAKACK2"/>
                  <protocol type="UNICAST3"/>
                  <protocol type="pbcast.STABLE"/>
                  <protocol type="pbcast.GMS"/>
                  <protocol type="MFC"/>
                  <protocol type="FRAG3"/>
              </stack>
          </stacks>
      </subsystem>                  
      <subsystem xmlns="urn:jboss:domain:jmx:1.3">
          <expose-resolved-model/>
          <expose-expression-model/>
          <remoting-connector/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:jpa:1.1">
          <jpa default-datasource="" default-extended-persistence-inheritance="DEEP"/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:jsf:1.1"/>
      <subsystem xmlns="urn:jboss:domain:mail:3.0">
          <mail-session name="default" jndi-name="java:jboss/mail/Default">
              <smtp-server outbound-socket-binding-ref="mail-smtp"/>
          </mail-session>
      </subsystem>
      <subsystem xmlns="urn:wildfly:microprofile-config-smallrye:1.0"/>
      <subsystem xmlns="urn:wildfly:microprofile-health-smallrye:2.0" security-enabled="false" empty-liveness-checks-status="${env.MP_HEALTH_EMPTY_LIVENESS_CHECKS_STATUS:UP}" empty-readiness-checks-status="${env.MP_HEALTH_EMPTY_READINESS_CHECKS_STATUS:UP}"/>
      <subsystem xmlns="urn:wildfly:microprofile-metrics-smallrye:2.0" security-enabled="false" exposed-subsystems="*" prefix="${wildfly.metrics.prefix:jboss}"/>
      <subsystem xmlns="urn:wildfly:microprofile-opentracing-smallrye:1.0"/>
      <subsystem xmlns="urn:jboss:domain:modcluster:5.0">
          <proxy name="default" advertise-socket="modcluster" listener="ajp">
              <dynamic-load-provider>
                  <load-metric type="cpu"/>
              </dynamic-load-provider>
          </proxy>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:naming:2.0">
          <remote-naming/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:pojo:1.0"/>
      <subsystem xmlns="urn:jboss:domain:remoting:4.0">
          <http-connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm"/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:request-controller:1.0"/>
      <subsystem xmlns="urn:jboss:domain:resource-adapters:5.0"/>
      <subsystem xmlns="urn:jboss:domain:sar:1.0"/>
      <subsystem xmlns="urn:jboss:domain:security:2.0">
          <security-domains>
              <security-domain name="cubrid-password" cache-type="default">
                  <authentication>
                      <login-module code="org.picketbox.datasource.security.SecureIdentityLoginModule" flag="required">
                          <module-option name="username" value="public"/>
                          <module-option name="password" value="2d6219b35e931895a11f65ce06a77a33c"/>
                          <module-option name="managedConnectionFactoryName" value="jbossjca:service=LocalTxCM,name=cubridDS"/>
                      </login-module>
                  </authentication>
              </security-domain>
              <security-domain name="other" cache-type="default">
                  <authentication>
                      <login-module code="Remoting" flag="optional">
                          <module-option name="password-stacking" value="useFirstPass"/>
                      </login-module>
                      <login-module code="RealmDirect" flag="required">
                          <module-option name="password-stacking" value="useFirstPass"/>
                      </login-module>
                  </authentication>
              </security-domain>
              <security-domain name="jboss-web-policy" cache-type="default">
                  <authorization>
                      <policy-module code="Delegating" flag="required"/>
                  </authorization>
              </security-domain>
              <security-domain name="jaspitest" cache-type="default">
                  <authentication-jaspi>
                      <login-module-stack name="dummy">
                          <login-module code="Dummy" flag="optional"/>
                      </login-module-stack>
                      <auth-module code="Dummy"/>
                  </authentication-jaspi>
              </security-domain>
              <security-domain name="jboss-ejb-policy" cache-type="default">
                  <authorization>
                      <policy-module code="Delegating" flag="required"/>
                  </authrization>
              </security-domain>
          </security-domains>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:security-manager:1.0">
          <deployment-permissions>
              <maximum-set>
                  <permission class="java.security.AllPermission"/>
              </maximum-set>
          </deployment-permissions>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:singleton:1.0">
          <singleton-policies default="default">
              <singleton-policy name="default" cache-container="server">
                  <simple-election-policy/>
              </singleton-policy>
          </singleton-policies>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:transaction:5.0">
          <core-environment node-identifier="${jboss.tx.node.id:1}">
              <process-id>
                  <uuid/>
              </process-id>
          </core-environment>
          <recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
          <coordinator-environment statistics-enabled="${wildfly.transactions.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
          <object-store path="tx-object-store" relative-to="jboss.server.data.dir"/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:undertow:10.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
          <buffer-cache name="default"/>
          <server name="default-server">
              <ajp-listener name="ajp" max-post-size="524288000" socket-binding="ajp" max-connections="1024"/>
              <http-listener name="default" max-post-size="524288000" socket-binding="http" redirect-socket="https" enable-http2="true"/>
              <https-listener name="https" max-post-size="524288000" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true"/>
              <host name="default-host" alias="localhost">
                  <location name="/" handler="welcom-content"/>
                  <http-invoker security-realm="ApplicationRealm"/>
                  <filter-ref name="secret-checker" predicate="equals(%p,${jboss.ajp.port:8009})"/>
              </host>
          </server>
          <servlet-container name="default">
              <jsp-config x-powered-by="false" development="false" check-interval="60"/>
              <websockets/>
          </servlet-container>
          <filters>
              <expression-filter name="secret-checker" expression="not equals(%{r,secret}, 'Q2xvdWQxMjMj') -> response-code(403)"/>
          </filters>
          <handlers>
              <file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
          </handlers>
      </subsystem>                 
      <subsystem xmlns="urn:jboss:domain:webservices:2.0" statistics-enabled="${wildfly.webservices.statistics-enabled:${wildfly.statistics-enabled:false}}">
          <wsdl-host>${jboss.bind.address:127.0.0.1}</wsdl-host>
          <endpoint-config name="Standard-Endpoint-Config"/>
          <endpoint-config name="Recording-Endpoint-Config">
              <pre-handler-chain name="recording-handlers" protocol-bindings="##SOAP11_HTTP ##SOAP11_HTTP_MTOM ##SOAP12_HTTP ##SOAP12_HTTP_MTOM">
                  <handler name="RecordingHandler" class="org.jboss.ws.common.invocation.RecordingServerHandler"/>
              </pre-handler-chain>
          </endpoint-config>
          <client-config name="Standard-Client-Config"/>
      </subsystem>
      <subsystem xmlns="urn:jboss:domain:weld:4.0"/>
   </profile>
   <interfaces>
       <interface name="management">
           <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
       </interface>
       <interface name="private">
           <inet-address value="${jboss.bind.address.private:127.0.0.1}"/>
       </interface>
       <interface name="public">
           <inet-address value="${jboss.bind.address:127.0.0.1}"/>
       </interface>       
   </interfaces>
   <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
       <socket-binding name="ajp" port="8009"/>
       <socket-binding name="http" port="8081"/>
       <socket-binding name="https" port="8443"/>
       <socket-binding name="jgroups-mping" interface="private" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45700"/>
       <socket-binding name="jgroups-tcp" interface="public" port="7600"/>
       <socket-binding name="jgroups-tcp-fd" interface="public" port="57600"/>
       <socket-binding name="jgroups-udp" interface="public" port="55200" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45688"/>
       <socket-binding name="jgroups-udp-fd" interface="public" port="54200"/>
       <socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9991}"/>
       <socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
       <socket-binding name="modcluster" multicast-address="${jboss.modcluster.multicast.address:224.0.1.105}" multicast-port="23364"/>
       <socket-binding name="txn-recovery-environment" port="4712"/>
       <socket-binding name="txn-status-manager" port="4713"/>
       <outbound-socket-binding name="mail-smtp">
           <remote-destination host="localhost" port="25"/>
       </outbound-socket-binding>
   </socket-binding-group>
   <deployments>
       <deployment name="sample.war" runtime-name="sample.war" enabled="false">
           <fs-exploded path="/WebApp/deploy/sample.war"/>
       </deployment>
   </deployments>
</server>

 

출처: https://chanchan-father.tistory.com/1009 [찬찬이 아빠 블로그:티스토리]

안되는 부분을 자세히 써주시면 좀 더 원하시는 정보를 얻을 듯 싶습니다.

WildFly(JBoss)에 올릴때 jboss-deployment-structure.xml과 jboss-web.xml이 필요한데

둘 다 필수파일은 아니지만 전자는 Logging라이브러리 등, 내가 프로젝트에 정의한 의존성을 무시하고 JBoss가 자체 라이브러리를 사용해서 오류를 일으킬 경우, 제외시키기 위한 목적으로 사용하고

후자는 Context Path정의와 DB연결에 JNDI를 사용한다면 호출할 DB정보를 지정하는 목적으로 사용합니다.

후자의 파일이 없으면 war파일명을 Context Path로 삼습니다.

각 내용물을 아래와 같지만 절대적인건 아니니 참조만 부탁드립니다.

jboss-deployment-structure.xml

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.1">
	<deployment>
		<exclusions>
			<!-- Disable jboss slf4j module to enable Logback -->
			<module name="org.slf4j" />
			<module name="org.slf4j.impl" />
			<module name="org.slf4j.jcl-over-slf4j"/>
			<module name="org.apache.commons.logging"/>
			<module name="org.apache.log4j"/>
			<module name="jdbc.resultsettable"/>
			<module name="jdbc.sqlonly"/>
		</exclusions>
	</deployment>
</jboss-deployment-structure>

 

jboss-web.xml

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
		http://www.jboss.com/xml/ns/javaee
		http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd">
	<!-- Wildfly 구동시의 Context Path 설정 -->
	<context-root>/myproject</context-root>
	
	<!-- Wildfly JNDI 설정 -->
	<resource-ref>
		<res-ref-name>jdbc/mydb</res-ref-name>
		<jndi-name>java:/mydb</jndi-name>
	</resource-ref>
</jboss-web>
 
jboss-web.xml /myproject jdbc/mydbjava:/mydb
 
 
1. JNDI 설정은 별도로 WildFly standalone.xml 혹은 datasource 설정에 등록되어 있어야 합니다.
<datasource jndi-name="java:/mydb" pool-name="MyDBPool" enabled="true">
    <connection-url>jdbc:mysql://localhost:3306/mydb</connection-url>
    <driver>mysql</driver>
    <security>
        <user-name>myuser</user-name>
        <password>mypassword</password>
    </security>
</datasource>

2. web.xml과 일치해야 합니다.
web.xml의 resource-ref에도 다음과 같이 일치하는 항목이 필요합니다:

<resource-ref>
    <res-ref-name>jdbc/mydb</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

 

 

 

1JndiObjectFactoryBean 방식 (XML 기반)

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:/mydb" />
    <property name="resourceRef" value="true" />
</bean>
  • jndiName은 jboss-web.xml의 <jndi-name>과 정확히 일치해야 합니다.
  • resourceRef를 true로 설정하면 내부적으로 java:comp/env/를 붙입니다.
    그러나 java:/mydb는 full JNDI name이므로 이 경우 false 또는 생략 가능합니다.

📌 정리

구분설정
jboss-web.xml 설정 <jndi-name>java:/mydb</jndi-name>
web.xml 설정 <res-ref-name>jdbc/mydb</res-ref-name>
Spring 설정 (JNDI) value="java:/mydb"

 

 

 

해당 블로그 글([보안가이드] Tomcat Version 정보 노출 방지)에서는 Apache Tomcat의 버전 정보가 외부에 노출될 경우 보안상 위험이 증가하므로, 이를 방지하기 위한 설정 방법을 상세히 설명하고 있습니다.온실 속 선인장 🌵🌵


🔍 문제점: Tomcat 버전 정보 노출

Tomcat을 기본 설정으로 사용할 경우, 다음과 같은 방식으로 버전 정보가 노출될 수 있습니다:

이러한 정보는 공격자가 특정 버전의 알려진 취약점을 이용하여 시스템을 공격하는 데 활용될 수 있습니다.온실 속 선인장 🌵🌵


🔧 해결 방법: 버전 정보 제거 설정

1. Response Header에서 버전 정보 제거

Tomcat의 server.xml 파일에서 <Connector> 태그에 server 속성을 추가하여 서버 정보를 변경합니다:온실 속 선인장 🌵🌵+1LainyZine: Programmer's Guide+1

xml
복사편집
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" server="Web Server" />

이렇게 설정하면 Response Header의 Server 값이 "Web Server"로 표시되어 실제 Tomcat 버전 정보가 숨겨집니다.온실 속 선인장 🌵🌵

2. 기본 에러 페이지에서 버전 정보 제거

{Tomcat 설치 경로}/lib/org/apache/catalina/util 디렉토리 내의 ServerInfo.properties 파일을 수정하거나 생성하여 다음과 같이 설정합니다:온실 속 선인장 🌵🌵

properties
복사편집
server.info=Web Server server.number=

이 설정을 적용하면 기본 에러 페이지에 표시되는 버전 정보가 "Web Server"로 변경됩니다.온실 속 선인장 🌵🌵

3. 에러 리포트에서 버전 정보 제거

server.xml 파일에 다음과 같은 <Valve> 설정을 추가하여 에러 리포트에 서버 정보가 노출되지 않도록 합니다:온실 속 선인장 🌵🌵

xml
복사편집
<Valve className="org.apache.catalina.valves.ErrorReportValve" showReport="false" showServerInfo="false" />

이 설정을 통해 에러 리포트에서 상세한 서버 정보와 보고서가 표시되지 않도록 할 수 있습니다.


✅ 결론

Tomcat의 버전 정보 노출은 보안상 심각한 위협이 될 수 있습니다. 위에서 설명한 설정을 통해 불필요한 정보 노출을 방지하고, 시스템의 보안을 강화하는 것이 중요합니다.

자세한 내용은 원문을 참고하시기 바랍니다: https://happylie.tistory.com/180

WEB/Spring

[eGovFramework]하나의 프로젝트에서 2개의 DB 사용 하기(Postgresql, Tibero DB)

우리마 2021. 1. 8. 14:57
 

안녕하세요. 이번 글에서는 eGovFramework3.8 환경에서 두 개의 DBMS를 붙이는 방법에 대해서 끄적이려고 해요. 필자는 기존에 Postgresql을 사용하다가 Tibero DB를 붙였어요. 해당 DB의 드라이버는 maven repository에서 가져와서 pom.xml에 추가해주시면 됩니다.

 

Maven Repository: Search/Browse/Explore

Integrations SDK Last Release on Dec 22, 2020

mvnrepository.com

context-datasource.xml 설정 - Datasource 추가 하기

먼저 datasource를 추가해줘야 합니다. 

src/main/resource/egovframework/spring 아래에 context-datasource.xml 파일이 있습니다.

Package Presentaion

기존의 Postgresql에 대한 Datasource는 아래와 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<bean id="egov.propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
     <property name="locations">
         <list>
             <value>classpath:/egovframework/egovProps/globals.properties</value>
         </list>
     </property>
</bean>
 
<alias name="dataSource-postgresql" alias="dataSource"/>
<!-- JDBC-PostgreSQL -->
    <bean id="dataSource-postgresql" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${Globals.DriverClassName}" />
        <property name="url" value="${Globals.Url}" />
        <property name="username" value="${Globals.UserName}" />
        <property name="password" value="${Globals.Password}" />
    </bean>
 
cs

여기서 이제 Tibero DB에 대한 Datasource를 아래와 같이 추가해 줍니다. 물론 globalglobals.properties파일에 추가하고자 하는 DB정보를 추가해줍니다. 저는 Tibero를 붙여서 사용했습니다.

1
2
3
4
5
6
7
8
9
10
11
<alias name="dataSource-tibero" alias="tibero.dataSource"/>
<!-- tibero -->
    <bean id="dataSource-tibero" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${Globals.Tibero.DriverClassName}"/>
        <property name="url" value="${Globals.Tibero.Url}" />
        <property name="username" value="${Globals.Tibero.UserName}"/>
        <property name="password" value="${Globals.Tibero.Password}"/>
        <property name="validationQuery" value="select 1 from dual" />
        <property name="testWhileIdle" value="true" />
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
    </bean>
 
cs
context-mapper.xml 설정 - SqlSessionFactoryBean, SqlSessionTemplate 추가 

파일의 위치는 위의 context-datasource.xml의 위치와 같습니다.

위의 Package Presentaion사진을 참고하세요.

 

기존의 postgresql의 sqlsession bean 설정은 아래와 같습니다.

postgresql을 사용하는 쿼리 문은 <property name="mapperLocations" value="classpath:/egovframework/sqlmap/mappers/**/*.xml" />

여기에 작성되어 있습니다. 

1
2
3
4
5
6
7
8
9
10
<!-- SqlSession setup for MyBatis Database Layer -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:/egovframework/sqlmap/config/sql-mapper-config.xml" />
        <property name="mapperLocations" value="classpath:/egovframework/sqlmap/mappers/**/*.xml" />
    </bean>
 
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSession"/>
    </bean>
 
cs

여기에 추가하고자 하는 DB(저는 Tibero DB)의 sqlsession id를 새로 하나 지정해서 bean등록을 아래와 같이 추가합니다.

저는 sqlSession2, sqlSessionTemplate2라고 지정했습니다.

Tibero DB를 사용하는 쿼리문을 작성할 디렉터리를 하나 새로 만들어서 mapperLocations의 value에 경로를 적습니다. (Package Presentaion사진을 참고) 와일드카드 문자는 원하시는 것을 사용해도 됩니다.

1
2
3
4
5
6
7
8
9
<!-- Tibero SqlSession -->
<bean id="sqlSession2" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="tibero.dataSource" />
    <property name="mapperLocations" value="classpath:/egovframework/sqlmap/mappers/disaster/tibero/*.xml" />
</bean>
 
<bean id="sqlSessionTemplate2" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg index="0" ref="sqlSession2"/>
</bean>
 
cs
 AbstractDAO class 추가

이전까지는 egovframework.com.cmm.service.impl 패키지의 EgovComAbstractDAO를 사용해서 쿼리문을 동작시켰을 겁니다. 추가할 DB에는 새로운 Abstract Calss를 추가하여 추가할 DB 전용 추상 클래스를 만들어줍니다.

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/* TiberoAbstractDAO   */
package egovframework.wini.disaster.service.impl;
 
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
 
public abstract class TiberoAbstractDAO extends SqlSessionDaoSupport{
 
    /**
     * Annotation 형식으로 sqlSession(SqlSessionFactoryBean)을 받아와
     * 이를 super(SqlSessionDaoSupport)의 setSqlSessionFactory 메서드를 호출하여 설정해 준다.
     * <p>
     * SqlSessionTemplate이 지정된 경우된 경우 이 SqlSessionFactory가 무시된다. (Batch 처리를 위해서는 SqlSessionTemplate가 필요)
     * </p>
     *
     * @param sqlSession SqlSessionFactory로 MyBatis와의 연계를 위한 기본 클래스
     */
    @Resource(name = "sqlSession2")
    public void setSqlSessionFactory(SqlSessionFactory sqlSession) {
        super.setSqlSessionFactory(sqlSession);
    }
 
    /**
     * 입력 처리 SQL mapping 을 실행한다.
     *
     * @param queryId -  입력 처리 SQL mapping 쿼리 ID
     *
     * @return DBMS가 지원하는 경우 insert 적용 결과 count
     */
    public int insert(String queryId) {
        return getSqlSession().insert(queryId);
    }
 
    /**
     * 입력 처리 SQL mapping 을 실행한다.
     *
     * @param queryId -  입력 처리 SQL mapping 쿼리 ID
     * @param parameterObject - 입력 처리 SQL mapping 입력 데이터를 세팅한 파라메터 객체(보통 VO 또는 Map)
     *
     * @return DBMS가 지원하는 경우 insert 적용 결과 count
     */
    public int insert(String queryId, Object parameterObject) {
        return getSqlSession().insert(queryId, parameterObject);
    }
 
    /**
     * 수정 처리 SQL mapping 을 실행한다.
     *
     * @param queryId - 수정 처리 SQL mapping 쿼리 ID
     *
     * @return DBMS가 지원하는 경우 update 적용 결과 count
     */
    public int update(String queryId) {
        return getSqlSession().update(queryId);
    }
 
    /**
     * 수정 처리 SQL mapping 을 실행한다.
     *
     * @param queryId - 수정 처리 SQL mapping 쿼리 ID
     * @param parameterObject - 수정 처리 SQL mapping 입력 데이터(key 조건 및 변경 데이터)를 세팅한 파라메터 객체(보통 VO 또는 Map)
     *
     * @return DBMS가 지원하는 경우 update 적용 결과 count
     */
    public int update(String queryId, Object parameterObject) {
        return getSqlSession().update(queryId, parameterObject);
    }
 
    /**
     * 삭제 처리 SQL mapping 을 실행한다.
     *
     * @param queryId - 삭제 처리 SQL mapping 쿼리 ID
     *
     * @return DBMS가 지원하는 경우 delete 적용 결과 count
     */
    public int delete(String queryId) {
        return getSqlSession().delete(queryId);
    }
 
    /**
     * 삭제 처리 SQL mapping 을 실행한다.
     *
     * @param queryId - 삭제 처리 SQL mapping 쿼리 ID
     * @param parameterObject - 삭제 처리 SQL mapping 입력 데이터(일반적으로 key 조건)를  세팅한 파라메터 객체(보통 VO 또는 Map)
     *
     * @return DBMS가 지원하는 경우 delete 적용 결과 count
     */
    public int delete(String queryId, Object parameterObject) {
        return getSqlSession().delete(queryId, parameterObject);
    }
 
    //CHECKSTYLE:OFF
    /**
     * 명명규칙에 맞춰 selectOne()로 변경한다.
     * @deprecated select() 메소드로 대체
     *
     * @see EgovAbstractMapper.selectOne()
     */
    //CHECKSTYLE:ON
    @Deprecated
    public Object selectByPk(String queryId, Object parameterObject) {
        return getSqlSession().selectOne(queryId, parameterObject);
    }
 
    /**
     * 단건조회 처리 SQL mapping 을 실행한다.
     *
     * @param queryId - 단건 조회 처리 SQL mapping 쿼리 ID
     *
     * @return 결과 객체 - SQL mapping 파일에서 지정한 resultType/resultMap 에 의한 단일 결과 객체(보통 VO 또는 Map)
     */
    public <T> T selectOne(String queryId) {
        return getSqlSession().selectOne(queryId);
    }
 
    /**
     * 단건조회 처리 SQL mapping 을 실행한다.
     *
     * @param queryId - 단건 조회 처리 SQL mapping 쿼리 ID
     * @param parameterObject - 단건 조회 처리 SQL mapping 입력 데이터(key)를 세팅한 파라메터 객체(보통 VO 또는 Map)
     *
     * @return 결과 객체 - SQL mapping 파일에서 지정한 resultType/resultMap 에 의한 단일 결과 객체(보통 VO 또는 Map)
     */
    public <T> T selectOne(String queryId, Object parameterObject) {
        return getSqlSession().selectOne(queryId, parameterObject);
    }
 
    /**
     * 결과 목록을 Map 을 변환한다.
     * 모든 구문이 파라미터를 필요로 하지는 않기 때문에, 파라미터 객체를 요구하지 않는 형태로 오버로드되었다.
     *
     * @param queryId - 단건 조회 처리 SQL mapping 쿼리 ID
     * @param mapKey - 결과 객체의 프로퍼티 중 하나를 키로 사용
     *
     * @return 결과 객체 - SQL mapping 파일에서 지정한 resultType/resultMap 에 의한 단일 결과 객체(보통 VO 또는 Map)의 Map
     */
    public <K, V> Map<K, V> selectMap(String queryId, String mapKey) {
        return getSqlSession().selectMap(queryId, mapKey);
    }
 
    /**
     * 결과 목록을 Map 을 변환한다.
     * 모든 구문이 파라미터를 필요로 하지는 않기 때문에, 파라미터 객체를 요구하지 않는 형태로 오버로드되었다.
     *
     * @param queryId - 단건 조회 처리 SQL mapping 쿼리 ID
     * @param parameterObject - 맵 조회 처리 SQL mapping 입력 데이터(조회 조건)를 세팅한 파라메터 객체(보통 VO 또는 Map)
     * @param mapKey - 결과 객체의 프로퍼티 중 하나를 키로 사용
     *
     * @return 결과 객체 - SQL mapping 파일에서 지정한 resultType/resultMap 에 의한 단일 결과 객체(보통 VO 또는 Map)의 Map
     */
    public <K, V> Map<K, V> selectMap(String queryId, Object parameterObject, String mapKey) {
        return getSqlSession().selectMap(queryId, parameterObject, mapKey);
    }
 
    /**
     * 결과 목록을 Map 을 변환한다.
     * 모든 구문이 파라미터를 필요로 하지는 않기 때문에, 파라미터 객체를 요구하지 않는 형태로 오버로드되었다.
     *
     * @param queryId - 단건 조회 처리 SQL mapping 쿼리 ID
     * @param parameterObject - 맵 조회 처리 SQL mapping 입력 데이터(조회 조건)를 세팅한 파라메터 객체(보통 VO 또는 Map)
     * @param mapKey - 결과 객체의 프로퍼티 중 하나를 키로 사용
     * @param rowBounds - 특정 개수 만큼의 레코드를 건너띄게 함
     *
     * @return 결과 객체 - SQL mapping 파일에서 지정한 resultType/resultMap 에 의한 단일 결과 객체(보통 VO 또는 Map)의 Map
     */
    public <K, V> Map<K, V> selectMap(String queryId, Object parameterObject, String mapKey, RowBounds rowBounds) {
        return getSqlSession().selectMap(queryId, parameterObject, mapKey, rowBounds);
    }
 
    //CHECKSTYLE:OFF
    /**
     * 명명규칙에 맞춰 selectList()로 변경한다.
     *
     * @see EgovAbstractMapper.selectList()
     * @deprecated List<?> 메소드로 대체
     */
    //CHECKSTYLE:ON
    @Deprecated
    public List<?> list(String queryId, Object parameterObject) {
        return getSqlSession().selectList(queryId, parameterObject);
    }
 
    /**
     * 리스트 조회 처리 SQL mapping 을 실행한다.
     *
     * @param queryId - 리스트 조회 처리 SQL mapping 쿼리 ID
     *
     * @return 결과 List 객체 - SQL mapping 파일에서 지정한  resultType/resultMap 에 의한 결과 객체(보통 VO 또는 Map)의 List
     */
    public <E> List<E> selectList(String queryId) {
        return getSqlSession().selectList(queryId);
    }
 
    /**
     * 리스트 조회 처리 SQL mapping 을 실행한다.
     *
     * @param queryId - 리스트 조회 처리 SQL mapping 쿼리 ID
     * @param parameterObject - 리스트 조회 처리 SQL mapping 입력 데이터(조회 조건)를 세팅한 파라메터 객체(보통 VO 또는 Map)
     *
     * @return 결과 List 객체 - SQL mapping 파일에서 지정한  resultType/resultMap 에 의한 결과 객체(보통 VO 또는 Map)의 List
     */
    public <E> List<E> selectList(String queryId, Object parameterObject) {
        return getSqlSession().selectList(queryId, parameterObject);
    }
 
    /**
     * 리스트 조회 처리 SQL mapping 을 실행한다.
     *
     * @param queryId - 리스트 조회 처리 SQL mapping 쿼리 ID
     * @param parameterObject - 리스트 조회 처리 SQL mapping 입력 데이터(조회 조건)를 세팅한 파라메터 객체(보통 VO 또는 Map)
     * @param rowBounds - 특정 개수 만큼의 레코드를 건너띄게 함
     *
     * @return 결과 List 객체 - SQL mapping 파일에서 지정한  resultType/resultMap 에 의한 결과 객체(보통 VO 또는 Map)의 List
     */
    public <E> List<E> selectList(String queryId, Object parameterObject, RowBounds rowBounds) {
        return getSqlSession().selectList(queryId, parameterObject, rowBounds);
    }
 
    /**
     * 부분 범위 리스트 조회 처리 SQL mapping 을 실행한다.
     * (부분 범위 - pageIndex 와 pageSize 기반으로 현재 부분 범위 조회를 위한 skipResults, maxResults 를 계산하여 ibatis 호출)
     *
     * @param queryId - 리스트 조회 처리 SQL mapping 쿼리 ID
     * @param parameterObject - 리스트 조회 처리 SQL mapping 입력 데이터(조회 조건)를 세팅한 파라메터 객체(보통 VO 또는 Map)
     * @param pageIndex - 현재 페이지 번호
     * @param pageSize - 한 페이지 조회 수(pageSize)
     *
     * @return 부분 범위 결과 List 객체 - SQL mapping 파일에서 지정한 resultType/resultMap 에 의한 부분 범위 결과 객체(보통 VO 또는 Map) List
     */
    public List<?> listWithPaging(String queryId, Object parameterObject, int pageIndex, int pageSize) {
        int skipResults = pageIndex * pageSize;
        //int maxResults = (pageIndex * pageSize) + pageSize;
 
        RowBounds rowBounds = new RowBounds(skipResults, pageSize);
 
        return getSqlSession().selectList(queryId, parameterObject, rowBounds);
    }
 
    /**
     * SQL 조회 결과를 ResultHandler를 이용해서 출력한다.
     * ResultHandler를 상속해 구현한 커스텀 핸들러의 handleResult() 메서드에 따라 실행된다.
     *
     * @param queryId - 리스트 조회 처리 SQL mapping 쿼리 ID
     * @param handler - 조회 결과를 제어하기 위해 구현한 ResultHandler
     *&n

https://onecutwook.tistory.com/25

https://steady-record.tistory.com/entry/WebSocket

 

[Spring] WebSocket 기초 예제

Socket? WebSocket?🔎 - Socket Socket는 네트워크 통신을 위한 도구로, 무전기나 전화기와 같이 프로그램 간에 데이터를 주고받을 수 있게 해준다. 이는 특정한 인스턴스가 아닌 통신 규격을 나타낸다.

steady-record.tistory.com

[Spring] WebSocket 기초 예제

2023. 12. 1. 22:01

Socket? WebSocket?🔎

 

- Socket

  • Socket는 네트워크 통신을 위한 도구로, 무전기나 전화기와 같이 프로그램 간에 데이터를 주고받을 수 있게 해준다. 이는 특정한 인스턴스가 아닌 통신 규격을 나타낸다.
  • 프로그래밍 언어들은 이미 Socket을 구현해두어 프로그래머가 손쉽게 네트워크 통신을 구현할 수 있다.
  • 브라우저도 네트워크를 통해 데이터를 주고받을 때 Socket를 사용하여 통신한다. 그러나 최근에는 웹 기술의 발전으로 인해 Socket 사용률이 줄어들었다.

- WebSocket

  • WebSocket은 웹상에서 동작하는 Socket으로, 기존의 웹 통신 방식과는 다르게 양방향 통신을 지원한다.
  • Ajax와 유사한 면이 있지만 Ajax는 단방향 통신에 주로 사용되며, WebSocket은 웹 페이지에서 서버로부터 데이터를 받는 것뿐만 아니라, 웹 페이지에서 서버로 데이터를 보내는 양방향 통신이 가능하다. 이를 통해 다양한 실시간 데이터를 웹 애플리케이션에 적용할 수 있다.
  • WebSocket은 기존의 웹 통신 방식보다 빠르고 효율적이며, 실시간 기능을 제공하기 위해 널리 사용되고 있다.

WebSocket 프로젝트🔎

WebSocket를 이해할 수 있는 프로젝트를 진행한다.

 

- 파일 구성

상위 패키지(폴더) 하위 패키지(폴더) 파일명
src/main/java com.test.controller SocketController.java
  com.test.server SocketServer.java
WEB-INF views test.jsp

 


- 환경 설정

1. 자바 및 스프링 버전 변경 - pom.xml 

2. 의존성 추가

 

WebSocket를 사용하기 위한 의존성을 추가한다.

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-websocket</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
	
		<dependency>
			<groupId>javax.websocket</groupId>
			<artifactId>javax.websocket-api</artifactId>
			<version>1.1</version>
		</dependency>

 


- SocketServer.java

WebSoket 으로 클라이언트와 서버가 통신할 때는 Controller의 역할은 view를 띄어주는 역할만 존재한다. 

package com.test.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class SocketController {
	
	@GetMapping(value = "/test.do")
	public String test(Model model) {
		return "test";
	}
}

 


📢 잠깐 여기서, 클라이언트와 SocketServer 의 관계

1. 일방적인 데이터 송수신

웹 소켓을 사용하면 양방향 통신이 가능하며, 클라이언트와 서버 간에 언제든 데이터를 주고 받을 수 있다. 이는 HTTP와는 다르게 일방적인 클라이언트에서 요청하고 서버가 응답하는 구조가 아닌, 양쪽에서 언제든 데이터를 주고 받을 수 있다.

 

2. 클라이언트의 연결 시작

Socketserver는 클라이언트가 누군지 모르기 때문에  웹 소켓에서는 클라이언트가 먼저 연결을 시작해야 한다. 이를 통해 클라이언트는 서버에게 연결을 요청하고, 서버는 해당 연결을 수락하여 양방향 통신이 가능한 상태가 된다.


3. @ServerEndpoint

@ServerEndpoint 어노테이션은 Java에서 웹 소켓 엔드포인트를 정의하는 데 사용된다. 종단점은 웹 소켓 서버에서 클라이언트의 요청을 처리하고, 연결을 관리하는 핵심 구성 요소이다.

 

4. 연결 지속성

한 쪽에서 일방적으로 연결을 끊어버리지 않는 한, 웹 소켓 연결은 계속해서 지속된다. 이 특징은 HTTP와 달리 지속적인 양방향 통신이 가능하도록 한다.


- WebSocket 연결하기

위 2번 특징으로 클라이언트(jsp)에서 먼저 연결 시도를 한다.

화면의 연결 버튼을 누르면 4가지 단계가 이뤄져야한다.

1. 소켓 생성

2. 서버 접속(연결)

3. 통신

4. 서버 접속 해제(종료)

 

test.jsp

test.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocketTest</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
</head>
<body>
	<!-- test.jsp -->
	<h1>WebSocket <small>연결 테스트</small></h1>
	
	<div>
		<button type="button" class="in" id="btnConnect">연결하기</button>
		<button type="button" class="out" id="btnDisConnect">종료하기</button>
	</div>
	<hr>
	
	<div>
		<input type="text" class="long" id="msg">
		<button type="button" id="btnMsg">보내기</button>
	</div>
	
	<div class="message full"></div>
	<script src="https://code.jquery.com/jquery-1.12.4.js" ></script>
</body>
</html>

 

 

test.jsp (JavaScript)

	<script>
		const url = 'ws://localhost:8090/socket/testserver.do';
		
		let ws; //웹 소켓 참조 변수
        
		$('#btnConnect').click(function() {
			
			ws = new WebSocket(url);
			
			ws.onopen = function(evt) {
				log('서버와 연결하였습니다.');
			};
			
			ws.onclose = function(evt) {
				log('서버와 연결이 종료되었습니다.');
			};
			
			ws.onmessage = function(evt) {
				log(evt.data);
			};
			
			ws.onerror = function(evt) {
				log('에러가 발생했습니다.' + evt);
			};
		});
		
		$('#btnDisConnect').click(function() {
			ws.close();
			log('서버와 연결 종료를 시도합니다.');
			
		});
		
		function log(msg) {
			$('.message').prepend(`
				<div>[\${new Date().toLocaleTimeString()}] \${msg}</div>		
			`);
		}
		
		$('#btnMsg').click(function() {
			ws.send($('#msg').val());
			log('메시지를 전송했습니다.');
			
			$('#msg').val('');
		});
		
	</script>

 

 

const url = 'ws://localhost:8090/socket/testserver.do';

클라이언트와 서버 연결 할 때는 'http' 이 아닌 WebSocket 의 약자인 'ws' 프로토콜을 사용한다.

위 주소 중 testserver.do는 서버의 @ServerEndpoint 와 연결하여 클라이언트에서 서버를 매핑하는 역할을 한다. 

 

ws = new WebSocket(url);

WebSocket 메소드를 사용하면 소켓 생성과 동시에 서버에 접속 시도한다.

 

웹 소켓 이벤트

웹 소켓에는 각종 행위들이 이벤트로 구현되어있어, 클라이언트는 비동기 방식으로 다른 업무를 하다가 이벤트로 연락 오는 것을 확인할 수 있다.

ws.onopen : 서버측에서 소켓 연결을 받아들이고 연결이 되는 순간 이벤트가 발생한다.

ws.onclose : 웹 소켓 연결이 닫힐 때 발생한다.

ws.onmessage : 웹 소켓으로부터 메시지를 수신했을 때 발생한다.

ws.onerror : 웹 소켓 통신 중 에러가 발생했을 때 호출된다.

 

 

ws.send($('#msg').val());

연결된 서버에게 메시지를 전송할 때는 ws.send('전달할 메시지') 를 사용한다.

메시지를 서버에 전송하고나면 다음 입력을 위해 초기화를 한다.

 

SocketServer.java

package com.test.server;

@ServerEndpoint("/testserver.do")
public class SocketServer {

	@OnOpen
	public void handelOpen() {
		System.out.println("클라이언트가 접속했습니다.");
	}
	
	@OnClose
	public void handleClose() {
		System.out.println("클라이언트가 종료했습니다.");
	}
	
	@OnMessage
	public String handleMasseage(String msg) {
		System.out.println("클라이언트가 보낸 메시지: " + msg);
		
		return "(응답)" + msg;
	}
	
	@OnError
	public void handleError(Throwable e) {
		System.out.println("에러 발생 " + e.getMessage());
	}
	
}

 

@ServerEndpoint("/testserver.do")

위에서 클라이언트가 testserver.do 를 매핑하였다.

 

@OnMessage

서버 측에서 웹 소켓 이벤트를 처리하기 위해 어노테이션을 사용한다.

이 어노테이션은 클라이언트가 서버에게 메시지를 전송했을 때(ws.send) 반응하는 이벤트이다.  전달한 메시지가 매개변수로 설정된다.

 

보통 메소드 이름은 'handle + 이벤트' 으로 작명한다.

 

연결 및 메시지 전송 모습

 

연결, 전송, 연결종료
공유하기
게시글 관리
구독하기
 

Geolocation API로 실시간 위치 정보 가져오기

2024. 9. 8. 18:58· JavaScript

https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API

 

Geolocation API - Web APIs | MDN

The Geolocation API allows the user to provide their location to web applications if they so desire. For privacy reasons, the user is asked for permission to report location information.

developer.mozilla.org

1. Geolocation API란?

Geolocation API는 웹사이트가 사용자의 기기에서 위치 정보를 요청할 수 있도록 해주는 기능입니다.

위치 정보는 사용자의 허락을 받아야만 가져올 수 있습니다.

2. 위치 정보 가져오기: getCurrentPosition()

위치 정보를 한 번만 가져오려면 getCurrentPosition() 메서드를 사용합니다.

이 메서드는 성공 시 실행될 함수(필수), 실패 시 실행될 함수(필수), 그리고 추가 설정 옵션(선택)을 인수로 받습니다.

JAVASCRIPT

 

navigator.geolocation.getCurrentPosition(
    (position) => {
        console.log("위도: " + position.coords.latitude);
        console.log("경도: " + position.coords.longitude);
    },
    (error) => {
        console.error("오류 발생: ", error);
    }
);

3. 위치 정보 객체 (position) 자세히 알아보기

성공적으로 위치 정보를 가져오면 position 객체가 반환됩니다.

이 객체에는 사용자 기기의 여러 위치 정보가 들어 있습니다.

  • coords.latitude: 위도 (ex: 37.5172)
  • coords.longitude: 경도 (ex: 127.0473)
  • coords.altitude: 고도, 미터 단위 (사용할 수 없으면 null).
  • coords.accuracy: 위치의 정확도, 미터 단위.
  • coords.altitudeAccuracy: 고도의 정확도 (사용할 수 없으면 null).
  • coords.heading: 기기가 가리키고 있는 방향 (정지 상태일 경우 null).
  • coords.speed: 기기의 이동 속도, m/s 단위 (정지 상태일 경우 null)
JAVASCRIPT

 

navigator.geolocation.getCurrentPosition(
    (position) => {
        const { latitude, longitude, accuracy, altitude, heading, speed } = position.coords;
        console.log(`위도: ${latitude}, 경도: ${longitude}`);
        console.log(`정확도: ${accuracy}m`);
        console.log(`고도: ${altitude !== null ? altitude + "m" : "정보 없음"}`);
        console.log(`방향: ${heading !== null ? heading + "°" : "정지 상태"}`);
        console.log(`속도: ${speed !== null ? speed + "m/s" : "정지 상태"}`);
    }
);

4. 오류 처리

위치 정보를 가져오는 중 발생하는 오류는 크게 세 가지로 나눌 수 있습니다.

  • PERMISSION_DENIED: 사용자가 위치 정보 접근을 거부한 경우.
  • POSITION_UNAVAILABLE: 기기의 위치 정보를 사용할 수 없는 경우.
  • TIMEOUT: 위치 정보를 가져오는 시간이 초과된 경우.
JAVASCRIPT

 

navigator.geolocation.getCurrentPosition(
    (position) => {
        // 위치 정보를 성공적으로 가져옴
    },
    (error) => {
        switch (error.code) {
            case error.PERMISSION_DENIED:
                alert("위치 정보 접근이 거부되었습니다.");
                break;
            case error.POSITION_UNAVAILABLE:
                alert("위치 정보를 사용할 수 없습니다.");
                break;
            case error.TIMEOUT:
                alert("위치 정보를 가져오는 데 시간이 너무 오래 걸렸습니다.");
                break;
            default:
                alert("알 수 없는 오류가 발생했습니다.");
        }
    }
);

5. 위치 요청 시 옵션 설정하기

getCurrentPosition() 메서드는 추가적인 옵션을 설정할 수 있습니다.

  • enableHighAccuracy: 위치 정보의 정확도를 높일지 여부(기본값 false)
    true로 설정하면 더 정확한 위치 정보를 제공하지만, 배터리 소모량이 증가할 수 있습니다.
  • timeout: 위치 정보를 가져오는 데 걸리는 최대 시간 (밀리초 단위).
  • maximumAge: 이전 위치 정보를 얼마 동안 캐시할지 (밀리초 단위). 0으로 설정 시 항상 최신 정보를 요청합니다.
JAVASCRIPT

 

navigator.geolocation.getCurrentPosition(
    (position) => {
        console.log(`위도: ${position.coords.latitude}, 경도: ${position.coords.longitude}`);
    },
    (error) => {
        console.error("위치 정보를 가져오는 중 오류 발생: ", error);
    },
    {
        enableHighAccuracy: true,  // 고정밀도 위치 요청
        timeout: 5000,             // 5초 이내에 위치 정보를 가져오지 않으면 오류 처리
        maximumAge: 0              // 캐시된 위치 정보 사용 안 함
    }
);

 

https://hy-un.tistory.com/entry/Geolocation-API%EB%A1%9C-%EC%8B%A4%EC%8B%9C%EA%B0%84-%EC%9C%84%EC%B9%98-%EC%A0%95%EB%B3%B4-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0

Geolocation API 사용하기

보안 컨텍스트: 이 기능은 일부 또는 모든 지원 브라우저 보안 컨텍스트 (HTTPS)에서만 사용할 수 있습니다.

Geolocation API는 사용자의 현재 위치를 가져오는 API로, 지도에 사용자 위치를 표시하는 등 다양한 용도로 사용할 수 있습니다. 이 글에서는 Geolocation API의 기초 사용법을 설명합니다.

geolocation 객체

Geolocation API navigator.geolocation 객체를 통해 사용할 수 있습니다.

geolocation 객체가 존재하는 경우 위치 정보 서비스를 지원하는 것입니다. 객체의 존재 여부는 다음과 같이 알아낼 수 있습니다.

jsCopy to Clipboard
if ("geolocation" in navigator) {
  /* 위치정보 사용 가능 */
} else {
  /* 위치정보 사용 불가능 */
}

현재 위치 가져오기

사용자의 현재 위치는 getCurrentPosition() 메서드를 호출해서 가져올 수 있습니다. 이 메서드는 사용자의 위치를 탐지하는 비동기 요청을 시작하고, 위치 관련 하드웨어에 최신 정보를 요청하며, 위치를 알아낸 후 주어진 콜백 함수를 호출합니다. 선택적으로, 오류가 발생하면 호출할 콜백을 두 번째 매개변수로 지정할 수 있습니다. 또 다른 선택 사항인 세 번째 매개변수는 위치 정보의 최대 수명, 요청의 최대 대기시간, 고정밀 위치정보 여부 등의 옵션을 담은 객체입니다.

참고: getCurrentPosition()의 기본 설정에서는 정밀도가 낮더라도 최대한 빠르게 응답을 반환하므로, 정확도보다 속도가 중요한 상황에서 유용합니다. 예를 들어, GPS 기능을 가진 장비는 보정 과정에 수 분이 걸릴 수도 있으므로 그동안 IP 위치와 Wi-Fi 등 정확하지 않은 출처에 기반한 위치 정보를 반환할 수 있습니다.

jsCopy to Clipboard
navigator.geolocation.getCurrentPosition((position) => {
  doSomething(position.coords.latitude, position.coords.longitude);
});

위의 예제는 사용자 위치가 확인되면 doSomething() 함수를 실행합니다.

현재 위치 추적하기

장치의 이동이나 위치 정밀도 향상으로 인해 위치 정보가 바뀔 때 호출할 콜백 함수를 watchPosition() 메서드로 설정할 수 있습니다. 이 메서드의 매개변수는 getCurrentPosition()과 같습니다. 이 콜백은 여러 번 호출될 수 있으므로 브라우저가 사용자의 움직임에 따라 위치를 업데이트하거나, 고정밀 위치 기술을 적용해 보다 정밀한 위치를 표시할 수 있습니다. getCurrentPosition()과 마찬가지로 선택 사항인 오류 콜백 역시 여러 번 호출될 수 있습니다.

참고: getCurrentPosition()을 먼저 호출하지 않아도 watchPosition()을 사용할 수 있습니다.

jsCopy to Clipboard
const watchID = navigator.geolocation.watchPosition((position) => {
  doSomething(position.coords.latitude, position.coords.longitude);
});

watchPosition() 메서드는 위치 추적 요청을 식별할 수 있는 고유 숫자를 반환합니다. 이 숫자를 clearWatch() 메서드에 전달하면 해당 위치 추적을 종료할 수 있습니다.

jsCopy to Clipboard
navigator.geolocation.clearWatch(watchID);

응답 미세 조정

getCurrentPosition() watchPosition() 둘 다 성공 콜백, 실패 콜백, 그리고 옵션 객체를 받을 수 있습니다.

이 옵션 객체로는 고정밀도 활성화 여부, 위치 정보의 최대 수명(수명이 끝나기 전에는 이전에 반환했던 위치 정보를 저장했다가, 같은 요청을 또 받으면 그대로 반환합니다), 그리고 위치 정보 요청의 응답을 기다릴 최대 대기시간을 지정할 수 있습니다.

옵션 객체를 사용한 watchPosition의 호출 예시는 다음과 같습니다.

jsCopy to Clipboard
function success(position) {
  doSomething(position.coords.latitude, position.coords.longitude);
}

function error() {
  alert("죄송합니다. 위치 정보를 사용할 수 없습니다.");
}

const options = {
  enableHighAccuracy: true,
  maximumAge: 30000,
  timeout: 27000,
};

const watchID = navigator.geolocation.watchPosition(success, error, options);

위치 표현

사용자의 위치는 GeolocationPosition 객체 인스턴스와, 그 안의 GeolocationCoordinates 객체 인스턴스로 표현됩니다.

GeolocationPosition은 오직 두 가지, GeolocationCoordinates 인스턴스를 가진 coords 속성과, 위치 정보의 기록 시점을 타임스탬프(Unix 시간, 밀리초)로 나타내는 timestamp 속성만 갖습니다.

GeolocationCoordinates 인스턴스는 여러 속성을 갖지만, 그중 가장 많이 쓰게 될 두 가지는 지도 위에 위치를 표시할 때 필요한 latitude와 longitude입니다. 따라서 대부분의 Geolocation 성공 콜백은 아래와 같이 꽤 간단한 형태입니다.

jsCopy to Clipboard
function success(position) {
  const latitude = position.coords.latitude;
  const longitude = position.coords.longitude;

  // 위도와 경도를 사용해 작업 수행
}

그러나 GeolocationCoordinates 객체에서 고도, 속도, 장치의 방향, 위경도와 고도의 오차범위 등 다른 다양한 정보도 가져올 수 있습니다.

오류 처리

getCurrentPosition() 또는 watchPosition()에 오류 콜백을 제공한 경우, 콜백은 첫 번째 매개변수로 GeolocationPositionError 객체를 받습니다. 해당 객체는 오류의 유형을 나타내는 code 속성과, 사람이 읽을 수 있는 형태로 오류 코드의 뜻을 설명한 message 속성을 갖습니다.

다음 형태로 사용할 수 있습니다.

jsCopy to Clipboard
function errorCallback(error) {
  alert(`ERROR(${error.code}): ${error.message}`);
}

예제

다음 예제는 Geolocation API를 사용해 사용자의 위경도를 가져오는 데 성공하면, 사용자의 위치로 향하는 openstreetmap.org 링크를 생성하고 하이퍼링크에 지정합니다.

HTML

htmlCopy to Clipboardplay
<button id="find-me">내 위치 보기</button><br />
<p id="status"></p>
<a id="map-link" target="_blank"></a>

JavaScript

jsCopy to Clipboardplay
function geoFindMe() {
  const status = document.querySelector("#status");
  const mapLink = document.querySelector("#map-link");

  mapLink.href = "";
  mapLink.textContent = "";

  function success(position) {
    const latitude = position.coords.latitude;
    const longitude = position.coords.longitude;

    status.textContent = "";
    mapLink.href = `https://www.openstreetmap.org/#map=18/${latitude}/${longitude}`;
    mapLink.textContent = `위도: ${latitude} °, 경도: ${longitude} °`;
  }

  function error() {
    status.textContent = "현재 위치를 가져올 수 없음";
  }

  if (!navigator.geolocation) {
    status.textContent = "브라우저가 위치 정보를 지원하지 않음";
  } else {
    status.textContent = "위치 파악 중…";
    navigator.geolocation.getCurrentPosition(success, error);
  }
}

document.querySelector("#find-me").addEventListener("click", geoFindMe);



Socket? WebSocket?🔎

 

- Socket

  • Socket는 네트워크 통신을 위한 도구로, 무전기나 전화기와 같이 프로그램 간에 데이터를 주고받을 수 있게 해준다. 이는 특정한 인스턴스가 아닌 통신 규격을 나타낸다.
  • 프로그래밍 언어들은 이미 Socket을 구현해두어 프로그래머가 손쉽게 네트워크 통신을 구현할 수 있다.
  • 브라우저도 네트워크를 통해 데이터를 주고받을 때 Socket를 사용하여 통신한다. 그러나 최근에는 웹 기술의 발전으로 인해 Socket 사용률이 줄어들었다.

- WebSocket

  • WebSocket은 웹상에서 동작하는 Socket으로, 기존의 웹 통신 방식과는 다르게 양방향 통신을 지원한다.
  • Ajax와 유사한 면이 있지만 Ajax는 단방향 통신에 주로 사용되며, WebSocket은 웹 페이지에서 서버로부터 데이터를 받는 것뿐만 아니라, 웹 페이지에서 서버로 데이터를 보내는 양방향 통신이 가능하다. 이를 통해 다양한 실시간 데이터를 웹 애플리케이션에 적용할 수 있다.
  • WebSocket은 기존의 웹 통신 방식보다 빠르고 효율적이며, 실시간 기능을 제공하기 위해 널리 사용되고 있다.

WebSocket 프로젝트🔎

WebSocket를 이해할 수 있는 프로젝트를 진행한다.

 

- 파일 구성

상위 패키지(폴더) 하위 패키지(폴더) 파일명
src/main/java com.test.controller SocketController.java
  com.test.server SocketServer.java
WEB-INF views test.jsp

 


- 환경 설정

1. 자바 및 스프링 버전 변경 - pom.xml 

2. 의존성 추가

 

WebSocket를 사용하기 위한 의존성을 추가한다.

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-websocket</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
	
		<dependency>
			<groupId>javax.websocket</groupId>
			<artifactId>javax.websocket-api</artifactId>
			<version>1.1</version>
		</dependency>

 


- SocketServer.java

WebSoket 으로 클라이언트와 서버가 통신할 때는 Controller의 역할은 view를 띄어주는 역할만 존재한다. 

package com.test.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class SocketController {
	
	@GetMapping(value = "/test.do")
	public String test(Model model) {
		return "test";
	}
}

 


📢 잠깐 여기서, 클라이언트와 SocketServer 의 관계

1. 일방적인 데이터 송수신

웹 소켓을 사용하면 양방향 통신이 가능하며, 클라이언트와 서버 간에 언제든 데이터를 주고 받을 수 있다. 이는 HTTP와는 다르게 일방적인 클라이언트에서 요청하고 서버가 응답하는 구조가 아닌, 양쪽에서 언제든 데이터를 주고 받을 수 있다.

 

2. 클라이언트의 연결 시작

Socketserver는 클라이언트가 누군지 모르기 때문에  웹 소켓에서는 클라이언트가 먼저 연결을 시작해야 한다. 이를 통해 클라이언트는 서버에게 연결을 요청하고, 서버는 해당 연결을 수락하여 양방향 통신이 가능한 상태가 된다.


3. @ServerEndpoint

@ServerEndpoint 어노테이션은 Java에서 웹 소켓 엔드포인트를 정의하는 데 사용된다. 종단점은 웹 소켓 서버에서 클라이언트의 요청을 처리하고, 연결을 관리하는 핵심 구성 요소이다.

 

4. 연결 지속성

한 쪽에서 일방적으로 연결을 끊어버리지 않는 한, 웹 소켓 연결은 계속해서 지속된다. 이 특징은 HTTP와 달리 지속적인 양방향 통신이 가능하도록 한다.


- WebSocket 연결하기

위 2번 특징으로 클라이언트(jsp)에서 먼저 연결 시도를 한다.

화면의 연결 버튼을 누르면 4가지 단계가 이뤄져야한다.

1. 소켓 생성

2. 서버 접속(연결)

3. 통신

4. 서버 접속 해제(종료)

 

test.jsp

test.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocketTest</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
</head>
<body>
	<!-- test.jsp -->
	<h1>WebSocket <small>연결 테스트</small></h1>
	
	<div>
		<button type="button" class="in" id="btnConnect">연결하기</button>
		<button type="button" class="out" id="btnDisConnect">종료하기</button>
	</div>
	<hr>
	
	<div>
		<input type="text" class="long" id="msg">
		<button type="button" id="btnMsg">보내기</button>
	</div>
	
	<div class="message full"></div>
	<script src="https://code.jquery.com/jquery-1.12.4.js" ></script>
</body>
</html>

 

 

test.jsp (JavaScript)

	<script>
		const url = 'ws://localhost:8090/socket/testserver.do';
		
		let ws; //웹 소켓 참조 변수
        
		$('#btnConnect').click(function() {
			
			ws = new WebSocket(url);
			
			ws.onopen = function(evt) {
				log('서버와 연결하였습니다.');
			};
			
			ws.onclose = function(evt) {
				log('서버와 연결이 종료되었습니다.');
			};
			
			ws.onmessage = function(evt) {
				log(evt.data);
			};
			
			ws.onerror = function(evt) {
				log('에러가 발생했습니다.' + evt);
			};
		});
		
		$('#btnDisConnect').click(function() {
			ws.close();
			log('서버와 연결 종료를 시도합니다.');
			
		});
		
		function log(msg) {
			$('.message').prepend(`
				<div>[\${new Date().toLocaleTimeString()}] \${msg}</div>		
			`);
		}
		
		$('#btnMsg').click(function() {
			ws.send($('#msg').val());
			log('메시지를 전송했습니다.');
			
			$('#msg').val('');
		});
		
	</script>

 

 

const url = 'ws://localhost:8090/socket/testserver.do';

클라이언트와 서버 연결 할 때는 'http' 이 아닌 WebSocket 의 약자인 'ws' 프로토콜을 사용한다.

위 주소 중 testserver.do는 서버의 @ServerEndpoint 와 연결하여 클라이언트에서 서버를 매핑하는 역할을 한다. 

 

ws = new WebSocket(url);

WebSocket 메소드를 사용하면 소켓 생성과 동시에 서버에 접속 시도한다.

 

웹 소켓 이벤트

웹 소켓에는 각종 행위들이 이벤트로 구현되어있어, 클라이언트는 비동기 방식으로 다른 업무를 하다가 이벤트로 연락 오는 것을 확인할 수 있다.

ws.onopen : 서버측에서 소켓 연결을 받아들이고 연결이 되는 순간 이벤트가 발생한다.

ws.onclose : 웹 소켓 연결이 닫힐 때 발생한다.

ws.onmessage : 웹 소켓으로부터 메시지를 수신했을 때 발생한다.

ws.onerror : 웹 소켓 통신 중 에러가 발생했을 때 호출된다.

 

 

ws.send($('#msg').val());

연결된 서버에게 메시지를 전송할 때는 ws.send('전달할 메시지') 를 사용한다.

메시지를 서버에 전송하고나면 다음 입력을 위해 초기화를 한다.

 

SocketServer.java

package com.test.server;

@ServerEndpoint("/testserver.do")
public class SocketServer {

	@OnOpen
	public void handelOpen() {
		System.out.println("클라이언트가 접속했습니다.");
	}
	
	@OnClose
	public void handleClose() {
		System.out.println("클라이언트가 종료했습니다.");
	}
	
	@OnMessage
	public String handleMasseage(String msg) {
		System.out.println("클라이언트가 보낸 메시지: " + msg);
		
		return "(응답)" + msg;
	}
	
	@OnError
	public void handleError(Throwable e) {
		System.out.println("에러 발생 " + e.getMessage());
	}
	
}

 

@ServerEndpoint("/testserver.do")

위에서 클라이언트가 testserver.do 를 매핑하였다.

 

@OnMessage

서버 측에서 웹 소켓 이벤트를 처리하기 위해 어노테이션을 사용한다.

이 어노테이션은 클라이언트가 서버에게 메시지를 전송했을 때(ws.send) 반응하는 이벤트이다.  전달한 메시지가 매개변수로 설정된다.

 

보통 메소드 이름은 'handle + 이벤트' 으로 작명한다.

 

연결 및 메시지 전송 모습

 

연결, 전송, 연결종료

[강의 출처] opentutorials.org/course/3084/18894

 

웹서버 운영하기 : 맥 - 생활코딩

자신의 운영체제에 맞는 수업을 찾아서 학습해주세요. 맥에 웹서버 설치하기 웹서버와 http  웹브라우저와 웹서버의 통신 --- 맥에 웹서버 설치 이번 시간에는 아파치 웹서버를 맥 컴퓨터에 설치

opentutorials.org

기타 참고페이지들은 본문에 적어두었다.


 

생활코딩 Web1 Internet편에 직접 웹서버를 운영해보는 단계가 있다.

생활코딩에서는 bitnami라는 프로그램을 통해 실습을 하는데, 아래와 같은 문구가 있는 게 아닌가.

 

"맥에는 아파치가 기본적으로 깔려있습니다. 그래서 실습을 하기가 무척 쉽습니다."

 

그래서 직접 해보기로 했다. 맥에 기본적으로 깔려 있는 아파치로 웹서버를 돌려보자!

 

Mac 내장 Apache로 웹서버 운영하기

 

우선 먼저 Google 검색을 해보았다. '맥 아파치'.

여러 글들이 많이 나오는데, 가장 많이 참조한 것은 이쪽:

xho95.github.io/macos/apache/webserver/mod_wsgi/2016/10/02/Apache-WebServer.html

88240.tistory.com/476

 

1. 맥 터미널에서 '아파치'와 'php' 버전을 확인한다.

$ apachectl -v
$ php -v

내 경우에는 아파치 2.4.41 버전, php 7.3.11 버전이 설치되어 있었다.

 

2. 아파치를 실행한다.

$ sudo apachectl start

sudo 권한이라서 password를 묻는 단계가 있다. 접속한 맥 계정 비밀번호를 입력하니 확인완료.

 

3. 브라우저에서 localhost로 접속해본다. (혹은 127.0.0.1)

사파리에서 localhost를 입력한 결과. 아파치의 기본 indexl.html 파일이다.

무사히 출력된다! 아파치 서버 활성화가 무사히 끝났다. 이제는 실습에서 만들었던 웹페이지를 띄워볼 차례.

 

4. index.html 파일 찾기 (생활코딩 Web1 웹서버 실습)

먼저 아까 출력되었던 'It works!' 파일이 어디에 있는지 알아보았다.

/Library/WebServer/Documents 디렉토리라고 한다. 해당 디렉토리로 이동 후 Finder로 열어보았다.

$ cd /Library/WebServer/Documents
$ open .

해당 디렉토리로  이동하니, 이런 이름의 파일이 있다.

/Library/WebServer/Documents/index.html

에디터로 열어보니, 아래와 같이 작성되어 있다. html문서다.

<html><body><h1>It works!</h1></body></html>

생활코딩에서 실습했던 방법을 생각해보면,

 

"htdocs 디렉터리의 파일들을 모두 삭제하고, 프로젝트 폴더에 있는 파일을 복사합니다."

여기의 index.html 파일만 교체해도 목적은 이룰 수 있을 것 같다. 시도해 본다.

index.html.en 파일을 다른 곳으로 이동하고, 내가 작성했던 파일을 복사해온 다음, 다시 localhost에 접속해보았다.

생활코딩 Web1을 들으면서 직접 만들었던 웹페이지.

성공! 링크로 연결해뒀던 페이지들 간의 이동도 의도대로 잘 실행되었다.

와이파이로 연결되어있는 스마트폰으로도 접속해보았다. 무사히 실행된다!

여기까지 하면 생활코딩 범위는 끝.

 

문제는... 이 루트는 일반적인 방법으로 파일 삭제가 안 될 뿐더러, 웹서버는 이렇게 운영하는 게 아닐 것 같다는 불안감이 든다는 것.

아까 테스트했던 파일들은 급한대로 sudo rm으로 하나하나 지웠다. 그냥 rm을 입력하면 Permission denied가 뜬다.

$ sudo rm index.html

다른 사람들은 환경설정을 어떻게 하는지 좀 더 알아보기로 했다.

 

5. 환경설정 하기: userdir 활성화하기  or  DocumentRoot 폴더 변경하기

보통은 위의 두 가지 방법으로 세팅을 하는 것 같다. 나는 이 중 userdir 활성화를 택하기로 했다.

userdir 활성화의 이점은 localhost/~username처럼 하위 링크를 얻을 수 있다는 것. 방법은 아래와 같다.

 

1. /private/etc/apache2/extra 디렉토리의 httpd-userdir.conf 파일을 편집

$ cd /private/etc/apache2/extra
$ sudo vi httpd-userdir.conf

-httpd-userdir.conf 파일에서 '# Include /private/etc/apache2/users/*.conf' 부분의 주석처리(# )를 삭제

 

마찬가지로 sudo 권한이라서 password 요청이 들어올 수 있다. 패스워드를 입력하면 vi 편집기가 뜬다.

vi 편집기에 익숙하지 않아서 조금 헤맸는데, 그래도 아래 링크 등을 참고하면 금방 적응할 수 있다.

 

coding-factory.tistory.com/505

 

[Linux] 리눅스 문서 편집기 vi 사용법 & 명령어 총정리

파일을 작성하거나 수정하기 위해서는 편집기가 필요합니다. 윈도우에서는 메모장을 편집기의 기본으로 지원하는 반면 리눅스에서는 기본 편집기로 vi 라는 편집기를 지원합니다. vi는 리눅스��

coding-factory.tistory.com

마우스를 사용하는 시스템이 아니라서, 키보드로 지금 명령을 할지 입력을 할지를 지정해줘야 한다. 커서 이동은 방향키로도 가능하다.

 

처음 써본다면 esc, i, :만 기억하면 된다.

화살표키를 이용해서 편집할 곳으로 커서를 이동한 다음, 키보드 상에서  'i'키 를 누르면 화면 맨 아랫줄에

-- INSERT --

라는 표시가 뜬다. 그 상태에서는 텍스트 입력 및 수정이 가능하다.

수정이 끝났다면 esc를 누르고 나서, ':'를 누르자. (쉬프트도 눌러줘야 한다) 그러면 다시 화면 맨 아랫줄에

:

라는 표시가 뜰 것이다. 저장하고 종료할 거라면, 아래처럼 : 뒤에 wq를 입력하고 엔터를 누르면 된다.

:wq

다시 터미널 기존 위치로 돌아갈 것이다. 혹시 강제종료하고 싶다면 wq 대신에 q!를 입력하면 된다.

 

2. /private/etc/apache2 디렉토리의 httpd.conf 파일을 편집

내 경우에는 위의 경로에 httpd.conf 파일이 있었다. 이번에는 Atom으로 열어서, 우선 아래 두 줄의 주석처리(#)를 제거하고,

LoadModule userdir_module libexec/apache2/mod_userdir.so
Include /private/etc/apache2/extra/httpd-userdir.conf

혹시 모를 ServerName 관련 오류를 피하기 위해, 주석을 제거하고 ServerName 설정을 변경하고 저장했다.

(Atom의 경우, 저장할 때 Atom Helper가 권한 관련하여 비밀번호를 요청할 수 있다.)

ServerName localhost

 

3. Sites 폴더 생성

localhost/~username 요청시 베이스로 사용할 디렉토리를 만드는 작업이다.

/Users/유저명 의 유저명 경로에 Sites 폴더를 만들면 된다. 나는 터미널을 이용했다.

$ cd ~
$ mkdir Sites

 

4. Sites 폴더에 접근 권한 주기

/private/etc/apache2/users 경로에 유저명.conf 파일을 만들어주는 작업이다. Guest.conf 파일을 복사해서 내용만 수정해도 된다.

여기서 꽤 고전했다. conf 파일의 내용은 여기를 참고해서 아래와 같이 작성했다.

<Directory "/Users/username/Sites/">
  Options Multiviews Indexes
  Require all granted
</Directory>

첫번째 줄의 username을 내 계정명으로 변경한 상태로 저장하고, 아파치를 재시작 후 접속을 시도해보았더니

 

권한이 없어서 접속할 수 없다는 오류페이지. 흔히 말하는 403 에러인듯.

 

에러 로그를 찾아보니 이런 메시지가 뜬다.

cat /var/log/apache2/error_log # 에러 로그를 찍어보자

(13)Permission denied:  AH00035: access to /~username denied (filesystem path '/Users/username/Sites') because search permissions are missing on a component of the path

구글의 도움을 받아 아래와 같은 해결법을 찾았다.

 

mytory.net/archives/3143

 

아파치 Forbidden You don’t have permission to access / on this server. 에러 해결

아파치에서 웹 서버의 폴더에 접근할 수 없어서 뜨는 에러다. 우선 아파치 환경 설정에서 해당 폴더 접근을 허용하고, 아파치 사용자에게 폴더의 실행 권한과 파일의 읽기 권한을 줘야 한다.

mytory.net

터미널로 이동해서 Sites 폴더에 권한 755를 부여했다.

$ cd ~
$ sudo chmod 755 Sites

755 권한은 소유자는 읽기, 쓰기, 실행이 가능하고, 그 외 사용자는 읽기, 실행이 가능한 타입.

여전히 Forbidden이다.

 

apple.stackexchange.com/questions/95660/how-to-fix-403-in-mac-os-x-built-in-apache/136941#136941

 

How to fix 403 in Mac OS X built-in Apache?

I'm trying to set a local environment on my new MacBook Air 13": built-in Apache with my own DocumentRoot, PHP, and MySQL. I usually update /etc/hosts just to run my local websites with a pretty

apple.stackexchange.com

httpd.conf 파일의 User 이름을 변경해서 해결할 수 있다고 한다.

User _www

해당 파일을 확인해보니 실제로 User명이 _www로 되어있다. _www를 사용자명으로 변경했다.

그리고 해당 답변자가 추가로 조언해준 보안 이슈를 해결하고 나서

Listen 80

->

Listen 127.0.0.1:80

아파치를 재실행해본다.

$ sudo apachectl restart
http://localost/~username/index.html로 접속에 성공했다

결과는 성공!

와이파이 환경 내에서 접속하려면 위의 Listen 127.0.0.1:80 부분을 Listen 80으로 그대로 두어야 한다.

[Oracle] Oracle XE에서 사용자 생성 오류, ORA-65096: 공통 사용자 또는 롤 이름이 부적합합니다. invalid common user or role name
by breezyday 2022. 8. 2.
Oracle에서 개발 및 테스트를 위해 Oracle XE를 무료로 사용할 수 있도록 배포하고 있습니다. 그러나 몇 가지 제약사항들이 있는 데 그중에 하나가 사용자 생성 시 사용자 이름에 대한 제약이 있습니다.

1. ORA-65096 : 공통 사용자 또는 롤 이름이 부적합합니다.
CREATE USER C##myuser IDENTIFIED BY pwd123;
 

Oracle XE에서는 system 계정으로 로그인해서 사용자를 만들 때, C##을 붙인 사용자는 만들 수 있지만 일반 이름은 사용할 수 없는 제약이 있습니다. 그래서 위의 SQL은 문제가 없지만 아래와 같은 일반적인 SQL문은 오류가 발생합니다.

 

CREATE USER my_user IDENTIFIED BY pwd123
DEFAULT TABLESPACE myts
 

위의 SQL을 실행하면 오류가 발생하고, 오류 메시지는 아래와 같습니다.

 

명령의 28 행에서 시작하는 중 오류 발생 -
CREATE USER my_user IDENTIFIED BY pwd123
DEFAULT TABLESPACE myts
오류 보고 -
ORA-65096: 공통 사용자 또는 롤 이름이 부적합합니다.
65096. 00000 -  "invalid common user or role name"
*Cause:    An attempt was made to create a common user or role with a name
           that was not valid for common users or roles. In addition to the
           usual rules for user and role names, common user and role names
           must consist only of ASCII characters, and must contain the prefix
           specified in common_user_prefix parameter.
*Action:   Specify a valid common user or role name.
 

2. 해결 방법
Oracle XE에서 제약을 걸어두기 위해 system 계정으로 로그인할 경우 SESSION이 잠겨진 SESSION으로 접속하게 됩니다. 그래서 아래 명령을 사용하여 SESSION 설정을 변경하면 기존의 SQL 구문들을 제약 없이 사용할 수 있습니다.

 

ALTER SESSION SET "_ORACLE_SCRIPT"=true;
 

Oracle XE에서 개발 및 테스트를 하고 있는 개발자라면 system으로 로그인해서 DDL을 다룰 경우 위 명령을 먼저 실행해주면 다른 SQL문 작업 중에도 혼돈 없이 작업을 진행할 수 있겠습니다.

 
 

오라클 테이블 스페이스(Table Space)란 무엇인가?

오라클은 데이터를 관리하는 데이터베이스입니다. 데이터를 어딘가에 저장해놓고 사용하는 시스템이라고 볼 수 있습니다. 그리고 데이터 저장 단위 중 가장 상위에 있는 단위를 테이블 스페이스라고 합니다. 데이터 저장 단위는 물리적, 논리적단위로 나눌 수 있습니다. 물리적 단위는 파일을 의미하고 논리적 단위는 데이터블록 -> 익스텐트 -> 세그먼트 -> 테이블스페이스 이렇게 나뉩니다. 데이터 블록 여러개가 모여 익스텐트 하나를 만들고, 익스텐트 여러개가 모여 하나의 세그먼트를 구성하는 식입니다.  테이블 스페이스는 가장 상위개념입니다.

 

오라클 테이블 스페이스 사용법

SQL 개발 툴이 있으시면 개발  툴을 실행시키시면 되고 없으시다면 윈도우 실행창을 열고 SQL PLUS를 실행시킨 뒤 System 아이디로 로그인한뒤 테이블 스페이스 설정 작업을 하시면 됩니다.

 

테이블 스페이스 생성

Copy
create tablespace [테이블 스페이스명]
datafile 'D:\dev\oradata' --파일경로
size 10M --초기 데이터 파일 크기 설정
autoextend on next 10M -- 초기 크기 공간을 모두 사용하는 경우 자동으로 파일의 크기가 커지는 기능
maxsize 100M -- 데이터파일이 최대로 커질 수 있는 크기 지정 기본값 = unlimited
uniform size 1M -- EXTENT 한개의 크기를 설정

 

전체 테이블 스페이스 조회

Copy
select * from dba_tablespaces;

 

전체 테이블 스페이스 경로 및 용량 조회

Copy
SELECT
A.TABLESPACE_NAME "테이블스페이스명",
A.FILE_NAME "파일경로",
(A.BYTES - B.FREE) "사용공간",
B.FREE "여유 공간",
A.BYTES "총크기",
TO_CHAR( (B.FREE / A.BYTES * 100) , '999.99')||'%' "여유공간"
FROM
(
SELECT FILE_ID,
TABLESPACE_NAME,
FILE_NAME,
SUBSTR(FILE_NAME,1,200) FILE_NM,
SUM(BYTES) BYTES
FROM DBA_DATA_FILES
GROUP BY FILE_ID,TABLESPACE_NAME,FILE_NAME,SUBSTR(FILE_NAME,1,200)
)A,
(
SELECT TABLESPACE_NAME,
FILE_ID,
SUM(NVL(BYTES,0)) FREE
FROM DBA_FREE_SPACE
GROUP BY TABLESPACE_NAME,FILE_ID
)B
WHERE A.TABLESPACE_NAME=B.TABLESPACE_NAME
AND A.FILE_ID = B.FILE_ID;

 

테이블의 테이블 스페이스 변경

Copy
alter table [테이블명] move tablespace [테이블 스페이스명]

 

테이블 스페이스 속성 변경

Copy
-- 해당 테이블스페이스의 물리적인 파일의 이름 또는 위치변경
alter tablespace rename [A] to [B]
 
-- 해당 테이블스테이스의 용량을 1024메가로 변경
alter tablespace [테이블스페이스명] add datafile [추가할데이터파일명] size 1024M;
 
-- 해당 데이터파일경로에 해당하는 테이블스페이스의 크기가 FULL이 되면 자동으로 100메가씩 증가.
alter database datafile [데이터파일경로] 'autoextend on next 100m maxsize unlmited;

 

테이블 스페이스 삭제

Copy
-- 테이블스페이스 내의 객체(테이블,인덱스등)를 전체 삭제
drop tablespace [테이블 스페이스명] include contents;
 
--테이블스페이스의 모든 세그먼트를 삭제. (데이타가 있는 테이블 스페이스 제외)
drop tablespace [테이블 스페이스명] including contents;
 
--삭제된 테이블스페이스를 참조하는 다른 테이블스페이스의 테이블로부터 참조무결성 제약 조건을 삭제
drop tablespace [테이블 스페이스명] cascade constraints;
 
--테이블 스페이스의 물리적파일까지 삭제
drop tablespace [테이블 스페이스명] including contents and datafiles;

 

테이블 스페이스 작동방식

오라클 에서는 테이블스페이스라고 불리우는 테이블이 저장될 공간을 먼저 만들고 나서 테이블을 생성합니다. 테이블에 실질적으로 저장되는 장소라고 생각하시면 됩니다. 이러한 작동방식은 각각의 테이블을 테이블스페이스별로 나누어서 관리와 퍼포먼스의 향상을 가지고 옵니다. 테이블스페이스를 생성하면 정의된 용량만큼 미리 확보한 테이블스페이스가 생성되어지고 생성되어진 테이블스페이스에 테이블의 데이타가 저장됩니다. 이렇게 설정된 데이터 스페이스에 용량이 가득차면 오라클 서버가 죽습니다. 그러므로 관리를 잘해주어야합니다. 하지만 또 테이블 스페이스마다 용량을 너무나도 크게 잡아버리면 문제가 되는게 용량을 적게 차지하고 있다고해서 가변적으로 max용량이 줄어들지는 않습니다. 고로 또 용량낭비가 되어버릴 수 있는 문제가 될 수 있습니다.. 

 

골치아프시죠?? 괜찮습니다. 테이블 스페이스는 자동으로 할당해주는 부분이 많아 크게 DBA가 아니라면 건드릴 필요가 없습니다. 아마 그럴 권한도 없으실거에요. 자동으로 할당해주는 부분을 간략하게 소개드리자면 만약 테이블 생성 시 테이블  스페이스를 지정해주지 않으면 오라클 서버에서 자동으로 지정해주기도 하고 또 오라클은 유저를 생성하면서 디폴트 테이블 스페이스를 자동으로 지정해줍니다. 테이블을 만들게 되면 그 테이블 스페이스에 들어 가게되고 그 테이블 스페이스는 테이블 스페이스 생성때 설정하는 경로에 위치하게됩니다. DBA가 아니라 오라클을 활용하는 개발자 정도라면 크게 신경쓰지 않으셔도 됩니다. 

[Oracle] 계정 및 테이블스페이스 생성

 tawoo0  2019. 5. 27. 14:59

*계정 생성 및 테이블 스페이스 생성

1. 오라클 sys 계정으로 접속한다. cmd창에서 바로 접속시

C:\>sqlplus

계정 system

비번 bims

2. 테이블 스페이스 생성

create tablespace 테이블스페이스명

datafile '/경로/테이블스페이스파일명.dbf'

size 초기용량(100m,1g 등) reuse

autoextend on next 자동증가 용량

maxsize unlimited;

ex)

create tablespace ASQ_DATA2

datafile '/home/oracle/tablespace/ASQ_DATA2.dbf'

size 300m reuse

autoextend on next 1024k

maxsize unlimited;

3. sys계정 접속후 유저계정생성

create user 유저명 identified by 패스워드 default tablespace 테이블스페이스명;

ex) create user KBN2 identified by KBN2 default tablespace ASQ_DATA2;

create user 유저명 identified by 패스워드 default tablespace 테이블스페이스명 TEMPORARY TABLESPACE 정렬용테이블스에스명;

ex) create user KBN2 identified by KBN2 default tablespace kbn_tablespace TEMPORARY TABLESPACE temp;

4.생성한계정 권한부여

grant connect, resource to 유저명;

ex)grant connect, resource to KBN2;

grant connect, resource,dba to tawoo0;

5.유저 계정 삭제시

drop user 삭제할계정 cascade

ex)drop user KBN2 cascade;

cf) 유저 계정을 삭제하고 테이블스페이스를 삭제하고 테이블스페이스 파일을 삭제하면 mysql의 drop database DB명과 같다.

6. 유저 권한 회수

revoke 권한 from 유저명;

revoke dba from user1;

7. 테이블스페이스 삭제

DROP TABLESPACE 테이블스페이스이름 INCLUDING CONTENTS;

ex) DROP TABLESPACE kbn_talbespace INCLUDING CONTENTS;

** 권한 종류

1). CONNECT : 사용자가 데이터베이스에 접속 가능하도록 하기 위해 다음과 같이 가장 기본적인 시스템 권한

8가지를 묶어 놓았습니다. (ALTER SESSION, CREATE CLUSTER, CREATE DATABASE LINK, CREATE SEQUENCE,

CREATE SESSION, CREATE SYNONYM, CREATE TABLE, CREATE VIEW)

2). RESOURCE : 사용자 객체(테이블, 뷰, 인덱스)를 생성할 수 있도록 하기위해서 시스템 권한을 묶어 놓았습니다. (CREATE CLUSTER, CREATE PROCEDURE, CREATE SEQUENCE, CREATE TABLE, CREATE TRIGGER)

3). DBA : 사용자들이 소유한 데이터베이스를 관리하고 사용자들을 작성하고 변경하고 제거할 수 있도록 하는

모든 권한을 가집니다.

참고 : http://www.gurubee.net/lecture/1160

 

* EXPORT 옵션

 

  - userid : EXPORT를 실행시키고 있는 username/password 명

  - file : 생성되는 EXPORT덤프 파일명

  - full : 전체 데이터베이스를 EXPORT할것인가의 여부 (Full Level EXPORT) (Y/N 플래그)

  - owner : EXPORT 될 데이터베이스의 소유자 명 (User Level EXPORT)[owner=user]

  - tables : EXPORT될 테이블의 리스트(Table Level EXPORT) [tables=(table1, table2, ...)]

  - log : EXPORT 실행 과정을 지정된 로그 파일에 저장

 

1. Full Level EXPORT

  전체 데이터베이스가 엑스포트 된다. 모든 테이블스페이스, 모든 사용자, 또한 모든 객체, 데이터들이 포함 된다.

  exp  userid=system/manager file='C:\full.dmp' full=y

    

2. User Level EXPORT

  사용자 자신이 만든 모든 오브젝트를 그 user가 EXPORT하는 방법

  exp userid=scott/tiger  file='C:\scott.dmp'

  혹시 비밀번호 특수문자 있을시 :   exp userid='scott'/'tiger!^'  file='C:\scott.dmp'

 

  SYSTEM계정으로 특정 user소유의 오브젝트들을 EXPORT 하는 방법

  exp userid=system/manager owner=scott  file='C:\scottuser.dmp' 

    

3. Table Level EXPORT

  SYSTEM계정으로 특정 유저의 table을 EXPORT하는 예제 

  다른 계정으로 EXPORT시 table의 user명까지 지정해야 EXPORT가 성공한다.

  exp userid=system/manager file='C:exp.dmp' tables=(scott.EMP, scott.DEPT)

 

  scott user로 table을 몇 개만EXPORT하는 예제

  자신의 table을 EXPORT할 때에는 user명을 지정할 필요가 없다. 

  exp userid=scott/tiger file='C:\exp.dmp' tables=(EMP, DEPT) log=exp.log

 

 

참고 : http://www.gurubee.net/lecture/1161

 

* IMPORT 옵션

 

  - userid : IMPORT를 실생시키는 계정의 username/password 명

  - file : IMPORT될 EXPORT 덤프 파일명

  - show : 파일 내용이 화면에 표시되어야 할 것인가를 나타냄(Y/N 플래그)

  - ignore : IMPORT중 CREATE명령을 실행할 때 만나게 되는 에러들을 무시할 것인지 결정(Y/N 플래그)

  - full : FULL엑스포트 덤프 파일이 IMPORT 할때 사용한다.

  - tables : IMPORT될 테이블 리스트

  - commit : 배열(배열의 크기는 BUFFER에 의해 설정됩니다) 단위로 COMMIT을 할것인가 결정 기본적으로는 테이블 단위로 COMMIT을 한다.

  - fromuser : EXPORT덤프 파일로 부터 읽혀져야 하는 객체들을 갖고 있는 테이터베이스 계정

  - touser : EXPORT덤프 안에 있는 객체들이 IMPORT될 데이터베이스 계정

 

1. IMPORT 예제

   

   전체 데이터베이스가 IMPORT(Full Level Export file을 Import)

   imp userid=system/manager file='C:\full.dmp'  full=y

 

   User Level Export file을 Import

   imp userid=scott/tiger file='C:\scott.dmp'

 

   User Level Export file을 다른 계정으로 IMPORT

   scott 유저의 데이터를 EXPORT받아 test 유저에게 IMPORT하는 예제 

   exp userid=system/manager file='C:\scott.dmp' owner=scott

   imp userid=system/manager file='C:\scott.dmp' fromuser=scott touser=test   

 

출처: https://godlvkhj.tistory.com/215 [하은양 믿음군 효실맘 호홍홍집s:티스토리]

1. Docker

우선 도커가 설치되어있어야 합니다.
도커 설치는 기존 포스팅을 참고 해주시기 바랍니다!

$ docker -v
Docker version 20.10.17, build 100c701

도커 버전을 확인합니다.
도커가 정상 설치되었으므로 본격적으로 테스트에 사용할 Alpine 리눅스를 설치해 보겠습니다.

docker pull alpine

이미지 부터 다운로드 해줍니다.

docker run -d -it --name alpine-container alpine:latest sh

그다음 테스트에 사용할 알파인 리눅스 컨테이너를 생성해줍니다.

2. Docker 컨테이너로 파일 복사하기

호스트에 있는 파일을 도커 컨테이너의 특정 경로로 복사하는 명령어는 다음과 같다.

docker cp <복사할 파일 경로> <컨테이너 이름>:<컨테이너 내부 파일 경로>

만일 호스트에 있는 test.txt 파일을 컨테이너의 /test 경로로 복사한다면, 다음과 같이 사용한다.

docker cp test.txt alpine-container:/test

만일 디렉토리를 옮기고 싶을때는 어떻게 해야할까?
디렉토리를 복사하는 경우도 별다른 옵션없이 복사가 가능하다.

3. Docker 컨테이너에서 파일 가져오기

그럼 반대로 도커 컨테이너에 있는 파일을 호스트로 가져오려면 어떻게 해야할까?
매우 단순하다. 파일 경로와 컨테이너의 경로를 바꿔주면 된다.

docker cp <컨테이너 이름>:<컨테이너 내부 파일 경로> <복사할 파일 경로> 

만일 도커 컨테이너의 test.txt 파일을 호스트의 경로인 /test 으로 복사를 원한다면, 다음과 같이 사용한다.

docker cp alpine-container:/test.txt /test/

역시 동일하게 디렉토리도 별다른 옵션없이 복사가 가능하다.

docker ps 
실행중이 도커 보기

docker ps -a
전체 도커 보기

docker rm [컨테이너 id]
도커에서 컨테이너 삭제 하기

docker images

docker rmi[이미지id]
도커 이미지 삭제 하기

docker rmi -f [이미지id]

 

일단 docker 라는 것을 처음 접하고, container를 실행해 본 후 가장 당황 스러웠던 것은 

 

"container에 어떻게 접속하지?"

 

였다. ( 필자는 그랬다.. ) 

 

일단 container 자체가 하나의 Proccess 였기에 container가 daemon으로 실행하고 나면 여기에 어떻게 접속해야할지 난감한 상황이..

 

root@~~# docker ps -a

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES

c456623003b1        nimmis/apache       "/my_init"          40 seconds ago      Up 39 seconds       0.0.0.0:8080->80/tcp   high_ritchie  

[ Status가 Up 상태인거 보니 뭔가 실행 중이다. 접속은? ]

 

접속하는 방법은 매우 간단하다. 

docker exec 명령을 이용하면 된다.  docker exec 는 container에 특정 명령을 실행할 수 있는 것인데 이때 명령을 /bin/bash 라고 하면 된다. 

 

우리가 "접속" 하고 싶다는 의미는 해당 container 의 shell 에 접속하겠다는 의미이다. 

주의해야할 것은 docker exec 명령을 할때 옵션으로 -it 라고 덧붙여 주어야 한다. 이는 STDIN 표준 입출력을 열고 가상 tty (pseudo-TTY) 를 통해 접속하겠다는 의미이다. 

 

root@~~# docker exec -it  c456623003b1 /bin/bash

 

root@c456623003b1:~# 

 

위와 같이 hostname이 해당 container id로 바뀐 것을 볼 수 있다. 즉, container 내부에 접속한 상태라는 것이다. 

 

마지막으로 접속을 종료할때는 간단히 exit 명령을 통해 가능하다. 

 

출처: https://bluese05.tistory.com/21 [ㅍㅍㅋㄷ:티스토리]

0. 서론

데이터베이스전문가(SQLP) 자격증 취득을 위해 공부하던 중, mac M1에 오라클을 띄워서 실습 공부를 해야할 필요가 있었다. 그러나, 맥북 Apple Silicon(M1)에서는 로컬로 오라클을 띄울 수가 없다.

그래도, 아래 블로그를 찾아 Docker/Colima를 활용해서 Oracle을 띄울 수 있게 되었다.

참고 블로그

1. 설치

1.1 colima

docker desktop은 매우 무거운 프로그램이어서, 가벼운 CLI 환경에서 도커를 실행할 수 있는 오픈 소스인 colima를 사용한다.

brew install colima 

1.2 docker

docker desktop은 docker 공식 웹 홈페이지에서 설치할 수 있다.
Docker 웹 홈페이지

아니면, brew로 설치해도 된다.

# Docker Desktop
brew install --cask docker 

# Docker Engine
brew install docker

2. 실행

colima와 docker 모두 설치 후, colime를 x86_64 환경으로 띄워준다.

colima start --memory 4 --arch x86_64 

정상적으로 실행되고 있는지 확인하려면, docker ps나 images로 확인한다.

docker ps
docker images

모든 명령어를 포함해서 docker run
아직 미숙한 사람을 위해 컨테이너명까지 명시

# 컨테이너명 = oracle으로 명시
docker run --restart unless-stopped --name oracle -e ORACLE_PASSWORD=pass -p 1521:1521 -d gvenzl/oracle-xe 


#-d 를 넣으며 백단에서 계속 실행되...
docker run --name oracle -d -p 1521:1521 jaspeen/oracle-xe-11g

3. 활용

docker log 확인

# docker logs -f (컨테이너명)
docker logs -f oracle

4. DB접속

접속정보

  • host: localhost
  • database: xe (orcl로 되어 있으면 바꿔줘야 함)
  • port: 1521
  • user: system
  • password: XXXX

5. 샘플계정

도커에는 샘플계정이 포함되어 있지 않기 때문에 만들어줘야 한다.

# 한 줄씩 생성
docker exec -it oracle sqlplus
CREATE USER scott identified by tiger;
GRANT CONNECT, resource, dba to scott;

생성 후에는 아래 쿼리로 유저가 정상적으로 생성 된 것을 확인

select username from dba_users where username = 'SCOTT';

SCOTT 접속

docker exec -it oracle sqlplus

 

https://velog.io/@gpg/setting-docker-oracle

docker ps 
실행중이 도커 보기

docker ps -a
전체 도커 보기

docker rm [컨테이너 id]
도커에서 컨테이너 삭제 하기

docker images

docker rmi[이미지id]
도커 이미지 삭제 하기

docker rmi -f [이미지id]

 

$ docker search oracle-xe-11g
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
oracleinanutshell/oracle-xe-11g 206
wnameless/oracle-xe-11g-r2 Oracle Express Edition 11g Release 2 on Ubun… 79
orangehrm/oracle-xe-11g docker container with Oracle Express Editio… 16 [OK]
jaspeen/oracle-xe-11g Fork from sath89/docker-oracle-xe-11g - smal… 6 [OK]
christophesurmont/oracle-xe-11g Clone of the wnameless/oracle-xe-11g. 6
ukhomeofficedigital/oracle-xe-11g Oracle Database Express Edition 11g Container 4 [OK]
thebookpeople/oracle-xe-11g 3
wscherphof/oracle-xe-11g-r2 Oracle® Database Express Edition 11g Release… 3
acktsw/oracle-xe-11g fork from https://hub.docker.com/r/sath89/or… 2 [OK]
mcgregorandrew/oracle-xe-11g Oracle image with password expiry time set t… 2
alxfduch/oracle-xe-11g-tridion Oracle Express 11g R2 on Ubuntu 16.04 LTS Tr… 2
webdizz/oracle-xe-11g-sa This is a simple image based on sath89/oracl… 1 [OK]
dotcms/oracle-xe-11g 0
zeroturnaround/oracle-xe-11g 0
activeeon/oracle-xe-11g 0
nritholtz/oracle-xe-11g nritholtz/oracle-xe-11g 0
andyrbell/oracle-xe-11g-centos Oracle Express Edition 11g Release 2 on Cent… 0
gaesi/oracle-xe-11g Based on: oracleinanutshell/oracle-xe-11g 0
switchsoftware/oracle-xe-11g 0
aerisconsulting/oracle-xe-11g Oracle Express 11g R2 on Ubuntu 16.04 LTS (b… 0
paliari/oracle-xe-11g 0
jark/oracle-xe-11g-r2-cdc 0
avuletica/oracle-xe-11g-r2 Dockerfile of Oracle Database Express Editio… 0
larmic/oracle-xe-11g Using wnameless/oracle-xe-11g with created u… 0
toneloc01/oracle-xe-11g Out-of-the-box oralce xe image from ubuntu 1… 0
 

저 중에 하나를 docker pull 명령을 이용해서 받으면 된다.

$ docker pull jaspeen/oracle-xe-11g
Using default tag: latest
latest: Pulling from jaspeen/oracle-xe-11g
Image docker.io/jaspeen/oracle-xe-11g:latest uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/
863735b9fd15: Downloading [=====================> ] 27.89MB/65.67MB
4fbaa2f403df: Download complete
44be94a95984: Download complete
a3ed95caeb02: Download complete
05b9ddeb40d9: Download complete
b44894d2d2af: Download complete
1492d1fc5b9f: Download complete
c0f3c6ec8986: Waiting
fbfc89a21b1b: Waiting
740047056d21: Waiti
 

오라클 도커 컨테이너 실행

이제 받은 오라클 도커 이미지를 이용해서 오라클 인스턴스를 띄워보자.

$ docker run --name oracle -d -p 1521:1521 jaspeen/oracle-xe-11g
 

이제 sqlplus 를 실행해서 오라클 인스턴스에 붙어보자

$ docker exec -it oracle sqlplus
 
SQL*Plus: Release 11.2.0.2.0 Production on Fri Feb 25 12:44:34 2022
 
Copyright (c) 1982, 2011, Oracle. All rights reserved.
 
Enter user-name: system
Enter password:
 
Connected to:
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
 
SQL>

 0. 도입

가끔 정상종료를 하지 않으면 톰캣이 특정 포트를 계속 사용한다.
종료해주자.

📍 1. lsof

📌 lsof란

lsof는 list open files(열려있는 파일 나열)을 뜻하는 명령으로, 수많은 유닉스 계열 운영 체제에서 열려있는 모든 파일과, 그 파일들을 열고 있는 프로세스들의 목록을 출력한다.

📌 lsof - i

> lsof -i :8080
COMMAND  PID     USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
JAVA    48458 username  15u  IPv4 0xgf254g4a48d52d65      0t0  TCP *:http-alt (LISTEN)

📌 kill -9 PID

위 lsof의 PID를 kill

> kill -9 48458

'MAC' 카테고리의 다른 글

MacOS 맥에서 Node 완전삭제하기  (0) 2023.02.16
맥 OS : 터미널에서 자신의 IP 주소 보는 방법  (0) 2019.07.29

문제점

Bitbucket과는 달리 Github에는 기본적으로 100MB 이상의 파일을 올릴 수 없다.

Conditions for large files — User Documentation
https://help.github.com/articles/conditions-for-large-files/

그래서 100MB보다 큰 크기의 파일을 올리려고 시도하면 다음과 같은 경고 메시지를 보게 된다.

$ git push
Counting objects: 3086, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2980/2980), done.
Writing objects: 100% (3086/3086), 363.25 MiB | 935.00 KiB/s, done.
Total 3086 (delta 1236), reused 111 (delta 57)
remote: error: GH001: Large files detected. You may want to try Git Large File Storage — https://git-lfs.github.com.
remote: error: Trace: ***
remote: error: See http://git.io/iEPt8g for more information.
remote: error: File *** is 120.94 MB; this exceeds GitHub’s file size limit of 100.00 MB
To git@github.com:***
 ! [remote rejected] master -> master (pre-receive hook declined)
 ! [remote rejected] *** -> *** (pre-receive hook declined)
error: failed to push some refs to ‘git@github.com:***’

HEAD의 마지막 Commit에는 100MB가 넘는 파일이 없더라도 이전 Commit 중에 100MB 이상의 파일이 포함된 적이 있다면 이 경고를 피할 수 없다. 그러다 보니 게임과 같이 대용량의 Binary 파일을 자주 다루는 프로젝트를 Github에 올릴 때에는 높은 확률로 위 메시지를 만나게 된다.

해결책

다행히도 해결책이 존재한다. 경고 메시지에도 안내되어 있듯이 몇 가지 조처를 해주면 100MB 이상의 파일도 Github에 올릴 수 있다.

1. git-lfs 적용

Commit 과정에서 지정한 파일을 작게 조각내주는 Git extension인 git-lfs — Git Large File Storage https://git-lfs.github.com/ — 를 로컬에 설치한 뒤, 적용하려는 Repository 경로에서 다음 명령을 실행한다.

$ git lfs install
Updated pre-push hook.
Git LFS initialized.

그다음 용량이 큰 파일을 git-lfs의 관리 대상으로 등록해준다. 다음 예시는 120MB 정도의 exe 파일을 Stage에 추가한 상황에서, 확장자가 exe인 모든 파일을 git-lfs의 관리 대상으로 지정하고 Commit을 수행한 모습이다.

$ git lfs track “*.exe”
Tracking *.exe$ git commit -m “Large file included”
[master (root-commit) dd2b715] Large file included
(...)

이제 하단에 있는 3번 과정대로 Github에 push를 시도하면 된다. 그런데 기존에 100MB 이상의 파일을 Commit한 적이 있다면 여전히 100MB 이상의 파일을 올릴 수 없다는 경고 메시지를 보게 된다. 그럴 땐 다음 2번 과정을 적용해야 한다.

2. BFG Repo-Cleaner 적용

기존 Commit에서 100MB보다 큰 파일의 로그를 강제로 없애줘야 한다. BFG Repo-Cleaner — BFG Repo-Cleaner https://rtyley.github.io/bfg-repo-cleaner/ — 를 이용하면 그 작업을 손쉽게 적용할 수 있다.

공식 사이트에서 bfq-x.x.x.jar — x.x.x는 버전 — 를 받고, 대상이 되는 Repository에서 다음과 같이 그동안의 Commit에 포함된 100MB 이상의 파일을 정리하는 명령을 실행한다.

$ java -jar bfg-x.x.x.jar --strip-blobs-bigger-than 100M
(...)
Deleted files
    — — — — — — -
    Filename Git id
    — — — — — — — — — — — — — — 
    ***.exe | c304fcfb (120.9 MB)
(...)

간혹 다음과 같은 오류가 나타날 수 있다.

$ java -jar bfg-x.x.x.jar --strip-blobs-bigger-than 100MUsing repo : C:\***\.gitScanning packfile for large blobs: 132
Scanning packfile for large blobs completed in 13 ms.
Warning : no large blobs matching criteria found in packfiles — does the repo need to be packed?
Please specify tasks for The BFG :
bfg x.x.x
(...)

그럴 땐 아래 명령을 먼저 수행하고 다시 위의 bfg-x.x.x.jar에 의한 명령을 실행한다.

$ git repack && git gc
Counting objects: 3002, done.
(...)

3. git-push 재시도

위 과정들을 적용한 뒤 push를 시도하면 다음과 같이 성공 메시지를 볼 수 있다.

$ git push
Counting objects: 3089, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (1809/1809), done.
Writing objects: 100% (3089/3089), 234.95 MiB | 1.30 MiB/s, done.
Total 3089 (delta 1236), reused 2890 (delta 1229)
To git@github.com:***
 * [new branch] master -> master
 * [new branch] *** -> ***

마치며

개인적으로 Private repository를 무제한으로 만들 수 있다는 점 때문에 Github보다는 Bitbucket을 자주 사용한다. 이번에 큰 용량의 Binary 파일이 있는 프로젝트를 Github의 Private repository에 올릴 일이 있어서 용량 제한 정보를 찾아 봤는데 Github은 개별 파일당 100MB의 제한이 있고 Repository 전체에 대한 용량 제한은 없는 반면, Bitbucket은 개별 파일에 대한 용량 제한은 없지만 Repository당 2GB의 전체 용량 제한이 있다. 따라서 Private repository를 써야할 때 유료 결제가 부담이 안 되는 상황이라면 git-lfs 덕분에 Github을 쓰는 것이 더 효율적인 선택이라고 본다. 물론 전체 크기가 2GB가 넘는 프로젝트가 아니라면 Bitbucket으로 충분하다고 할 수 있겠다.

도움 주신 분

  • jjunCoder님의 제보로 오탈자를 수정했습니다. (2017. 2. 28)

참고자료

  1. Conditions for large files — User Documentation https://help.github.com/articles/conditions-for-large-files/
  2. Git Large File Storage https://git-lfs.github.com/
  3. Removing files from a repository’s history — User Documentation https://help.github.com/articles/removing-files-from-a-repository-s-history/
  4. BFG Repo-Cleaner https://rtyley.github.io/bfg-repo-cleaner/
  5. git repack vs git gc — aggressive http://git.661346.n2.nabble.com/git-repack-vs-git-gc-aggressive-td7564559.html
  6. What kind of limits do you have on repository/file/upload size? — Atlasssian Documentation https://confluence.atlassian.com/bitbucket/what-kind-of-limits-do-you-have-on-repository-file-upload-size-273877699.html

팀 프로젝트를 하다보면

 

기존에 github에서 로그아웃하고

 

다른 계정으로 작업하고 싶은 일이 생길 것입니다.

 

전 이 과정에서 많은 시간을 허비했으므로 (....) 기록을 남깁니다.

 

 

 

 

 

 

그 때 작업을 하는 방법을 포스트 하겠습니다.

 

 

 

 

github에 새 repository를 만들고

 

기존에 하던 방식대로 진행하다보면

 

 

$ git push -u origin master

 

를 하면

 

remote: Permission to newaccount/projectname.git denied to oldaccount.

fatal: unable to access 'https://github.com/newaccount/projectname.git/': The requested URL returned error: 403

newaccount는 현재 계정을

newproject는 현재 업로드하려고 만들어 놓은 repository의 이름을 의미합니다

 

이런 에러가 뜰 것이다.

 

 

 

 

 

 

먼저 git에 등록된 이름과

email을 확인해봅시다.

 

 

 

 

git config user.name

git config user.email

 

을 하면

 

구 계정과 구 이메일이 나올 것입니다.

 

 

 

 

 

 

 

 

git config --global user.name 신계정

git config --global user.email 신이메일

 

로 바꿔주고

 

다시한번 확인해봅시다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

그리고 제어판의 사용자 계정에 들어갑니다.

 

사용자 계정 -> 자격 증명 관리에 들어갑니다.

 

이 곳은 윈도우OS가 관리하는 인증 정보를 보관하는 곳입니다.

github 정보도 여기에서 관리합니다.

 

 

 

 

 

 

 

 

 

 

 

다음 Windows 자격 증명에 들어가면

 

일반 자격 증명 탭에

 

기존에 사용하던 토큰들이 있을 것입니다.

 

git 과 관련된건 지워줍시다.

 

 

 

 

 

 

그리고 업로드 하고 싶은 프로젝트 우클

 

git bash here 클릭

 

 

 

 

 

 

 

 

git init

 

git remote add origin 레파지토리 주소

 

git pull origin master

 

git add .

 

git commit -m "first commit"

 

git push -u origin master

(git add 띄고 . ) (git commit 띄고 -m) (git push 띄고 -u)

 

 

순서대로 합시다.

 

 

 

 

 

 

 

 

그러면 push 하려는 순간

 

새로 로그인 하라는 창이 뜰겁니다.

 

 

 

새 계정과 이메일로 바꿔주고

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

하면 잘 됩니다.

 

 

 

자신의 respository에 들어가보면 잘 된 모습을 확인할 수 있을 것입니다.

 

 

 

수고하셨습니다.

 

https://meaownworld.tistory.com/entry/github-git-bash-%ED%84%B0%EB%AF%B8%EB%84%90-%EA%B3%84%EC%A0%95-%EB%B3%80%EA%B2%BD

우선 Eclipse나 STS는 정적파일 같은 경우에는 바로 자동반영이 되지만 서버단 JAVA코드같은 경우에는 jLebel이라는 유료 플러그인을 사용하여야한다.

IntelliJ에서도 정적파일 같은 경우에는 설정을통해 자동으로 반영할 수 있다.

(서버단 코드는 반영되지 않음. 이클립스에서 java파일 저장시 서버가 새롭게 로드되는 불편한? 증상과 비슷한 원리로 로딩됨...)

 

1. gradle.build 파일을 연다.

 

2. dependencies에 아래 코드 를 추가한다.

dependencies {

	...
    
	developmentOnly('org.springframework.boot:spring-boot-devtools')
    //혹은
    //developmentOnly 'org.springframework.boot:spring-boot-devtools'
}

 

 

3. 상단 메뉴바 file탭의 Settings

 

 

4. Settings 창이 열리면

Settings - Bulid,Execution, Deployment - compiler를 찾아 들어가거나,

검색란에 Compiler를 검색한다.

Settings - Bulid,Execution, Deployment - compiler

 

4. 우측화면 체크박스

 

Automatically show first error in editor 체크 

Build Project automatically 체크

 

5. 좌측 메뉴탭 Advanced Settings 선택

 

6. 우측 화면에서 Allow auto-make to start even if developed application is currently running 체크

 

 

7. bulid,Execution, Deployment - Build Tools - Gradle선택 혹은 검색창에 Gradle 검색

 

8. Build and run using 과 Run test using 두개 모두 Gradle로 되어있다면 IntelliJ IDEA로 변경한다.

 

7~8번은 컴파일 실행시 빌드를 Gradle이 아닌 IntelliJ IDEA로 설정하는 것인데, 이것은 자동반영 효과 뿐만 아니라 전반적인 빌드 속도를 향상시켜준다. (분산방식으로 빌드를 해준다나 뭐라나 잘 모르겠다 좀 빨라지긴 한다.)

 

9. 모든 설정 완료후에 확인차 인텔리제이를 껐다 재실행 시키자.

Log에 restartedMain이라는 단어가 출력되면 정상적으로 세팅이 되었다는 뜻

<!DOCTYPE html>
<html>
<head>
    <title>오늘 날짜 입력</title>
</head>
<body>
    <input type="text" id="dateInput">
    <script>
        // 오늘 날짜 가져오기
        const today = new Date();
        const year = today.getFullYear();
        const month = String(today.getMonth() + 1).padStart(2, '0'); // 월은 0부터 시작하므로 1을 더하고 두 자리로 포맷팅
        const day = String(today.getDate()).padStart(2, '0'); // 일자를 두 자리로 포맷팅

        // yyyy-mm-dd 형식으로 날짜 문자열 생성
        const formattedDate = `${year}-${month}-${day}`;

        // input 요소에 날짜 설정
        document.getElementById('dateInput').value = formattedDate;
    </script>
</body>
</html>

HTML의 input 요소의 type 속성을 "text"로 설정하고 사용자가 오늘 날짜를 입력할 수 있도록 하려면 JavaScript를 사용하여 오늘 날짜를 가져와서 input 요소의 value 속성에 설정해야 합니다.

이 코드에서는 JavaScript를 사용하여 오늘 날짜를 가져오고, 이 날짜를 "yyyy-mm-dd" 형식의 문자열로 변환한 다음 input 요소의 value 속성에 설정합니다. 결과적으로 input 필드에 오늘 날짜가 표시됩니다.

JavaScript에서 typeof 연산자는 피연산자의 데이터 타입을 문자열로 반환합니다. typeof는 다음과 같은 데이터 타입을 반환할 수 있습니다:

"undefined": 값이 할당되지 않은 변수 또는 존재하지 않는 객체의 속성
"boolean": 참(true) 또는 거짓(false) 값을 가진 불리언 타입
"number": 숫자 타입 (정수 및 실수)
"string": 문자열 타입
"object": 객체, 배열, null 값
"function": 함수 타입
"symbol": 심볼 타입 (ES6부터 추가됨)
typeof 연산자 사용 예시:

console.log(typeof undefined); // "undefined"
console.log(typeof true); // "boolean"
console.log(typeof 42); // "number"
console.log(typeof "Hello, world!"); // "string"
console.log(typeof {}); // "object"
console.log(typeof []); // "object" (배열도 객체로 간주됩니다)
console.log(typeof null); // "object" (null도 객체로 간주됩니다)
console.log(typeof function() {}); // "function"
console.log(typeof Symbol()); // "symbol"
주의할 점은 typeof 연산자가 배열과 null을 "object"로 반환한다는 것입니다. 배열을 구분하려면 Array.isArray() 함수를 사용하면 됩니다.

위 폴더에서 특정 단어를 찾으려면 find 명령어를 사용할 수 있습니다. 다음은 Linux 및 macOS에서 하위 폴더에서 특정 단어를 찾는 방법입니다:

bashCopy code
find /시작경로 -type f -exec grep -l '특정단어' {}
  • /시작경로: 검색을 시작할 디렉토리 경로를 지정합니다. 이것은 검색을 시작할 디렉토리를 나타냅니다. 예를 들어, 전체 시스템에서 검색하려면 /를 사용하고, 현재 디렉토리에서 검색하려면 .를 사용할 수 있습니다.
  • -type f: find 명령을 사용하여 파일만 검색하도록 지정합니다. 디렉토리는 검색에서 제외됩니다.
  • -exec grep -l '특정단어' {} \;: 각 파일에 대해 grep 명령을 실행하여 특정 단어를 찾습니다. -l 옵션은 해당 파일에서 단어를 찾으면 파일의 이름을 출력하도록 지정합니다. {}는 find 명령에서 찾은 각 파일의 이름을 나타냅니다.

예를 들어, 현재 디렉토리부터 하위 폴더에서 "example"라는 단어를 찾으려면 다음 명령을 사용할 수 있습니다:

 
bashCopy code
find . -type f -exec grep -l 'example' {} \;

이 명령은 현재 디렉토리부터 시작하여 모든 하위 폴더에서 "example"라는 단어가 포함된 파일을 찾아 파일 경로를 출력합니다.

https://velog.io/@seokkitdo

1. 삼항조건 연산자(The Ternary Operator)

if .. else 조건문을 한 라인으로 줄여주는 유용한 기법입니다.

기존

const x = 20;
let answer;

if (x > 10) {
    answer = "greater than 10";
} else {
    answer =  "less than 10";
}

축약

const answer = x > 10 ? "greater than 10" : "less than 10";

또한 중첩해서 사용도 가능합니다.

const answer = x > 10 ? "greater than 10" : x < 5 ? "less than 5" : "between 5 and 10";

2. 간략계산법(Short-circuit Evaluation Shorthand)

기존 변수를 다른 변수에 할당하고 싶을 때, 기존 변수가 null, undefined 또는 비어있는 값이 아닌지 확인하고 싶을 수 있습니다. 이 경우에는 보통 긴 if 조건문을 사용하거나 간략계산법을 축약코딩을 사용할 수 있습니다.

기존

if (variable1 !== null || variable1 !== undefined || variable1 !== '') {
     let variable2 = variable1;
}

축약

const variable2 = variable1  || 'new';

믿기지 않으신다면 es6console에 아래 코드를 복사하여 확인해보세요!

let variable1;
let variable2 = variable1  || 'bar';
console.log(variable2 === 'bar'); // prints true

variable1 = 'foo';
variable2 = variable1  || 'bar';
console.log(variable2); // prints foo

variable1에 falsy한 값을 넣을 경우 bar 문자열이 variable2에 할당될 겁니다.

3. 변수 선언

함수를 시작하기 전 변수를 선언하는 것은 좋은 자세입니다. 이 축약기법은 동시에 여러개의 변수를 선언함으로써 시간과 코드라인을 줄일 수 있습니다.

기존

let x;
let y;
let z = 3;

축약

let x, y, z=3;

4. If Presence Shorthand

사소한 것일지 모르나, 알아두면 좋을 것 같습니다. if 조건문을 사용 시 때때로 대입 연산자를 생략할 수 있습니다.

기존

if (likeJavaScript === true)

축약

if (likeJavaScript)

위 두가지 예제가 정확하게 일치하지는 않습니다. 그 이유는 기존방법의 경우 true일 경우에만 조건문을 실행하는 반면 축약기법에서는 truthy 일 경우 통과하도록 되어있기 때문입니다.

다음 예제를 보시면 a가 true가 아닐 경우, 조건문을 실행합니다.
기존

let a;
if ( a !== true ) {
// do something...
}

축약

let a;
if ( !a ) {
// do something...
}

5. 반복문(For Loop)

만약 외부 라이브러리에 의존하지 않고 바닐라 자바스크립트만을 사용하길 원한다면 이 팁은 아주 유용합니다.

기존

const fruits = ['mango', 'peach', 'banana'];
for (let i = 0; i < fruits.length; i++)

축약

for (let fruit of fruits)

단순히 인덱스에만 접근하길 원한다면 다음과 같은 방법도 있습니다.

for (let index in fruits)

또한 리터럴 객체의 키에 접근하려는 경우에도 마찬가지로 동작합니다.

const obj = {continent: 'Africa', country: 'Kenya', city: 'Nairobi'}
for (let key in obj)
  console.log(key) // output: continent, country, city

Array.forEach를 통한 축약기법

function logArrayElements(element, index, array) {
  console.log("a[" + index + "] = " + element);
}
[2, 5, 9].forEach(logArrayElements);
// a[0] = 2
// a[1] = 5
// a[2] = 9

6. 간략 계산법(Short-circuit Evaluation)

기본 값을 할당하기 위해 파라미터가 null 또는 undefined인지 확인하느라 6줄의 코드를 작성하는 것보다 Short-circuit Evaluation 계산법을 이용해 한 줄의 코드로 작성하는 방법이 있습니다.

기존

let dbHost;
if (process.env.DB_HOST) {
  dbHost = process.env.DB_HOST;
} else {
  dbHost = 'localhost';
}

축약

const dbHost = process.env.DB_HOST || 'localhost';

process.env.DB_HOST 값이 있을 경우 이 값을 dbHost에 할당하지만 없다면 localhost를 할당합니다. 이에 대한 정보는 여기 에서 더 살펴볼 수 있습니다.

7. 십진법 지수(Decimal Base Exponents)

0이 많이 포함된 숫자를 적을 때, 이 수많은 0들을 제외하고 숫자를 작성한다면 있어보이지 않을까요? 예를들어 1e7은 10,000,000 과 동일하며 1뒤에 7개의 0이 딸려온 것을 의미합니다.

기존

for (let i = 0; i < 10000; i++) {}

축약

for (let i = 0; i < 1e7; i++) {}

// All the below will evaluate to true
1e0 === 1;
1e1 === 10;
1e2 === 100;
1e3 === 1000;
1e4 === 10000;
1e5 === 100000;

8. 객체 프로퍼티

자바스크립트에서 객체 리터럴 표기법은 코딩을 더 쉽게 만듭니다. ES6 는 객체에 프로퍼티를 할당하는것을 더 쉽게 만들어 주었습니다. 만약 객체의 프로퍼티 이름이 키 이름과 같을 경우에 축약기법을 사용할 수 있습니다.

기존

const x = 1920, y = 1080;
const obj = { x:x, y:y };

축약

const obj = { x, y };

9. 화살표(Arrow) 함수

기존의 함수는 읽고 쓰기가 쉽도록 되어있지만 다른 함수 호출에 중첩하여 사용하게 될 경우 다소 길어지고 헷갈리게 됩니다.
기존

function sayHello(name) {
  console.log('Hello', name);
}

setTimeout(function() {
  console.log('Loaded')
}, 2000);

list.forEach(function(item) {
  console.log(item);
});

축약

sayHello = name => console.log('Hello', name);

setTimeout(() => console.log('Loaded'), 2000);

list.forEach(item => console.log(item));

화살표 함수와 일반 함수의 차이점은 그 생김새로도 확인할 수 있지만 this가 기존 함와 다르게 작동합니다. 따라서 위 두 예제는 완전히 동일한 예제는 아닙니다.
이 차이점에 대해 알고 싶으시다면 여기 를 클릭해주세요.

10. 묵시적 반환(Implicit Return)

return 은 함수 결과를 반환하는데 사용되는 키워드입니다. 한 줄로만 작성된 화살표 함수에서는 return 명령어가 없어도 자동으로 반환하도록 되어있습니다. 다만 중괄호를 생략해야지만 return 키워드도 생략할 수 있습니다.

여러 라인의 코드(객체 리터럴) 를 반환하려면 중괄호 대신 () 를 사용해서 함수를 감싸면 됩니다. 다음과 같이 한 줄로 코드가 작성되었음을 확인할 수 있습니다.

기존

function calcCircumference(diameter) {
  return Math.PI * diameter
}

축약

calcCircumference = diameter => (
  Math.PI * diameter;
)

11. 파라미터 기본값 지정

기존에는 if 문을 통해 함수의 파라미터에 기본 값을 지정해주었지만 ES6 에서는 함수 선언문 자체에 파라미터의 기본 값을 설정해 줄 수 있습니다.
기존

function volume(l, w, h) {
  if (w === undefined)
    w = 3;
  if (h === undefined)
    h = 4;
  return l * w * h;
}

축약

volume = (l, w = 3, h = 4 ) => (l * w * h);

volume(2) //output: 24

12. 템플릿 리터럴(Template Literals)

문자열로 ' + '를 입력하며 자바스크립트 값을 추가하는 손가락 노동에 지치지 않으시나요? 더 쉬운 방법은 없을까요? 만약 ES6 사용하실 줄 안다면 백틱(backtick)을 사용해서 스트링을 감싸고 변수를 ${}로 감싸서 손쉽게 연결 할 수 있습니다.

기존

const welcome = 'You have logged in as ' + first + ' ' + last + '.'

const db = 'http://' + host + ':' + port + '/' + database;

축약

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

const db = `http://${host}:${port}/${database}`;

13. 구조 분해 할당(Destructuring Assignment)

유명한 프레임워크로 개발을 하고 있다면 컴포넌트나 API간 데이터를 전송하기 위해서 객체 리터럴이나 배열로 이뤄진 데이터를 사용하게 될 가능성이 큽니다. 데이터 객체가 컴포넌트에 들어가게 되면, unpack이 필요합니다.

기존

const observable = require('mobx/observable');
const action = require('mobx/action');
const runInAction = require('mobx/runInAction');

const store = this.props.store;
const form = this.props.form;
const loading = this.props.loading;
const errors = this.props.errors;
const entity = this.props.entity;

축약

import { observable, action, runInAction } from 'mobx';

const { store, form, loading, errors, entity } = this.props;

추가적으로 커스텀 변수명을 지정할 수 있습니다.

const { store, form, loading, errors, entity:contact } = this.props;

위의 코드는 구조분해할당을 통해 entity를 가져오고 난 후 contact라는 변수명을 지정한 겁니다.

14. 여러줄로 문자열 쓰기

한 줄 이상의 문자열을 입력하게 될 경우가 있다면 기존의 방법보다 훨씬 편한 방법이 있습니다.

기존

const lorem = 'Lorem ipsum dolor sit amet, consectetur\n\t'
    + 'adipisicing elit, sed do eiusmod tempor incididunt\n\t'
    + 'ut labore et dolore magna aliqua. Ut enim ad minim\n\t'
    + 'veniam, quis nostrud exercitation ullamco laboris\n\t'
    + 'nisi ut aliquip ex ea commodo consequat. Duis aute\n\t'
    + 'irure dolor in reprehenderit in voluptate velit esse.\n\t'

아래와 같은 방법으로 백틱(backtick)을 사용하는 방법도 있습니다.

축약

const lorem = `Lorem ipsum dolor sit amet, consectetur
    adipisicing elit, sed do eiusmod tempor incididunt
    ut labore et dolore magna aliqua. Ut enim ad minim
    veniam, quis nostrud exercitation ullamco laboris
    nisi ut aliquip ex ea commodo consequat. Duis aute
    irure dolor in reprehenderit in voluptate velit esse.`

15. 전개 연산자(Spread operator)

ES6 에서 소개된 스프레드 연산자는 자바스크립트 코드를 더 효율적이고 재미있게 사용할 수 있는 방법들을 제시합니다. 간단히는 배열의 값을 변환하는데 사용할 수 있습니다. 스프레드 연산자를 사용하는 방법은 점 세개(...)를 붙이면 됩니다.

기존

// joining arrays
const odd = [1, 3, 5];
const nums = [2 ,4 , 6].concat(odd);

// cloning arrays
const arr = [1, 2, 3, 4];
const arr2 = arr.slice()

축약

// joining arrays
const odd = [1, 3, 5 ];
const nums = [2 ,4 , 6, ...odd];
console.log(nums); // [ 2, 4, 6, 1, 3, 5 ]

// cloning arrays
const arr = [1, 2, 3, 4];
const arr2 = [...arr];

concat() 함수와는 다르게 스프레드 연산자는 배열 내부의 원하는 위치 어디에나 추가할 수 있습니다.

const odd = [1, 3, 5 ];
const nums = [2, ...odd, 4 , 6];

스프레드 연산자는 또한 ES6 의 구조화 대입법(destructuring notation)와 함게 사용할 수도 있습니다.

const { a, b, ...z } = { a: 1, b: 2, c: 3, d: 4 };
console.log(a) // 1
console.log(b) // 2
console.log(z) // { c: 3, d: 4 }

16. 필수(기본) 파라미터(Mandatory Parameter)

기본적으로 자바스크립트 함수의 파라미터값을 받지 않았을 경우, undifined로 지정합니다. 몇몇 다른 언어들은 에러 메시지를 나타내기도 합니다. 이런 기본 파라미터는 강제로 할당하는 방법은 if문을 사용해서 undefined일 경우 에러가 나도록 하거나,
Mandatory Parameter를 사용하는 방법이 있습니다.

기존

function foo(bar) {
  if(bar === undefined) {
    throw new Error('Missing parameter!');
  }
  return bar;
}

축약

mandatory = () => {
  throw new Error('Missing parameter!');
}

foo = (bar = mandatory()) => {
  return bar;
}

17. Array.find

자바스크립트로 특정 값을 찾기 위한 함수를 작서앟다보면 보통 for 루프를 이용해서 접근을 하곤 합니다. 그러나 ES6 에서 find()라는 새로운 함수가 생겼습니다.

기존

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

function findDog(name) {
  for(let i = 0; i<pets.length; ++i) {
    if(pets[i].type === 'Dog' && pets[i].name === name) {
      return pets[i];
    }
  }
}

축약

pet = pets.find(pet => pet.type ==='Dog' && pet.name === 'Tommy');
console.log(pet); // { type: 'Dog', name: 'Tommy' }

18. Object [key]

Foo.bar를 Foo['bar'] 로 적을 수 있다는 걸 알고 있으신가요? 왜 후자와 같이 코딩을 해야 하는지 의문이 들 수도 있지만, 재사용이 용이한 코드 블락을 작성하기 위해서는 매우 효율적인 방법입니다.
아래의 간단한 validation 함수를 확인해보세요

기존

function validate(values) {
  if(!values.first)
    return false;
  if(!values.last)
    return false;
  return true;
}

console.log(validate({first:'Bruce',last:'Wayne'})); // true

위 함수로 validation 기능을 완벽하게 사용할 수 있습니다. 하지만 form 요소들과 validation 옵션으로 사용해야하는 영역과 규칙이 많을 경우 위 함수는 점점 복잡해지고 길어지게 됩니다. 이를 방지하기 위해서 실행시 옵션을 부과할 수 있는 포괄적인 validation함수를 작성하는 방법을 알아보겠습니다.

축약

// object validation rules
const schema = {
  first: {
    required:true
  },
  last: {
    required:true
  }
}

// universal validation function
const validate = (schema, values) => {
  for(field in schema) {
    if(schema[field].required) {
      if(!values[field]) {
        return false;
      }
    }
  }
  return true;
}


console.log(validate(schema, {first:'Bruce'})); // false
console.log(validate(schema, {first:'Bruce',last:'Wayne'})); // true

위의 예시처럼 사용한다면 모든 form에 공통으로 적용할 수 있는 validation 함수를 작용할 수 있습니다.

19. 단항 비트 논리부정 연산자 (Double Bitwise NOT)

비트 연산자는 자바스크립트를 처음 배울 때를 제외하고는 한 번도 적용해 본 적 없는 연산자일 겁니다. 애당초 이진법으로 코딩하지 않는다면 1과 0을 사용 할 일이 없죠.

하지만 단항 비트 논리부정 연산자를 효율적으로 사용할 수 있는 방법을 알려드립니다.
바로 Math.floor() 함수의 대체용으로 사용할 수 있다는 것이죠. 또 Math.floor()함수보다 훨씬 빠르게 작동한다는 장점도 있습니다. 단항 비트 논리부정 연산자에 대해서는 여기 에서 더 알아보실 수 있습니다.

기존

Math.floor(4.9) === 4  //true

축약

~~4.9 === 4  //true

20. 거듭제곱(Exponent Power)

Math.pow를 통해 거듭제곱을 나타낼 수 있습니다.

기존

Math.pow(2,3); // 8
Math.pow(2,2); // 4
Math.pow(4,3); // 64

축약

2**3 // 8
2**4 // 4
4**3 // 64

21. 문자열 숫자 변환

때때로 필요한 데이터는 숫자 형식이어야 하는데 문자열 타입이 오는 경우가 있을 수 있습니다. 하지만 이러한 타입변환은 손쉽게 해결할 수 있습니다.

기존

const num1 = parseInt("100");
const num2 =  parseFloat("100.01");

축약

const num1 = +"100"; // converts to int data type
const num2 =  +"100.01"; // converts to float data type

'study > Front' 카테고리의 다른 글

java script 오늘날짜 입력  (0) 2023.10.25
Javascript typeof. typeof undefined  (0) 2023.10.25
find  (0) 2023.10.24
formData axios selectbox  (0) 2023.10.16
axios.js  (0) 2023.10.16

+ Recent posts