ChamomileGuides 3.0.4 Help

캐모마일 개발 표준 가이드

개요

목적

  • 본 문서는 캐모마일3.0 고도화 프로젝트 개발을 위한 표준을 제시하는데 목적이 있습니다.

범위

  • 본 문서는 목표 시스템 구축을 위한 신규 개발되는 시스템을 범위로 하며 솔루션 및 라이브러리는 대상에서 제외됩니다.

Name Rule 가이드

Naming 표기법

기본 Naming Rule

  • 이해가 가능한 Full English Description 방식을 사용합니다.

  • 독립어나 두 단어가 조합될 경우 두 번째 명사의 시작 문자는 대문자로 시작합니다.

  • 이미 잘 알려진 이니셜 단어는 대문자로 구성합니다.

  • 정의되는 이름의 길이는 최대 30자 이하로 사용합니다 ( e.g. 클래스, 인터페이스, 메서드, 변수, 상수, 파일 명)

  • 예약어를 사용하지 않는다.

  • 상수는 영문 대문자 스네이크 표기법을 사용한다. ex) CONTENT_MANAGEMENT

  • 변수, 함수에는 카멜 표기법을 사용한다.

  • URL, HTML 같은 범용적인 대문자 약어는 대문자 그대로 사용한다

Java Programming Naming Rule

Package

  • Package 명은 반드시 소문자만 사용합니다.

  • Package를 정의할 때는 레벨화하여 명명함을 기본으로 합니다.

  • 각 레벨에 올 수 있는 단어는 2~15자 내외의 영문 소문자를 사용합니다.

Package 레벨 구조

Level

예시

설명

1

api

Controller 클래스 Swagger 인터페이스

2

dto

requestVO 관리

3

domain

업무 별 VO(Value Object) 관리

4

service

Service 클래스들을 관리

5

config

어플리케이션의 설정 파일들을 관리

6

exception

Exception 공통 처리 및 업무 별 사용되는 공통 Exception 클래스 들을 관리

  • Class 이름은 간단하고 명시적으로 작성합니다.

  • Class 이름은 각 단어를 대문자로 표기하는 PascalCase로 작성합니다.

  • 단어 사이의 구분을 위한 밑줄("_")을 사용하지 않습니다.

  • Controller class: "서비스 명 + Controller.java"형태로 사용합니다. (e.g. RestController.java)

  • Exception class: "명사 + Exception.java" 형태로 사용합니다. (e.g. RuntimeException.java)

Method

  • 일반적으로 Method는 클래스의 여러 가지 행위를 나타내는 것이기 때문에 첫 단어는 동사로 시작합니다.

  • 동사만으로 의미 전달이 불명확한 경우에는 동사 + 명사 형태로 표기합니다.

  • CamelCase로 작성합니다.

Method 명칭

설명

getMethod

- 특정 상세 조회


- 특정 Entity / Field의 값을 설정

getTotalCount

목록 조회의 총 건수

setMethod

특정 Entity / Field의 값을 설정

selectMethod

목록 조회

insertMethod

데이터 등록 (Insert Transaction)

updateMethod

데이터 업데이트 (Update Transaction)

deleteMethod

데이터 삭제 (Delete Transaction)

isMethod

특정 속성 여부 검사

hasMethod

특정 속성 소유 검사

변수

  • 변수 이름을 정의할 때는 약어 사용은 자제하며, 되도록 변수명만 보고 의미를 알 수 있도록 단어 그대로 사용하는 것을 권장합니다.

  • CamelCase로 작성합니다.

  • 첫 글자는 밑줄(_ )이나 달러 문자로 ($) 시작하지 않습니다.

상수 Constant

  • 상수 선언은 반드시 " static final "을 사용합니다.

  • 상수는 전부 대문자 스네이크 표기법으로 표기합니다.

  • 단어와 단어 사이는 밑줄로 (_) 연결합니다.

  • 첫 글자는 밑줄(_ )이나 달러 문자로 ($) 시작하지 않습니다.

  • 누구나 이해할 수 있는 영문 이름을 사용합니다.

Mapping XML

Java의 대표적 ORM Framework 중의 하나인 Apache MyBatis Framework를 사용하는 경우 SQL Mapping 정보가 저장되는 각종 XML 내의 여러 항목들의 이름을 지정할 때 아래와 같은 규칙을 이용해 파일을 생성하도록 합니다.

  • Map XML 파일은 기본적으로 Mapper 인터페이스당 하나를 생성하도록 합니``다.

  • 파일명은 " Mapper" 접미사를 사용하여 인터페이스와 XML 파일을 동일하게 생성합니다. (예: MasterSampleMapper.java > MasterSampleMapper.xml)

  • 확장자는 "xml"만 사용합니다.

Mapping XML ID Naming Rule

  • Mapping XML은 SQLMap XML 파일 내에서 사용하는 <select>, <insert>, <update>, <delete>, <parameterMap>, <resultMap>, <typeAlias> 등의 XML Tag들을 뜻하며, "ID"는 이들 구문을 구분하기 위한 unique한 값을 뜻합니다.

  • 기본적으로 Mapping XML ID는 Java의 Method 명명 규칙을 이용하여 작성하도록 합니다.

  • **Mapping XML ID는 기본적으로 Class의 Method 명과 동일하게 사용합니다.

  • SQLMap XML 파일에서 namespace를 반드시 지정합니다.

  • Namespace는 SQL 문장의 ID 중복을 회피하기 위한 방편이며, Namespace는 패키지 이름을 사용합니다.

    • 예: Namespace는 XXXMapper 인터페이스의 풀 패키지를 사용합니다.

  • ID는 실제로 호출하는 Mapper 인터페이스의 메서드명과 동일하게 작성하는 것이 좋습니다.

    • 예: XXXMapper.javaYYY()을 이용해 데이터 처리를 해야 한다면, Mapping XML ID는 <select id="YYY"> 형태로 작성하는 것을 뜻합니다.

JAVA 코딩 가이드

  • Java 코딩 가이드는 프로그래밍 시 지켜야 할 형식적인 규칙을 정의하고, Coding Style을 표준화 하여 제공함으로써 향후 효율적인 프로그램 유지 보수와 가독성을 최대화 하고, 모든 개발자가 상호 간 Code를 읽고 이해하기 쉽게 함으로써 그에 따른 비용을 최소화 할 수 있다.

기본 Style

Line Length

  • 모든 줄은 120자 이내에서 완성 되어야 한다. 만약 더 필요할 경우, 연산자 앞에서 개행 한 후 다음 줄에서 이어서 작업 한다.

들여쓰기 (Indentation)

  • 소스 코드에 대한 가독성 향상을 위해 아래와 같은 들여쓰기를 사용한다.

    • 들여쓰기는 Tab 문자가 아닌 공백(Space) 문자를 사용한다.

    • 1 Indent = 4 Spaces ( 4 bytes )

