모델관리 zip 파일 읽는 로직(대략 구조만) 커밋
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
package com.kamco.cd.kamcoback.common.utils.zip;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class CsvFileProcessor implements ZipEntryProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(String fileName) {
|
||||||
|
return fileName.toLowerCase().endsWith(".csv");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(String fileName, InputStream is) throws IOException {
|
||||||
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
|
||||||
|
br.lines()
|
||||||
|
.forEach(
|
||||||
|
line -> {
|
||||||
|
String[] cols = line.split(",");
|
||||||
|
// CSV 처리
|
||||||
|
for (String col : cols) {
|
||||||
|
log.info(col); //TODO : 추후에 csv 파일 읽어서 작업 필요할 때 정의하기
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package com.kamco.cd.kamcoback.common.utils.zip;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonFactory;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.core.JsonToken;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class JsonStreamingFileProcessor implements ZipEntryProcessor {
|
||||||
|
|
||||||
|
private final JsonFactory jsonFactory;
|
||||||
|
|
||||||
|
public JsonStreamingFileProcessor(ObjectMapper objectMapper) {
|
||||||
|
// ZipInputStream 보호용 설정
|
||||||
|
objectMapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false);
|
||||||
|
this.jsonFactory = objectMapper.getFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(String fileName) {
|
||||||
|
return fileName.toLowerCase().endsWith(".json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(String fileName, InputStream is) throws IOException {
|
||||||
|
|
||||||
|
log.info("JSON process start: {}", fileName);
|
||||||
|
|
||||||
|
JsonParser parser = jsonFactory.createParser(is);
|
||||||
|
|
||||||
|
// JSON 구조에 상관없이 token 단위로 순회
|
||||||
|
while (parser.nextToken() != null) {
|
||||||
|
handleToken(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("JSON process end: {}", fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleToken(JsonParser parser) throws IOException {
|
||||||
|
JsonToken token = parser.currentToken();
|
||||||
|
|
||||||
|
if (token == JsonToken.FIELD_NAME) {
|
||||||
|
String fieldName = parser.getCurrentName();
|
||||||
|
//TODO: json 파일 읽어야 할 내용 정의되면 항목 확정하기
|
||||||
|
switch (fieldName) {
|
||||||
|
case "type" -> {
|
||||||
|
parser.nextToken();
|
||||||
|
String type = parser.getValueAsString();
|
||||||
|
log.info("type: {}", type);
|
||||||
|
}
|
||||||
|
case "name" -> {
|
||||||
|
parser.nextToken();
|
||||||
|
String name = parser.getValueAsString();
|
||||||
|
log.info("Name: {}", name);
|
||||||
|
}
|
||||||
|
case "features" -> {
|
||||||
|
parser.nextToken();
|
||||||
|
String features = parser.readValueAsTree().toString();
|
||||||
|
log.info("features: {}", features);
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
parser.nextToken();
|
||||||
|
parser.skipChildren();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.kamco.cd.kamcoback.common.utils.zip;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class TextFileProcessor implements ZipEntryProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(String fileName) {
|
||||||
|
return fileName.toLowerCase().endsWith(".txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(String fileName, InputStream is) throws IOException {
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
log.info(line); //TODO : 추후 txt 파일 읽어서 작업할 때 정의하기
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.kamco.cd.kamcoback.common.utils.zip;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public interface ZipEntryProcessor {
|
||||||
|
|
||||||
|
boolean supports(String fileName);
|
||||||
|
|
||||||
|
void process(String fileName, InputStream is) throws IOException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.kamco.cd.kamcoback.common.utils.zip;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class ZipUtils {
|
||||||
|
|
||||||
|
private final List<ZipEntryProcessor> processors;
|
||||||
|
|
||||||
|
public ZipUtils(List<ZipEntryProcessor> processors) {
|
||||||
|
this.processors = processors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void processZip(InputStream zipStream) throws IOException {
|
||||||
|
try (ZipInputStream zis = new ZipInputStream(zipStream)) {
|
||||||
|
|
||||||
|
ZipEntry entry;
|
||||||
|
while ((entry = zis.getNextEntry()) != null) {
|
||||||
|
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String fileName = entry.getName();
|
||||||
|
processors.stream()
|
||||||
|
.filter(p -> p.supports(fileName))
|
||||||
|
.findFirst()
|
||||||
|
.ifPresent(
|
||||||
|
processor -> {
|
||||||
|
try {
|
||||||
|
processor.process(fileName, zis);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new UncheckedIOException(ioe);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
zis.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.kamco.cd.kamcoback.model;
|
package com.kamco.cd.kamcoback.model;
|
||||||
|
|
||||||
|
import com.kamco.cd.kamcoback.common.utils.zip.ZipUtils;
|
||||||
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
|
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
|
||||||
import com.kamco.cd.kamcoback.model.dto.ModelMngDto;
|
import com.kamco.cd.kamcoback.model.dto.ModelMngDto;
|
||||||
import com.kamco.cd.kamcoback.model.service.ModelMngService;
|
import com.kamco.cd.kamcoback.model.service.ModelMngService;
|
||||||
@@ -10,15 +11,21 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
|||||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.transaction.Transactional;
|
import jakarta.transaction.Transactional;
|
||||||
|
import java.io.IOException;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@Tag(name = "모델 관리", description = "모델 관리 API")
|
@Tag(name = "모델 관리", description = "모델 관리 API")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -29,45 +36,54 @@ public class ModelMngApiController {
|
|||||||
|
|
||||||
private final ModelMngService modelMngService;
|
private final ModelMngService modelMngService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ZipUtils zipUtils;
|
||||||
|
|
||||||
@Operation(summary = "모델관리 목록")
|
@Operation(summary = "모델관리 목록")
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public ApiResponseDto<Page<ModelMngDto.ModelList>> findModelMgmtList(
|
public ApiResponseDto<Page<ModelMngDto.ModelList>> findModelMgmtList(
|
||||||
@RequestParam(required = false) LocalDate startDate,
|
@RequestParam(required = false) LocalDate startDate,
|
||||||
@RequestParam(required = false) LocalDate endDate,
|
@RequestParam(required = false) LocalDate endDate,
|
||||||
@RequestParam(required = false, defaultValue = "createCompleteDttm") String sortColumn,
|
@RequestParam(required = false, defaultValue = "createCompleteDttm") String sortColumn,
|
||||||
@RequestParam(required = false) String modelType,
|
@RequestParam(required = false) String modelType,
|
||||||
@RequestParam(required = false) String searchVal,
|
@RequestParam(required = false) String searchVal,
|
||||||
@RequestParam(defaultValue = "0") int page,
|
@RequestParam(defaultValue = "0") int page,
|
||||||
@RequestParam(defaultValue = "20") int size) {
|
@RequestParam(defaultValue = "20") int size) {
|
||||||
ModelMngDto.searchReq searchReq = new ModelMngDto.searchReq(page, size, sortColumn + ",desc");
|
ModelMngDto.searchReq searchReq = new ModelMngDto.searchReq(page, size, sortColumn + ",desc");
|
||||||
|
|
||||||
Page<ModelMngDto.ModelList> result =
|
Page<ModelMngDto.ModelList> result =
|
||||||
modelMngService.findModelMgmtList(searchReq, startDate, endDate, modelType, searchVal);
|
modelMngService.findModelMgmtList(searchReq, startDate, endDate, modelType, searchVal);
|
||||||
|
|
||||||
return ApiResponseDto.ok(result);
|
return ApiResponseDto.ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "삭제", description = "모델을 삭제 합니다.")
|
@Operation(summary = "삭제", description = "모델을 삭제 합니다.")
|
||||||
@ApiResponses(
|
@ApiResponses(
|
||||||
value = {
|
value = {
|
||||||
@ApiResponse(
|
@ApiResponse(
|
||||||
responseCode = "204",
|
responseCode = "204",
|
||||||
description = "모델 삭제 성공",
|
description = "모델 삭제 성공",
|
||||||
content =
|
content =
|
||||||
@Content(
|
@Content(
|
||||||
mediaType = "application/json",
|
mediaType = "application/json",
|
||||||
schema = @Schema(implementation = Long.class))),
|
schema = @Schema(implementation = Long.class))),
|
||||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||||
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
||||||
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
||||||
})
|
})
|
||||||
@DeleteMapping("/{modelVer}")
|
@DeleteMapping("/{modelVer}")
|
||||||
public ApiResponseDto<ApiResponseDto.ResponseObj> removeModel(
|
public ApiResponseDto<ApiResponseDto.ResponseObj> removeModel(
|
||||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||||
description = "모델 삭제 요청 정보",
|
description = "모델 삭제 요청 정보",
|
||||||
required = true)
|
required = true)
|
||||||
@PathVariable
|
@PathVariable
|
||||||
String modelVer) {
|
String modelVer) {
|
||||||
return ApiResponseDto.okObject(modelMngService.removeModel(modelVer));
|
return ApiResponseDto.okObject(modelMngService.removeModel(modelVer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "모델 zip 파일 업로드", description = "모델 zip 파일 업로드")
|
||||||
|
@PostMapping(value = "/upload/zip", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
|
public void upload(@RequestPart MultipartFile zipFilie) throws IOException {
|
||||||
|
zipUtils.processZip(zipFilie.getInputStream());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user