AJAX 파일업로드 & 미리보기

2022. 1. 5. 11:45spring

<미리보기>

html

<div class="form-group w-100">
    <label for="examTicket" class="m-2 text-primary">수험표</label>
    <small class="form-text text-danger">* 수험표는 관리자의 승인 후 수정할 수 없습니다.</small>
    <th:block th:if="${#strings.equals(userInfo.membershipCd, '10')}">
        <form enctype="multipart/form-data" id="uploadImageForm">
            <input type="file" enctype="multipart/form-data" method="POST" class="form-control"
                   accept=".jpg, .jpeg, .png, .bmp"
                   id="imageInput" name="examTicketFile" th:value="${userInfo.examTicket}">
        </form>
    </th:block>
    <img class="w-100 my-3" alt="" th:src="${userInfo.examTicketPath}" id="examTicketImg">
</div


js

//이미지 미리보기
var sel_file;

$(document).ready(function() {
    $("#imageInput").on("change", handleImgFileSelect);
});

function handleImgFileSelect(e) {
    var files = e.target.files;
    var filesArr = Array.prototype.slice.call(files);

    var reg = /(.*?)\/(jpg|jpeg|png|bmp)$/;

    filesArr.forEach(function(f) {
        if (!f.type.match(reg)) {
            alert("확장자는 이미지 확장자만 가능합니다.");
            return;
        }

        sel_file = f;

        var reader = new FileReader();
        reader.onload = function(e) {
            $("#examTicketImg").attr("src", e.target.result);
        }
        reader.readAsDataURL(f);
    });
}



< 업로드 >
application.yml

spring:
  config:
    activate:
      on-profile: local
  servlet:
    multipart:
      #      enabled: true # 멀티파트 업로드 지원여부 (default: true)
      #      file-size-threshold: 1MB #  파일이 메모리에 기록되는 임계값 (default: 0B)
      location: C:/Temp # 업로드된 파일의 임시 저장 공간
      max-file-size: 100MB # 파일의 최대 사이즈 (default: 1MB)
      max-request-size: 100MB # 요청의 최대 사이즈 (default: 10MB)


config.java

package com.web.lawingmachine.app.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

//    addResourceHandler : 스프링부트에서 확인할 폴더 위치 설정 (img 폴더 밑에 아무거나 다 들어갈 수 있다)
//    addResourceLocations : 실제 시스템의 폴더 위치, 윈도우 시스템의 경우 'file:///경로' 형태로 사용

        registry.addResourceHandler("/upload/**").addResourceLocations("file:///C:/Temp/upload/");
    }
}

위 예제에서 알 수 있듯이 URI 가 /upload/ 이하로 요청이 될 경우 로컬 Disk 의 /opt/upload/ 경로에 있는 파일을 사용자에게 제공하겠다는 의미입니다. /upload/ 경로 이하의 모든 경로와 파일명은 /opt/upload/ 에서 동일하게 찾아서 제공해줍니다.
주의할 것은 resourceLocation 지정 시 로컬 경로일 때 "file:///" 접두어를 빼먹으면 안된다는 것입니다.


js

function uploadImage() {

    var header = $("meta[name='_csrf_header']").attr('content');
    var token = $("meta[name='_csrf']").attr('content');

    let url = '/mypage/myprofile/uploadImage';
    let formData = new FormData();
    formData.append("examTicketFile", $("#imageInput")[0].files[0]); // input 추가

    $.ajax({
        type: "POST",
        enctype: 'multipart/form-data',
        url: url,
        data: formData,
        processData: false,
        contentType: false,
        beforeSend: function (xhr) {
            xhr.setRequestHeader(header, token);
        },
        success: function (result) {
            let image = result['value'];
            console.log(image);
            $("#examTicket").attr("src", image);
        },
        error: function (result) {
            alert(result['message']);
        }
    });

-> beforeSend는 security 환경에서 post Ajax를 보낼 때 403 오류가 생기는 것 때문에 설정했다.

controller

    @Value("${spring.servlet.multipart.location}")
    private String BASE_PATH;
    
        @PostMapping("/myprofile/uploadImage")
    @ResponseBody
    public ResultMessageVO uploadImage(HttpServletRequest req, @RequestParam("examTicketFile") MultipartFile imageFile) throws IOException {

        ResultMessageVO result = new ResultMessageVO();

        if (!imageFile.isEmpty()) {

            String filename = imageFile.getOriginalFilename();
            String ext = null;

            if (filename != null) {
                if (filename.contains(".")) {
                    ext = filename.substring(filename.lastIndexOf("."));
                } else {
                    ext = "";
                }
            }

            if (!".jpg".equals(ext) && !".jpeg".equals(ext) && !".png".equals(ext) && !".bmp".equals(ext)) {
                result.setMessage("이미지 파일을 업로드 해주세요.(.jpg, .jpeg, .png, .bmp)");
                result.setResultCode("FAIL");
                return result;
            }

            String dirPath = "/upload/" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); // 오늘날짜
            String filepath = BASE_PATH.endsWith("/") ? BASE_PATH + dirPath : BASE_PATH + "/" + dirPath;

            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            String nfileName = uuid + ext;

            File targetFile = new File(filepath, nfileName);

            if (!targetFile.exists()) {
                targetFile.mkdirs();
            } else {
                targetFile.delete();
            }

            try {
                imageFile.transferTo(targetFile);
            } catch (IllegalStateException e) {
                e.printStackTrace();
            }

            String examTicketPath = dirPath + "/" + nfileName;

            SessionUser sessionUser = (SessionUser) req.getSession().getAttribute("sessionUser");
            int resultCnt = userService.uploadImage(examTicketPath, filename, sessionUser.getUserId());
            if (resultCnt > 0) {
                result.setValue(examTicketPath);
            }
        }

        return result;
    }

'spring' 카테고리의 다른 글

springboot mvn build test error  (0) 2022.01.08
@ConfigurationProperties  (0) 2022.01.07
java.net.BindException: Address already in use: bind  (0) 2022.01.04
Invalid CSRF token found for ...  (0) 2022.01.03
Request header is too large  (0) 2022.01.03