๊ด€๋ฆฌ ๋ฉ”๋‰ด

JiYoung Dev ๐Ÿ–ฅ

[Spring boot] ์ฒจ๋ถ€ํŒŒ์ผ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ๋ณธ๋ฌธ

Question

[Spring boot] ์ฒจ๋ถ€ํŒŒ์ผ ๊ธฐ๋Šฅ ์ถ”๊ฐ€

Shinjio 2023. 8. 22. 10:16

Spring boot - JPA ํ™œ์šฉ ๊ฒŒ์‹œํŒ ์ฒจ๋ถ€ํŒŒ์ผ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ํ•˜๊ธฐ 

 

FIleStore ์ฝคํฌ๋„ŒํŠธ ์ถ”๊ฐ€ 

  1. ์ฒจ๋ถ€ํŒŒ์ผ ์ €์žฅ ๊ฒฝ๋กœ ์ง€์ • 
  2. ์ฒจ๋ถ€ํŒŒ์ผ ์ด๋ฆ„ ๋ณ€ํ™˜ (์ž‘์„ฑ์ž๊ฐ€ ์—…๋กœ๋“œํ•œ ํŒŒ์ผ๋ช… → ์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ํŒŒ์ผ๋ช…)
  3. ํŒŒ์ผ ์ €์žฅ

 

package com.sjy.shopping.attachfile;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import com.sjy.shopping.model.entity.UploadFile;

@Component
public class FileStore {

	//๋ฃจํŠธ ๊ฒฝ๋กœ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
	private final static String rootPath = System.getProperty("user.dir");
	
	//ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ ๊ฒฝ๋กœ์— ์žˆ๋Š” files ๋””๋ ‰ํ† ๋ฆฌ
	private final static String fileDir = rootPath + "/src/main/resources/static/files/";
	
	public static String getPullPath(String filename) { return fileDir + filename;}
	
	public static UploadFile storeFile(MultipartFile multipartFile) throws IOException{
		if(multipartFile.isEmpty()) {
			return null;
		}
		
		String originalFilename = multipartFile.getOriginalFilename();
		//์ž‘์„ฑ์ž๊ฐ€ ์—…๋กœ๋“œํ•œ ํŒŒ์ผ๋ช… -> ์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ํŒŒ์ผ๋ช…์œผ๋กœ ๋ณ€ํ™˜
		//ํŒŒ์ผ๋ช… ์ค‘๋ณต๋˜์ง€ ์•Š๋„๋ก UUID๋กœ ์ •ํ•˜๊ณ  ํ™•์žฅ์ž๋Š” ๊ทธ๋Œ€๋กœ!
		String storeFilename = UUID.randomUUID() + "." + extractExt(originalFilename);
		
		//ํŒŒ์ผ์„ ์ €์žฅํ•˜๋Š” ๋ถ€๋ถ„ : ํŒŒ์ผ ๊ฒฝ๋กœ + storeFilename์— ์ €์žฅ
		multipartFile.transferTo(new File(getPullPath(storeFilename)));
		
		return new UploadFile(originalFilename, storeFilename);
	}
	
	
    // ํ™•์žฅ์ž ์ถ”์ถœ
    private static String extractExt(String originalFilename) {
        int pos = originalFilename.lastIndexOf(".");
        return originalFilename.substring(pos + 1);
    }
	
}

 

 

์ฒจ๋ถ€ํŒŒ์ผ Entity ์ถ”๊ฐ€ - UploadFile

  1. id, ์—…๋กœ๋“œํ•œ ํŒŒ์ผ๋ช…, ์ €์žฅ๋œ ํŒŒ์ผ๋ช…์„ ์ปฌ๋Ÿผ์œผ๋กœ ๊ฐ€์ง
  2. posts(๊ฒŒ์‹œ๋ฌผ) Entity์™€๋Š” id ์ปฌ๋Ÿผ์œผ๋กœ join

 

package com.sjy.shopping.model.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity(name="uploadfile")
public class UploadFile {
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "attach_id")
	private Long id;
	
	@Column(name = "upload_filename")
	private String uploadFilename; //์ž‘์„ฑ์ž๊ฐ€ ์—…๋กœ๋“œํ•œ ํŒŒ์ผ๋ช…
	
	@Column(name = "store_filename")
	private String storeFilename; //์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ํŒŒ์ผ๋ช…
	
	@Builder
	public UploadFile(String uploadFilename, String storeFilename) {
		this.uploadFilename = uploadFilename;
		this.storeFilename = storeFilename;
	}
}

 

 

