Wanna be Brilliant Full-Stack Developer

2/14SpringBoot 프로필 페이지 만들기 -image 모델 본문

카테고리 없음

2/14SpringBoot 프로필 페이지 만들기 -image 모델

Flashpacker 2022. 2. 14. 15:44


목표 포토 이미지 등록 및 포토 이미지 렌더링! 

사진을 등록해서 업로드하는것을 진행해보려고한다! 

 

처음으로 upload.jsp에 들어가면 

form 태그가 있고 그 안에 input 태그가 2개가 들어있는데 하나의 인풋태그에는 사진을 담을것이고! 

2번쨰 인풋 태그에는 사진을 설명하는 내용이 담을것이고 업로드하면 사진이 전송이 되어질것이다! 

 

첫번쨰로 해야할것은 모델을 먼저 만들어야한다.!

도메인 안에 이미지라는 새로운 패키지를 만들고 이미지 클래스를 만든다. 

 

그다음에 이미지를 넣을떄 필요한 캡션이라는것도 추가하고 

PpostImageUrl데이터베이스에 사진을 넣는것이 아니라 사진은 서버에 저장할것이고 경로를 DB에 insert 할것이다.

또한 데이터베이스에는 언제나 시간이 들어가야하기떄문에 ( 데이터가 언제들어갔는지 확인위해) 

private LocalDateTime createDate;

@PrePersist
public void createDate() {
this.createDate = LocalDateTime.now();
}를 추가한다! 

 

필요한것이 더있는데 지금은 만들수 없으니 주석으로 표시하려고한다 

User 를 넣었기 떄문에 연관관계를 파악해야하는데!

한명의 유저는 몇개의 이미지를 등록할수있는가? 한명의 유저는 여러명의 이미지를 등록할수있다.

유저가 1이고 이미지는 N이다. 

반대로 보면 하나의 이미지는 몇명의 유저가 만들어낼수있는가?  

내가 이미지를 등록할것인데 두명이 하나의 이미지를 등록할수 없기 떄문에 

이미지 입장에서 보면 하나의 이미지를 한명의 유저가 업로드 할수 있다. 

그래서 관계는 N: 1의 관계가 된다. 

 

위에 id, captin,postimageUrl 같은것들은 각자 int, varchar, timestamp와 같은것들로 저장이 되지만 

문제는 User가 데이터베이스에 저장될떄 이러한 오브젝트 자체를 데이터베이스에 저장할수 없고 

이대로 저장하게 되면 포린키로 저장이된다. 

그래서 포린키의 이름을 지정해줘야한다 

package com.cos.photogramstart.domain.image;

import java.time.LocalDateTime;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PrePersist;

import com.cos.photogramstart.domain.subscribe.Subscribe;
import com.cos.photogramstart.domain.user.User;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class Image { // N, 1
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY) 
	private int id;
	private String caption; // 설명 
	private String postImageUrl; // 사진을 전송받아서 그 사진을 서버에 특정 폴더에 저장 - DB에 그 저장된 경로를 insert\

	@JoinColumn(name = "userId")
	@ManyToOne
	private User user;// 1, 1
	
	//이미지 좋아요
	
	// 댓글 
	
	private LocalDateTime createDate;
	
	@PrePersist
	public void createDate() {
		this.createDate = LocalDateTime.now();
	}

}

이미지 컨트롤러에서 데이터를 받기위한 DTO를 또만들것이다! 

파일과 캡션을 받아야하고 우리가 이미지를 업로드 하기위해서는 로그인이 되어있는 유저 정보가 필요하다 

또한 사진을 업로드할때 유저 1 이면 user/1 , 2번이면 user/2로 오게되는데!

 

서버에 업로드를 하는 폴더를 만들어놓고 그곳에 이미지를 저장을 할건데 만약 1.jpg을 저장하면

DB에는 경로를 저장하게 될텐데 /upload/1.jpg 이렇게 저장될것이다. 

1.jpg가 또들어오게되면 덮어씌우게 되기때문에 

사용자는 파일이 어떤파일이 있는지 모르기떄문에 마음대로 넣기 때문에 우리가 구분해야한다. 

구분을 하기 위해 필요한것이 UUID라는것이다. 

 

UUID라는 네트워크 상에서 고유성이 보장되는 id를 만들기 위한 표준 규약

유일성이 보장되는 중복이 안되게 나오는 유일한 암호코드라고 생각할수있다. 

진짜 안좋은 확률로 똑같은 UUID가 만들어질 수도 있다. 그러면 UUID가 중복될수도 있기떄문에

그래서 파일아이디를 UUID를 더해서 만들것이다. 

package com.cos.photogramstart.service;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.cos.photogramstart.config.auth.PrincipalDetails;
import com.cos.photogramstart.domain.image.ImageRepository;
import com.cos.photogramstart.web.dto.image.ImageUploadDto;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Service		
public class ImageService {
	