변수 선언

  • 변수의 선언은 프로그램 시작 부분에 두는 것을 기본으로 하며, 1라인에 1개의 변수 만을 선언 한다.

Block의 구성

  • 각 블록 문장의 중괄호 열기“{“ 는 블록이 들어가는 라인의 가장 마지막 문자 위치에,

  • 중괄호 닫기 부호 “}“는 별도의 라인의 첫 번째 문자와 위치를 맞춘다.

  • 소스 코드는 레벨이 낮아 질 때마다 한 단계 들어가는 계단형 코딩을 한다.

public class GrpcSampleAdapter implements GetGrpcSamplePort, PostGrpcSamplePort { private SampleGrpc.SampleBlockingStub sampleStub; @Override public List<Sample> selectGrpcSample() { List<Sample> grpcSampleList = new ArrayList<>(); Iterator<SampleResponse> response = this.sampleStub.selectGrpcSample(null); response.forEachRemaining(sampleResponse -> { SampleFieldEntry fieldEntry = sampleResponse.getResult(); Sample sample = Sample.builder() .seq(fieldEntry.getSeq()) .title(fieldEntry.getTitle()) .contents(fieldEntry.getContents()) .txt(fieldEntry.getTxt()) .build(); grpcSampleList.add(sample); }); return grpcSampleList; } }

주석 (Comment)

구현 주석

  • 구현 주석은 각각의 구현에 대한 추가적인 설명이 필요할 때, 또는 코드를 주석 처리할 때 사용할 수 있습니다.

Block 주석

  • Block 주석은 파일, 메서드, 자료 구조, 알고리즘에 대한 설명을 제공하는 데 사용됩니다.

  • Block 주석은 클래스 파일의 맨 처음, 각 메서드 앞단에 사용해야 합니다.

  • 메서드 안에서 사용할 경우, 설명하고자 하는 코드와 같은 간격으로 Indentation을 줍니다.

  • Block 주석을 사용할 때는 다른 코드와의 구별을 위해 시작하기 전에 공백 행을 하나 띄어줍니다.

/** * &lt;pre> * 테스트 관련 컨트롤러. * &lt;/pre> * * @author GildongHong * @since 2023-09-26 * @version 3.0 * @Modification * &lt;pre> * since author description * =========== ============= =========================== * 2023-09-26 GildongHong 최초 생성 * * &lt;/pre> * Copyright (C) 2023 by LDCC., All right reserved. */ public class Test() { public void test() { } }

짧은 주석(Single-Line )

  • 짧은 주석은 소스 코드와 같은 수준으로 들여쓰기를 한 상태에서 한 줄로 표현될 수 있습니다.

  • 주석을 한 줄로 쓸 수 없을 경우, Block 주석 포맷을 사용합니다.

if (condition) { /* Single-Line 주석을 작성합니다. */ ... }

Trailing 주석

  • 아주 짧은 주석이 필요한 경우 주석이 설명하는 코드와 같은 라인에 작성합니다.

  • 실제 코드와는 구분 가능하도록 충분히 간격을 두어야 합니다.

javaCopy code if (a == 2) { return TRUE; /* a 가 2 인 경우 */ } else { return a; /* a 가 2가 아닌 경우 */ }

End-Of-Line 주석

  • 주석 기호 // 는 한 줄 모두를 주석 처리하거나 한 줄의 일부분을 주석 처리해야 할 경우 사용할 수 있습니다.

  • 어떤 코드의 일부분을 주석 처리하기 위해서 여러 줄에 연속해서 사용하는 것은 허락되나, 긴 내용을 주석에 포함하기 위해서 연속되는 여러 줄에 이 주석을 사용하는 것은 허락되지 않습니다.

