[Spring Boot] 15. 사진 업로드 ①

shr·2022년 2월 25일
0

Spring

목록 보기
14/23
post-thumbnail

사진 업로드 ①


쇼핑몰에서 상품 사진을 업로드한다는 전제 하에 작업을 진행한다.


  1. CKEditor4 다운로드

    CKEditor4에서 Standard Package를 다운로드한다. 압축을 풀면 나오는 ckeditor 파일을 복사해 사용하려는 프로젝트의 static 폴더에 붙여넣기한다.

    📝 어떤 버전, 어떤 패키지를 받아도 상관은 없다.

    그리고 C 드라이브 원하는 위치에 /upload/ckupload 폴더를 만들어 준다. 임시로 사진 파일을 저장해 둘 곳이다.


  1. src/main/resources - product - add.html 생성
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
        <title>Insert title here</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
        <link rel="stylesheet" href="/css/main.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
        <!-- sweetalert (alert창 예쁘게) -->
        <script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
        <script src="/ckeditor/ckeditor.js"></script>
        <script>
            $(document).ready(function() {
                // 파일 업로드를 할 경로를 지정하자. (with csrf)
                const $ckUploadPath = "/product/image?_csrf=" + $('#_csrf').val();
                CKEDITOR.replace('info', {
                    filebrowserUploadUrl : $ckUploadPath
                })
            })
        </script>
    </head>
    <body>
    <div id="page">
        <!-- 시맨틱 마크업 -->
        <header th:replace="/fragments/header.html">
        </header>
        <nav th:replace="/fragments/nav.html">
        </nav>
        <div id="main">
            <aside th:replace="/fragments/aside.html">
            </aside>
            <section>
                <input type="hidden" name="_csrf" id="_csrf" th:value="${_csrf.token}">
                <div class="form-group">
                    <!-- 이 textarea를 ckeditor에 넘겨 준다. -->
                    <textarea class="form-control" rows="5" id="info" name="info"></textarea>
                </div>			
            </section>
        </div>
        <footer th:replace="/fragments/footer.html">
        </footer>
    </div>
    </body>
    </html>

  1. src/main/java - com.example.demo.controller.mvc - ProductController 생성

    package com.example.demo.controller.mvc;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    
    @Controller
    public class ProductController {
        // 상품 추가
        @GetMapping("/product/add")
        public void add() {
    
        }
    }

  1. src/main/java- com.example.demo.controller.rest - ProductRestController 생성

    package com.example.demo.controller.rest;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;
    
    import com.example.demo.dto.CKResponse;
    import com.example.demo.service.ProductService;
    
    @RestController
    public class ProductRestController {
        @Autowired
        private ProductService service;
    
        // 'add.html'에서 지정해 두었던 주소
        @PostMapping("/product/image")
        // MultipartFile 파라미터명 고정! 
        public ResponseEntity<CKResponse> ckImageUpload(MultipartFile /* 파라미터명 upload로 고정 */ upload) {
            CKResponse ckResponse = service.ckImageUpload(upload);
            return ResponseEntity.ok(ckResponse);
        }
    }

    📝 ck를 이용해 서버에 사진을 업로드하면 특정 형식으로 응답해야 한다.

    🚨 MultipartFile 파라미터명은 upload로 고정해야 한다.


  1. src/main/java - com.example.demo.dto - CKResponse 생성

    package com.example.demo.dto;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    
    @Data
    @AllArgsConstructor
    public class CKResponse {
        // 업로드한 이미지 개수
        private Integer uploaded;
        // 파일명 - 이미지 이름이 겹칠 수 있으니까 이름을 바꿔서 저장한다.
        private String fileName;
        // 이미지를 볼 수 있는 주소
        private String url;
    }

  1. src/main/java - com.example.demo.service - ProductService 생성

    package com.example.demo.service;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.UUID;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    import org.springframework.web.multipart.MultipartFile;
    
    import com.example.demo.dto.CKResponse;
    
    @Service
    public class ProductService {
        // 임시로 직접 만든 폴더를 연결해 준다.
        @Value("c:/java/upload/ckupload")
        private String CKImageFolder;
    
        @Value("/images/")
        private String ckImagepath;
    
        public CKResponse ckImageUpload(MultipartFile image){
            if (/* ★ 여기 순서 바뀌지 않도록 주의! */ image != null && image.isEmpty() == false) {
                // 파일명 바꾸기
                String imageName = UUID.randomUUID() + "-" + image.getOriginalFilename();
    
                // 하드디스크에 이미지를 저장할 파일을 생성
                File file = new File(CKImageFolder, imageName);
    
                // 이미지를 파일로 이동
                try {
                    image.transferTo(file);
                } catch (IllegalStateException | IOException e) {
                    e.printStackTrace();
                }
                return new CKResponse(1, imageName, ckImagepath + imageName);
            }
            return null;
        }
    
    }

    📝 스프링에서는 /member/find_id?username=spring/member/find_id/spring으로 적을 수 있다. /images/라고 적을 수 있는 게 그 이유다.


    📝 url-encoded 형식은 null 체크 또는 ""(빈 문자열) 체크가 필요하지만, form-data는 null 또는 빈 객체 체크가 필요하다.

    💡 UUID (Universally Unique IDentifier)

    범용 고유 식별자를 말한다. 실용적인 목적을 위해 고유성이 보장되는 id를 만드는 표준 규약이다. 128비트의 숫자이며 32자리의 16진수로 표현된다.


  1. src/main/resources - application.properties에 코드 추가
    ### 파일 업로드하는 방법 : apache commons fileupload, servlet 3.1 이후 직접 지원
    spring.servlet.multipart.enabled=true
    spring.servlet.multipart.max-request-size = 30MB
    spring.servlet.multipart.max-file-size = 10MB
profile
못하다 보면 잘하게 되는 거야 ・ᴗ・̥̥̥

0개의 댓글