Spring Framework (12) 파일 업로드, 프로필 수정 - Day 59

jaehoon ahn·2025년 12월 11일

Spring boot

목록 보기
10/20
post-thumbnail

파일 업로드 → 서버 컴퓨터 + DB에 저장

Utility.java

package edu.kh.project.common.util;

import java.text.SimpleDateFormat;
import java.util.Date;

// 프로그램 전체적으로 사용될 유용한 기능 모음
public class Utility {

	public static int seqNum = 1; // 1 ~ 99999 번까지 1씩 증가하면서 값을 저장해줄 변수

	public static String fileRename(String originalFileName) {
		// 20251211100330_00001.jpg

		// SimpleDateFormat : 시간을 원하는 형태의 문자열로 간단히 변경해주는 객체
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");

		// java.util.Date() : 현재 시간을 저장한 자바 객체
		String date = sdf.format(new Date());

		String number = String.format("%05d", seqNum);
		
		seqNum++; // 1증가
		
		if(seqNum == 100000) {
			seqNum = 1;
		}
		
		// 확장자 구하기
		// String.substring(인덱스);
		// - 문자열을 인덱스부터 끝까지 잘라낸 결과를 반환
		
		// String.lastIndexOf("찾을문자열")
		// - 문자열에서 마지막 "찾을문자열"의 인덱스를 반환
		
		// originalFileName == 짱구.jpg
		
		String ext = originalFileName.substring(originalFileName.lastIndexOf("."));
		// ext == .jpg
		
		return date + "_" + number + ext;
		
	}
}

⇒ 위 코드를 통해 파일명을 수정해준다

MyPageController.java

