Coding/API

GitLab Repository API 사용방법 (Upload, Download)

왓츠뉴 whatsnew 2024. 12. 18. 15:06
반응형

1. GitLab Access Tokens 발급

 

GitLab 마이페이지-Settings-Access Token에 들어갑니다.

아래의 항목들을 입력하고 "Create personal access token"을 클릭합니다.

 

Name - 아무거나

Expires at - 만료기간으로 현재 날짜부터 최대 1년까지 설정할 수 있습니다.

Scopes - 모두 선택합니다.

 

 

Feed token에 토큰이 생성된 걸 볼 수 있습니다.

이 토큰을 활용해서 gitLab의 Repository API를 사용해 볼께요.

 

2. gitLab Repository API란?

이번에 회사에서 sql query로 DB의 데이터베이스 목록을 조회하고

조회한 데이터베이스 목록 결과를 poi 라이브러리로 엑셀파일로 그린 다음

생성된 엑셀 파일을 gitLab에 업로드하는 기능을 만들게 되었습니다.

gitLab은 git으로서의 기능으로만 활용해봤지,

직접 gitLab에 파일을 올린다거나 다운받는게 가능한지 모르고 있었는데요?

 

그걸 가능하게 해주는 gitLab에서 제공하는 API가, gitLab Repository API 입니다.

그리고 gitLab API를 사용하려면 1번에서 발급받은 Access Tokens이 필요하구요~

 


3. gitLab Upload 기능 구현하기

파일은 byte[] 파일을 기준으로 합니다.

조회한 쿼리 결과를 byte[] 파일로 작성하고, 만들어진 byte[] 파일을

gitLab 특정 Repository의, 특정 폴더에 올려보도록 하겠습니다.

 

(1) 업로드 될 폴더 생성

먼저, 개발하고 있는 프로젝트 하위에 엑셀파일이 업로드 될 폴더를 만들었습니다.

 

(2) gitLab에 파일 업로드 기능 작성

import lombok.extern.slf4j.Slf4j;

import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

@Slf4j
public class GitLabUploader {
    // GitLab API 토큰과 프로젝트 정보 설정
    private static final String GITLAB_TOKEN = "1번에서 받은 Access Tokens"; // GitLab Personal Access Token
    private static final String GITLAB_API_URL = "https://git.herit.co.kr/api/v4"; // GitLab API URL(고정값. 동일하게 작성)
    private static final String PROJECT_ID = "your_project_id"; // 프로젝트 ID ex: "12164"
    private static final String BRANCH = "업로드할 브랜치 이름"; //  ex: "main"

    public static void uploadFileToGitLab(String filePath, byte[] fileContent, String commitMessage) {
        try {
            // GitLab API URL 구성
            String urlString = GITLAB_API_URL + "/projects/" + PROJECT_ID + "/repository/files/" + filePath.replace("/", "%2F");
            URL url = new URL(urlString);

            // 파일 내용을 Base64로 인코딩 : 인코딩이 필수라고 합니다. 파일 자체로 올리고 싶은데... 이건 좀 더 연구해볼께요
            String encodedContent = Base64.getEncoder().encodeToString(fileContent);

            // JSON 요청 본문 생성
            String jsonBody = "{"
                    + "\"branch\": \"" + BRANCH + "\","
                    + "\"content\": \"" + encodedContent + "\","
                    + "\"commit_message\": \"" + commitMessage + "\""
                    + "}";

            log.info("JSON Body: {}", jsonBody); // 요청 본문 로그 확인

            // HTTP 요청 설정
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/json");
            connection.setRequestProperty("PRIVATE-TOKEN", GITLAB_TOKEN);
            connection.setDoOutput(true);

            // 요청 본문 전송
            try (OutputStream os = connection.getOutputStream()) {
                byte[] input = jsonBody.getBytes(StandardCharsets.UTF_8);
                os.write(input, 0, input.length);
            }

            // 응답 코드 확인
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_CREATED) {
                log.info("File uploaded successfully to GitLab: " + responseCode);
            } else {
               throw new Exception("Failed to upload file. HTTP response code: " + responseCode);
            }

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Error uploading file to GitLab: " + e.getMessage());
        }
    }
}

 

(3) 위의 업로드 클래스를 호출하는 서비스코드 구현

조회한 데이터베이스 쿼리결과를 byte[]로 담아서, (2)의 uploadFileToGitLab로 던져 gitLab에 업로드 명령을 내립니다.

