컴포넌트 > 기본 기능
개요
ChmmDataTable 의 기본 기능을 설명한다.
화면경로
Play Ground > UI Components > Grid > 기본기능
Basic 탭
기본적인 기능으로 구성된 그리드를 소개한다.
Use API 탭
API 를 통해서 데이터 조회를 하고 조건을 입력 받는 기능을 소개한다.
테이블 기본 설정
ChmmDataTable 컴포넌트의 설정 속성 값을 소개한다.
데이터 조회 (API)
API 조회 연동을 위한 속성과 메소드를 소개한다.
컴포넌트 > 페이징
개요
ChmmDataTable 페이징 처리에 대한 내용을 소개한다.
화면경로
Play Ground > UI Components > Grid > 페이징
페이징(true)
페이징 처리를 해서 조회하는 화면을 표시한다.
샘플코드
<ChmmDataTable
ref="dtTrue"
:value="dataTableValue"
data-key="id"
:paginator="true"
:rows="20"
:rows-per-page-options="[10, 20, 50, 100]"
current-page-report-template="총 {totalRecords} 건"
:page-link-size="10"
select-api="/chmm/message/list"
scroll-height="calc(100vh - 24rem)"
>
페이징(false)
페이징처리를 하지 않고 전체 조회한 화면을 표시한다.
샘플코드
<ChmmDataTable
ref="dtFalse"
:value="dataTableValue"
data-key="id"
:paginator="false"
select-api="/chmm/message/list"
scroll-height="calc(100vh - 24rem)"
:max-count="100"
>
페이징처리 속성
페이징 처리를 위한 속성을 소개한다.
페이징 미처리(전체조회)
전체조회를 위해 관련된 속성을 소개한다.
컴포넌트 > 무한스크롤
개요
기존 Datatable 에서는 지원하지 않는 Infinite Scroll을 지원하기 위해 기능을 추가
데이터테이블 영역의 스크롤바를 끝으로 내리면 다음 데이터를 조회하여 데이터테이블에 추가한다.
사용방법
-
조회할 데이터의 개수를 사용자가 지정할 수 있다.
-
paginator props를 false 값을 넣어 페이징기능을 사용하지 않아야 한다.
-
props 정보는 아래와 같다.
예시
- 스크롤을 최하단까지 내리면 다음 데이터를 가져온 것을 볼 수 있다.
코드
- 스크롤 이후 불러올 데이터 개수를 100개로 지정한 코드
컴포넌트 > 공통코드
개요
시스템에서 사용하는 공통코드를 공통코드 컴포넌트를 통해서 쉽게 만들 수 있도록 지원한다.
사용방법
-
공통코드 컴포넌트는 아래 3가지 타입을 지원한다.
- dropdown (Dropdown)
- radio (RadioButton Group)
- checkbox (SelectButton)
-
공통코드 컴포넌트는 공통코드 별 설정된 다국어 메시지로 표시한다.
-
props 정보는 아래와 같다.
예시
- dropdown 타입, radio 타입, checkbox 타입
코드
컴포넌트 > V-Input
개요
텍스트 Input 박스에서 Validation 체크를 지원한다.
사용방법
-
validation Input 컴포넌트는 8가지의 패턴을 지원한다.
- text (문자)
- number (숫자)
- email (이메일)
- phone (휴대전화번호)
- ip (IP)
- bizRegister (사업자번호)
- corpRegister (법인번호)
- resident (주민등록번호)
-
min-length, max-length props를 통해 문자와 숫자의 길이 체크를 할 수 있다.
-
required props를 통해 필수여부를 설정할 수 있다.
-
props 정보는 아래와 같다.
예시
- 각 패턴 별 validation 체크
코드
- 패턴을 ‘text’로하고 최소길이를 5, 최대길이를 50, 필수여부를 ‘true’로 설정한 예제 코드
컴포넌트 > Error_Handler
개요
캐모마일 프레임워크에서는 FrontEnd 프레임워크로 Nuxt.js – 3.4.1 버전을 사용하였으며, Nuxt 에서 지원하는 errorHandling 을 바탕으로 에러처리를 하도록 개발환경을 구성하였다.
- [에러 페이지 처리](# 에러 페이지 처리)
- [컴포넌트 에러 처리](# 컴포넌트 에러 처리)
- [API 에러 처리](# API 에러 처리)
- [인증 권한 에러 처리](# 인증 권한 에러 처리)
에러 페이지 처리
Nuxt 는 서버 생명 주기 동안 또는 Vue 애플리케이션(SSR 및 SPA 모두) 을 렌더링할 때 치명적인(fatal) 오류가 발생하면, JSON 응답( Accept: application/json
헤더로 요청한 경우) 또는 HTML 오류 페이지를 렌더링합니다.
소스 디렉터리에 app.vue
와 함께 ~/error.vue
를 추가하여 오류 페이지를 사용자 정의 할 수 있습니다.
error.vue
에서는 발생되는 에러에 따라 error.statusCode
를 감지하여 상태 별로 화면을 Redirect
하여 처리합니다.
오류 페이지 제거 시에는 Helper 함수 clearError
를 호출하여 Error 를 제거하고 정상 페이지로 전환합니다.
Nuxt 플러그인에 의존하는 것을 사용하기 전에
$route
또는useRouter
와 같은 플러그인이 오류를 던진 것처럼 오류를 지울 때까지 다시 실행되지 않는지 확인
? Nuxt – Rending an Error Page (nuxt.com)
ErrorPage Handling Flow
- 사용자 요청 (페이지 이동)
- 서버 오류 발생
- error.vue 에서 error.statusCode 를 확인하여 에러 페이지로 이동
graph TD
A(사용자요청)-->|서버 오류 발생|B{error.vue}
B-->|statusCode : 403| C[AccessDenied.vue]
B-->|statusCode : 404| D[NotFound.vue]
B-->|statusCode : 500| E[ServerError.vue]
에러 페이지 목록
StatusCode | Component | Description |
---|---|---|
403 |
AccessDenied.vue | 미들웨어에서 권한 없음 처리 |
404 |
NotFound.vue | 라우터에 등록되지 않은 페이지 요청 |
500 |
ServerError.vue | 서버 에러 (존재하지 않은 컴포넌트 사용, 서버사이드랜더링 오류 등) |
error.vue ( src/error.vue )
<script lang="ts" setup>
interface ErrorProps {
error: {
description?: string,
message?: string,
statusCode: string,
statusMessage: string,
url: string
};
}
const { error } = defineProps<ErrorProps>();
const component = computed(() => {
if (parseInt(error.statusCode) === 403) {
return defineAsyncComponent(() => import('~/components/layouts/error/AccessDenied.vue'));
}
return parseInt(error.statusCode) === 404
? defineAsyncComponent(() => import('~/components/layouts/error/NotFound.vue'))
: defineAsyncComponent(() => import('~/components/layouts/error/ServerError.vue'));
});
definePageMeta({
layout: 'empty',
title: 'Error'
});
</script>
<template>
<div>
<Head>
<Title>{{ error.statusMessage }}</Title>
</Head>
<Component :is="component" :error="error" />
</div>
</template>
컴포넌트 에러 처리
컴포넌트 에러처리는 랜더링 이후 Vue 컴포넌트 내부에서 개발자의 실수로 발생하는 에러 (Undefined 참조, 문법오류 등) 나 예외상황을 예측해서 던지는 에러 ( throw createError, throw new Error ) 에 대한 처리를 말한다.
-
전역 애플리케이션 레벨에서 처리하는 방식
nuxtApp.vueApp.config.errorHandler
를 사용하여 선언하면 애플리케이션 전역에서 발생하는 모든 에러를 처리 (Promise 객체, 비동기처리 에러 제외)- Vue 애플리케이션 내부에서 에러가 발생하면
errorHandler
가 호출 - 전역적인 에러처리 가능
export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.config.errorHandler = (error: any, context: (globalThis.ComponentPublicInstance | null), info: string) => { console.error('[errorHandler]', error) // 에러 처리 } }
-
Vue 컴포넌트 레벨에서 처리하는 방식
- 컴포넌트에서
errorCaptured
훅을 사용하여 에러를 캐치하고 처리 - 에러가 발생한 컴포넌트에서 직접 에러를 처리할 수 있으며, 에러를 캐치하는 컴포넌트가 없으면 부모 컴포넌트로 에러가 전파
errorCaptured
를 사용해서 컴포넌트 레벨에서 에러 처리가 가능하고 에러처리 이후에nuxtApp.vueApp.config.errorHandler
로 선언한 플러그인에서도 에러 처리 가능
export default { errorCaptured(err, vm, info) { if (err) { console.error('Component Error:', err); // 에러를 캐치한 컴포넌트에서 에러를 처리하거나 부모 컴포넌트로 전파 } }, };
- 컴포넌트에서
-
NuxtErrorBoundary
Nuxt 는 전체 사이트를 오류 페이지로 바꾸지 않고도 앱 내에서 클라이언트 측 오류를 처리할 수 있는
<NuxtErrorBoundary>
컴포넌트를 제공합니다.<NuxtErrorBoundary>
로 자식 컴포넌트를 감싸면 자식 컴포넌트에서 발생되는 에러를 상위로 전달하지 않고 대체 페이지로 전환하여 에러에 대한 처리가 가능합니다.-
@error : 컴포넌트에서 오류를 던질 때 이벤트 발생
-
#error : 오류 발생 시 표시할 대체 컨텐츠를 지정
-
정상 화면 | 자식 컴포넌트에서 에러가 발생한 화면 |
---|---|
![]() |
![]() |
errorPage.vue
<template>
<h4>부모 컴포넌트 (errorPage.vue)</h4>
<NuxtErrorBoundary >
<errorChildComponent/>
<template #error="{ error, clearError }">
<div>
<h4>에러 발생</h4>
<p>errorChildComponent 에서 에러가 발생했습니다!</p>
<pre>{{ error }}</pre>
<Button label="에러지우기" \@click="doClearError(error, clearError)"/>
</div>
</template>
</NuxtErrorBoundary>
</template>
<script>
import errorChildComponent from './errorPage/errorChildComponent.vue';
export default {
components: {
errorChildComponent
},
methods: {
doClearError(error, clearError) {
error.value = null
clearError()
},
}
};
</script>
errorChildComponent.vue
<template>
<div>
<h4>자식 컴포넌트 (errorChildComponent.vue) </h4>
<Button @click="triggerError" label="에러 발생시키기" />
</div>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
export default defineComponent({
name: "errorChildComponent",
methods: {
triggerError() {
const name = '캐모마일'
name = 'New 캐모마일'
}
}
})
</script>
-
에러 발생
Vue 컴포넌트 내부에서 발생할 수 있는 일반적인 에러 유형을 다음과 같이 나타낼 수 있다.
-
try/catch
<script>
에서 발생할 수 있는 에러에 대해서try/catch
로 감싸면 script 에러만 발생하고 catch 문에서 후속 에러 처리가 필요하며,
이 경우 errorCaptured 와 errorHandler 로는 에러가 전달되지 않는다.에러유형 : ReferenceError, TypeError, SyntaxError, 무한 루프 및 스택 오버플로우
- try/catch 처리
try { const name = '캐모마일' name = 'New 캐모마일' // TypeError: Assignment to constant variable } catch(e) { console.error(e) // 에러 처리 }
Result doTryCatch @ error.vue:74 <== error.vue 컴포넌트에서 에러 capture
callWithErrorHandling @ chunk-3Q27KRJ5.js:213
callWithAsyncErrorHandling @ chunk-3Q27KRJ5.js:221
invoker @ chunk-MNWBZQKJ.js:322- try/catch 미처리
const name = '캐모마일' name = 'New 캐모마일' // TypeError: Assignment to constant variable
Result nuxtApp.vueApp.config.errorHandler @ error.ts:13 <== 전역 errorHandler 에서 에러 capture
callWithErrorHandling @ chunk-3Q27KRJ5.js:213
handleError @ chunk-3Q27KRJ5.js:254
callWithErrorHandling @ chunk-3Q27KRJ5.js:215
callWithAsyncErrorHandling @ chunk-3Q27KRJ5.js:221
invoker @ chunk-MNWBZQKJ.js:322 -
throw createError
Nuxt 의 헬퍼 메서드를 사용하여 에러 전달throw createError({ statusCode: 404, statusMessage: 'statusMessage', message: 'message' })
캐모마일 error.ts
어플리케이션에서 에러 발생시 전역적으로 필요한 처리가 있으면, errorHandler
에 추가적인 에러처리 작업이 필요합니다.
기본적으로 캐모마일의 errorHandler
에서는 에러 발생시 showAlert 를 사용하여 Dialog 로 에러메시지를 표시합니다. ( ※ 불필요시 제거 )
error.ts ( src/plugins/error.ts )
import {showAlert, showConfirm} from "~/utils/commonDialogUtil";
export default defineNuxtPlugin((nuxtApp) => {
/**
* 전역 애플리케이션 레벨에서 발생되는 에러 처리
* @param error
* @param context
* @param info
* @description throw new Error, throw createError 발생이나 Component 상의 에러 발생시
* Promise 객체에서 발생되는 에러 확인 불가
*/
nuxtApp.vueApp.config.errorHandler = (error: any, context: (globalThis.ComponentPublicInstance | null), info: string) => {
console.error('vue:error ', error)
showAlert(error.message, null, 'Error Message'); // 에러 발생시 공통 경고창으로 표시
}
});
에러 메시지 다이얼로그 |
---|
![]() |
API 에러 처리
Nuxt 에서 제공하는 useFetch 에 대한 API 에러 처리
- onResponseError, onRequestError 에서 처리
<script lang="ts">
export default defineComponent({
methods: {
async doApiError() {
const { data, pending, error, refresh } = await useFetch('/api/auth/login', {
onResponse({ request, response, options }) {
// Process the response data
localStorage.setItem('token', response._data.token)
},
onResponseError({ request, response, options }) {
// Handle the response errors
console.log('[onResponseError]', response.status, response.statusText)
},
});
},
},
});
</script>
인증 권한 에러 처리
error.global.ts ( src/middleware/error.global.ts )
-
Nuxt 프로젝트의
middleware
디렉토리에defineNuxtRouteMiddleware
를 사용하여 선언 -
Nuxt.js에서 미들웨어는 라우팅 처리에 사용되는 기능으로, 페이지가 렌더링되기 전에 특정한 처리를 수행하고 싶을 때 유용하게 사용
-
미들웨어는 라우트 전환 시점에 실행되며, 페이지 컴포넌트가 렌더링되기 전에 실행되는데, 이를 통해
인증
,권한 검사
,로깅
등과 같은 전역적인 작업을 처리할 수 있습니다.
인증 / 권한 관련 처리 정의 후 진행
가이드 참조 : https://nuxt.com/docs/api/utils/define-nuxt-route-middleware#definenuxtroutemiddleware
export default defineNuxtRouteMiddleware ((to, from) => {
if ('middleware' in to.query) {
return showError('error in middleware')
}
})
Error Helper Methods
useError
function useError (): Ref<Error | { url, statusCode, statusMessage, message, description, data }>
이 함수는 처리 중인 전역 Nuxt 오류를 반환합니다.
? Docs > API > Composables > Use Error 에서 자세히 알아보세요 .
createError
function createError (err: { cause, data, message, name, stack, statusCode, statusMessage, fatal }): Error
이 기능을 사용하여 추가 메타데이터가 있는 오류 개체를 만들 수 있습니다. 앱의 Vue 및 Nitro 부분 모두에서 사용할 수 있으며 던져야 합니다.
createError
로 생성된 오류가 발생하는 경우 :
-
서버 측에서는
clearError
로 지울 수 있는 전체 화면 오류 페이지를 트리거합니다. -
클라이언트 측에서는 처리할 치명적이지 않은 오류가 발생합니다. 전체 화면 오류 페이지를 트리거해야 하는 경우,
fatal: true
를 설정하여 이를 수행할 수 있습니다 .
createError() 와 new Error()
fn name | createError() | new Error() |
---|---|---|
description | Nuxt.js 에서 제공하는 http-errors 라이브러리를 사용하여 간편하게 에러 객체 생성 |
JavaScript 의 기본적인 에러 생성 방법으로 HTTP 상태코드 와 같은 추가적인 정보는 수동으로 설정 |
parameter | err: { cause, data, message, name, stack, statusCode, statusMessage, fatal } |
message?: string options?: ErrorOptions |
createError()
const error = throw createError({
statusCode: 404,
statusMessage: 'Page Not Found !',
message: '페이지를 찾을 수 없습니다.'
})
console.log(error.statusCode); // 404
console.log(error.message); // "페이지를 찾을 수 없습니다."
new Error()
const error = new Error('예상치 못한 에러 발생');
console.log(error.message); // "예상치 못한 에러 발생"
showError
function showError (err: string | Error | { statusCode, statusMessage }): Error
이 함수는 클라이언트 측에서 또는 (서버 측에서) 미들웨어, 플러그인 또는 setup()
기능 내에서 직접 호출할 수 있습니다. clearError
로 지울 수 있는 전체 화면 오류 페이지를 트리거합니다.
대신 throw createError()
를 사용하는 것이 좋습니다 .
?Docs > API > Utils > Show Error 에서 자세히 알아보세요 .
컴포넌트 > CustomAPI
개요
useCustomFetch의 동작 방식을 설명한다.
어드민에서는 API를 호출하기 위해 Nuxt에 내장되어있는 useFetch를 사용 한다.
useFetch는 useAsyncData와 $fetch를 감싼 Nuxt에서 제공하는 composable이다.
어드민에서는 useFetch를 한번 더 감싸서 useCustomFetch.ts를 composable로 등록하여 사용한다.
useCustomFetch 사용 이유
어드민에서 useFetch를 사용할 때 2개의 인자를 전달한다.
- URL : Request RUL
- Options : ofecth options + AsyncData options
어드민에서는 useFetch를 호출할 때마다 공통적으로 수행해야하는 로직이 존재하여 반복작업을 최소화 하기 위해서 useCustomFetch로 useFetch를 감싸서 사용한다.
공통로직은 useCustomFetch에 들어가 있지만, method구분을 위해서 아래와 같이 export하여 사용한다.
/**
* useCustomFetch Get요청
* @param url API URL
* @param params API 요청 파라미터
* @param options UseFetchOptions
* @param errorAlert 오류 발생 시, alert 생성 유무
* @returns
*/
function useGetFetch(url: string, params?: any, options?: any, errorAlert?: boolean) {
return useCustomFetch(url, 'GET', params, options, errorAlert);
}
function usePostFetch(url: string, params?: any, options?: any, errorAlert?: boolean) {
return useCustomFetch(url, 'POST', params, options, errorAlert);
}
function usePutFetch(url: string, params?: any, options?: any, errorAlert?: boolean) {
return useCustomFetch(url, 'PUT', params, options, errorAlert);
}
function useDeleteFetch(url: string, params?: any, options?: any, errorAlert?: boolean) {
return useCustomFetch(url, 'DELETE', params, options, errorAlert);
}
export { useGetFetch, usePostFetch, usePutFetch, useDeleteFetch };
useCustomFetch 가 하는 일
-
UseFetch Option 값 디폴트 세팅
const defaultFetchOptions: UseFetchOptions<T> = { // 1-1. baseURL, method, parameter 세팅 baseURL: config.public.apiBase, method, // 1-2. useFetch 응답을 처리하는 콜백함수 onResponse({ response }) { // 1-2-1. http 응답 상태코드가 200이 아니라면 return if (response.status / 10 !== 20) { return; } const contentType = response.headers.get('Content-Type'); // 1-2-2. 응답 헤더의 content-type이 'text/plain'이라면 JSON.parse() 처리 if (contentType?.includes('text/plain')) { try { response._data = JSON.parse(response._data); } catch(exception) { throw exception; } } }, // 1-3. useFecth 에러 발생 시, 실행되는 함수 onResponseError(response) { const { status, statusText, _data } = response.response; failHandler(status, _data.message, errorAlert); } };
-
권한 체크
const needAuth = !NO_AUTH_API.some((v: string) => url.includes(v)); // 2-1. 권한 체크가 필요한 API 요청인지 확인 if (needAuth) { const { accessToken, checkTokenTimeout, logUserOut } = useAuthStore(); // 2-2. 토큰 유효기간 확인 if (!checkTokenTimeout()) { logUserOut(); return {}; } // 2-3. 헤더에 토큰 추가 defaultFetchOptions.headers = { Authorization: `Bearer ${accessToken}` }; }
-
디폴트 세팅한 useFetch options과 인자로 받은 useFetch options을 merge
const mergedFetchOptions = defu(options, defaultFetchOptions);
-
useFetch 호출
const { data, pending, error, status, refresh } = await useFetch(url, mergedFetchOptions);
-
useFetch 호출 결과에 따른 분기
// 5-1. SSR시, 최초 useFetch가 pending되어 useFetch 재 호출 필요 if (pending.value) { return useCustomFetch(url, method, params, options, errorAlert); } // 5-2. useFetch 호출 결과가 성공이 아니라면 failHandler 호출 // (status type : 'idle' | 'pending' | 'success' | 'error') if (status.value !== 'success') { failHandler(error.value?.status, error.value?.message, errorAlert); } // 5-3. useFetch 호출 결과가 성공이라면, useFetch 응답 그대로 리턴 return { data, pending, error, status, refresh };
컴포넌트 > 다국어
개요
다국어를 적용하기 위한 개발 가이드를 제공한다.
어드민에서는 vue-i18n 플러그인을 사용하여, 다국어를 적용하였다.
- 다국어를 적용하기 위해서는 key: message 형태의 값을 언어별로 가지고 있어야 한다.
다국어 설치
어드민에서는 npm을 이용하여 설치하였다.
※ vue3부터는 vue-i18n v9이상의 버전을 사용해야한다.
npm install vue-i18n@9
다국어 설정
plugins/i18n.ts 파일을 생성하여 다음과 같이 설정 하였다.
export default defineNuxtPlugin(async ({ vueApp }) => {
// 1. 기본 다국어 메세지 파일을 조회
const defaultMessages: {[key: string]: { [key: string]: string }} = languageService.defaultMessages;
// 2. i18n 옵션 세팅
const i18n = createI18n({
// 2-1. v8에서 제공하는 vue-i18n API
legacy: false,
// 2-2. i18n 프로퍼티와 함수를 각 컴포넌트에서 접근하게 할 지 여부
globalInjection: true,
// 2-3. 기본 언어 설정
locale: "ko",
// 2-4. 다국어 메세지 설정 (API를 통해 DB 다국어 메세지 조회)
messages: await languageService.getLanguageMessageList(),
// 2-5. i18n에 메세지가 없는 경우 실행되는 함수로, 1.번에서 조회한 파일에서 메세지를 다시 찾는다.
missing: (locale, key): string => {
if(defaultMessages[locale] && defaultMessages[locale][key]) {
console.warn('[i18n]: Database에 메세지가 존재하지 않아, 기본 메세지 파일에서 조회합니다.', key, defaultMessages[locale][key]);
return defaultMessages[locale][key] ?? key;
}
console.warn('[i18n]: 기본 메세지 파일에 메세지가 존재하지 않습니다.', key);
return key;
}
});
vueApp.use(i18n);
});
다국어 적용
-
다국어 적용
AS-IS <span>권한상하관계등록</span> TO-BE <span>{{ $t('menu.data.menu00000036') }}</span>
-
언어(locale) 변경
오른쪽 위의 국가를 선택하면 아래의 함수가 실행되어, 언어를 변경 한다.
changeLanguage(event) {
// i18n locale 변경
this.$i18n.locale = event.value.languageCode;
},
PrimeVue 다국어 설정
어드민에서는 Primevue에서 제공하는 Component를 주로 사용한다.
Calendar와 같은 Component에도 다국어를 제공하기 위해 Primevue 전역으로 다국어를 적용하였다.
참고 : https://primevue.org/configuration/#locale
- 다국어 메세지 파일 생성
Primevue에서 다국어를 적용하기 위해 제공하는 key에 대한 message값은 언어별로 만들어 파일로 보관하였다. 영어, 한국어, 중국어 이외의 언어가 추가될 경우, 아래 경로에 파일을 추가해야 한다.
경로 : public/data/language/primevue/
- 다국어 적용
오른쪽 위의 국가를 선택하여 언어를 바꾸는 경우, 아래 코드가 실행되어 primevue의 언어 설정 값을 변경 하게 된다.
const primevue = usePrimeVue();
const changePrimevueLocale = locale => {
if(Object.keys(localeMessages).includes(locale)) {
primevue.config.locale = localeMessages[locale];
}
}