ImgService : 배포 server에 img 파일 저장하기

권희·2025년 10월 9일

졸업작품

목록 보기
5/7

목차

1. 배포 서버에 Img파일 저장하기

2. ImgTransaction

3. TestCode

1. 배포서버에 Img파일 저장하기

  1. controller를 통해서 Img 파일을 받는다
  2. 배포 서버의 Img 폴더 내에 Img 파일을 저장한다
  3. 저장된 Img의 주소값만 db에 저장한다
  4. front에게 db의 Img파일의 주소값을 주면 front가 Img url로 요청을 넣는다
  5. 저장된 Img파일을 front에게 반환한다

1. controller에서 Img 파일을 받는다

front에서 MultipartFile형식의 Img파일을 넘겨주기 위해서는 form-data 형식으로 받아야 한다.
@ModelAttribute 를 통해서 Dto와 같이 받거나 @RequestPart를 사용해 따로 받을 수 있다.

@PostMapping()
public ResponseEntity register(
	@ModelArribute RequestRegisterDto dto
    @RequestPart("file") MultipartFile img
){
	...
}

class RequestRegisterDto { MultipartFile img; ... others }

2,3. Img파일 저장, db에 주소값 저장

파일 이름 그대로 저장하기 위해 노력했다.

public ImgEntity saveImg(MutipartFile imgFile) {
	String fileName = imgFile.getOriginFilename();
	Path path = Paths.get(System.getProperty("user.dir"), IMG_DEFAULT_PATH, fileName);
   
   Files.write(path, imgFile.getBytes());
   
   ImgEntity savedImg = new ImgEntity(fileName);
   ImgRepository.save(savedImg);
   
   return savedImg;

혹시라도 db에 똑같은 이름이 있다면 1~10 까지 숫자를 추가로 붙이는 방법을 추가했다

4,5. front에게 주소값 반환, nginx serving

front에게는 위에서 저장한 ImgEntity의 uri(fileName)값을 반환한다

--- back ResponseDto 반환
class ResponseDto { String imgURI = imgEntity.getURI(); }

-- front Img파일 요청
<HTML>
	<img src="backserver/img/${ResponseDto.imgURI}" />
</HTML>

Img tag에 의해서 back으로 GET 방식으로 backserver/img/{ImgURI}로 요청이 들어온다
Img요청을 Spring 을 사용해서 반환해도 되지만 Nginx를 통해서 반환하는 것이 server의 부담을 조금이니마 줄일 것 같아서 nginx를 사용했다

 location /img/ {
        root /usr/share/nginx/html; 
        try_files $uri $uri/ =404;
 }

location / {
     proxy_pass http://springboot:8080;
     proxy_set_header Host $host;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header X-Forwarded-Proto $scheme;
     proxy_pass_header Access-Control-Allow-Origin;
     proxy_pass_header Access-Control-Allow-Credentials;
}

ImgTransaction

문제점 : img파일은 transaction에 rollback되지 않는다

img를 어디에 저장하든 Img파일 자체는 transaction을 지원해주지 않는다.

	ImgEntity imgEntity = imgService.save(imgFile);
   UserEntity newUser = new UserEntity(imgEntity);
   userRepository.save(newUser); // throw RunTimeException("email conflict")

userReposirory.save(userUser); 부분에서 exception이 발생하면 newUser, imgEntity는 rollback이 되지만 저장된 imgFile은 rollback되지 않는다.

해결 방법 : Aop를 사용한 Custom Transaction 구현

  1. ImgService의 함수들을 호출하는 service 함수들에 Aop를 사용한 ImgTransaction을 건다

  2. ImgService 함수들에 마지막 변수로 ArrayList<Path> path를 받는다

  3. 저장한 모든 Img파일들을 path에 추가한다

  4. aop가 끝나면서 exception이 발생했다면 path들의 Img파일들을 지운다

    	@Around("@annotioan(imgTransaction)")
     	public Object around(ProceedingJoinPoint, Imgtransaction transaction) {
       	ArrayList<Path> path = new ArrayList<>();
     		Objects[]
     		try{ 
     			Object[] args = joinPoint.getArgs();
               args[args.length-1] = imgPaths;
               return joinPoint.proceed(args);
     		} catch(Eception e) { imgService.deleteImgFile(img); }
     	}
     
     	public ImgEntity saveImg(MutipartFile imgFile, ArrayList<Path\> path);

    단점

    imgService 함수를 호추하는 모든 함수에 마지막 인자에 ArrayList<Path>가 추가되어야 한다.

     	public void UserService.register(RequestRegisterDto dto, ArrayList<Path> path);

    다른 방법도 존재하긴 하지만 aop를 사용해서 직접 구현해보고 싶어서 이 방법을 선택했다.
    내가 직접 구현한 방법인 만큼 TestCode를 정확하게 짜고 모듈화에 노력했다.

TestCode

Test 대상

  1. imgService.saveImg();
  2. ArrayList<Path> imgPaths 에 값이 잘 저장되는지
  3. rollback이 잘 되는지
profile
나의 개발 기록

0개의 댓글