Initial commit

This commit is contained in:
2026-05-29 17:49:25 +09:00
commit 330105cb27
1081 changed files with 148694 additions and 0 deletions
@@ -0,0 +1,57 @@
= Knox 결재 상태 동기화
== 결재 Batch 설정
Knox 결재 문서는 10분마다 배치가 실행되어 동기화 되고 있다.
* config.properties : 동기화 배치 실행 주기 설정
[source,properties]
----
## Knox Approval Sync
knox.approval.sync.cron=0 0/10 * * * ?
----
* QuartzConfig.java: Scheduler 등록
* KnoxSyncBatchConfig.java: 배치 Job, Trigger 등록
* KnoxSyncBatchExecutor.java: 서비스 호출
== 결재 동기화 로직
배치에서 실행되는 동기화 로직을 구현한 서비스는 knoxApprovalSyncServiceImpl.java 파일의 synchronizeKnox() 메소드 이며 동기화 로직은 간략하게 아래와 같다.
. SDL 결재 테이블에서 결재 진행중인 문서 목록 대상 조회.
. 대상 목록의 결재ID로 Knox REST를 조회하여 Revision이 변경되었는지 확인.
. Revision 변경된 대상에 대해서 결재 정보 동기화 처리.
. 동기화 완료 후 결재 후처리 진행.
결재 동기화 시 오류가 발생한 결재 문건은 결재정보 테이블(TN_CF_APPROVAL)에 결재 동기화 상태값(APPROVAL_FAULT)이 false로 Update되며 다음 배치 실행시 대상으로 선정되지 않는다. +
이런 경우 이벤트 로그 테이블(TN_CF_APPROVAL_EVENT)의 로그를 확인하여 다시 동기화 해야 한다면 결재 관리 상세화면에서 개별 동기화가 가능하다.
image::approvalSync_01.png[]
== 결재 전후처리
결재 동기화 처리전 또는 처리후 결재 문서 상태에 대한 비지니스를 처리할 수 있도록 인터페이스를 제공하고 있다.
ApprovalInterceptor 를 결재 문서별로 상속 받는 구현 클래스를 만들면 된다.
* 구현 예시(KnoxApprovalSampleInterceptor.java)
[source,java]
----
@Log4j2
@ApprovalDocumentType(names = {"knoxSample"})
public class KnoxApprovalSampleInterceptor implements ApprovalInterceptor {
@Autowired
KnoxApprovalSampleService knoxApprovalSampleService;
@Override
public void afterSubmit(Approval approval, List<ApprovalStep> approvalStepList, Map<String, Object> attribute) {
log.debug("execute ApprovalSampleInterceptor afterSubmit");
//Knox 상신 후 문서 상태 업데이트
knoxApprovalSampleService.updateSampleApprovalDocument(approval.getDbDocId(), ApprovalDocStatus.INPROCESS);
}
-- 생략 --
----
@@ -0,0 +1,124 @@
= Knox 상신
== 결재 Entity Class 생성 및 설정
결재 기능을 구현해야 하는 업무의 Entity Class를 생성하고 Annotation을 설정하고 기본 결재 Class를 상속 받는다.
[source,java]
----
@Data
@EqualsAndHashCode(callSuper = true)
@ApprovalDocument(docType = "knoxSample", description = "Sample Approval Doc. (Knox)", approvalClass = Approval.class, templateEngine = TemplateEngineType.VELOCITY,
templateFile = "/templates/approval/approval-sample.vm", docSecuType = ApprovalDocSecuType.PERSONAL,
isArbitrary = true, bodyType = ApprovalBodyType.MIME)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class KnoxApprovalSampleDocument extends DefaultApprovalDocument {
private static final long serialVersionUID = 1L;
private String docId;
private String contents;
private String creator;
}
----
업무프로세스 Entity Class 에 @ApprovalDocument 을 달아 주고 DefaultApprovalDocument를 상속 받아야만 결재 Object 라는 것을 결재 모듈에서 알수 있다.
=== @ApprovalDocument
@ApprovalDocument를 이용해 결재 문서의 속정을 정의한다.
[cols=5]
|====
|props명
|필수여부
|Type
|Default
|설명
|docType
|필수
|String
|
|사용자가 식별할수 있는 이름
|description
|필수
|String
|
|결재 문서에 대한 설명
|approvalClass
|필수
|class
|Approval.class
|결재 문서를 DB에 저장할때 사용하는 클래스명
|templateEngine
|필수
|TemplateEngineType
|VELOCITY
|결재 본문 파싱에 필요한 템플릿 엔진. THYMELEAF, VELOCITY 2개의 템플릿 엔진을 사용할 수 있다.
|templateFile 또는 templateKey
|필수
|String
|
|templateFile: 템플릿 파일 이름을 경로와 확장자 포함해서 설정한다. +
tempageKey: 결재양식 관리 메뉴에서 지정한 key
|docSecuType
|
|ApprovalDocSecuType
|PERSONAL
|결재 문서의 보안 형태
|isBodyModify
|
|boolean
|true
|문서의 기본 결재 본문 수정 true일 때만 UI에서 수정 가능
|isRouteModify
|
|boolean
|true
|문서의 기본 결재 경로 수정 true일 때만 UI에서 수정 가능
|isArbitrary
|
|boolean
|false
|문서의 기본 결재 전결 true일 때만 UI에서 수정 가능
|bodyType
|
|ApprovalBodyType
|MIME
|전송할 문서의 형태 TEXT, HTML, MIME
|isInternalApproval
|
|boolean
|false
|true: 내부결재, false: Knox결재
|====
== 결재 본문 등록
결재 본문은 VELOCITY 또는 THYMELEAF 로 등록 할 수 있다. +
SDL에서 제공하는 결재 샘플에서는 VELOCITY 파일로 제공하고 있으며 vm 파일을 작성하고, +
위의 Entity Class 샘플에서와 같이 `@ApprovalDocument` 의 `templateEngine=엔진타입` 과 `templateFile="템플릿파일경로"` 값을 등록한다.
== 결재 상신
=== 결재 상신 UI
샘플 문서를 등록 하고나면 상세하면 하단에 결재 경로를 설정할 수 있는 결재 스텝을 입력 받는 Component가 표시된다. +
결재 문서 화면 개발시 이 Component를 붙여서 상신 기능을 구현한다.
image::approvalSumit_01.png[]
@@ -0,0 +1,34 @@
= MHTML 변환
== 개요
프로젝트에서 메일발송이나 결재상신한 후 방화벽 밖(모바일)에서 조회시 이미지, css가 적용되지 않는 문제를 해결하기 위해 MHT로 변환
.MHT 변환 결과 예
[source, text]
----
Date: Fri, 9 Aug 2019 14:55:20 +0900 (KST)
Message-ID: <963810424.1.1565330120404@DESKTOP-TUEGPQT>
Subject: =?UTF-8?B?66mU64m0IOq2jO2VnCDrp4zro4wg7JiI7KCVIOyViOuCtA==?=
MIME-Version: 1.0
Content-Type: multipart/related;
boundary="----=_Part_0_398737318.1565330120140"
------=_Part_0_398737318.1565330120140
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: base64
PCFkb2N0eXBlIGh0bWw+DQo8aHRtbD4NCjxoZWFkPg0KPG1ldGEgY2hhcnNldD0idXRmLTgiPg0K
PHRpdGxlPuuplOuJtCDqtoztlZwg66eM66OMIOyYiOyglSDslYjrgrQ8L3RpdGxlPg0KPC9oZWFk
Pg0KDQo8Ym9keT4NCjxkaXYgc3R5bGU9IndpZHRoOjEwMCU7YmFja2dyb3VuZC1jb2xvcjojZmZm
(중략)
------=_Part_0_398737318.1565330120140
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64
Content-ID: <simbol.png>
iVBORw0KGgoAAAANSUhEUgAAAQEAAAEBCAYAAAB47BD9AAAwaUlEQVR42u3deZxddX3/8QuC4kPt
Rqu2iK222pYW2yogCNbyE81MVRSFIEuAewmBsGQl+zqZmexhExEV0AQCSSDrZLZkJjOZzGRmQhAM
RXYqbrVaFZHJTOCe+/29v+fc7z3nnn35nnPP8v3j9XAeLWVScz/P7/ee73fu5AghuSD90+Pt5Trk
(중략)
------=_Part_0_398737318.1565330120140--
----
+220
View File
@@ -0,0 +1,220 @@
= 결재
== 개요
SDL에서는 Knox결재와 동기화 되는 결재 모듈을 제공하고 있는데, 여기서는 Knox Portal REST API 연계 서비스 신청 및 Knox결재 서비스 연계 부분에 대하여 설명한다. 결재화면 및 기능구현 설명은 해당 가이드를 참조한다.
=== Knox결재 연계 설정
. Knox REST API 연계 서비스 신청이 되었다면, 발급받은 `system-id`, `token` 값을 설정한다.
.knox.properties (스테이지)
[source,properties]
----
knox.system-id=xxxxxxxxxxx
knox.token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
knox.address.prefix=openapi.samsung.net
knox.approval-service=/approval/api/v2.0/approvals
----
.knox.properties (운영)
[source,properties]
----
knox.system-id=xxxxxxxxxxx
knox.token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // <1>
knox.address.prefix=openapi.samsung.net,openapi.w1.samsung.net,openapi.w2.samsung.net # <2>
knox.approval-service=/approval/api/v2.0/approvals
----
<1> 토큰 (comma(,)로 구분, 거점 순서와 동일)
<2> 거점 (국내, 구주, 미주)
[start=2]
. 결재화면 및 기능구현 설명은 해당 가이드를 참조한다.
* <<_knox_상신,Knox상신>>
NOTE: 개발자의 IP도 반드시 Knox stage 방화벽에 등록하여야만 개발자 PC에서 상신이 된다. 또한 Knox 스테이지(http://www.stage.samsung.net) 에 개발자와 결재자의 계정도 생성 해야만 개발을 진행 할 수 있다.
== API
KnoxApprovalController는 Knox에서 제공하는 Approval API를 직접 연결하는 API를 제공한다.
시스템의 비즈니스 로직을 거치지 않고 Knox API를 직접 호출 하기 때문에 서비스 호출에 문제가 있는지 파악하는데 유용하다.
NOTE: KnoxApprovalController에서 제공하는 API URI은 Knox REST Service의 API URI와 같다.
. Knox 일반 결재 상신 +
POST /knox/approvals/submit +
* 파라미터는 KnoxApproval 클래스를 참고한다.
* attachments는 첨부파일, knoxApprovalStr는 KnoxApproval의 Json String 값이다.
[source,java]
----
@PostMapping("/submit")
public KnoxApproval submitGeneral(@Parameter(value = "첨부파일", required = true) MultipartFile attachments,
@Parameter(value = "상신정보", required = true) String knoxApprovalStr) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
KnoxApproval knoxApproval = objectMapper.readValue(knoxApprovalStr, KnoxApproval.class);
String serverLocation = Account.currentUser().getServerLocation();
if (StringUtils.isEmpty(serverLocation)) serverLocation = "KR";
String fileId = fileManagerService.store(attachments);
List<Resource> fileList = new ArrayList<>();
fileList.add(fileManagerService.getResource(fileId));
return knoxApprovalService.submit(knoxApproval, fileList, serverLocation);
}
----
[start=2]
. Knox 보안 결재 상신 +
POST /knox/approvals/secu-submit +
* 파라미터는 일반 결재 상신과 같지만 보안문서타입이 "CONFIDENTAIL" 이다.
[source,java]
----
knoxApproval.setDocSecuType("CONFIDENTAIL");
----
[start=3]
. Knox 결재 상세 상황 조회 +
GET /knox/approvals/{apInfId}/detail +
* 결재 연계 ID로 결재 문서의 정보를 상세 조회한다.
. Knox 결재 본문 조회 +
GET /knox/approvals/{apInfId}/content +
* 결재 연계 ID로 결재 문서의 본문을 조회한다.
. Knox 결재 상황 조회 +
POST /knox/approvals/status +
* 결재문서의 진행 상태를 조회한다.
* 복수개의 결재 연계 ID를 요청하여 각각 해당하는 문서변경횟수와 결재상태정보를 응답받는다. 이를 이용하여 결재문서 동기화시 변경된 건에 대해 결재 상태를 업데이트 한다.
[source,java]
----
public List<KnoxApprovalStatus> getStatus(@RequestBody List<KnoxApprovalStatus> knoxApprovalStatusList) {
----
[start=6]
. Knox 결재 연계 ID 조회 +
POST /knox/approvals/apinfids +
* 결재 ID로 결재 연계 ID를 조회한다.
[source,java]
----
public KnoxApproval getApInfIds(@RequestParam String apId) {
----
[start=7]
. Knox 상신함 리스트 조회 +
POST /knox/approvals/submission +
* 상신자가 상신한 정보를 조회한다.
[source,java]
----
public List<KnoxApproval> getApInfIdInfos(@RequestParam String epId) {
----
[start=8]
. Knox 연계 이력 조회 +
GET /knox/approvals/apinfidinfos +
* 요청 시스템에서 상신된 결재문서의 연계 이력을 조회한다.
. Knox 상신 취소 +
POST /knox/approvals/{apInfId}/cancel +
* 결재 문서를 상신취소한다.
. Knox 완결 처리 +
POST /knox/approvals/{apInfId}/autoprogress +
* 결재문서를 완결처리한다.
== KnoxApprovalService
KnoxApprovalService는 시스템에서 결재 문서를 상신 할때 필요한 API들을 제공한다.
[source, java]
----
/**
* 일반 상신, 보안 상신
* @param knoxApproval
* @param attachments
* @param locale
* @return
*/
KnoxApproval submit(KnoxApproval knoxApproval, List<Resource> attachments, String locale);
/**
* 취소
* @param apInfId
* @param locale
* @return
*/
KnoxApproval cancel(String apInfId, String opinion, String locale);
/**
* 완결 처리
* @param apInfId
* @param locale
* @return
*/
KnoxApproval autoProgress(String apInfId, String flag, String timeZone, String locale);
/**
* 결재 상황 조회
* @param knoxApprovalStatusList
* @param locale
* @return
*/
List<KnoxApprovalStatus> getStatus(List<KnoxApprovalStatus> knoxApprovalStatusList, String locale);
/**
* 결재상세상황조회
* @param apInfId
* @param locale
* @return
*/
KnoxApproval getDetail(String apInfId, String locale);
/**
* 결재본문조회
* @param apInfId
* @param locale
* @return
*/
KnoxApproval getContent(String apInfId, String locale);
/**
* 결재연계ID조회
* @param apId
* @return
*/
KnoxApproval getApInfIds(String apId, String locale);
/**
* 상신함리스트조회
* @param epId
* @return
*/
List<KnoxApproval> getSubmission(String epId, String locale);
/**
* 연계이력조회
* @param endDate yyyyMMddHHmm 형식
* @param page 페이지 처리
* @param duration 단위 : 분 / 최소 1분 ~ 최대 60분
* @return
*/
List<KnoxApproval> getApInfIdInfos(String endDate, String page, String duration, String locale);
----
각각의 메서드들은 Knox Rest 연계 서비스에서 요구하는 가이드대로 REST 형식을 갖추어 필요한 로직들을 수행한다.
@@ -0,0 +1,46 @@
= 결재 경로 관리
== 개요
시스템의 결재 문서 샘플을 RUNTIME 동안 가지고 있다가 결재시에 사용한다.
* ApprovalManager.java -> ApprovalDocument.java -> SampleApprovalDocument.java
. ApprovalManager : @ApprovalDocument라는 어노테이션이 달린 클래스를 찾는다.
. SampleApprovalDocument : 결재경로 관리 목록에 결재 문서 샘플을 보여준다.
== Table
* 결재 경로 : TN_CF_DYNAMIC_APPROVAL_PATH
* 필수 결재자 : TN_CF_REQUIRED_APPROVAL_USER
== API
.ApprovalController.java
. 시스템 전체 결재 문서 조회 +
GET /approval/approval-doc-types
. 결재 경로 조회 +
GET /approval/dynamic-approval-paths/{docType} +
Query ID : selectDynamicApprovalPath
* 기본결재 경로 목록을 보여준다.
. 결재 경로 저장 +
POST /approval/dynamic-approval-paths/{docType} +
Query ID : deleteDynamicApprovalPath, insertDynamicApprovalPath
. 필수 결재자 목록 조회 +
GET /approval/required-approval-users/{docType} +
Query ID : selectRequiredApprovalUserList
* 필수 결재자 목록을 보여준다.
. 필수 결재자 저장 +
POST /approval/required-approval-users/{docType} +
Query ID : deleteRequiredApprovalUser, insertRequiredApprovalUser
== 화면
지정된 문서타입에 따른 결재경로를 관리기능 > 결재/메일 관리 > 결재경로 관리를 통해 지정할 수 있다.
image::front_07_04.png[]
* 지정된 문서타입 목록을 확인할 수 있다.
image::front_07_05.png[]
* 문서타입을 선택 후 해당 문서에 대한 기본 결재경로와 필수 결재자를 추가할 수 있다.
* 결재 상신시 결재자 목록에 지정된 기본결재 경로가 자동 추가되며, 지정된 필수 결재자가 있는 경우 추가하라는 알림을 준다. (다수중 1인 가능)
@@ -0,0 +1,35 @@
= 결재 관리
== 개요
결재 관리를 통해 내부/knox 결재 목록을 확인할 수 있다.
== Table
* 결재 : TN_CF_APPROVAL
* 결재 이벤트 : TN_CF_APPROVAL_EVENT
* 결재 스텝 : TN_CF_APPROVAL_STEP
== API
.ApprovalController.java
. 시스템 전체 결재 문서 조회 +
GET /approval/approval-doc-types +
* 결재경로 관리의 문서타입을 가져온다.
. 시스템 전체 결재 목록 조회(페이징) +
GET /approval/approval-with-paging +
Query ID : selectApprovalPagingList
. 결재 상세정보 조회 +
GET /approval/{approvalRequestId} +
Query ID : selectApprovalStep, selectApprovalEventList
== 화면
image::front_07_01.png[]
=== 검색 조건
** 구분 : knox 결재/ 내부결재
** 상태 : 결재중/완료/후완결/반려/취소
** 문서명 : 결재양식 목록
** 상신자 : 결재 요청한 상신자
** 동기화 상태 : 성공/실패
** 기간 : 결재요청 기간
@@ -0,0 +1,56 @@
= 결재 양식 관리
== 개요
결재 양식을 관리한다.
== Table
* 템플릿 : TN_CF_TEMPLATE
== API
.TemplateController.java
. 템플릿 목록 조회(페이징) +
GET /templates-with-paging/group/{templateGroupCode} +
Query ID : selectTemplatePagingList
* TEMPLATE_GROUP_CODE 컬럼의 'APPROVAL'을 조회한다.
. 템플릿 상세 조회 +
GET /templates/group/{templateGroupCode}/key/{templateKey} +
Query ID : selectTemplate
. 템플릿 상세 조회 (By ID) +
GET /templates/{id} +
Query ID : selectTemplate
* 양식의 상세 내용을 조회 하거나 팝업 미리보기를 할 수 있다.
. 템플릿 Key 중복 체크 +
GET /templates/dup-check/group/{templateGroupCode}/key/{templateKey} +
Query ID : selectTemplate
* 저장 전 템플릿 Key 중복 여부를 검사한다.
. 템플릿 등록 +
POST /templates/group/{templateGroupCode} +
Query ID : insertTemplate
* 양식을 저장한다.
. 템플릿 수정 +
POST /templates/{id} +
Query ID : updateTemplate
. 템플릿 삭제 +
DELETE /templates/{id} +
Query ID : deleteTemplate
== 화면
결재양식을 관리기능 > 결재/메일관리 > 결재양식 관리를 통해 볼 수 있다.
image::front_07_06.png[]
* 등록된 결재양식 목록을 결재양식 관리를 통해 볼 수 있다.
* 목록의 Key 컬럼을 클릭하여 결재양식 정보를 수정할 수 있다.
* 팝업 미리보기 컬럼을 클릭하여 등록된 결재양식의 첨부파일을 확인 할 수 있다.
image::front_07_07.png[]
* Key : 유니크한 결재양식 키를 지정(영문, 숫자만 가능)
* 제목 : 결재양식의 제목
* 설명 : 결재양식의 설명
* 첨부파일 : 결재양식 첨부파일
@@ -0,0 +1,111 @@
= 내부 결재
== 개요
SDL에서 제공하는 내부결재 기능. +
결재를 위한 문서 Entity등록과 내부결재 후처리를 위한 Interceptor 클래스 구현으로 간단하게 결재 기능을 구현할 수 있다. +
샘플로 제공하는 화면의 결재 스텝을 지정하는 Component를 필요한 결재 문서 화면에 적용하여 사용할 수 있으며 샘플 Controller를 참조하여 문서와 결재 스텝 목록을 저장하여 approvalService.submit 메소드를 호출하면 된다.
== Table
* 결재 정보 : TN_CF_APPROVAL
* 결재 스텝 정보 : TN_CF_APPROVAL_STEP
* Sample Document : TN_CF_SAMPLE_APPROVAL_INTERNAL_DOCUMENT
== API
.ApprovalController.java
. 상신함 목록 조회(내부 결재) +
GET /internal-approvals/submit +
Query ID : selectInternalApprovalPagingListBySubmit
* 사용자가 상신한 내부결재 문서를 조회한다.
. 미결함 목록 조회(내부 결재) +
GET /internal-approvals/not-approve +
Query ID : selectInternalApprovalPagingListByNotApprove
* 미결중인 내부결재 문서를 조회한다.
. 기결함 목록 조회(내부 결재) +
GET /internal-approvals/approved +
Query ID : selectInternalApprovalPagingListByApproved
* 사용자가 결재 완료한 내부결재 문서를 조회한다.
. 통보함 목록 조회(내부 결재) +
GET /internal-approvals/notice +
Query ID : selectInternalApprovalPagingListByNotice
* 사용자가 통보 대상인 결재문서를 조회한다.
. 내부결재 문서 상신 취소 +
POST /internal-approvals/{approvalRequestId}/cancel +
Service : cancelInternalApproval
Query ID : updateInternalApprovalStep
* 결재 문서 상신을 취소한다.
. 내부결재 문서 결재 승인 또는 합의 +
POST /internal-approvals/{approvalRequestId}/confirm +
Service : confirmInternalApproval
Query ID : updateInternalApprovalStep
* 결재 문서 승인 또는 합의 한다.
. 내부결재 문서 반려 +
POST /internal-approvals/{approvalRequestId}/reject +
Service : rejectInternalApproval
Query ID : updateInternalApprovalStep
* 결재 문서를 반려 한다.
.ApprovalSampleController.java
. 내부결재 문서 목록 조회(페이징) +
GET /internal-approval/sample-document-with-paging +
Query ID : selectSampleApprovalDocumentPagingList
* Sample Document 문서 목록을 조회한다.
. 내부 결재 문서 상신(Sample Document) +
POST /internal-approval/submit/sample-document
* Knox 결재 정보 동기화 로직을 제외한 다른 부분은 Knox 결재 상신과 동일하다.
* 동기화 배치 로직 대상에서 제외된다.
* 내부결재 전후 처리 로직은 문서 타입별로 Interceptor 클래스를 구현하여 처리한다.
[source,java]
----
@Log4j2
@ApprovalDocumentType(names = {"internalSample"})
public class InternalApprovalSampleInterceptor implements ApprovalInterceptor {
@Autowired
InternalApprovalSampleService internalApprovalSampleService;
@Override
public void afterSubmit(Approval approval, List<ApprovalStep> approvalStepList, Map<String, Object> attribute) {
log.debug("execute ApprovalSampleInterceptor afterSubmit");
//상신 후 문서 상태 업데이트
internalApprovalSampleService.updateSampleApprovalDocument(approval.getDbDocId(), ApprovalDocStatus.INPROCESS);
}
--생략--
}
----
== 화면
. 내부결재 문서 상신함
image::internalApproval_01.png[]
image::internalApproval_05.png[]
* 사용자가 상신한 내부결재 문서 목록을 조회한다.
* 상세화면에 진입하여 상신취소가 가능하다.
[start=2]
. 내부결재 문서 미결함
image::internalApproval_02.png[]
image::internalApproval_06.png[]
* 사용자의 결재 차순에 있는 내부결재 문서 목록을 조회한다.
* 상세화면에 진입하여 승인/합의 또는 반려가 가능하다.
[start=3]
. 내부결재 문서 기결함
image::internalApproval_03.png[]
* 사용자의 결재 완료한 내부결재 문서 목록을 조회한다.
[start=4]
. 내부결재 문서 통보함
image::internalApproval_04.png[]
* 결재 완료 후 사용자에게 통보된 내부결재 문서 목록을 조회한다.
@@ -0,0 +1,35 @@
= 대리 결재
== 개요
내부결재에 적용되는 대리결재자를 지정하는 기능을 제공한다. +
(Knox 결재 대리결재는 Knox portal에서 지정 가능함) +
== Table
* 결재 정보 : TN_CF_APPROVAL_DELEGATE
== API
.ApprovalController.java
. 대리결재자 조회 +
GET /approval/approver-delegate +
Query ID : selectApproverDelegate
* 사용자의 대리결재자를 조회한다.
. 대리결재자 저장 +
POST /approval/approver-delegate +
Query ID : updateApproverDelegate, insertApproverDelegate
* 사용자의 대리결재자를 저장한다.(등록 또는 변경)
. 대리결재자 삭제 +
DELETE /approval/approver-delegate +
Query ID : deleteApproverDelegate
* 사용자의 대리결재자를 삭제한다.
== 화면
. 대리결재자 조회 및 지정
image::approverDelegate_01.png[]
* 사용자 정보 > 대리결재 메뉴를 통해서 대리결재자 등록이 가능하다.
* 기등록된 대리결재자가 존재한다면 대리결재자 팝업 상단에 표시되며 삭제하거나 다른 사용자를 선택하여 변경가능 하다.
@@ -0,0 +1,85 @@
= 메신저
== 개요
Knox Portal에서 제공하는 메신저 관련 Rest API 를 이용한 연계 서비스 제공
=== Knox REST API 연계 서비스 신청
Knox REST API 연계 서비스 신청은 <<_knox_rest_api_연계_서비스_신청,Knox REST API 연계 서비스 신청>> 항목을 참조한다.
=== Knox Rest 메신저 연계 설정
메일, 결재 Knox Rest API 연계와 마찬가지로 연계를 위한 사전 준비가 되었다면, knox.properties 에 메신저 관련 설정이 되어 있는지 확인한다.
.knox.properties
[source,properties]
----
knox.messenger.contact-service=/messenger/contact/api/v1.0
knox.messenger.msgctx-service=/messenger/msgctx/api/v1.0
knox.messenger.message-service=/messenger/message/api/v1.0
----
=== Knox 메신저 연계 서비스
REST를 통해서 메신저와 연계하는 서비스로 주요 메서드는 KnoxMessengerService 인터페이스에 정의되어 있다.
[source, java]
----
public interface KnoxMessengerService {
/**
* 디바이스 ID 조회 : 사용자 ID 와 맵핑되는 단말의 ID 값
* @return 디바이스 ID
*/
String getDeviceId();
/**
* 메시지 암호화 키 조회 : 메시지를 암호화하기 위한 키 값
* @param deviceId 디바이스 ID
* @return 메시지 암호화 키
*/
String getKey(String deviceId);
/**
* Knox Potal login ID를 이용하여 Knox Messenger 수신자들을 조회한다.
* @param deviceId 디바이스 ID
* @param singleIds 수신자 Knox ID 리스트
* @return Knox Messenger 수신자 ID 리스트
*/
List<String> getUserIds(String deviceId, List<String> singleIds);
/**
* 공지 메시지를 발신할 대화방이 없는 경우 신규 대화방 생성을 요청한다.
* @param deviceId 디바이스 ID
* @param key 암호화 키
* @param userIds Knox Messenger 수신자 ID 리스트
* @return 대화방 생성 요청 응답 결과
*/
Map<String, Object> createChatroom(String deviceId, String key, List<String> userIds);
/**
* Message 서버 API 에서 필요한 암호화된 바디를 만들기 위한 function
* @param key - msgCtx 를 통해 전달받은 key 값
* @param body - 암호화 해야 될 String
* @return 암호화된 String
*/
String encrypt(String key, String body);
/**
* Response 로 전달된 암호화 body 를 복호화 하기 위한 function <br/>
* 암호화의 역순으로 Base64 복호화 -> AES256 복호화
* @param body - 암호화 되어 있는 body
* @return 복호화된 response String
*/
String decrypt(String body);
/**
* 신규 생성한 대화방 또는 기존에 사용중인 대화방에 공지 메시지를 발송한다.
* @param deviceId 디바이스 ID
* @param key 암호화 키
* @param chatroomId 생성된 대화방 ID
* @param chatMsg 메시지 내용
* @return 메시지 발신 요청 응답 결과
*/
Map<String, Object> chat(String deviceId, String key, String chatroomId, String chatMsg);
}
----
자세한 API 스펙은 Swagger API 문서의 knox-messenger-controller 항목을 참고한다.
+75
View File
@@ -0,0 +1,75 @@
= 메일
=== Knox REST API 연계 서비스 신청
Knox REST API 연계 서비스 신청은 <<_knox_rest_api_연계_서비스_신청,Knox REST API 연계 서비스 신청>> 항목을 참조한다.
=== Knox메일 연계 설정
Knox REST API 연계 서비스 신청이 되었다면, 발급받은 `system-id`, `token` 값을 설정한다.
.knox.properties (스테이지)
[source,properties]
----
knox.system-id=xxxxxxxxxxx
knox.token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
knox.address.prefix=openapi.samsung.net
knox.mail-service=/mail/api/v2.0
----
.knox.properties (운영)
[source,properties]
----
knox.system-id=xxxxxxxxxxx
knox.token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // <1>
knox.address.prefix=openapi.samsung.net,openapi.w1.samsung.net,openapi.w2.samsung.net # <2>
knox.mail-service=/mail/api/v2.0
----
<1> 토큰 (comma(,)로 구분, 거점 순서와 동일)
<2> 거점 (국내, 구주, 미주)
=== KnoxMailService
Knox REST API 연계를 통해서 메일발신, 상태조회등을 하는 서비스로 주요 메서드는 KnoxMailService 인터페이스에 정의되어 있다.
KnoxMailService는 시스템에서 Knox 메일 서비스와 연계할 때 필요한 API들을 제공한다.
[source, java]
----
public interface KnoxMailService {
/**
* Knox 메일 발신
* @param sendMail 발신 메일 정보 (첨부파일정보(AttachFile) 포함)
* @return Knox 메일 아이디
*/
String sendMail(SendMail sendMail);
/**
* Knox 메일 발신
* @param sendMail 발신 메일 정보
* @param attachResources 메일 첨부가 파일 리소스일 경우
* @return Knox 메일 아이디
*/
String sendMail(SendMail sendMail, List<Resource> attachResources);
/**
* Knox 메일별 수신상태 조회
* @param mailIds Knox 메일 아이디 리스트
* @param sendMail 메일 정보
* @return Knox 메일 상태
*/
MailStatus[] getDeliveryStatusCount(List<String> mailIds, SendMail sendMail);
/**
* Knox 메일 수신인별 수신상태 조회
* @param mailId Knox 메일 아이디
* @param sendMail 메일 정보
* @return Knox 메일 수신인별 수신상태 정보
*/
Recipient[] getDeliveryStatus(String mailId, SendMail sendMail);
}
----
각각의 구현 메서드들은 Knox Rest 연계 서비스에서 요구하는 가이드대로 REST 형식을 갖추어 필요한 로직들을 수행한다.
자세한 API 스펙은 Swagger API 문서의 knox-mail-controller 항목을 참고한다. +
메일 발송 샘플 코드는 MailSampleController 소스코드를 참고한다.
IMPORTANT: Knox 연계 메일 발송을 위해서는 발신자/수신자 모두 Knox 계정이 존재해야만 테스트가 가능하다.
@@ -0,0 +1,161 @@
= 메일 그룹 관리
== 개요
메일 그룹 및 맵핑 정보 관리 기능 제공.
== UI Design & Function
=== 메일 그룹 목록(MailGroupList.vue)
메일 그룹 등록, 수정 및 삭제가 가능하다.
image::mailGroupList.png[mailGroupList.png]
* 기능 설명
. 메일 그룹 목록 조회
. 메일 그룹 상세정보 조회
. 메일 그룹 등록 : 등록 버튼 클릭 시 메일 그룹 입력 popup 호출.
. 메일 그룹 수정 : checkbox 선택 후 수정 버튼 클릭 시 변경을 위한 popup 호출.
. 메일 그룹 삭제 : checkbox 선택 후 삭제 버튼 클릭 시 삭제.
=== 메일 그룹 맵핑 수정(MailGroupMappEdit.vue)
메일 그룹 맵핑 목록 등록 및 삭제가 가능하다.
image::mailGroupMappEdit.png[mailGroupMappList.png]
* 기능 설명
. 메일 그룹 맵핑 목록 조회
. 메일 그룹 맵핑 저장
.. 사용자 추가 : 버튼 클릭 시 사용자 추가 popup 호출.
.. 역할 추가 : 버튼 클릭 시 역할 추가 popup 호출.
.. 업무그룹 추가 : 버튼 클릭 시 업무그룹 추가 popup 호출.
== API & Service
=== API
* API : MailGroupController.java
. 메일 그룹 목록 조회 : GET /mail-group-with-paging
. 메일 그룹 상세정보 조회 : GET /mail-group/{mailGroupId}
. 메일 그룹 등록 : POST /mail-group
. 메일 그룹 수정 : PUT /mail-group
. 메일 그룹 삭제 : DELETE /mail-group
. 메일 그룹 맵핑 목록 조회 : GET /mail-group-mapp-with-paging
. 메일 그룹 맵핑 저장 : POST /mail-group-mapp/{mailGroupId}
* Service : MailGroupServiceImpl.java
. 메일 그룹 맵핑 저장 +
맵핑 정보 저장 시 기등록 되어 있는 맵핑 목록 삭제 후
전체 목록을 다시 저장하도록 구현.
[source,java]
----
@Override
@Transactional
public void saveMailGroupMapp(String mailGroupId, List<MailGroupMapp> mailGroupMappList) {
mailGroupDao.deleteMailGroupMapp(mailGroupId);
for(MailGroupMapp mailGroupMapp : mailGroupMappList) {
mailGroupMapp.setMailGroupId(mailGroupId);
mailGroupDao.insertMailGroupMapp(mailGroupMapp);
}
}
----
== Entity Table & SQL
=== Entity Table
* TN_CF_MAIL_GROUP : 메일 그룹
* TN_CF_MAIL_GROUP_MAPP : 메일 그룹 맵핑
=== SQL
. 메일 그룹 목록 조회
[source,xml]
----
<select id="selectMailGroupPagingList" parameterType="java.util.HashMap" resultMap="mailGroupResult">
SELECT T.*
FROM (SELECT ROW_NUMBER() OVER(ORDER BY LABEL ASC) ROWNUM,
--생략--
----
[start=2]
. 메일 그룹 상세정보 조회
[source,xml]
----
<select id="selectMailGroup" parameterType="java.util.HashMap" resultMap="mailGroupResult">
SELECT <include refid="columnMailGroup" />,
(SELECT USER_NAME
--생략--
----
[start=3]
. 메일그룹 등록
[source,xml]
----
<insert id="insertMailGroup" parameterType="java.util.HashMap">
INSERT INTO <include refid="tableMailGroup" />
(<include refid="columnMailGroup" />)
--생략--
----
[start=4]
. 메일그룹 수정
[source,xml]
----
<update id="updateMailGroup" parameterType="java.util.HashMap">
UPDATE <include refid="tableMailGroup" />
SET LABEL = #{label},
--생략--
----
[start=5]
. 메일그룹 삭제
[source,xml]
----
<delete id="deleteMailGroup" parameterType="java.util.HashMap">
UPDATE <include refid="tableMailGroup" />
SET DELETED = '1',
--생략--
----
[start=6]
. 메일그룹 맵핑 목록 조회
[source,xml]
----
<delete id="deleteMailGroup" parameterType="java.util.HashMap">
UPDATE <include refid="tableMailGroup" />
SET DELETED = '1',
--생략--
----
[start=7]
. 메일그룹 맵핑 저장
[source,xml]
----
<delete id="deleteMailGroupMapp" parameterType="java.util.HashMap">
DELETE FROM <include refid="tableMailGroupMapp" />
WHERE MAIL_GROUP_ID = #{mailGroupId}
</delete>
<insert id="insertMailGroupMapp" parameterType="java.util.HashMap">
INSERT INTO <include refid="tableMailGroupMapp" />
(<include refid="columnMailGroupMapp" />)
--생략--
----
@@ -0,0 +1,87 @@
= 메일 상태 조회
== 개요
Knox REST 메일수신상황조회 API와 연계하여 발신한 메일의 상태를 조회할 수 있다.
=== Knox메일 연계 설정
Knox REST 메일수신상황조회를 위해서는 Knox메일 연계 설정이 되어 있어야 한다. +
Knox메일 연계 설정은 <<_메일,메일>> 항목의 <<_knox메일_연계_설정,Knox메일 연계 설정>> 항목을 참조한다.
=== 메일별 수신 상황 카운트 조회
발신한 메일의 메일 아이디값을 이용하여 발신한 메일을 수신한 수신자들의 개봉상태를
요약한 카운트 정보조회
Service:: KnoxMailService
Method::
+
[source,java]
----
/**
* Knox 메일별 수신상태 조회
* @param mailIds Knox 메일 아이디 리스트
* @param sendMail 메일 정보
* @return Knox 메일 상태
*/
MailStatus[] getDeliveryStatusCount(List<String> mailIds, SendMail sendMail);
----
* SendMail 객체에 senderId (발신자 EP ID) 값 설정 필수
=== 수신인 별 수신 상황 조회
발신한 메일의 메일 아이디값을 이용하여 발신한 메일의 수신자 별 수신 상태 정보를 조회
Service:: KnoxMailService
Method::
+
[source,java]
----
/**
* Knox 메일 수신인별 수신상태 조회
* @param mailId Knox 메일 아이디
* @param sendMail 메일 정보
* @return Knox 메일 수신인별 수신상태 정보
*/
Recipient[] getDeliveryStatus(String mailId, SendMail sendMail);
----
* SendMail 객체에 senderId (발신자 EP ID) 값 설정 필수
=== 사용 예
.SentMailHistoryServiceImpl
[source,java]
----
@Override
public Map<String, Object> getSentMail(String mailId) {
Map<String, Object> rtnMap = new HashMap<>();
MailStatus mailStatus = new MailStatus();
List<Recipient> recipientList;
List<String> mailIds = new ArrayList<>();
mailIds.add(mailId);
SendMail sendMail = sentMailHistoryDao.getSentMail(mailId);
try {
// 14일 이전 문서는 Knox에서 조회
mailStatus = knoxMailService.getDeliveryStatusCount(mailIds, sendMail)[0]; // <1>
recipientList = Arrays.asList(knoxMailService.getDeliveryStatus(mailId, sendMail)); // <2>
if (ObjectUtils.isNotEmpty(recipientList)) {
// 메일 수신 상태 동기화
updateRecipient(mailId, recipientList);
} else {
recipientList = sentMailHistoryDao.getRecipientList(mailId);
}
} catch (Exception ex) {
log.error(ex.getMessage());
//Knox 에서 메일을 조회 할수 없을 경우, 14일이 경과 되었거나 Mail Box를 못찾을 경우
recipientList = sentMailHistoryDao.getRecipientList(mailId);
}
rtnMap.put("mailStatus", mailStatus);
rtnMap.put("recipientList", recipientList);
rtnMap.put("sendMail", sendMail);
return rtnMap;
}
----
<1> Knox 메일별 수신자들의 개봉상태 카운트 조회
<2> Knox 수신인 별 메일 수신 상황 조회
@@ -0,0 +1,58 @@
= 메일 양식 관리
== 개요
메일 양식을 관리한다. +
<<_결재_양식_관리,결재 양식 관리>>와 비교해서 'MAIL'로 조회하는 것 외에 동일하다.
== Table
* 템플릿 : TN_CF_TEMPLATE
== API
.TemplateController.java
. 템플릿 목록 조회(페이징) +
GET /templates-with-paging/group/{templateGroupCode} +
Query ID : selectTemplatePagingList
* TEMPLATE_GROUP_CODE 컬럼의 'MAIL'을 조회한다.
. 템플릿 상세 조회 +
GET /templates/group/{templateGroupCode}/key/{templateKey} +
Query ID : selectTemplate
. 템플릿 상세 조회 (By ID) +
GET /templates/{id} +
Query ID : selectTemplate
* 양식의 상세 내용을 조회 하거나 팝업 미리보기를 할 수 있다.
. 템플릿 Key 중복 체크 +
GET /templates/dup-check/group/{templateGroupCode}/key/{templateKey} +
Query ID : selectTemplate
* 저장 전 템플릿 Key 중복 여부를 검사한다.
. 템플릿 등록 +
POST /templates/group/{templateGroupCode} +
Query ID : insertTemplate
* 양식을 저장한다.
. 템플릿 수정 +
POST /templates/{id} +
Query ID : updateTemplate
. 템플릿 삭제 +
DELETE /templates/{id} +
Query ID : deleteTemplate
== 화면
메일양식을 관리기능 > 결재/메일관리 > 메일양식 관리를 통해 할 수 있다.
image::mailTemplate.png[]
* 등록된 메일양식 목록을 메일양식 관리를 통해 볼 수 있다.
* 목록의 Key 컬럼을 클릭하여 메일양식 정보를 수정할 수 있다.
* 팝업 미리보기 컬럼을 클릭하여 등록된 메일양식의 첨부파일을 확인 할 수 있다.
image::mailTemplate1.png[]
* Key : 유니크한 메일양식 키를 지정(영문, 숫자만 가능)
* 제목 : 메일양식의 제목
* 설명 : 메일양식의 설명
* 첨부파일 : 메일양식 첨부파일
@@ -0,0 +1,19 @@
= 보낸 메일 이력
== 개요
메일 발송 내역 및 수신 상태를 조회할 수 있다.
=== 보낸 메일 목록
image::sentMailHistory.png[]
<1> 기간, 제목별 검색 가능
<2> 클릭시 상세 내역 조회
=== 보낸 메일 상세 정보
image::sentMailHistoryInfo.png[]
<1> 보낸 메일의 수신인별 개봉 여부
<2> 보낸 메일 본문 확인 가능
<3> 수신인과 수신상태 정보 목록
@@ -0,0 +1,93 @@
= 임직원
== 개요
Knox Portal에서 제공하는 임직원 관련 Rest API 를 이용한 연계 서비스 제공
=== Knox REST API 연계 서비스 신청
Knox REST API 연계 서비스 신청은 <<_knox_rest_api_연계_서비스_신청,Knox REST API 연계 서비스 신청>> 항목을 참조한다.
=== Knox임직원 연계 설정
Knox REST API 연계 서비스 신청이 되었다면, 발급받은 `system-id`, `token` 값을 설정한다.
.knox.properties (스테이지)
[source,properties]
----
knox.system-id=xxxxxxxxxxx
knox.token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
knox.address.prefix=openapi.samsung.net
knox.emp-service=/employee/api/v2.0
----
.knox.properties (운영)
[source,properties]
----
knox.system-id=xxxxxxxxxxx
knox.token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // <1>
knox.address.prefix=openapi.samsung.net,openapi.w1.samsung.net,openapi.w2.samsung.net # <2>
knox.emp-service=/employee/api/v2.0
----
<1> 토큰 (comma(,)로 구분, 거점 순서와 동일)
<2> 거점 (국내, 구주, 미주)
=== Knox임직원 API 연계 서비스
Knox REST API 연계를 통해서 임직원 및 조직 정보 조회 기능을 제공하는 서비스로 주요 메서드는 KnoxUserService 인터페이스에 정의되어 있다.
KnoxUserService는 시스템에서 임직원 및 조직 정보를 조회할때 필요한 API들을 제공한다.
[source, java]
----
public interface KnoxUserService {
/**
* Knox 임직원 조회(By EpId)
* @param epId EP ID
* @return Knox 사용자
*/
Employee[] getKnoxEmployeesByEpId(String epId);
/**
* Knox 임직원 조회(By UserName)
* @param userName 사용자 이름
* @return Knox 사용자
*/
Employee[] getKnoxEmployeesByUserName(String userName);
/**
* Knox 임직원 조회(By KnoxId)
* @param knoxId Knox ID
* @return Knox 사용자
*/
Employee[] getKnoxEmployeesByKnoxId(String knoxId);
/**
* Knox 임직원 조회(By Email)
* @param email 이메일
* @return Knox 사용자
*/
Employee[] getKnoxEmployeesByEmail(String email);
/**
* Knox 조직도 조회(By CompanyCode)
* @param companyCode 회사 코드
* @return Knox 조직도
*/
Organization[] getKnoxOrganizationsByCompanyCode(String companyCode);
/**
* Knox 조직도 조회(By DepartmentCode)
* @param companyCode 회사 코드
* @param departmentCode 부서 코드
* @return Knox 조직도
*/
Organization[] getKnoxOrganizationsByDepartmentCode(String companyCode, String departmentCode);
/**
* Knox 직급 조회
* @param companyCode 회사 코드
* @return Knox 직급
*/
Title[] getKnoxTitles(String companyCode);
}
----
자세한 API 스펙은 Swagger API 문서의 knox-user-controller 항목을 참고한다.
@@ -0,0 +1,132 @@
= 주소록
== 개요
Knox Portal에서 제공하는 연락처 관련 Rest API 를 이용한 연계 서비스 제공
=== Knox REST API 연계 서비스 신청
Knox REST API 연계 서비스 신청은 <<_knox_rest_api_연계_서비스_신청,Knox REST API 연계 서비스 신청>> 항목을 참조한다.
=== Knox Rest 연락처 연계 설정
메일, 결재 Knox Rest API 연계와 마찬가지로 연계를 위한 사전 준비가 되었다면, knox.properties 에 연락처 관련 설정이 되어 있는지 확인한다.
.knox.properties
[source,properties]
----
knox.pims-service=/pims/contacts/api/v2.0
----
=== Knox 연락처 연계 서비스
REST를 통해서 연락처를 연계하는 서비스로 주요 메서드는 KnoxContactService 인터페이스에 정의되어 있다.
[source, java]
----
public interface KnoxContactService {
/**
* 연락처 그룹 생성
* @param contactGroupDto
* @param userId
* @return
*/
ContactGroupDto createGroup(ContactGroupDto contactGroupDto, String userId);
/**
* 연락처 그룹 수정
* @param groupId
* @param contactGroupDto
* @param userId
* @return
*/
ContactGroupDto updateGroup(String groupId, ContactGroupDto contactGroupDto, String userId);
/**
* 연락처 그룹 삭제
* @param groupId
* @param userId
* @return
*/
String deleteGroup(String groupId, String userId);
/**
* 연락처 그룹 조회
* @param groupId
* @param userId
* @return
*/
ContactGroupDto getGroup(String groupId, String userId);
/**
* 연락처 그룹 목록 조회
* @param pubType
* @param userId
* @return
*/
ContactGroupDto[] getGroups(String pubType, String userId);
/**
* 연락처 생성
* @param contactDto
* @param userId
* @return
*/
ContactDto createCard(ContactDto contactDto, String userId);
/**
* 연락처 수정
* @param contactId
* @param contactDto
* @param userId
* @return
*/
ContactDto updateCard(String contactId, ContactDto contactDto, String userId);
/**
* 연락처 삭제
* @param contactId
* @param userId
* @return
*/
String deleteCard(String contactId, String userId);
/**
* 연락처 조회
* @param contactId
* @param userId
* @return
*/
ContactDto getCard(String contactId, String userId);
/**
* 연락처 목록 조회
* @param pubType
* @param userId
* @return
*/
ContactDto[] getCards(String pubType, String userId);
/**
* KNOX REST GET MAPPING
* @param <T>
* @param methodName
* @param params
* @param paths
* @param classType
* @return
*/
<T> T contactsGet(String methodName, MultiValueMap<String, String> params, Map<String, String> paths, Class<T> classType);
/**
* KNOX REST POST MAPPING
* @param <T>
* @param methodName
* @param bodyMap
* @param params
* @param paths
* @param classType
* @return
*/
<T> T contactsPost(String methodName, Map<String, Object> bodyMap, MultiValueMap<String, String> params, Map<String, String> paths, Class<T> classType);
}
----
자세한 API 스펙은 Swagger API 문서의 knox-contact-controller 항목을 참고한다.