[SpringBoot] 파일 업로드

🌈 m1naworld ·2022년 9월 19일
post-thumbnail

❗️ 구현 목적:

csv파일을 업로드하고, 받아 읽어 DB에 데이터를 업데이트 하기 위한 기능 구현


프론트에서의 코드

아래는 함께 프로젝트를 하고 있는 프론트 분 블로그이다. 잘 정리되어있으니! 참고하면 좋을 것 같다. 🌟
📍 https://cchloe0927.tistory.com/49


우선 알아두면 좋은 점

포스트맨을 통해 파일 데이터를 가지고 테스트하고 싶을 때, POST 메소드를 통해 Body에 form-data 형식으로 테스트가 가능하다.


백에서의 코드

받아온 파일을 webapp폴더에 저장하고 그 파일을 읽어 DB에 저장하는 로직이다.

@PostMapping("/update/user")
public ResponseEntity<Map<String, Object>> insertUserData(@RequestPart(required = false) MultipartFile file, HttpServletRequest request) throws IOException {
	
    // 받아온 파일을 webapp폴더 하위 data폴더에 저장
	String resourceSrc = request.getServletContext().getRealPath("/data/");
    File dest = new File(resourceSrc + file.getOriginalFilename());
 	file.transferTo(dest);
    
    // 파일을 읽어 디비 저장 함수
    String result = adminService.updateUser(dest);
    
    ... 이하 생략

파일 데이터는 @RequestPart를 통해 MultipartFile 타입을 바인딩할 수 있다. (참고)


adminService 폴더에 updateUser함수는 다음과 같다.
 public String updateUser(File dest) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(dest));
        String line;
        int result = 0;
        if((line= br.readLine())!=null) {
            while ((line = br.readLine()) != null) {
                String[] datalines = line.split(",");
                try {
                    int classes = Integer.parseInt(datalines[0]);
                    String userId = datalines[1];
                    String name = datalines[2];
                    
                    // DB에 데이터 삽입
                    result = adminMapper.insertUser(classes, userId, name);
                } catch (NumberFormatException e) {
                    continue;  // 첫번째 줄(제목 행) 제외하기 위함
                }
            }
            br.close();
            if(result >= 1){
                return "success";
            }
        }
        return "fail";
    }

adminMapper에 insertUser함수는 다음과 같다.

 // 최신기수 인재들 업데이트(중복시 pass 없을시엔 insert)
    @Insert("INSERT IGNORE INTO USER(CLASSES, USER_ID, USER_NAME, FLOOR) VALUES(#{classes}, #{userId}, #{userName}, 3)")
    int insertUser (@Param("classes") int classes, @Param("userId") String userId, @Param("userName") String name);

IGNORE을 통해 중복된 데이터가 들어올 시에는 데이터 삽입을 하지 않도록 구현하였다.



📌 포스트맨에서는 잘되었는데 프론트와의 통신을 할 때 오류가 많아 애를 먹었다.

  1. 프론트에서 Content-Type을 multipart/form-data로 지정해주어 보내주어야 한다는 예시가 많았는데 'FileUploadException: the request was rejected because no multipart boundary was found' 오류가 자꾸 떴다. 결국 Content-Type을 지정해서 보내주는 코드를 빼니 잘 되었는데, 이유를 찾다보니 내가 데이터를 받을 때 @RequestPart를 통해 받아서 생긴 문제가 아닌가 싶다.

  2. 프론트에서 보낸 파일은 백으로 잘 들어오나 백에서 보낸 결과값을 프론트에선 받지 못하도 못하고 에러가 떴다. 파일이 잘 들어오길래 문제 없겠거니 했는데 Content-Type을 지정해주지 않아서 파일은 cors에 걸쳐지지 않았던 것. 그러나 해당 라우터는 cors 설정이 안되어 있어 cors에 걸려 통신이 안되었던 것 같다. 에러또한 cors가 아닌 failed to fetch at onUploadSubmit로 떠서 한번에 알아보지 못했다.
    주의⚠️ 새로운 라우터를 팠으면 cors 설정을 기본으로 해줄것 !! cors 설정 에러였는데 괜히 고생한 현정쓰 미앙,, 🙏🏻

profile
개발자로 사는 내 삶은 즐거워 👾

0개의 댓글