MakerHyeon

[springBoot] 프로필 페이지 -Image모델 만들기/서버에 업로드하기 본문

SpringBoot

[springBoot] 프로필 페이지 -Image모델 만들기/서버에 업로드하기

유쾌한고등어 2023. 1. 9. 14:04

프로필 페이지 -Image모델 만들기/서버에 업로드하기


● Image모델 만들기

1. Image table 생성

- 사진을 전송받아서 그 사진을 서버의 특정폴더에 저장후, DB에 저장된 경로를 insert
- 유저 : 이미지 = 1: N, 이미지 : 유저 = N : 1 (@ManyToOne)
- 오브젝트는 FK로 저장된다. 따라서 JoinColumn명을 지정해준다.

// Image.java

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class Image {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String caption;
    private String postImageUrl;

    @JoinColumn(name="userId")
    @ManyToOne
    private User user;

    // 이미지 좋아요,댓글도 추후 만들예정!

    private LocalDateTime createDate;

    @PrePersist
    public void createDate(){
        this.createDate = LocalDateTime.now();
    }
}

 

2.해당 table Repository만들기

// ImageRepository.java

public interface ImageRepository extends JpaRepository<Image,Integer> {
}

● Image Upload to Server

3. Image Upload DTO생성

- upload.jsp의 name="file", name="caption" 데이터를 받기위한 Dto생성

// ImageUploadDto.java

@Data
public class ImageUploadDto {
    private MultipartFile file;
    private String caption;
}

 

4. imageController 파라미터 설정

- 컨트롤러는 사용자에게 데이터를 받고, 서비스를 호출하는 역할을 담당

// ImageController.java
	...
	@PostMapping("/image")
    public String image(ImageUploadDto imageUploadDto,
    @AuthenticationPrincipal PrincipalDetails principalDetails){
        //서비스 호출
        
        // 해당유저의 페이지로 redirection
        return "redirect:/user/"+principalDetails.getUser().getId();

    }

 

5. application.yml에서 file path 경로 설정

- file path를 지정할때 맨 뒤에 \ 를 붙여주어야 함에 유의

- 유지보수성을 위해, yml에 경로를 적어두고 @Value로 Path 불러와 적용하는게 좋다.

// application.yml

file:
  path: C:\Users\USER\Desktop\metacoding\upload\

6. ImageService 에서 사진업로드함수 구현부 작성

- @Value로 Path값 지정 (private String uploadFolder = "C:\Users\USER\Desktop\metacoding\")

- 통신 I/O 는 예외가 발생할 수 있기 때문에 예외처리(try-catch) 를 해준다. 

- 이미지 중복 방지를 위해 UUID를 사용한다.

-UUID란(Universally Unique IDentifier), 네트워크 상에서 고유성이 보장되는 id를 만들기 위한 표준 규약으로, 중복이없고 유일성이 보장되는 코드

 

// ImageService.java

@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();
        System.out.println("이미지 파일이름: "+imageFileName);

        Path imageFilePath = Paths.get(uploadFolder + imageFileName);

        try{
            Files.write(imageFilePath,imageUploadDto.getFile().getBytes());
        } catch (Exception e){
            e.printStackTrace();
        }

    }
}

 

7. imageController 에서 업로드서비스 호출

// ImageController.java

@RequiredArgsConstructor
@Controller
public class ImageController {

    private final ImageService imageService;

    ...
    @PostMapping("/image")
    public String image(ImageUploadDto imageUploadDto, 
    @AuthenticationPrincipal PrincipalDetails principalDetails){
    
    	// 서비스 호출
        imageService.사진업로드(imageUploadDto,principalDetails);

        return "redirect:/user/"+principalDetails.getUser().getId();
    }
}

 

8. form에서 event action 지정

- enctype="multipart/form-data" : 여러가지 종류의 데이터를 묶어서 전송할때 쓰는 타입

- image file과 key=value 데이터를 동시에 전송하기 위함

// upload.jsp

<form class="upload-form" action="/image" method="post" enctype="multipart/form-data">
                    <input  type="file" name="file"  onchange="imageChoose(this)"/>
                    <div class="upload-img">
                        <img src="/images/person.jpeg" alt="" id="imageUploadPreview" />
                    </div>
                    
                    <!--사진설명 + 업로드버튼-->
                    <div class="upload-form-detail">
                   		 <input type="text" placeholder="사진설명" name="caption"/>
                        <button class="cta blue">업로드</button>
                    </div>

 


● 결과

- 이미지 업로드가 정상적으로 완료된것을 확인 가능 하다.

 


● upload폴더를 프로젝트 외부에 두는 이유 ?

 

- 서버가 실행되면 .java파일들이 전부 컴파일되어서 타켓폴더안에 들어가게되고 (.class),이를 실행하게 된다.
만약에 업로드 폴더를 프로젝트 내부에 만들게되면,이것이 실행시 Target에 반영이 된다.
- Target파일로 .class, 정적파일을 집어넣는 행위를 deploy라고 한다.
- deploy(배포)될때 시간이 걸린다. 이때문에 이미지가 타겟안으로 들어가기도 전에 서버가 실행될 수 있다. Deploy되는 시간보다 화면으로 돌아가는 시간이 더 빠르다면, 시간차 문제로 엑박이 뜨게된다.
- 프로젝트 외부에 업로드폴더를 두면 Deploy될 필요가없다. 찾을때도 target에 있는걸 찾는 게아니라 upload폴더에 있는것을 찾는다.
- 즉 정리하면,위같은 이유로 파일은 프로젝트 내부에 두지않아야한다.

 

*정리
1.프로젝트 내부에 있으면 [업로드->프로젝트 내부->deploy]되는 시간보다 프로필페이지로 가는 시간이 더 빠를 수 있다.
2.프로젝트 외부에두면 deploy가 안되기때문에 업로드하자마자 프로필페이지로 가도 엑박이 안뜬다!

 

 

 

Comments