javaCopy code if (foo > 1) { // 처리를 실행합니다. ... } else { return false; // false를 반환합니다. }

문서화 주석

  • 문서화 주석은 Java 소프트웨어에 포함되어 있는 javadoc 툴을 사용하여 문서화 주석을 포함하는 HTML 파일을 자동으로 생성할 수 있습니다. 또한, 소스 코드가 없는 개발자들도 읽고 이해할 수 있도록, 실제 구현된 코드와는 상관이 없는 코드의 명세 사항(specification)을 포함합니다. 문서화 주석은 클래스, 인터페이스, 생성자, 메서드, 필드를 설명하고 작성할 수 있습니다.

  • ※ 만일, 클래스, 인터페이스, 변수 또는 메서드에 대한 어떤 정보를 제공하고 싶지만 문서화 주석에 어울리지 않는다고 생각되면 클래스 선언 바로 후에 Block 주석 또는 Single-Line 주석을 사용합니다. (예: 클래스 구현에 대한 세부 사항들은 클래스에 대한 문서화 주석이 아닌 클래스 선언문 다음에 Block 주석을 사용합니다.)

  • Java는 문서화 주석을 주석 이후에 처음 나오는 선언문과 연결시키기 때문에 메서드 또는 생성자 구현 안에 위치해서는 안됩니다.

기타

  • 코드 내부에 특별한 사항을 기술할 경우 행 단위 주석(//)을 사용하지만, 가급적 사용을 줄입니다.

  • 특별한 로직을 구현했거나 실수하기 쉬운 부분에 대한 강조를 하고자 할 경우가 아니라면, 가급적 코드 block 내에서의 주석 사용은 자제합니다.

  • 주석이 너무 자주 나오면 오히려 코드의 질이 떨어지게 됩니다. 따라서, 코딩 시에 주석이 필요하다고 느껴지는 부분은 그 부분의 프로그램 코드를 더욱 깔끔하게 만들 방안이 없는지 재검토하는 것이 좋습니다.

문 (Statements)

"if" Statements

  • 모든 if 문에는 항상 중괄호를 사용합니다. 이렇게 함으로써 코드를 일관성 있고 확장에 쉽게 대응할 수 있기 때문입니다.

javaCopy code // RIGHT if (value == 0) { doSomething(); } else { doAnother(); } // WRONG if (value == 0) doSomething(); // WRONG if (value == 0) doSomething();

"for" Statements

for 문은 다음과 같이 작성합니다. for문의 초기 값 또는 증감 값 부분에서 콤마 연산자(comma operator)를 사용해야 할 경우, 세 개 이상의 변수를 사용하는 복잡성은 피합니다.

javaCopy code for (초기 값; 종료 조건; 증감 값) { statements; } // 향상된 for문 for (변수타입 변수이름 : 배열이름) { statements; }

"while" Statements

  • while 문은 다음과 같이 작성합니다.

javaCopy code while (조건문) { statements; } // 빈 while문은 다음과 같이 작성합니다. while (조건문);

"do-while" Statements

  • do-while 문은 다음과 같이 작성합니다.

javaCopy code do { statements; } while (조건문);

"switch" Statements**

  • switch 문은 다음과 같이 작성합니다. 모든 switch 문은 반드시 default case를 포함해야 합니다. default case 내의 break는 중복되지만, 추후 다른 case가 추가되는 경우 에러를 방지할 수 있습니다.

javaCopy code switch (조건문) { case A: statements; /* 계속 수행 (다음 라인) */ case B: statements; break; case C: statements; break; default: statements; break; }

"try-catch" Statements**

  • try-catch 문은 다음과 같이 작성합니다. try-catch 문은 try 블록 수행의 성공/실패 여부와 상관 없이 수행되는 finally를 사용할 수 있습니다.

javaCopy code try { statements; } catch (ExceptionClass e) { statements; } finally { statements; }

"return" Statements

  • 복잡한 표현식이나 리턴 값을 더 명확하게 표현하기 위한 것이 아니라면, 리턴 값이 있는 return 문에는 괄호를 사용하지 않습니다.

javaCopy code // WRONG return(true); // RIGHT return true; // RIGHT return (s.length() + s.offset);

단순문 (Simple Statements)

  • 각 줄에는 최대 하나의 문(Statements)만 사용하도록 합니다.

javaCopy code // WRONG a = b + c; count++; // RIGHT a = b + c; // RIGHT count++;

복합문 (Compound Statements)

  • 복합문은 중괄호 ""에 포함된 여러 개의 statement를 포함한 문장입니다.

  • {} 안에 있는 문장은 복합문 보다 한 번 더 들여쓰기를 해야 합니다.

  • 여는 중괄호 "{" 는 복합문을 시작하는 줄의 마지막에 위치해야 합니다.

  • 닫는 중괄호 "}" 는 새로운 줄에 써야 하고, 복합문의 시작과 끝은 동일한 들여쓰기를 해야 합니다.

javaCopy code // if-else 또는 for와 같이 어떤 statement든 제어 구조의 일부분이라면 중괄호로 모든 statement를 감싸야 합니다. if (condition) { // statements... } else { // statements... }

공백 (White Space)

빈 줄 (Blank Line)

  • 빈 줄은 논리적으로 연관된 코드를 묶음으로써 코드의 가독성을 향상시킵니다.

  • 메서드 사이

  • 메서드에서 로컬 변수와 그 메서드의 첫 번째 문장 사이

  • 시작 주석문과 package문, 그리고 package문과 import문 사이

빈 칸 (Blank Space)

  • 빈 칸은 다음과 같은 경우에 사용합니다.

    • 키워드 다음의 괄호는 space에 의해 분리됩니다. (e.g. while (true))

    • 메서드 이름과 괄호 사이에는 빈칸을 두지 않습니다. 이것은 키워드와 메서드 호출을 쉽게 구분할 수 있게 해 줍니다.

    • 매개변수 리스트에서 콤마 다음에 빈칸을 둡니다.

    • 콤마(,)를 제외한 모든 이항 연산은 연산자로부터 한 칸 띄워야 합니다. 단항 연산자인 증가 연산자(++ )와 감소 연산자(- )의 경우 피 연산자와 분리해서는 안됩니다.

javaCopy code a += c + d; a = (a + b) / (c + d); while (d++ == s++) { n++; } printSize("size is " + foo + "\n");
  • 한 문장 안에서 표현은 빈칸으로 구별됩니다.

javaCopy code for (expr1; expr2; expr3)
  • 변수 타입을 변환하는 cast의 경우, cast 후 빈 칸을 둡니다.

javaCopy code myMethod((byte) aNum, (Object) x); myMethod((int) (cp + 5), ((int) (i + 3)) + 1);

선언 (Declarations)

변수 선언

  • 각 변수는 주석 처리를 위해 각 라인별로 선언되어야 합니다. 변수명은 세로로 들여쓰기를 맞추어 쉽게 읽을 수 있도록 하며, 타입에 따른 특별한 선언 순서는 없습니다. 특별한 경우(연산처리와 연관되어 초기화 되는 경우)를 제외하고 로컬 변수는 선언한 곳에서 초기화를 합니다.

javaCopy code int level; // RIGHT int level, size; // WRONG int level, tags[]; // WRONG :: 다른 타입의 변수를 같은 라인에 선언하면 안됩니다.
  • ※ 타입과 변수 사이에는 1칸의 공백을 이용합니다. 그러나 탭을 사용하는 것도 허용됩니다.

javaCopy code int level; int size; Object currentEntry;

package 및 import

  • package 문은 소스의 가장 상단에 작성하고, 그 하단에 import문을 표시합니다.

  • package 문과 import 문 사이에 한 줄을 띄어줍니다.

  • package 명은 소문자로 정의합니다.

javaCopy code package chmm.application.adapter.in.controller; import java.util.ArrayList; import java.util.List;

클래스/인터페이스 선언

  • 클래스와 인터페이스 선언 시 다음과 같은 원칙을 따릅니다.

    • 메서드 이름과 그 메서드의 파라미터 리스트의 시작인 괄호 ( 사이에는 빈 공간이 없어야 합니다.

    • 여는 중괄호 {는 클래스/인터페이스/메서드 선언과 동일한 줄의 끝에 작성합니다.

    • 닫는 중괄호 }는 여는 중괄호 { 후에 바로 나와야 하는 null 문인 경우를 제외하고는 동일한 들여쓰기를 하는 새로운 줄에서 사용합니다.

javaCopy code class Sample extends Object { int var1; int var2; Sample(int i, intj) { var1 = i; var2 = j; } }

SQL 작성 가이드

Comment

  • 주석(comment)은 개발자가 작성한 Query의 이해를 돕는 설명이나 디버깅을 위해 작성합니다.

Query Description

  • Query XML의 주석은 <!-- 로 시작하여 --> 로 끝납니다. Query에 대한 주석은 다음과 같은 정보를 포함합니다:

    • 설명: 쿼리가 처리하는 업무를 다른 개발자들이 이해할 수 있는 수준으로 간단 명료하게 작성합니다.

    • 작성일자: 쿼리를 작성한 일자를 기록합니다. (yyyy.mm.dd)

    • 작성자: 해당 쿼리를 작성한 사람의 chmm.com 이메일 계정을 입력합니다.

<!-- 설명 : 샘플의 목록을 조회하는 쿼리입니다. 작성일자 : 2021.07.21 작성자 : xxxx@chmm.com --> <select id="selectSample" resultType="SampleEntity"> ... ... ... </select>

Query Inline Comment

  • XML Query 내의 주석은 /* 로 시작하여 */ 로 끝납니다. Query 내의 주석은 다른 개발자들이 해당 쿼리를 이해할 수 있도록 comment를 남기기 위해 사용합니다. 실행 쿼리 아이디를 주석으로 남깁니다. 아이디는 확장자를 제외한 xml 파일명 + '.' + Query id를 사용합니다.

<select id="selectSample" resultType="SampleEntity"> SELECT /* SampleMapper.selectSample */ seq , title FROM master_sample </select>
  • 컬럼이나 쿼리 내에 주석을 사용할 필요가 있는 경우:

<select id="selectSample" resultType="SampleEntity"> SELECT /* SampleMapper.selectSample */ seq /* MASTER_SAMPLE PK */ , title /* 샘플의 제목 */ FROM master_sample </select>

공백(White Space)

  • 공백은 작성된 쿼리의 depth를 구분하고 개발자 별 IDE의 Formatter로부터 코드를 일관성 있게 유지하여 가독성을 높이는데 사용합니다. 공백은 Tab(space 4칸)과 Space(space 1칸)으로 구분합니다.

  • 들여쓰기 전 IDE의 tab을 space 4개로 변경하도록 설정합니다. STS의 tab의 space로 변경 설정을 참고합니다.

CDATA

  • Query 구문에 XML 파싱 시 구문으로 인식할 수 있는 **특수 기호를 사용할 경우 오류가 발생할 수 있습니다. 특수기호를 문자열로 인식할 수 있도록 CDATA(Character Data )를 사용하여 처리합니다. 문자열 처리 구문은 <![CDATA[ ... ]]>를 사용하며 아래와 같이 처리합니다.

<select id="selectSample" resultType="SampleEntity"> SELECT * FROM master_sample WHERE seq <![CDATA[>]]> 1 </select>

Query 작성 패턴

  • 쿼리 작성 시 개발자 별로 다른 패턴을 통일하기 위해 쿼리의 작성 패턴을 가이드합니다.

    1. 키워드, 예약어는 대문자로 작성합니다.

    2. 컬럼명과 테이블 명은 소문자로 작성합니다.

    3. 쿼리의 첫 줄은 xml 파일명과 쿼리 아이디를 주석으로 포함시킵니다.

    4. 쿼리의 예약어의 끝나는 지점의 라인을 맞춰 컬럼, 테이블 명과 영역이 구분될 수 있도록 작성합니다.

    5. 한 라인에 하나의 컬럼만 작성합니다. 라인을 구분하는 콤마(,)는 라인이 시작하는 시점에 사용합니다.

    6. 쿼리의 파라미터 매핑 시 jdbcType은 사용하지 않습니다.

<select id="selectCodeMaster" parameterType="String" resultType="chmm.application.domain.code.CodeMaster"> SELECT /* CommonCodeReaderMapper.selectCodeMaster */ code_id , code_name , code_dscr , code_lngt , code_patr_code , hgrn_code_id , sys_name , tabl_owner_name , tabl_name , crtr_id , cret_dttm , amnr_id , amnd_dttm , dlt_ysno FROM eom.t_md_cmm_code_m WHERE code_id = #{codeId} </select>
  • line 2: 1번, 3번 예약어 대문자 사용 및 첫 번째 줄의 쿼리 아이디 주석 사용

  • line 3 ~ 16: 2번, 5번 컬럼명의 소문자 사용 및 한 줄에 하나의 컬럼 조회, 라인을 구분하는 콤마를 라인 시작 지점에 사용

  • line 2, 17, 18: 1번 예약어의 대문자 사용 및 4번 예약어의 끝나는 라인을 맞춰 영역에 대한 구분

  • line 18: 6번 쿼리 파라미터 매핑 시 jdbcType은 사용하지 않음 #{codeId} (O), #{codeId, jdbcType=VARCHAR} (X)

Exception

  • 프로그램 개발시 예외 처리에 대한 통일성을 유지하고 서비스 호출한 부분에 상황에 따른 적절한 예외 처리를 위해 공통으로 적용한다.

예외 핸들러 (Exception Handler)

    1. @ExceptionHandler 사용하여 유형별로 예외처리에 대응할 수 있습니다.

    1. ControllerExceptionHandler: @RestController에서 예외가 발생할 때 공통으로 예외를 처리하는 클래스입니다.

    1. @RestControllerAdvice 어노테이션을 사용하여 @RestController에서 발생하는 예외를 처리합니다.

    1. @ExceptionHandler 어노테이션을 통해 예외 유형별로 컨트롤할 수 있습니다.

예외 발생 처리 (throw Exception)

  • 예외가 발생하면 API를 호출한 서비스에게 오류가 발생한 상황을 알려주도록 합니다. 개발자가 발생 상황을 명확히 인지하고 개별적으로 처리하는 경우가 아니라면, 호출된 상위 서비스로 예외를 throw하도록 작성합니다.

    • DAO단에서 Exception 처리

      • DAO 단에서는 스프링에서 제공하는 SqlMapClientDaoSupport를 상속받아 사용하면 SQLException 대신 스프링이 제공하는 예외 클래스(Runtime Exception인 DataAccessException)로 변환해 주기 때문에 별도의 SQL관련 Exception 로직을 사용하지 않는다.

    • Service단에서 Exception 처리

      • Service단에서 DAO에서 발생한 Exception을 별도의 Exception 처리를 하지 않는다.

      • Controller단으로 throw하여 Exception 처리

    • Controller 단에서 입셉션을 처리할 수 있으며, 클라이언트 응답을 보내기 위해서는 처리 후 다시 ChamomileException으로 감싸서 throw를 해야 한다. 이렇게 throw된 ChamomileException은 @RestControllerAdvice에서 처리된다.

    • ChamomileExceptionCode 의 경우 별도의 enum 파일로 관리 된다.

throw new ChamomileException(ChamomileExceptionCode.MissingParameter);
  • 공통 코드(CommonCodeException)를 활용한 예외처리

    • chamomile.chmm_category_info(대분류), chamomile.chmm_code_info(중분류), chamomile.chmm_code_item_info(소분류) 에 공통 코드를 등록한다.

    • 등록된 공통코드는 대분류ID.중분류ID.소분류ID 의 형태로 String 값을 기준으로 key를 가진다.

    • CommonCodeException 인자로 key를 조회하여 예외를 처리한다.

    • 공통코드를 찾지 못한 경우, ChamomileExceptionCode.COMMON_CODE_NOT_FOUND가 발생한다.

throw new CommonCodeException("category00053.code00001.item00001");

공통 Exception Handler의 사용

  • @RestControllerAdvice를 사용하면 Spring에서 예외가 발생할 때 자동으로 관리합니다.

  • Exception Handler에서 io.ServerInterceptor를 구현한 Interceptor의 클래스를 등록하면, 해당Service에서 예외 발생 시 공통으로 처리가 가능합니다.

로깅 (Logging Guide)

  • 프로젝트에서 개발되는 여러 애플리케이션에서 디버깅을 위해 로그를 출력하거나 예외/오류 상황이 발생할 경우, 오류 정보를 출력하여 개발 및 운영 시 문제 상황에 대한 판단과 빠른 조치를 할 수 있도록 로그를 출력하는 방법과 출력된 로그를 관리하는 방법에 대해 가이드합니다.

로깅 (Logging)

  • Spring Boot는 모든 내부 로깅에 Commons Logging을 사용하지만 기본 로그 구현은 오픈되어 있습니다. Java Util Logging, Log4J2Logback에 대한 기본 구성이 제공됩니다. 각각의 경우에 logger는 선택적 파일 출력도 사용 가능한 콘솔 출력을 사용하도록 사전 구성되어 있습니다.

    • Log는 반드시 Framework에서 제공한 Logger만을 사용한다.

    • Log는 debug, info, warn, error로 구별하여 사용한다.

    • Log는 반드시 발생 시간과 위치 그리고 내용을 포함한다.

    • Log는 한 줄만 출력한다(debug log 제외).

    • debug log는 개발자가 개발 시에만 사용하고, 운영 중에는 사용하지 않는다.

    • info log는 운영자에게 도움이 될 내용을 기록한다.

    • warn log는 error는 아니나 잠재적인 error의 발생이 가능한 내용을 기록한다.

    • error log는 error code와 함께 error에 대한 내용을 기록한다.

    • Unchecked Exception이 발생할 경우에는 Stack Trace내용을 로그에 남기도록 한다.

제한 사항 (Restriction)

  • System.out.println()은 사용하지 않습니다. 디버그 메시지를 출력하기 위해 종종 System.out.println()을 사용하는 경우, 이러한 방식은 동기화 처리로 인해 성능 문제와 로그 관리 문제를 야기할 수 있습니다.

로그 레벨 (Log Level)

  • 로그 레벨은 TRACE, DEBUG, INFO, WARN, ERROR로 구분되며, 각각 상세한 정보부터 에러까지를 표현합니다.

Log Level

설명

TRACE

추적 레벨은 Debug보다 훨씬 상세한 정보를 나타낸다.

DEBUG

개발자가 작성한 프로그램을 디버깅 하기 위한 상세 정보를 표시 한다.

INFO

프로그램의 상태 정보 (처리 시작, 처리 완료 등...)와 같은 정보성 로그를 표시 한다.

WARN

처리 가능한 문제, 향후 시스템 에러의 원인이 될 수 있는 경고성 메시지를 표시 한다.

ERROR

요청을 처리하는 중 발생한 오류를 표시 한다. (※ Logback에는 FATAL 레벨이 없고, ERROR에 매핑 된다.)

로그 우선 순위 (Log Priority)

로그는 레벨에 따라 TRACE < DEBUG < INFO < WARN < ERROR의 우선 순위로 기록되며, 출력 레벨의 설정에 따라 설정 레벨 이상의 로그를 출력합니다.

로그 출력 예시 (Log 출력 Sample)

import lombok.extern.slf4j.Slf4j; @Slf4j public class RestSampleController { @PostMapping(path = "/create-test") public ChamomileResponse<Void> createTest (@Validated @RequestBody TestVO request) throws Exception { log.debug("test"); return new ChamomileResponse<>(); } }

SpringBoot

Profile

  • 기본 프로파일은 local, dev, prd로 3개를 관리합니다.

  • 개발 툴에서 프로파일 설정은 실행 인자로 Dspring.profiles.active=local 형태로 지정합니다.

Config

  • 기본 설정데이터는 application.yml파일에 작성하되, 패스워드증 민감한 데이터의 경우 jasypt 암호화 하여 관리합니다.

프로젝트 구성

  • 단위 프로젝트는 항상 chmm-core 라이브러리가 추가 되어 있습니다.

<dependency> <groupId>net.lotte.chamomile</groupId> <artifactId>chamomile-core</artifactId> </dependency> <dependency> <groupId>net.lotte.chamomile.boot</groupId> <artifactId>chamomile-boot-starter</artifactId> </dependency> <dependency> <groupId>net.lotte.chamomile.module</groupId> <artifactId>chamomile-security-jwt</artifactId> </dependency> <dependency> <groupId>net.lotte.chamomile.module</groupId> <artifactId>chamomile-database</artifactId> </dependency> <dependency> <groupId>net.lotte.chamomile.module</groupId> <artifactId>chamomile-database-audit</artifactId> </dependency> <dependency> <groupId>net.lotte.chamomile.module</groupId> <artifactId>chamomile-web</artifactId> </dependency>

프레임워크 주요 모듈

카테고리

설명

Core

예외, 로깅, 라이센스 등 프레임워크에 사용되는 핵심 모듈

Test

H2 DB를 사용하여 개발과 분리된 테스트 환경 제공

Commoncode

공통코드 관련 기능 제공

Database

Batch, 파일업로드 처리 등 DB 관련 기능 제공

Database-audit

DB 작업에 대한 데이터를 모니터링하고 수집하는 기능 제공

File

파일 업로드/다운로드 등 파일 관련 기능 제공

File-drm

DRM 파일 관련 기능 제공

File-excel

엑셀 업로드/다운로드/생성 관련 기능 제공

ftp

FTP/SFTP 등의 기능 제공

I18n

다국어 처리 관련 모듈

Mask

마스킹 처리 관련 모듈

Menu

트리 구조의 메뉴 데이터를 리스트 형태로 가져오는 기능 제공

Notification

SMTP 서버 기반 메일 발송 기능 제공

User

DB 사용자 관리를 위한 CRUD 기능 제공

Util

String, XML, UUID 등의 변환기능을 제공

Web

웹 어플리케이션과 관련하여 기본적인 필터, 에러 처리, 핸들러 등의 기능 제공

Security

Spring Security 기반의 기본 설정, 세션 및 쿠키 기반의 인증 처리 기능 제공

Security-jwt

JWT 기반 인증 처리 제공, 인증 구성 커스터마이징 개선

cache

hazelcast cache 기능 제공

cache-redis

redis cache 기능 제공

Adapter-nexcacro

Nexacro 등의 상용 UI 솔루션과 연동할 수 있는 기능 제공

Adapter-nexcaro14

Nexacro 등의 상용 UI 솔루션과 연동할 수 있는 기능 제공

Adapter-nexcaro17

Nexacro 등의 상용 UI 솔루션과 연동할 수 있는 기능 제공

Controller 작성 방법

** * &lt;pre> * 권한 관련 컨트롤러. * &lt;/pre> * * @author teahoPark * @since 2023-09-26 * @version 3.0 * @Modification * &lt;pre> * since author description * =========== ============= =========================== * 2023-09-26 TaehoPark 최초 생성 * * &lt;/pre> * Copyright (C) 2023 by LDCC., All right reserved. */ @Slf4j @RestController @RequestMapping(path = "/chmm/auth") @RequiredArgsConstructor public class AuthController implements AuthControllerDoc { private final AuthService authService; private final FileUploader fileUpload; @GetMapping(path = "/list") public ChamomileResponse<Page<AuthVO>> getAuthList(AuthQuery authQuery, Pageable pageable) { Page<AuthVO> results = authService.getAuthList(authQuery, pageable); return new ChamomileResponse<>(results); } }

Service 클래스 작성 방법

/** * &lt;pre> * 권한 관련 서비스 인터페이스 구현체. * &lt;/pre> * * @author TaehoPark * @since 2023-09-20 * @version 3.0 * @Modification * &lt;pre> * since author description * =========== ============= =========================== * 2023-09-20 TaehoPark 최초 생성 * * &lt;/pre> * Copyright (C) 2023 by LDCC., All right reserved. */ @Slf4j @Service @Transactional @RequiredArgsConstructor public class AuthServiceImpl implements AuthService { private final AuthMapper authMapper; @Override public Page<AuthVO> getAuthList(AuthQuery authQuery, Pageable pageable) { return authMapper.findAuthListData(authQuery, pageable); } }

Mapper 작성 방법

/** * &lt;pre> * 권한 관련 마이바티스 매핑 인터페이스. * &lt;/pre> * * @author TaehoPark * @since 2023-09-26 * @version 3.0 * @Modification * &lt;pre> * since author description * =========== ============= =========================== * 2023-09-26 TaehoPark 최초 생성 * * &lt;/pre> * Copyright (C) 2023 by LDCC., All right reserved. */ @Mapper public interface AuthMapper { Page<AuthVO> findAuthListData(AuthQuery query, Pageable pageable); List<AuthVO> findAuthListData(AuthQuery query); }
  • 위 내용은 프로젝트 구성과 관련된 Spring Boot 개발 프레임워크 사용 가이드입니다. 필요에 따라 추가적인 내용이나 세부 사항을 더 확인하시려면 해당 프로젝트에서 사용하는 라이브러리의 문서와 가이드를 참고하시면 도움이 될 것입니다

표기법 명칭

설명

예제

Pascal Case

(파스칼 표기법)

첫 문자를 대문자로 시작하며, 의미 구분을 위해 대문자를 사용

ContentManagement

Camel Case

(카멜 표기법)

첫 문자를 소문자로 시작하며, 의미 구분을 위해 대문자를 사용

contentManagement

Hungarian Case

(헝가리안 표기법)

사전에 정의된 접두어를 사용

strContentManagement

Lower Case

(소문자 표기법)

전체를 소문자로 사용

contentmanagement

Upper Case

(대문자 표기법)

전체를 대문자로 사용

CONTENTMANAGEMENT

Underscored Case

(언더스코어 표기법)

의미 구분을 위해 언더스코어를 사용

content_management

Hyphen Case

(하이픈 표기법)

의미 구분을 위해 하이픈을 사용

conent-management

RestAPI

  • API란 Application Programming Interface의 약자로 프로그램을 실행하는 인터페이스입니다. API를 통해 프로그램에 요청을 전달하기 위한 통로 혹은 방법으로 생각할 수 있습니다. 라이브러리를 설치하고 호출하는 함수도 API라고 합니다.

RESTful API의 탄생

  • REST는 Representational State Transfer의 약어로서 2000년도에 로이 필딩 (Roy Fielding)의 박사학위 논문에서 최초로 소개되었습니다. 로이 필딩은 HTTP의 주요 저자 중 한 사람으로 그 당시 웹(HTTP) 설계의 우수성에 비해 제대로 사용되어지지 못하는 모습에 안타까워하며 웹의 장점을 최대한 활용할 수 있는 아키텍처로써 REST를 발표했습니다. REST API는 HTTP Method별로 역할을 명시하는 것이 특징입니다.

RESTful API에서 HTTP Method

  • GET: 조회 (받겠다)

  • POST: 리소스 생성 (보내겠다)

  • PUT: 리소스 전체 갱신(놓겠다/넣겠다)

  • DELETE: 리소스 삭제 (지정한 서버의 파일을 삭제하겠다)

  • 캐모마일 에서는 GET, POST만 사용한다.

REST API 디자인 가이드

  • URI는 정보의 자원을 표현해야 한다.

  • 자원에 대한 행위는 HTTP Method(GET, POST)로 표현한다.

  • 캐모마일에서는 GET, POST 사용

URL Rules

Content-Type

  • application/json

Use HTTP status

  • 응답 상태 코드만으로도 많은 정보를 전달할 수 있기 때문에 응답의 상태코드 값을 명확히 돌려주는 것은 중요합니다.

의미에 맞는 HTTP status를 리턴

  • Bad:status는 200으로 성공인데 body 내용엔 실패에 관한 내용을 리턴하고 있다. 모든 응답을 200으로 처리하고 body 내용으로 성공|실패를 판단하는 구조에서 사용된다. 잘못된 설계다.

HTTP/1.1 200 OK { "result" : false "status" : 400 }
  • Good:

HTTP/1.1 400 Bad Request { "code" : 400, "message" : "check your parameter" "data" : "test" }

HTTP status만으로 상태 에러

  • 세부 에러 사항은 응답 객체에 표시하거나, 해당 에러를 확인할 수 있는 link를 표시한다. HTTP 상태 코드를 응답 객체에 중복으로 표시할 필요 없습니다.

  • Bad:

    cssCopy code HTTP/1.1 404 Not Found { "code" : 404, "error_code": -765 }
  • Good:

    cssCopy code HTTP/1.1 404 Not Found { "code" : -765, "message" : "https://api.test.com/errors/-765" "data" : "https://api.test.com/errors/-765" }

Resource Path

  • API Service 의 REST 한 URI 이름을 짓기 위해서는 몇가지 원칙이 있다.

  • URI 생성 원칙

    1. 문서가 없이도 API 의 기능을 직관적으로 알 수 있는 이름을 사용한다.

    2. 좋은 이름은 좋은 개발을 할 수 있도록 도와준다.

    3. 이름 생성이 어렵다면 좋지 않은 설계의 징후로 볼 수 있다.

    4. API를 사용하는 사람 관점에서 생각한다.

    5. 전체 API 에 걸쳐서 일관성 있게 생성한다.

    • 좋은 URI 의 조건

      1. 발음하기, 검색하기 쉬운 이름

      2. 문제 지향성 (Problem Orientation)

      3. ‘어떻게’ 보다 ‘무엇’을 표현

      4. 역할과 의도 제시

      5. 의도 제시 형 이름

      6. 세부 구현에 의존적이지 않게

  • Resource path 생성 규칙은 아래 표 에서 확인 할 수 있다.

Controller Method Naming Convention

Mapping Result

List

getBooks()

HTTP GET /books

Book getBook(bookId)

HTTP GET /books/

void insertBook(Book book)

HTTP POST /books

void updateBook(bookId, Book book)

HTTP PUT /books/

void deleteBook(bookId)

HTTP DELETE /books/

  • Resource path 생성 규칙에 의한 Controller Class 생성 예시

/** * &lt;pre> * 권한 관련 컨트롤러. * &lt;/pre> * * @author test * @since 2023-09-26 * @version 3.0 * @Modification * &lt;pre> * since author description * =========== ============= =========================== * 2023-09-26 test 최초 생성 * * &lt;/pre> * Copyright (C) 2023 by LDCC., All right reserved. */ @Slf4j @RestController @RequestMapping(path = "/chmm/auth") @RequiredArgsConstructor public class AuthController implements AuthControllerDoc { private final AuthService authService; private final FileUploader fileUpload; @GetMapping(path = "/list") public ChamomileResponse<Page<AuthVO>> getAuthList(AuthQuery authQuery, Pageable pageable) { Page<AuthVO> results = authService.getAuthList(authQuery, pageable); return new ChamomileResponse<>(results); } @PostMapping(path = "/create") public ChamomileResponse<Void> createAuth(@Validated @RequestBody AuthVO request) throws Exception { authService.createAuth(request); return new ChamomileResponse<>(); } @PostMapping(path = "/update") public ChamomileResponse<Void> updateAuth(@Validated @RequestBody AuthVO request) throws Exception { authService.updateAuth(request); return new ChamomileResponse<>(); } @PostMapping(path = "/delete") public ChamomileResponse<Void> deleteAuth(@RequestBody List<AuthVO> authVOList) throws Exception { authService.deleteAuth(authVOList); return new ChamomileResponse<>(); } }
  • 아래는 Resource 표현 방법에 대한 예시 이다.

HTTP Method

Scope

Usage Description

URI Example

Request Message

Response Message

GET

Item

GET resource: 특정 상품의 상세 정보를 가져 옵니다. 잘못된 예) /books?bookId=112 (Path variable을 Query String으로 표현하지 않습니다.)

/books/

URI

JSON

GET

List

GET resources: 전체 상품 목록을 가져 옵니다.

/books

URI

JSON

POST

Item

POST resource: 신규 상품를 등록 합니다.

/books

JSON

HTTP Status

POST

List

POST resources: 신규 상품를 multiple로 등록 합니다.

/books

JSON

HTTP Status

PUT

Item

PUT resource: 특정 상품의 정보를 갱신 합니다. 잘못된 예) /books?bookId=112 (Path variable을 Query String으로 표현하지 않습니다.)

/books/

JSON

HTTP Status

PUT

List

PUT resources: 도서 상품를 multiple로 갱신 합니다.

/books

JSON

HTTP Status

DELETE

Item

DELETE resource: 특정 상품 정보를 삭제 합니다.

/books/

URI

HTTP Status

DELETE

List

DELETE resources: 도서 상품를 multiple로 삭제 합니다.

/books

JSON

HTTP Status

HTTP Encoding

  • Http Encoding 는 5 가지의 Content Type을 지원한다.

    • application/xml

      • POST, PUT 요청 시 XML형식의 데이터를 포함할 수 있다.

    • application/json

      • POST 요청 시 JSON형식의 데이터를 포함할 수 있다.

    • application/javascript

      • javascript를 포함하는 데이터를 전송하기 위하여 application/javascript Content Type을 사용 할 수 있다.

    • application/x-www-form-urlencoded

      • API를 호출하여 Parameter를 전달하는 경우 Parameter는 HTML폼의 기본 인코딩 방식인 application/x-www-form-urlencoded 형태로 인코딩 할 수 있다.

      • 요청하는 Parameter 수가 적을 경우에만 사용해야 한다.

    • multipart/form-data

      • 이미지를 포함한 데이터를 전송하기 위해 Content Type을 multipart/form-data로 설정하여 사용 할 수 있다.

HTTP 응답 상태 코드

  • 마지막으로 응답 상태코드를 간단히 살펴보도록 하겠습니다. 잘 설계된 REST API는 URI만 잘 설계된 것이 아닌 그 리소스에 대한 응답을 잘 내어주는 것까지 포함되어야 합니다. 정확한 응답의 상태코드만으로도 많은 정보를 전달할 수가 있기 때문에 응답의 상태코드 값을 명확히 돌려주는 것은 생각보다 중요한 일이 될 수도 있습니다. 혹시 200이나 4XX관련 특정 코드 정도만 사용하고 있다면 처리 상태에 대한 좀 더 명확한 상태코드 값을 사용할 수 있기를 권장하는 바입니다.

  • 상태코드에 대해서는 몇 가지만 정리하도록 하겠습니다.

상태코드

200

클라이언트의 요청을 정상적으로 수행함

201

클라이언트가 어떠한 리소스 생성을 요청, 해당 리소스가 성공적으로 생성됨(POST를 통한 리소스 생성 작업 시)

400

클라이언트의 요청이 부적절 할 경우 사용하는 응답 코드

401

클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청했을 때 사용하는 응답 코드

(로그인 하지 않은 유저가 로그인 했을 때, 요청 가능한 리소스를 요청했을 때)

403

유저 인증상태와 관계 없이 응답하고 싶지 않은 리소스를 클라이언트가 요청했을 때 사용하는 응답 코드

(403 보다는 400이나 404를 사용할 것을 권고. 403 자체가 리소스가 존재한다는 뜻이기 때문에)

405

클라이언트가 요청한 리소스에서는 사용 불가능한 Method를 이용했을 경우 사용하는 응답 코드

301

클라이언트가 요청한 리소스에 대한 URI가 변경 되었을 때 사용하는 응답 코드

(응답 시 Location header에 변경된 URI를 적어 줘야 합니다.)

500

서버에 문제가 있을 경우 사용하는 응답 코드

Api Swagger

  • RestApi를 편리하게 문서화 해 주고, 이를 통해서 개발자가 편리하게 API를 호출해보고 테스트를 할 수 있는 플러그인 입니다.

Swagger 의존성 추가

<dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-ui</artifactId> <version>1.6.9</version> </dependency>
  • Swagger를 사용하기위해 pom.xml에 해당 의존성을 추가합니다

Swagger 설정 추가

@Configuration public class SwaggerConfig { private static final String BASE_PACKAGE = "net.lotte.chamomile.admin"; @Bean public OpenAPI openAPI() { SecurityScheme securityScheme = new SecurityScheme() .type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT") .in(SecurityScheme.In.HEADER).name("Authorization"); SecurityRequirement securityRequirement = new SecurityRequirement().addList("bearerAuth"); return new OpenAPI() .components(new Components().addSecuritySchemes("bearerAuth", securityScheme)) .security(Collections.singletonList(securityRequirement)); } @Bean public GroupedOpenApi authApi(){ final String url = "auth"; return GroupedOpenApi.builder() .group(url) .pathsToMatch("/chmm/"+url+"/**") .packagesToScan(BASE_PACKAGE+"."+url) .build(); } @Bean public GroupedOpenApi authGroupApi(){ final String url = "auth-group"; return GroupedOpenApi.builder() .group(url) .pathsToMatch("/chmm/"+url+"/**") .packagesToScan(BASE_PACKAGE+".authgroup") .build(); } }
  • BASE_PACKAGE 변수:

    • BASE_PACKAGE 상수는 스캔해야 하는 패키지의 베이스 주소를 담고 있습니다. 이 경우에는 ** net.lotte.chamomile.admin **이라는 패키지가 사용되며, Swagger 문서화 과정에서 이 패키지 내의 컨트롤러들을 스캔하게 됩니다.

  • OpenAPI Bean:

    • OpenAPI 타입의 Bean을 정의합니다. 이 Bean은 전체 API에 대한 OpenAPI 사양을 설정합니다. 여기에는 보안 설정도 포함됩니다.

      • SecurityScheme: JWT 기반의 인증 메커니즘을 설정합니다. HTTP Authorization 헤더를 사용하여 bearer 토큰을 전달하는 방식으로 구성됩니다.

      • SecurityRequirement: ** SecurityScheme **을 사용하기 위해 필요한 ** SecurityRequirement **를 추가합니다. 이를 통해 API를 호출할 때마다 인증 토큰을 제공해야 함을 명시합니다.

  • GroupedOpenApi Beans:

    • GroupedOpenApi 객체들을 Bean으로 생성합니다. 이 객체들은 특정 API 그룹에 대한 Swagger 문서화 설정을 제공합니다.

      • authApi: ** auth **라는 그룹을 정의하고, URL 경로 ** /chmm/auth/** **에 매칭되는 API를 문서화합니다. 또한, net.lotte.chamomile.admin.auth 패키지를 스캔하여 해당 컨트롤러들을 문서화에 포함시킵니다.

      • authGroupApi: 또 다른 그룹 ** auth-group **을 정의하고, URL 경로 ** /chmm/auth-group/** **에 매칭되는 API를 문서화합니다. 여기서는 net.lotte.chamomile.admin.authgroup 패키지를 스캔합니다.

Swagger 화면

  • 플러그인 설치후 주소창에 호스트:포트/swagger-ui.html를 입력하게되면 다음과 같이 Swagger가 적용된 화면을 볼 수 있다.

https://blog.kakaocdn.net/dn/cTw1Gk/btq2gEWWm1P/S4I5jKsabkl7PuvOKJbkr0/img.jpg

Swagger 기능

  • @Operation (summary = "권한 목록 요청", description = "권한의 목록을 조회합니다.")

  • 캐모마일의 경우 스웨거는 필요시 별도의 인터페이스를 구성해서 진행합니다.

@Operation(summary = "권한 목록 요청", description = "권한의 목록을 조회합니다.") ChamomileResponse<Page<AuthVO>> getAuthList(AuthQuery request, Pageable pageable);
Untitled

@Schema

  • 해당 필드가 어떤 의미인지 적을수 있습니다.

public class AuthQuery { @Schema(description = "권한아이디", example = "admin") private String searchRoleId; //권한아이디(검색) @Schema(description = "권한명", example = " ") private String searchRoleName; //권한명(검색) }

@ApiModelProperty

  • 어노테이션을 적용하게되면 다음처럼 확인할 수 있습니다..

  • 테스트를 하려면 우측상단에 Try it out버튼을 클릭해 봅니다.

Untitled
  • 테스트를 하고나면 해당 API를 호출했을때 응답데이터가 정상적으로 내려온걸 확인할 수 있고json확장자의 파일로 API 결과를 다운로드 받을 수 있습니다.

  • 적용 예제

  • API 들의 스펙을 명세, 관리, 테스트를 위해 Swagger UI 를 사용 합니다.

API 에서의 Swagger 사용 예제 코드

@Tag(name = "캐모마일 어드민 권한 AuthAPI") public interface AuthControllerDoc { @Operation(summary = "권한 목록 요청", description = "권한의 목록을 조회합니다.") ChamomileResponse<Page<AuthVO>> getAuthList(AuthQuery request, Pageable pageable); @Operation(summary = "권한 생성 요청", description = "권한를 생성합니다.") ChamomileResponse<Void> createAuth(@RequestBody( content = @Content( examples = @ExampleObject(value = "{\n" + " \"authId\": \"test1\",\n" + " \"authName\": \"테스트1\",\n" + " \"useYn\": \"1\"\n" + "}") ) ) AuthVO request) throws Exception; @Operation(summary = "권한 수정 요청", description = "권한를 수정합니다.") ChamomileResponse<Void> updateAuth(@RequestBody( content = @Content( examples = @ExampleObject(value = "{\n" + " \"authId\": \"test1\",\n" + " \"authName\": \"테스트1\",\n" + " \"useYn\": \"1\"\n" + "}") ) ) AuthVO request) throws Exception; @Operation(summary = "권한 삭제 요청", description = "권한를 삭제합니다.") ChamomileResponse<Void> deleteAuth(@RequestBody( content = @Content( examples = @ExampleObject(value = "[{\n" + " \"authId\": \"test1\"\n" + "}]") ) ) List<AuthVO> request) throws Exception; @Operation(summary = "권한 중복확인 ", description = "권한 중복확인을 합니다. ") ChamomileResponse<AuthVO> authCheckId(@RequestBody( content = @Content( examples = @ExampleObject(value = "{\n" + " \"searchAuthId\": \"test1\"\n" + "}") ) ) AuthQuery request) throws Exception; @Operation(summary = "엑세파일 저장 ", description = "엑셀 파일을 저장합니다.") ResponseEntity<byte[]> excelDownload(AuthQuery request) throws Exception; @Operation(summary = "엑세템플릿 저장 ", description = "엑셀 템플릿을 저장합니다.") ResponseEntity<byte[]> excelSample() throws Exception; @Operation(summary = "엑셀 업로드 ", description = "엑셀을 업로드 합니다.") ChamomileResponse<Void> excelUpload(MultipartFile request) throws Exception; }
@Data public class AuthQuery { @Schema(description = "권한아이디", example = "admin") private String searchAutId; //권한아이디(검색) @Schema(description = "권한명", example = " ") private String searchAuthName; //권한명(검색) @Schema(description = "사용여부", example = " ") private String searchUseYn; //사용여부(검색) }

공식 홈 : https://swagger.io/

Last modified: 10 1월 2025