PostController ์ˆ˜์ • (๊ธ€ ๋“ฑ๋ก)

  1. @RequestPart() MultipartFile
  2. ๊ธ€ ๋“ฑ๋ก์‹œ ์ž…๋ ฅ๋ฐ›์€ ์ฒจ๋ถ€ํŒŒ์ผ์„ ์„œ๋ฒ„์— ์ €์žฅ
  3. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—๋Š” ํŒŒ์ผ๋ช… ์ €์žฅ 

 

	//๊ธ€ ๋“ฑ๋ก
	@PostMapping("/post/add")
	public void post(HttpServletRequest request, HttpSession session, HttpServletResponse response, @RequestPart("attach") MultipartFile file) throws Exception {
		Users user = (Users)session.getAttribute("loginUser");	
		
		//์ฒจ๋ถ€ํŒŒ์ผ ์ฒ˜๋ฆฌ
		UploadFile attachFile = null;
		try {
			attachFile = FileStore.storeFile(file);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		PostReqDto requestDto = new PostReqDto(request.getParameter("title"), request.getParameter("contents"), user, request.getParameter("category_name"), attachFile);
		System.out.println(requestDto.getCategory_name());
		log.info("view to controll with post");
		postService.addPost(requestDto);
		response.sendRedirect("/list");
	}

 

 

 

PostService ์ˆ˜์ • 

 

	@Transactional
	public Posts addPost(PostReqDto requestDto) {
		Category category = categoryRepository.findByName(requestDto.getCategory_name());
		UploadFile file = attachRepository.save(requestDto.getFile());
		Posts post = new Posts(requestDto.getTitle(), requestDto.getContents(), requestDto.getUser(), category, file);
		return postRepository.save(post);
	}

 

 

 

attachRepository ์ƒ์„ฑ

 

package com.sjy.shopping.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.sjy.shopping.model.entity.UploadFile;

public interface AttachRepository extends JpaRepository<UploadFile, Long> {

}

 

 

Front - request

form ํƒœ๊ทธ ๋‚ด <input type="file"> ๋กœ ํŒŒ์ผ ์ „์†ก

 

<div class="form-group">
    <label class="control-label col-sm-2" for="attach">์ฒจ๋ถ€ํŒŒ์ผ:</label>
    <div class="col-sm-10">
        <input type="file" class="form-control" id="attach" name="attach">
    </div>
</div>

 

 

Front - response

 

<tr>
    <td>์ฒจ๋ถ€ํŒŒ์ผ(ํด๋ฆญ์‹œ ๋‹ค์šด)</td>
    <td><a th:if="${post.file}" th:href="|/attach/${post.id}|" th:text="${post.file.uploadFilename}"/></td>
</tr>

 

 

์ฒจ๋ถ€ํŒŒ์ผ ํด๋ฆญ์‹œ ๋‹ค์šด

PostController์— ์ž‘์„ฑ

 

    //์ฒจ๋ถ€ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ
    @GetMapping("/attach/{id}")
    public ResponseEntity<UrlResource> download(@PathVariable long id) throws MalformedURLException{
    	Posts post = postService.findPost(id);
    	String storeFilename = post.getFile().getStoreFilename();
    	String uploadFilename = post.getFile().getUploadFilename();
    	
    	UrlResource urlResource = new UrlResource("file:" + FileStore.getPullPath(storeFilename));
    	
    	//ํ•œ๊ธ€ ์ธ์ฝ”๋”ฉ
    	String encodedUploadFileName = UriUtils.encode(uploadFilename, StandardCharsets.UTF_8);
    	String contentDisposition = "attachment; filename=\"" + encodedUploadFileName + "\"";
    	
    	//header์— CONTENT_DIPOSITION ์„ค์ •์„ ํ†ตํ•ด ํด๋ฆญ์‹œ ๋‹ค์šด๋กœ๋“œ ์„ค์ •
    	return ResponseEntity.ok()
    			.header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
    			.body(urlResource);

    }

 

 

 

 

 

์ฐธ๊ณ ์ž๋ฃŒ

 

[Spring Boot] ํŒŒ์ผ ์—…๋กœ๋“œ

Spring Boot ํŒŒ์ผ ์—…๋กœ๋“œ ์˜ˆ์ œ [Spring Boot] CRUD ๊ฒŒ์‹œํŒ (DB ์‚ฌ์šฉ X, ํšŒ์› ๊ธฐ๋Šฅ X) ์ด ์˜ˆ์ œ์— ํŒŒ์ผ ์—…๋กœ๋“œ, ๋‹ค์šด๋กœ๋“œ + ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ, ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ด๋ณด๋ฉฐ ํŒŒ์ผ์—…๋กœ๋“œ ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž Thymele

chb2005.tistory.com