@PostMapping("file/test2") // /myPage/file/test1 POST 요청 매핑
	public String fileUpload2(@RequestParam("uploadFile") MultipartFile uploadFile,
			@SessionAttribute("loginMember") Member loginMember, RedirectAttributes ra) {
		try {
			int memberNo = loginMember.getMemberNo();
			int result = service.fileUpload2(uploadFile, memberNo);

			String message = null;

			if (result > 0) {
				message = "파일 업로드 성공";
			} else {
				message = "파일 업로드 실패";
			}
			
			ra.addFlashAttribute("message", message);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "redirect:/myPage/fileTest";

	}
  • 현재 세션에 있는 로그인된 회원 번호와 uploadFile을 서비스로 넘겨준다

MyPageService.java

@Override
	public int fileUpload2(MultipartFile uploadFile, int memberNo) throws Exception {
		// MultipartFile이 제공하는 메소드
		// - isEmpty() : 업로드된 파일이 없을경우 true / 있다면 false
		// - getSize() : 파일 크기
		// - getOriginalFileName() : 원본 파일명
		// - transferTo(경로) :
		// 메모리 또는 임시 저장 경로에 업로드된 파일을

		// 업로드된 파일이 없다면
		if (uploadFile.isEmpty()) {
			return 0;
		}

		// 업로드된 파일이 있다면

		// 1. 서버에 저장될 서버 폴더 경로 만들기

		// 파일이 저장될 서버 폴더 경로
		String folderPath = "C:/uploadFiles/test/";

		// 클라이언트가 파일이 저장된 폴더에 접근할 수 있는 주소(요청 주소)
		String webPath = "/myPage/file/";

		// 2. DB에 전달할 데이터를 DTO로 묶어서 INSERT
		// webPath, memberNo, 원본파일명, 변경된파일명

		String fileRename = Utility.fileRename(uploadFile.getOriginalFilename());

		// Builder 패턴을 이용해서 UploadFile 객체 생성
		// 장점 1) 반복되는 참조변수명, set 구문 생략
		// 장점 2) method chaining을 이용하여 한줄로 작성 가능

		UploadFile uf = UploadFile.builder().memberNo(memberNo).filePath(webPath)
				.fileOriginalName(uploadFile.getOriginalFilename()).fileRename(fileRename).build();

		int result = mapper.insertUploadFile(uf);

		// 3. 삽입 (INSERT) 성공 시 파일을 지정된 폴더에 저장
		// 삽입 실패 시
		if (result == 0)
			return 0;

		// 삽입 성공 시
		// C:/uploadFiles/test/변경된파일명으로
		// 파일을 서버 컴퓨터에 저장!
		uploadFile.transferTo(new File(folderPath + fileRename));
		// C:/uploadFiles/test/20251211100330_00001.jpg

		return result;
	}
  • uploadFIle이 없다면 return 0 (실패)
  • Utility에 정의된 fileRename 메서드에 uploadFile의 이름을 전달해서 수정된 파일명을 받아준다.
  • builder 패턴으로 UploadFile 타입에 값을 넣어준다
  • 그리고 DB에 insert를 진행
  • 실패했다면 0을 return
  • 성공했다면 서버 컴퓨터에 저장

⇒ 서버 컴퓨터와 DB에 모두 저장된 것을 확인할 수 있다.

여러 파일 업로드

input 속성 중 multiple

<input type="file" name="bbb" multiple />

⇒ 여러 파일을 선택할 수 있다.

MyPageController.java

@PostMapping("file/test3")
	public String fileUpload3(@RequestParam("aaa") List<MultipartFile> aaaList,
			@RequestParam("bbb") List<MultipartFile> bbbList, @SessionAttribute("loginMember") Member loginMember,
			RedirectAttributes ra) throws Exception {
		// aaa 파일 미제출 시
		// 0번, 1번 인덱스로 구성되어있음 - 파일은 모두 비어있음

		// log.info("aaaList = " + aaaList); // [요소, 요소]

		// bbb(multiple) 파일 미제출 시
		// 0번 인덱스로 구성 - 파일이 비어있음
		// log.info("bbbList = " + bbbList); // [요소]

		// 여러 파일 업로드 할 수 있는 서비스 호출할 것
		int result = service.fileUpload3(aaaList, bbbList, loginMember.getMemberNo());

		// result == aaaList와 bbbList에 업로드된 파일 갯수

		String message = null;

		if (result == 0) {
			message = "업로드된 파일이 없습니다";
		} else {
			message = result + "개의 파일이 업로드 되었습니다!";
		}

		ra.addFlashAttribute("message", message);

		return "redirect:/myPage/fileTest";
	}
  • aaaList(한개씩 추가한 사진), bbbList(여러개 선택할 수 있는 사진)를 service로 넘겨준다.
  • 그 이후, 성공적으로 추가가 되었으면 message를 redirect한 경로로 전달

MyPageService.java

@Override
	public int fileUpload3(List<MultipartFile> aaaList, List<MultipartFile> bbbList, int memberNo) throws Exception {
		// 1. aaaList 처리
		int result1 = 0;

		// 업로드된 파일이 없을 경우를 제외하고 업로드
		for (MultipartFile file : aaaList) {
			if (file.isEmpty())
				// 파일이 없으면 다음 파일로 검사하러 가기
				continue; // 아래 코드 수행 X 다음 반복으로 넘어감...

			// fileUpload2() 메서드 호출(재활용)
			// -> 파일 하나 업로드 + DB INSERT
			result1 += fileUpload2(file, memberNo);
		}

		// 2. bbbList 처리
		int result2 = 0;

		// 업로드된 파일이 없을 경우를 제외하고 업로드
		for (MultipartFile file : bbbList) {
			if (file.isEmpty())
				// 파일이 없으면 다음 파일로 검사하러 가기
				continue; // 아래 코드 수행 X 다음 반복으로 넘어감...

			// fileUpload2() 메서드 호출(재활용)
			// -> 파일 하나 업로드 + DB INSERT
			result2 += fileUpload2(file, memberNo);
		}
		
		return result1 + result2;
	}
  • aaaList, bbbList를 각각 존재하는 파일을 DB에 저장해주고, 해당 결과값인 result1, result2를 더한 값을 controller에게 전달해준다.

프로필 수정

 [input type="file" 사용 시 유의 사항]

  1. 파일 선택 후 취소를 누르면 
    선택한 파일이 사라진다  (value == '')

  2. value로 대입할 수 있는 값은  '' (빈칸)만 가능하다

  3. 선택된 파일 정보를 저장하는 속성은
    value가 아니라 files이다

config.properties에 요청경로/서버저장경로

프로필이미지

/myPage/profile/ ↔ C:/uploadFIles/profile/

프로필 사진 변경

MyPageController.java

@PostMapping("profile") // /myPage/profile POST 요청 매핑
	public String profile(@RequestParam("profileImg") MultipartFile profileImg, RedirectAttributes ra,
			@SessionAttribute("loginMember") Member loginMember) throws Exception {

		// 서비스 호출
		int result = service.profile(profileImg, loginMember);

		String message = null;

		if (result > 0) {
			message = "변경 성공";
		} else {
			message = "변경 실패...";
		}

		ra.addFlashAttribute("message", message);
		return "redirect:profile"; // 리다이렉트 - /myPage/profile GET 요청
	}
  • 전달받은 profileImg와 현재 로그인한 멤버를 service로 넘겨준다.

MyPageService.java

@Override
	public int profile(MultipartFile profileImg, Member loginMember) throws Exception {
		// 프로필 이미지 경로(수정할 경로)
		String updatePath = null;

		// 변경명 저장
		String rename = null;

		// 업로드한 이미지가 있을 경우
		if (!profileImg.isEmpty()) {
			// updatePath 경로 조합
			// filePath, fileRename을 조합해서 member에 넣을 것

			// 1. 파일명 변경
			rename = Utility.fileRename(profileImg.getOriginalFilename());

			// 2. /myPage/profile/변경된파일명
			updatePath = profileWebPath + rename;
		}

		// 수정된 프로필 이미지 경로와 어떤 회원의 프로필을 수정할 것인지 알아야함
		// => 즉, 수정된 프로필 이미지 경로 + 회원 번호를 저장할 DTO 객체를 보내줄 것
		Member member = Member.builder().memberNo(loginMember.getMemberNo()).profileImg(updatePath).build();

		// UPDATE 수행
		int result = mapper.profile(member);

		if (result > 0) { // DB에 업데이트 성공
			// 프로필 이미지를 없앤 경우(NULL로 수정한 경우를 의미)를 제외한 경우
			// -> 즉, 업로드한 이미지가 있을 경우
			if (!profileImg.isEmpty()) {
				// 파일을 서버 지정된 폴더에 저장
				profileImg.transferTo(new File(profileFolderPath + rename));
				// C:/uploadFiles/profile/변경한이름
			}
			// 세션에 등록된 현재 로그인한 회원 정보에서
			// 프로필 이미지 경로를 DB에 업데이트한 경로로 변경
			loginMember.setProfileImg(updatePath);
		}
		return result;
	}
  • 만약 파일이 존재한다면, Utility에 fileRename 메서드에 전달받은 이미지의 이름을 보내줘서 rename해준다.
  • 그리고 updatePath에 profileWebPath경로와 rename된 값을 더해준다.
  • DB에 Update 해준 다음, profileImg가 null인경우(삭제하고 변경하기 눌렀을 때)가 아닐 때 서버에 이미지를 저장해준다.
  • 그리고 세션에 저장된 현재 로그인된 멤버의 profileImg을 DB에 저장된 이미지와 동일시해준다.

프로필 변경 후

0개의 댓글