public Response uploadTableGitLab(HashMap<String, Object> param) {
        Response response = null;
        byte[] excelFile;
        // 파일 작성
        try {
            excelFile = downloadSpec(param);
        } catch (Exception e) {
            e.printStackTrace();
            return response = CommonRes.builder()
                    .rsp_cd(HttpResponseStatus.SYSTEM_ERROR.getCode())
                    .rsp_msg(HttpResponseStatus.SYSTEM_ERROR.getDescription())
                    .build();
        }
        // 파일 업로드
        String fileName = "";
        try {
            if (excelFile != null) {
                // Git-Lab 폴더에 업로드
                List<String> schemaList = (List<String>) param.get("schema");
                LocalDateTime now = LocalDateTime.now();
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmm");
                String formattedDate = now.format(formatter);
                fileName = "tablespec_" + schemaList.get(0) + "_" + formattedDate + ".xlsx";
                String commitMessage = "Upload table specification file: " + fileName; //커밋메세지
                // GitLab 내 파일 경로 설정
                String filePath = "src/main/java/net/herit/rookieV2/features/tablespec/docs/" + fileName; 

                GitLabUploader.uploadFileToGitLab(filePath, excelFile, commitMessage);
            } else {
                return response = CommonRes.builder()
                        .rsp_cd(HttpResponseStatus.NOT_EXIST_DATA.getCode())
                        .rsp_msg(HttpResponseStatus.NOT_EXIST_DATA.getDescription())
                        .build();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return response = CommonRes.builder()
                    .rsp_cd(HttpResponseStatus.SYSTEM_ERROR.getCode())
                    .rsp_msg(HttpResponseStatus.SYSTEM_ERROR.getDescription())
                    .build();
        }

        response = TableSpecResponse.FileName.builder()
                .fileName(fileName)
                .build();

        return response;
    }

"// GitLab 내 파일 경로 설정" 부분에 실제 파일이 업로드 될 폴더 경로를 적어줍니다.

프로젝트명 하위인 "src/~파일업로드될폴더/"로 작성해주시면 됩니다.

 

(4) 위의 서비스를 호출하는 API 컨트롤러 작성

@Slf4j
@Api(tags = "테이블 명세화")
@RequestMapping("/tablespec")
@RestController
public class TableSpecController {
    @Autowired
    private TableSpecService svc;
    @Autowired
    private ExcelService svcExc;
    @Autowired
    private FileService fileReaderService;

    @Value("${spring.datasource.schema}")
    public String dbSchema;

    @Autowired(required=true)
    private HttpServletRequest request;
    
    @NonAuth
    @ApiOperation(value="04. 테이블 엑셀 GIT 업로드", notes = "테이블 명세 조회내역을 엑셀파일로 생성하여 업로드 합니다.", produces = "application/json", response = TableSpecResponse.Result.class)
    @ApiResponses({
            @ApiResponse(code = 200, message = "", response = TableSpecResponse.Result.class)
    })
    @PostMapping("/uploadGitLab")
    @LogTracer(apiAppType = "postman", logType = "API", apiClass = "PROC_TEST", svcClass = "JSON")
    public ResponseEntity<Response> uploadTableGitLab(@RequestBody @Valid TableSpecRequest.Search req) throws Exception {
        Response response = null;

        HashMap<String, Object> param = new HashMap<>();
        param.put("schema", req.getSchema());

        response = svcExc.uploadTableGitLab(param); //서비스 호출

        log.info(CommonUtil.responseToResponseBody(response));

        return new ResponseEntity<Response>(response, HttpStatus.OK);
    }
 }

 

(5) postman으로 테스트

gitLab에 Base64로 인코딩 된 파일이 업로드 되고,

업로드 된 파일명이 fileName으로 응답하도록 구현하였습니다.


4. gitLab Download 기능 구현하기

(1) gitLab에 파일 다운로드 기능 작성

파일업로드때 처럼, 파일 다운로드 기능을 작성합니다.

import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

@Slf4j
public class GitLabDownloader {
    // GitLab API 토큰과 프로젝트 정보 설정
    private static final String GITLAB_TOKEN = "1에서 발급받은 Access Token"; // GitLab Personal Access Token
    private static final String GITLAB_API_URL = "https://git.herit.co.kr/api/v4"; // GitLab API URL(고정값. 그대로 사용)
    private static final String PROJECT_ID = "프로젝트 ID"; //  ex: "15123"
    private static final String BRANCH = "다운로드할 브랜치 이름"; //ex: "main"
    /**
     * GitLab에서 파일을 다운로드하고 byte[]로 반환하는 메서드
     *
     * @param filePath GitLab 내 파일 경로 (예: "path/to/file.xlsx")
     * @return 파일 내용의 byte[] 데이터
     * @throws Exception 파일 다운로드 실패 시 예외 발생
     */
    public static byte[] downloadFileFromGitLab(String filePath) throws Exception {
        // GitLab API 파일 다운로드 URL 생성
        String encodedPath = URLEncoder.encode(filePath, StandardCharsets.UTF_8)
                .replace("+", "%20");  // 공백을 %20으로 변환 : / -> %2F

        String urlString = GITLAB_API_URL + "/projects/" + PROJECT_ID + "/repository/files/"
                + encodedPath + "/raw?ref=" + BRANCH; // raw 작성 : 파일 정보가 아닌 파일의 내용을 읽고 싶을 때. 파일 정보까지 읽으려면 ?ref=만 작성

        URL url = new URL(urlString);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET"); //꼭, GET으로 요청해야함.
        connection.setRequestProperty("PRIVATE-TOKEN", GITLAB_TOKEN);

        // 응답 코드 확인
        int responseCode = connection.getResponseCode();
        if (responseCode == HttpURLConnection.HTTP_OK) {
            // Content-Type 체크
            String contentType = connection.getContentType();
            log.info(contentType);

            // InputStream을 byte[]로 변환하는 메소드
            try (InputStream inputStream = connection.getInputStream();
                 ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {

                byte[] data = new byte[4096]; // 4KB 버퍼
                int nRead;

                // InputStream에서 데이터를 읽어서 ByteArrayOutputStream에 저장
                while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
                    buffer.write(data, 0, nRead);
                }

                buffer.flush(); // 데이터를 완전히 기록 (ByteArrayOutputStream에서는 선택적)

                log.info(buffer.toByteArray().toString());
                return buffer.toByteArray(); // 최종 byte[] 반환
            }
        } else {
            log.error("Failed to download file from GitLab. Response Code: {}", responseCode);
            throw new Exception("Failed to download file from GitLab. Response Code: " + responseCode);
        }
    }
}

신기했던건, 테스트 도중 엑셀파일을 poi로 작성하지 않고

이미 완성된 .xlsx파일을 임의로 gitLab폴더에 올려놓은뒤

위의 다운로드 api로 다운받아보니, 정상적으로 다운받아지고 엑셀파일이 열렸습니다.

디코딩 기능이 들어있지만, 일반 파일도 다 다운받아지는듯!

(2) 위의 다운로드 클래스를 호출하는 서비스코드 구현

@Slf4j
@Service
public class ExcelService {
    @Autowired
    private TableSpecService tableSpecService;
    @Autowired
    public ImportExcelService createExc;
    @Autowired
    private ExcelProperties excelProperties;
public byte[] downloadTableGitLab(HashMap<String, Object> param) {
        byte[] fileData;
        try {
            // Git-Lab 폴더에서 'fileName'의 파일 다운로드
            String fileName = param.get("fileName").toString();
            String filePath = "src/main/java/net/herit/rookieV2/features/tablespec/docs/" + fileName; // GitLab 내 파일 경로 설정

            fileData = GitLabDownloader.downloadFileFromGitLab(filePath);
            // 파일 데이터가 비어있지 않은지 검증
            if (fileData == null || fileData.length == 0) {
                throw new Exception("File is empty or failed to download.");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new CommonException(HttpResponseStatus.SYSTEM_ERROR);
        }
        return fileData;
    }
}

(3) 위의 서비스를 호출하는 API 컨트롤러 작성

@Slf4j
@Api(tags = "테이블 명세화")
@RequestMapping("/tablespec")
@RestController
public class TableSpecController {
    @Autowired
    private TableSpecService svc;
    @Autowired
    private ExcelService svcExc;
    @Autowired
    private FileService fileReaderService;

    @Value("${spring.datasource.schema}")
    public String dbSchema;

    @Autowired(required=true)
    private HttpServletRequest request;
    @NonAuth
    @ApiOperation(value="05. 테이블 엑셀 GIT 다운로드", notes = "테이블 명세 조회내역을 엑셀파일로 생성하여 업로드 합니다."
            , produces = "application/json", response = TableSpecResponse.Result.class)
    @ApiResponses({
            @ApiResponse(code = 200, message = "", response = TableSpecResponse.Result.class)
    })
    @PostMapping("/downloadGitLab")
    @LogTracer(apiAppType = "postman", logType = "API", apiClass = "PROC_TEST", svcClass = "JSON")
    public ResponseEntity<byte[]> downloadTableGitLab(@RequestBody @Valid TableSpecRequest.Excel req) throws Exception {

        HashMap<String, Object> param = new HashMap<>();
        param.put("fileName", req.getFileName());

        // 파일 다운로드 서비스 호출
        byte[] excelFile = svcExc.downloadTableGitLab(param);

        // HTTP 응답 헤더 설정
        HttpHeaders headers = new HttpHeaders();
//        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        // HTTP 응답 헤더 설정 (파일 다운로드용)
        headers.setContentType(MediaType.valueOf("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
        headers.setContentDispositionFormData("attachment", req.getFileName());
        headers.setContentLength(excelFile.length);

        /*정상적으로 파일은 다운로드되었으나, 내용이 비어있는 상황은 주로 다음과 같은 원인이 있을 수 있습니다:

         * 파일 경로가 잘못되어 실제 데이터가 없는 경우
         * 인코딩이나 바이트 처리 시 중간 데이터 손실
         * API 호출에서 Content-Type을 명시적으로 처리하지 않는 경우 */
        return new ResponseEntity<>(excelFile, headers, HttpStatus.OK);
    }
}

컨트롤러 쪽은 업로드와 다르게 헤더 설정이 있으니

유의해서 참고해주세요.

(4) postman으로 테스트

request로 gitLab에 올라가있는 파일 중

다운로드 받을 파일명을 fileName에 작성해서 "Send and Download"로 요청하면

이렇게 다운로드 받을 수 있습니다.

 

728x90
반응형