SpringBoot - 자동 특허명세서 생성 서식 API

Yu Seong Kim·2025년 5월 7일
0

SpringBoot

목록 보기
26/29

개요

업체에서 사용할 WordAPI를 이용하여 특허 명세서를 자동으로 만들어주는 API를 개발하였습니다.
즉, 변리사분들은 아래 사진과 같이 명세서를 직접 입력하여 관리,작업을 진행합니다. 그러나 이러한 과정들을 최소화 하기 위하여 WordAPI를 제작하고, 그것을 API로 만들어 보았습니다.

WordAPI는 사내서버에서 관리되기 때문에 비공개합니다. 결과물과 API를 가져오는 방식 위주로 보시면 되겠습니다.

실제 키프리스에 공개된 특허 명세서 입니다. 기술분야, 배경기술, 내용, 과제, 청구항, 도면 등 다양한 소제목과 내용들로 이루어져 있고, 명세서는 이 틀을 크게 벗어나지 않거나 동일합니다.

WordAPI 란

  • 사용자가 개인 서식에 자신이 원하는 데이터를 {{}} 안에 넣습니다.
  • 예를들면 {{등록일}} , {{출원번호}} 등등
  • 그럼 해당 변리사가 쓰는 프로그램에서 자동으로 그 데이터를 저기있는 변수와 매칭이되고, 치환이 되어 프로그램 값이 들어갑니다. 그렇다면 변리사는 직접 수기로 입력하는 것이 아닌 자동으로 명세서에 데이터가 삽입이 될 것입니다.
  • Python Jinja2로 만들어졌습니다.

원리

  • 해당 데이터의 ID로 요청을 하면 그 ID에 있는 명세서 칼럼들이 서식에 있는 변수로 치환이 됩니다.
  • 그럼 WordAPI에서 서식 변수를 치환한다음 서식에 데이터가 삽입된 .docx 파일을 응답으로 반환합니다.
  • 그럼 사용자는 바로 다운로드를 받을 수 있고, 해당 파일은 출원번호+날짜로 만들어 집니다.

프로젝트 구조

해당 프로젝트에서 보안관련된 내용들은 지웠습니다.

서비스단 로직 설명

  1. ID 로 데이터 조회 → wordDao.findSpecification(id) 호출 해서 Description,Claim 정보 한 번에 가져옴
  2. 모든 데이터는 Dto로 변환

JSON 변환 및 데이터 확인

  1. DesctiptionResponseDto, ClaimResponseDto를 JSON 변환
  2. 로그로 JSON 변환 확인

외부 API 호출

  1. Form Data 방식으로 데이터 구성
  2. WebClient로 외부 API 호출
    • POST()
  3. 응답 데이터를 byte[]로 변환
    • 외부 API 응답을 **바이너리 데이터(byte[])로 수신

Word 파일 생성 및 반환

  1. 응답 데이터를 ByteArrayResouces로 변환
    • 파일 다운로드를 위한 설정 수행 (Content-Disposition 헤더 설정)
  2. ResponseEntity로 HTTP 응답 반환
    • 파일 다운로드 가능하도록 설정 (attachment; fimename=generated_word_id.docx)
  3. 동기 실행 (block())
    • WebClient의 비동기 호출을 동기 처리하여 즉시 실행 완료

📝 최종 정리

  1. DB에서 데이터 조회 → Description & Claim 변환
  2. ID 제외한 데이터만 JSON으로 변환 & 로깅
  3. WebClient로 외부 API 호출 (POST, Form Data)
  4. 응답 데이터를 Word 파일로 변환 & 다운로드 가능하도록 반환

🚀 결과: DB 데이터 기반 Word 파일 생성 & API 응답으로 파일 다운로드

테스트 중 트러블 슈팅

2025-03-07 11:18:08.024 ERROR 37064 --- [ctor-http-nio-2] o.s.s.service.Impl.WordApiServiceImpl
: API 요청 실패: 상태코드=500 INTERNAL_SERVER_ERROR, 응답=<!doctype html><html lang="en"><head><title>HT
TP Status 500 – Internal Server Error</title><style type="text/css">body {font-family:Tahoma,Arial
,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-si
ze:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-co
lor:#525D76;border:none;}</style></head><body><h1>HTTP Status 500 – Internal Server Error</h1><hr class="
line" /><p><b>Type</b> Exception Report</p><p><b>Message</b> A JSONObject text must begin with '{' at 1 
[character 2 line 1]</p><p><b>Description</b> The server encountered an unexpected condition that 
prevented it from fulfilling the request.</p><p><b>Exception</b></p><pre>org.json.JSONException: A JSONObject text must begin with '{' at 1 [character 2 line 1]
org.json.JSONTokener.syntaxError(JSONTokener.java:433)

-수정 전-
Sending JSON Data: {"title":"인공지능 기반 헬스케어 장치{ARTIFICIAL INTELLIGENCE-BA...
Sending JSON Claims: [{"claim":"기업용 학습 시스템 제공방법으로서, \n(a) 기업 ...

만들어진 WordAPI에 json 형식을 잘못보내었다.

-수정 후 -
Sending JSON Data: {"title":"인공지능 기반 헬스케어 장치{ARTIFICIAL INTELLIGENCE-BASED ....
Sending JSON Claims: {"claims":[{"claim":"기업용 학습 시스템 제공방법으로서, \n(a).....

post → 실패 그 유 Claim 리스트에서 앞에 []가 붙어있어서 json 파싱이 실패했다고 판단.

so. []를 제외하고 반환하도록 수정

서식 만들기

이 서식을 메인 서버에 올리면 사용자들이 입력한 데이터가 해당 서버의 서식에 가서 치환하고, 치환된 서식 파일을 돌려 받습니다.

서식은 Jinja2로 만들었습니다.

postman


swagger

잘 나옵니다.

WordAPI 불러오는 WebClient Return문 정리

return webClient.post()
                        .uri(externalApiUrl)
                        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                        .body(BodyInserters.fromFormData(formData))
                        .retrieve()
                        //에러처리하는부분
                        .onStatus(HttpStatus::isError, clientResponse ->
                                clientResponse.bodyToMono(String.class)
                                        .flatMap(errorBody -> {
                                            log.error("API 요청 실패: 상태코드={}, 응답={}", clientResponse.statusCode(), errorBody);
                                            return Mono.error(new RuntimeException("Word API 요청 실패: " + errorBody));
                                        })
                        )
                        .bodyToMono(byte[].class)
                        .map(fileBytes -> {
                            ByteArrayResource byteArrayResource = new ByteArrayResource(fileBytes);
                            HttpHeaders headers = new HttpHeaders();
                            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=GenIP_word_" + id + ".docx");
                            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);

                            return ResponseEntity.ok()
                                    .headers(headers)
                                    .body(byteArrayResource);
                        })
                        .block(); // 동기 실행

이렇게 특허 명세서를 자동으로 만들어주는 API를 만들어보았습니다.

profile
인생을 코딩하는 남자.

0개의 댓글