우선 프론트 단에서는 파일업로드 input을 만들어둔다
이 후 엑셀 파일은 다음과 같이 입력할 수 있게 해준다.
상단 비워져있는 부분은 설명으로 사용
다음 행은 제목으로 사용
이후 백엔드 코드
@PostMapping("/uploadExcel")
public ResponseEntity<String> uploadSlotExcel(
@ModelAttribute SlotExcelUploadRequestDto uploadDto,
@RequestParam("file") MultipartFile file
) throws IOException {
if (file.isEmpty()) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("파일이 비어 있습니다.");
}
try {
InputStream inputStream = file.getInputStream();
Workbook workbook = new XSSFWorkbook(inputStream);
slotService.saveExcelData(workbook, uploadDto);
return ResponseEntity.ok("파일이 성공적으로 업로드되었습니다.");
} catch (Exception e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("파일 업로드 중 오류가 발생했습니다.");
}
}
Service 코드
@Transactional
public void saveExcelData(Workbook workbook, SlotExcelUploadRequestDto uploadDto) {
Sheet sheet = workbook.getSheetAt(0);
Iterator<Row> rows = sheet.iterator();
int rowNum = 0;
while (rows.hasNext()) {
Row currentRow = rows.next();
// 행을 하나씩 찾아서 다음행이 있는지 없는지 확인
rowNum++;
if (rowNum > 2) {
// 행이 2번째 이상이면 아래 parseRowToSlot메소드 실행
List<SlotEntity> slots = parseRowToSlot(currentRow, uploadDto);
if (slots != null) {
slotRepository.saveAll(slots);
}
}
}
}
private List<SlotEntity> parseRowToSlot(Row row, SlotExcelUploadRequestDto uploadDto) {
try {
int i = 0;
String link = row.getCell(i++).getStringCellValue();
String mainKeyWord = row.getCell(i++).getStringCellValue();
String subKeyWord = row.getCell(i++).getStringCellValue();
String commercial = row.getCell(i++).getStringCellValue();
String sellerMemo = row.getCell(i++).getStringCellValue();
Cell startDateCell = row.getCell(i++);
LocalDate startDate;
if (startDateCell != null && startDateCell.getCellType() == CellType.NUMERIC) {
startDate = startDateCell.getDateCellValue().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
} else {
throw new IllegalArgumentException("시작일 셀의 값이 유효하지 않습니다.");
}
long workDay = (long) row.getCell(i++).getNumericCellValue();
LocalDate endDate = startDate.plusDays(workDay);
int slotQuantity = (int) row.getCell(i++).getNumericCellValue();
// 일딴 SlotInfo 테이블에 저장 (한개만 저장)
SlotInfoEntity slotInfo = new SlotInfoEntity();
slotInfo.setUrl(link);
slotInfo.setMainKeyword(mainKeyWord);
slotInfo.setSubKeyword(subKeyWord);
slotInfo.setCommercial(commercial);
slotInfo.setStartDate(String.valueOf(startDate));
slotInfo.setEndDate(String.valueOf(endDate));
slotInfoRepository.save(slotInfo);
// 이 후 기존에 "슬롯 수량"이라는 숫자를 받아서 그 수량만큼 슬롯을 추가할 수 있게 List로 입력
List<SlotEntity> slots = new ArrayList<>();
for (int j = 0; j < slotQuantity; j++) {
SlotEntity slot = new SlotEntity();
slot.setWorkDay(workDay);
slot.setMemoContent(sellerMemo);
slot.setStartDate(String.valueOf(startDate));
slot.setEndDate(String.valueOf(endDate));
LocalDateTime koreaTime = LocalDateTime.now(ZoneId.of("Asia/Seoul"));
slot.setCreateSlotTime(koreaTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
CategoryEntity category = categoryRepository.findById(Long.valueOf(uploadDto.getCategoryId()))
.orElseThrow(() -> new RuntimeException("카테고리가 유효하지 않습니다."));
MemberEntity user = memberRepository.findByUserId(uploadDto.getUserId())
.orElseThrow(() -> new RuntimeException("UserId가 유효하지 않습니다."));
slot.setCategory(category);
slot.setUserId(user);
slot.setSlotInfo(slotInfo);
slots.add(slot);
}
return slots;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
프론트 코드
const fileUpload = async (e: any) => {
e.preventDefault()
if (!file) {
alert('파일을 선택해 주세요.')
return
}
try {
const response = await uploadExcel(file, userId, params.categoryId)
if (response.ok) {
alert('파일 업로드 성공!')
} else {
alert('파일 업로드 실패!')
}
} catch (error) {
alert('업로드 중 오류가 발생했습니다.')
console.error('업로드 중 오류:', error)
}
}
export async function uploadExcel(
file: File,
userId: string,
categoryId: number,
) {
const formData = new FormData()
formData.append('file', file)
formData.append('userId', userId)
formData.append('categoryId', categoryId.toString())
console.log(categoryId.toString())
try {
const response = await fetch(
process.env.NEXT_PUBLIC_API_ADDRESS + 'slot/uploadExcel',
{
method: 'POST',
body: formData,
},
)
return response
} catch (err) {
console.error(err)
throw err
}
}
'Spring-boot' 카테고리의 다른 글
QueryDSL 적용기 (0) | 2024.09.24 |
---|---|
spring-boot 업로드 2 (1) | 2024.06.13 |
Spring-boot Google Sheets API #2 연동 (0) | 2024.04.25 |
Spring-boot Google Sheets API #1 (0) | 2024.04.25 |
Spring-boot 로그 기록 남겨두기 (0) | 2024.04.19 |