스프링프로젝트에서 엑셀파일을 업로드 한 뒤 각 열을 DB 컬럼과 맞춰서 저장하는 기능을 구현해보자.
엑셀데이터 예시
아이디
비밀번호
사용자이름
sea
1234
김바다
sun
5678
박태양
wind
1234
이바람
3행 3열로 이루어진 데이터를 DB에 넣어보려고한다.
pom.xml 먼저 dependency를 추가해야한다. 메이븐 레포지토리 사이트 에서 원하는 버전과 프로젝트를 선택한다.
1 2 3 4 5 <dependency > <groupId > org.apache.poi</groupId > <artifactId > poi-ooxml</artifactId > <version > 5.0.0</version > </dependency >
userController.java 1 2 3 4 5 6 @RequestMapping (value = "/addExcel" , method = RequestMethod.POST)public ResponseEntity<? extends BasicResponse> addExcel(HttpServletRequest request, HttpServletResponse response, MultipartFile file) { return ResponseEntity.ok().body(service.insertExcel(file)); };
userService.java 확장자 유효성 검사는 1안과 2안이 있는데 2안이 훨씬 좋다. 그 이유는 이름만 xls, xlsx로 바꿀 수 있기때문이다 아예 contentType이 XLSX인 것을 확인하는 것이 좋다.
FilenameUtils.getExtension(file.getOriginalFilename()).toLowerCase()로 한 뒤 xlsx이나 xls이 일치하는 지 확인
file.getFile().getContentType()을 변수에 담아서 ConstContentType.XLSX과 일치하는 지 확인
아래는 userService안의 addExcel 메서드 소스 코드이다. BasicResponse클래스는 그냥 response클래스이므로 생략하고 mapper클래스도 생략한다.
로직 순서이다.
파라미터에 파일이 있는지 확인 -> 없으면 return 에러
확장자가 엑셀인지 확인 -> 아니면 return 에러
엑셀테이터를 가져와서 각 행마다 VO객체에 저장 -> list에 저장
list를 DB에 insert
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 @Autowired ExcelUtil excelUtil; public BasicResponse addExcel (MultipartFile file) { BasicResponse res = new BasicResponse(); if (file.isEmpty()) { res.setEmpty(); res.setMessage("Excel 파일을 선택해주세요." ); return res; } String contentType = file.getFile().getContentType(); if (!contentType.equals(ConstContentType.XLSX)) { res.setEmpty(); res.setMessage("Excel 파일을 선택해주세요." ); return res; } List<UserVO> listUser = new ArrayList<UserVO>(); List<Map<String, Object>> listMap = excelUtil.getListData(file, 1 , 3 ); for (Map<String, Object> map : listMap) { UserVO userInfo = new UserVO(); userInfo.setUserId(map.get("1" ).toString()); userInfo.setPassword(map.get("2" ).toString()); userInfo.setUserName(map.get("3" ).toString()); listUser.add(userInfo); } for (UserVO oneUser : listUser){ userMapper.insertUser(oneUser); } }
getListData(file, 1, 3)의 의미 엑셀파일의 1번째 행부터 3번째 열까지의 데이터를 listMap에 담는다. 0번째 행부터 하지 않는 이유는 보통 0번째행은 머리글행으로 제목이나 구분명칭을 작성하기 때문이다. 3인 이유는 엑셀데이터에 3열이 있기때문이다. 가지고 있는 엑셀데이터에 따라 변경하면 된다.
ExcelUtil.java 제일 중요한 엑셀유틸객체이다.
getListData 메서드의 파라미터 정의
startRowNum : 시트 시작 행 번호이다. 시트 행은 0부터 시작한다.
columnLength : 시트 열의 총 개수
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 @Component public class ExcelUtil { public String getCellValue (XSSFCell cell) { String value = "" ; if (cell == null ){ return value; } switch (cell.getCellType()) { case STRING: value = cell.getStringCellValue(); break ; case NUMERIC: value = (int ) cell.getNumericCellValue() + "" ; break ; default : break ; } return value; } public List<Map<String, Object>> getListData(MultipartFile file, int startRowNum, int columnLength) { List<Map<String, Object>> excelList = new ArrayList<Map<String,Object>>(); try { OPCPackage opcPackage = OPCPackage.open(file.getInputStream()); @SuppressWarnings ("resource" ) XSSFWorkbook workbook = new XSSFWorkbook(opcPackage); XSSFSheet sheet = workbook.getSheetAt(0 ); int rowIndex = 0 ; int columnIndex = 0 ; for (rowIndex = startRowNum; rowIndex < sheet.getLastRowNum() + 1 ; rowIndex++) { XSSFRow row = sheet.getRow(rowIndex); if (row.getCell(0 ) != null && !row.getCell(0 ).toString().isBlank()) { Map<String, Object> map = new HashMap<String, Object>(); int cells = columnLength; for (columnIndex = 0 ; columnIndex <= cells; columnIndex++) { XSSFCell cell = row.getCell(columnIndex); map.put(String.valueOf(columnIndex), getCellValue(cell)); logger.info(rowIndex + " 행 : " + columnIndex+ " 열 = " + getCellValue(cell)); } excelList.add(map); } } } catch (InvalidFormatException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return excelList; } }
파일 업로드 사이즈 초과 에러 파일 사이즈를 초과해서 업로드할 수 있으므로 예외처리를 해준다.@RestControllerAdvice
를 사용한 BadRequestHandler 클래스에서 예외처리를 해주었다.
1 2 3 4 5 6 7 8 9 10 11 @RestControllerAdvice public class BadRequestHandler { @ExceptionHandler ({MaxUploadSizeExceededException.class }) public ResponseEntity <? extends BasicResponse > uploadException (MaxUploadSizeExceededException exc , HttpServletRequest request , HttpServletResponse response ) { return ResponseEntity.status(HttpStatus.PAYLOAD_TOO_LARGE).body(new ErrorResponse(String.valueOf(HttpStatus.PAYLOAD_TOO_LARGE.value()), "파일 사이즈를 초과하였습니다. (10MB 이하의 파일을 선택해주세요.)" )); } }