	private final ImageRepository imageRepository;
	
	@Value("${file.path}")
	private String uploadFolder;
	
	public void 사진업로드(ImageUploadDto imageUploadDto, PrincipalDetails principalDetails) {
		UUID uuid  = UUID.randomUUID();	 // uuid
		String imageFileName = uuid+ "_" + imageUploadDto.getFile().getOriginalFilename(); // 1.jpg
		System.out.println("이미지 파일이름: "+ imageFileName);
		
		Path imageFilePath = Paths.get(uploadFolder+imageFileName);
		
		//통신, I/O -> 예외 
		try {
			Files.write(imageFilePath, imageUploadDto.getFile().getBytes());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

실제로 저장할곳은  C:/workspace/springbootwork/upload/ 그래서 저 안에 upload폴더를 만든다 

 

통신, I/O 같은경우는 예외가 발생할수 있다. 내가 만약에 1.jpg 파일을 읽고싶은데 실수로 1.jpg가 하드디스크에 없을수도있는데 이러한것들은 컴파일시에는못잡고 런타임시에만 잡을수있다. 

 

여러가지 종류의 타입을 묶어서 전송할떄 쓰이는 타입 multipart/form-data 

파일과 key value 데이터를 전송하고 싶으면 저타입이다. 

 


파일 업로드를 완료한상태에서 

왜 외부에 업로드라는 폴더를 만들어서 집어넣은지 설명을 해보려고한다

우리가 워크스페이스(개발공간) 안에 photogram이라는 폴더 프로젝트를만들었고  

그리고 또한 업로드라는 경로(폴더)를 만들었다.

왜 포토그램 안에 안만들고 외부에 만들었을까?

포토그램에는 내가 개발하고 있는 코드들 .java 파일들이 있다.

서버를 실행하면 이코드를 실행하는것이 아니라 실제로 실행이 되려면 이 코드가 컴파일 되서 .class 파일로 변경되어 실행되어야한다.

결국은 컴파일 되고 실행이 되려면 

target이라는 폴더가있는데 포토그램안에 있는데 그곳에다가 서버가 실행될떄 컴파일을 해서 .class파일들이 이곳에 들어간다. 실행은 target 파일에 있는 클래스 파일들이 실행됩니다. 

 

만약에 업로드라는 폴더를 포토그램 안에 만들게 되면 

이포토그램이라는 폴더 안에 만들어진 모든것들은 타겟 폴더안에 다 반영이 되어야하는데 사진은 컴파일은 안하지만 target에 똑같이 밀어넣어진다. 

컴파일해서 자바코드를 집어넣는것과 일반적인 정적인 파일들을 집어넣는 행위를 deploy라고 불리는데 이들이 실행이 되는것인데 

내가 만약에 사진을 업로드를 해서 포토그램 안에 있는 업로드 폴더에 넣게 되면 사진을 업로드가 됬는데 서버가 실행되서 사진이 업로드 되면 포토그램 내부에 있으니까 업로드 폴더 안에 1.jpg가 저장되고 여기에 저장된 1.jpg 파일이

타겟 폴더로 이동이 되어야한다.

타겟 폴더 내부에 있는것들이 실행되는데 여기서 문제가 머냐면 결국 이렇게 들어가는 행위를 deploy라고 불린다고 말했는데 upload 폴더에 있는 사진이 deploy할떄 시간이 걸리는데 

 

예를 들어 자바파일같은것들은 컴파일되서 들어가는것은 그렇게 오래 안걸리는데 이런 파일들은 용량이 있기 떄문에 시간이 더 오래걸릴수 있다. 

서버 실행될떄 타깃폴더안에 모든것을 넣어서 실행해야하는데 1.jpg안에 타깃 폴더안에 들어가기도전에 실행이 될수도 있기 때문에 

그말은 무슨 말이냐면 우리가 웹페이지에서 사진을 등록하려고 파일 선택해서 업로드하는 순간 내 포토그램 업로드 폴더에 들어가고나서 deploy되는 시간보다 화면으로 넘어가는 시간이 빠르면 시간 차이 떄문에 그 화면은 엑박이 나온다. 

 

외부에 업로드 파일을 둬서 그곳에 1.jpg를 넣으면 deploy될 필요가 없고 사진을 업로드 하면 사진이 바로 업로드 되고 찾을떄도 타겟에 있는것을 찾는것이 아니라 upload 폴더를 찾기 떄문에 움직일 필요가 없어서 엑스박스가 안뜬다. 

 

이러한 파일들은 업로드 할떄 내 프로젝트 내부안에 두는것을 추천하지 않는다. 

 


결론: 이 부분에 대해서 개념을 알고있는게 좋다. 왜 폴더를 외부에 두는지 확실히 알게 될것이다.