스프링

 

 

https://greatps1215.tistory.com/5

 

https://extracold.tistory.com/40

 

위 두 사이트를 참조로 진행

폴더 : 152.스프링_멀티파일 업로드

 

pom.xml

<dependency> 
    <groupId>org.imgscalr</groupId> 
    <artifactId>imgscalr-lib</artifactId> 
    <version>4.2</version>
</dependency>
 
 
<dependency> 
    <groupId>org.lazyluke</groupId> 
    <artifactId>log4jdbc-remix</artifactId> 
    <version>0.2.7</version> 
</dependency>

 

 

jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<style type="text/css">
#request_file { display: none;}
.my_button {
            display: inline-block;
            width: 200px;
            text-align: center;
            padding: 10px;
            background-color: #006BCC;
            color: #fff !important;
            text-decoration: none;
            border-radius: 5px;
        }
.my_button:hover{color: #fff;}
.imgs_wrap {
       border: none;
       margin-top: 30px;
       margin-bottom: 30px;
       padding-top: 10px;
       padding-bottom: 10px;
 
   }
  .imgs_wrap img {
      max-width: auto;
      margin-left: 10px;
      margin-right: 10px;    
      max-height: 120px;
    padding: 5px;  
  }
 
.col-xs-5ths,
.col-sm-5ths,
.col-md-5ths,
.col-lg-5ths {
    position: relative;
    min-height: 1px;
    padding-right: 15px;
    padding-left: 15px;
}
 
.col-xs-5ths {
    width: 20%;
    float: left;
}
 
@media (min-width: 768px) {
    .col-sm-5ths {
        width: 20%;
        float: left;
    }
}
 
@media (min-width: 992px) {
    .col-md-5ths {
        width: 20%;
        float: left;
    }
}
 
@media (min-width: 1200px) {
    .col-lg-5ths {
        width: 20%;
        float: left;
    }
}
    </style> 
     
    <div id="myModal1" class="modal modal-child" data-backdrop-limit="1" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
            aria-hidden="true" data-modal-parent="#myModal">
            <div class="modal-dialog modal-lg">
                <div class="modal-content" style="height: 800px;">
                    <!-- body -->
                    <div class="modal-body" style="padding: 50px; padding-top: 40px; width: 440px; height: 400px;">
 
                        <!-- 부모 모달 -->
                        <button type="button" class="close" data-dismiss="modal"
                            id="close1" aria-label="Close"
                            style="position: relative; bottom: 320px; left: 770px;">
                            <span class="ion-android-close" aria-hidden="true" style="color: #000; cursor: pointer;"></span>
                        </button>
                        <div class="row justify-content-center mt-0">
                            <div
                                class="col-11 col-sm-9 col-md-7 col-lg-6 text-center p-0 mt-3 mb-2"
                                style="width: 500px; padding-left: 10px;">
                                <div class="card px-0 pt-4 pb-0 mt-3 mb-3" style="width: 700px; position: relative; right: 140px; border: none;">
                                    <h3 id="top"></h3>
                                    <div class="row" style="height: 500px">
                                        <div class="col-md-12 mx-0">
                                         
                                            <form id="msform"  method="post" enctype="multipart/form-data">
                                                 
                                                <!-- progressbar -->
                                                <ul id="progressbar">
                                                    <li class="active" id="account"><strong>건물 유형</strong></li>
                                                    <li id="personal"><strong>수리 유형</strong></li>
                                                    <li id="payment"><strong>첨부 사진</strong></li>
                                                    <li id="confirm"><strong>간단 요청</strong></li>
                                                </ul>
                                                 
                                                <!-- fieldsets -->
                                                <fieldset>
                                                    <div class="form-card " style="height: 450px;">
                                                        <!-- 여기 라디오 버튼 : form -->
                                                        <b>* 선택해주세요.</b><br> <br> 
                                                         
                                                        <div class="row">
                                                            <div class="col-8 col-sm-8">
                                                                <input type="radio" name="building_type" value="1" id="structure1" checked="checked">
                                                                <span>아파트</span>
                                                            </div>
                                                             
                                                            <div class="col-4 col-sm-4">
                                                                <input type="radio" name="building_type"  value="2"  id="structure1"> 
                                                                <span>단독주택</span>
                                                            </div>
                                                             
                                                            <div class="col-8 col-sm-8">
                                                                <input type="radio" name="building_type"   value="3" id="structure1">
                                                                <span>빌라/연립주택</span>                                                                
                                                            </div>
                                                             
                                                            <div class="col-4 col-sm-4">
                                                                <input type="radio" name="building_type"   value="4" id="structure1">
                                                                <span>빌딩/상가</span>                                                              
                                                            </div>
                                                             
                                                            <div class="col-8 col-sm-8">
                                                                <input type="radio" name="building_type"   value="5" id="structure1">
                                                                <span>기타</span>                                                                 
                                                            </div>                                                    
                                                             
                                                        </div>
                                                     
                                                        <div class="row">
                                                            <div class="col-12 col-sm-12">
                                                            <textarea rows="4" cols="20" maxlength="50" style="border: 1px solid lightgray;" id="building_text" name="building_text"></textarea>
                                                            </div>
                                                        </div>
                                                         
                                                        <b class="page_number">1/4</b>
                                                    </div>
                                                    <!-- 버튼 -->
                                                    <input type="button" name="next" class="next action-button" value="다음" id="next" />
                                                </fieldset>
                                                 
                                                <fieldset style="display: none;">
                                                    <div class="form-card " style="height: 450px;">
                                                        <!-- 여기 라디오 버튼 : form -->
                                                        <b>* 선택해주세요.</b><br> <br> 
                                                         
                                                        <div class="row">
                                                            <div class="col-8 col-sm-8">
                                                                <input type="radio" name="repair_type"  value="1"  id="structure1" checked="checked">
                                                                <span>전자제품 수리</span> 
                                                            </div>
         
 
                                                            <div class="col-4 col-sm-4">
                                                                <input type="radio" name="repair_type"  value="2"  id="structure1" >
                                                                <span>가구수리</span> 
                                                            </div>
 
                                                            <div class="col-8 col-sm-8">
                                                                <input type="radio" name="repair_type"  value="3"  id="structure1" >
                                                                <span>열쇠/도어락 수리</span> 
                                                            </div>                                                        
                             
                                                            <div class="col-4 col-sm-4">
                                                                <input type="radio" name="repair_type"  value="4"  id="structure1" >
                                                                <span>전기 배선 수리</span> 
                                                            </div>                                                                
 
                                                            <div class="col-8 col-sm-8">
                                                                <input type="radio" name="repair_type" value="5"  id="structure1">
                                                                <span>방충망 및 방범창 수리</span> 
                                                            </div>                                            
                                                 
                                                            <div class="col-4 col-sm-4">
                                                                <input type="radio" name="repair_type" value="6"  id="structure1">
                                                                <span>문 수리</span> 
                                                            </div>                                                            
 
                                                            <div class="col-8 col-sm-8">
                                                                <input type="radio" name="repair_type" value="7"  id="structure1">
                                                                <span>수도 관련 수리</span> 
                                                            </div>
                                                             
                                                            <div class="col-4 col-sm-4">
                                                                <input type="radio" name="repair_type" value="8"  id="structure1">
                                                                <span>기타</span> 
                                                            </div>                                                                                                                                                                                                    
                                                        </div>
                                                         
                                                         
                                                    <div class="row">
                                                        <div class="col-12 col-sm-12">    
                                                            <textarea rows="4" cols="20" maxlength="50"  style="border: 1px solid lightgray;" id=repair_text name="repair_text"></textarea>
                                                         </div>   
                                                    </div>
                                                         
                                                        <b class="page_number">2/4</b>                                              
                                                    </div>
                                                     
                                                    <!-- 버튼 -->
                                                    <input type="button" name="previous" class="previous action-button-previous" value="이전" /> 
                                                    <input type="button" name="next" class="next action-button" value="다음" />
                                                </fieldset>
                                                 
                                                <fieldset style="display: none;">
                                                    <div class="form-card" style="height: 400px;">
                                                        <!-- 사진을 첨부해주세요.: form -->
                                                        <span style="font-size: 15px; color: lightgray;">*최대 10장</span>
     
                                                        <div>
                                                            <div class="imgs_wrap row" style="height: 210px;width: 600px;border: none;top: -20px;position: relative;">
                                                                <img id="img" style="display: none;"/>
                                                            </div>
                                                        </div>
                                                         
                                                        <div class="row">       
                                                            <div class="input_wrap col-12 col-sm-12 text-center">
                                                                <a href="javascript:" onclick="fileUploadAction();" class="my_button">파일 업로드</a>
                                                                <input type="file" id="request_file" name="request_file" multiple="true" />
                                                            </div>
                                                        </div>
                                                        <b class="page_number">3/4</b>
                             
                                                                 
                                                    </div>
                                                    <!-- 버튼 -->
                                                    <input type="button" name="previous" class="previous action-button-previous" value="이전" /> 
                                                    <input type="button" name="next" class="next action-button" value="다음" />
                                                </fieldset>
                                                 
                                                <fieldset style="display: none;">
                                                    <div class="form-card">
                                                        <b>* 공식적인 요청 외 전문가에게 무리한 요구시 요청이 거절될 수 있습니다.</b>
                                                        <textarea rows="10" cols="20" maxlength="70" style="border: 1px solid lightgray;" id="simple_req_text" name="simple_req_text" placeholder="내용을 입력하세요."></textarea>
                                                        <b class="page_number">4/4</b>
                                                    </div>
                                                    <input type="button" class="previous action-button-previous" value="이전" /> 
                                                    <input type="button" name="finish" id="finish" class="action-button" value="요청"  />
                                                    <input type="hidden" name="expert_id" value="${param.expert}"  >
                                                </fieldset>
                                                 
                                                 
                                            </form>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
 
                    </div>
                    <!-- modal-body -->
                </div>
                <!-- .modal -->
            </div>
            <!-- .modal-dialog -->
        </div>
 
         
 
 
 
 
 
<script type="text/javascript">
// 이미지 정보들을 담을 배열
var sel_files = [];
 
$(document).ready(function() {
     $("#request_file").on("change", handleImgFileSelect);     
     $("#finish").on("click", function(event){
        submitAction(); 
     });
      
 }); 
 
function fileUploadAction() {
    $("#request_file").trigger('click');
}
 
function handleImgFileSelect(e) {
 
        // 이미지 정보들을 초기화
        sel_files = [];
        $(".imgs_wrap").empty();
 
        var files = e.target.files;
 
        if (files.length >= 10) {
            alert("최대 10장만 업로드 가능합니다.");
            return;
        }
 
        var filesArr = Array.prototype.slice.call(files);
 
        var index = 0;
        filesArr.forEach(function(f) {
            if (!f.type.match("image.*")) {
                alert("확장자는 이미지 확장자만 가능합니다.");
                return;
            }
 
            sel_files.push(f);
 
            var reader = new FileReader();
            reader.onload = function(e) {
                var html = "<div class='col-md-5ths col-xs-6 upload_image'  data-file='"+f.name+"' ><a href=\"javascript:void(0);\" onclick=\"deleteImageAction("
                        + index
                        + ")\" id=\"img_id_"
                        + index
                        + "\"><img src=\"" + e.target.result + "\" data-file='"+f.name+"'  class='request_img_file' title='Click to remove'></a></div>";
 
                $(".imgs_wrap").append(html);
                index++;
 
                 
                 $(".removeButton").on("click", function(){
                     $(this).closest('div').remove();
                     document.getElementById("file").value = "";
                  });
 
            }
            reader.readAsDataURL(f);
 
        });
 
}
 
function deleteImageAction(index) {
    sel_files.splice(index, 1);
    delete sel_files[index];
     
    var img_id = "#img_id_" + index;
     
    $(img_id).val("");
    $(img_id).parent("div").remove();   
    console.log("삭제 후 배열 값: "); 
    console.dir(sel_files);
}
 
 
 
function cleanInputs(fileEle, oriName){
    var fileData=$("#request_file").val();
    console.log(" fileData : 파일 ");
    console.dir(fileData);
     
}
 
function fileUploadAction() {
    $("#request_file").trigger('click');
}
 
function submitAction() {
    console.log("업로드 파일 갯수 : " + sel_files.length);
 
    if (sel_files.length < 1) {
        //alert("한개이상의 파일을 선택해주세요.");
        return;
    }
 
    var formData = new FormData($('#msform')[0]);
 
    //삭제 처리시  실질 적으로 업로드할 이미지명 과 비교할 데이터
     $(".upload_image").each(function(){
           console.log($(this).attr("data-file"));
           formData.append('realFiles',$(this).attr("data-file")); 
    });    
      
   formData.append("image_count", sel_files.length);    
     
    $.ajax({
        type : "POST",
        enctype : 'multipart/form-data',
        url : '/Request.Ajax',
        data : formData,
        processData : false,
        contentType : false,
        cache : false,
        success : function(result) {
 
            var re=$.trim(result);
            if(re=="success"){
                alert("등록 처리 되었습니다.");  
                location.reload();              
                // 썸네일 출력 ex 
                //http://localhost:8080/resources/resources/Requestupload/2020-7-19/thumb_rq202071981184285.jpg
            }else if(re=="error"){
                alert("등록에 실패 하였습니다.");
            }                       
        },
        error : function(e) {
 
        }
    });
 
}
</script>

 

 

 

 

 

Controller

	@ResponseBody
	@RequestMapping(value = "/Request.Ajax", method = RequestMethod.POST)
	public String  request_ajax(@RequestParam("realFiles") List realFiles , MultipartHttpServletRequest request,  @RequestParam Map paramMap) throws Exception {
		
		for(String realImage : realFiles) {           
			logger.info("realFiles : "+realImage);
        }
				
		String userId=(String)request.getSession().getAttribute("user_id");
		String expertId=(String)request.getSession().getAttribute("expert_id");	
		
		/** writer_type 1:사용자 로그인,  2:전문가 로그인 , 3:로그인 안한 유저  */
		int writerType=0;
		if(userId!=null) {			
			logger.info("사용자 로그인 아이디 : " +userId);
			writerType=1;
			paramMap.put("writer", userId);
		}else if(expertId!=null) {			
			logger.info("전문가 로그인 아이디 : " +expertId);
			writerType=2;
			paramMap.put("writer", expertId);
		}
		paramMap.put("writer_type", writerType);
				
		int result=expertservice.requestAjax(realFiles, request, paramMap);	
		return result!=5? "success": "error";		
	}
	

 

 

@Service

	@Override
	@Transactional
	public int requestAjax(List realFiles , MultipartHttpServletRequest request, Map paramMap) {
		logger.info("\n\n requestAjax  요청 파라미터 값 reqMap : " + paramMap.toString());

		//1.Request 테이블에 데이터 등록
		exdao.insertRequest(paramMap);
		logger.info(" 시퀀스 반환 값 : " + paramMap.get("request_no"));
		
		int result = 0;
		List fileList = new ArrayList();

		/** 파일이 존재할 경우 **/
		if (realFiles!=null && request.getFiles("request_file").get(0).getSize() != 0) {


			
			fileList = request.getFiles("request_file");
			Calendar c = Calendar.getInstance();
			int year = c.get(Calendar.YEAR);
			int month = c.get(Calendar.MONTH) + 1;
			int date = c.get(Calendar.DATE);
			String saveFolder = request.getSession().getServletContext().getRealPath("resources") + File.separator+"Requestupload" + File.separator;
			String homedir = saveFolder + year + "-" + month + "-" + date;

			File path1 = new File(homedir);

			if (!(path1.exists())) {
				path1.mkdir();
			}
			
			
			for(String realImage : realFiles) {           
						
						for (MultipartFile mf : fileList) {
															
								String originalFilename = mf.getOriginalFilename();
								if(realImage.equals(originalFilename)) {
									
									
										Random r = new Random();
										int random = r.nextInt(100000000);
					
										int index = originalFilename.lastIndexOf(".");
										String fileExtension = originalFilename.substring(index + 1);
										String realFileName = "rq" + year + month + date + random + "." + fileExtension;
										String dateFolder = year + "-" + month + "-" + date;
										String finalFile = saveFolder + dateFolder + File.separator + realFileName;
										String fileDBName = "/" + dateFolder + "/" + realFileName;
					
										try {
											// 파일생성
											mf.transferTo(new File(finalFile));
											
											String fileName = fileDBName;
											String fileOriginal = originalFilename;
											String fileThumbName = "/"+ makeThumbnail(saveFolder, fileDBName, originalFilename, dateFolder, realFileName);
											
											//paramMap.put("request_no", requestNo);
											paramMap.put("file_name", fileName);
											paramMap.put("file_original", fileOriginal);
											paramMap.put("file_thumb_name", fileThumbName);
											
											
											System.out.println("\n\n파일이름 . 위치 = " + index);
											System.out.println("원본 파일 명  = " + originalFilename);
											System.out.println("이미지 확장자 = " + fileExtension);
											System.out.println("새로운 파일명 = " + realFileName);
											System.out.println("최종 파일 저장 위치및 파일 명  " + finalFile);
											System.out.println("DB에 저장될 파일 내용  = " + fileDBName);
											System.out.println("DB에 저장될 썸네일 내용  = " + fileThumbName);
											System.out.println("데이터 베이스 등록 : file_name : " + fileName + " , file_original :" + fileOriginal+ " , file_thumb_name : " + fileThumbName);
																
											result=exdao.insertRequestFileData(paramMap);
											
										} catch (Exception e) {
											e.printStackTrace();
											result = 5;
										}
								
									
								}
			
						
						}
	            
	        }
	
		}
		return result;
	}

	/** 250 x 150 크기의 썸네일을 생성 */
	private String makeThumbnail(String saveFolder, String fileDBName, String originalFileName, String dateFolder,
			String refileName) throws Exception {
		int index = originalFileName.lastIndexOf(".");
		String fileExt = originalFileName.substring(index + 1);

		// 저장된 원본파일로부터 BufferedImage 객체를 생성
		BufferedImage srcImg = ImageIO.read(new File(saveFolder + fileDBName));

		// 썸네일의 너비와 높이
		int dw = 250, dh = 150;

		// 원본 이미지의 너비와 높이
		int ow = srcImg.getWidth();
		int oh = srcImg.getHeight();

		// 원본 너비를 기준으로 하여 썸네일의 비율로 높이를 계산
		int nw = ow;
		int nh = (ow * dh) / dw;

		// 계산된 높이가 원본보다 높다면 crop이 안되므로 원본 높이를 기준으로 썸네일의 비율로 너비를 계산
		if (nh > oh) {
			nw = (oh * dw) / dh;
			nh = oh;
		}

		// 계산된 크기로 원본이미지를 가운데에서 crop
		BufferedImage cropImg = Scalr.crop(srcImg, (ow - nw) / 2, (oh - nh) / 2, nw, nh);

		// 1.crop된 이미지로 썸네일을 생성
		// BufferedImage destImg = Scalr.resize(cropImg, dw, dh);

		// 2.원본 이미지의 비율을 유지하면서 높이를 150px
		BufferedImage destImg = Scalr.resize(srcImg, Scalr.Method.AUTOMATIC, Scalr.Mode.FIT_TO_HEIGHT, 150);

		// 3.원본 이미지의 비율을 유지하면서 너비를 250px
		// BufferedImage destImg = Scalr.resize(srcImg, Scalr.Method.AUTOMATIC,
		// Scalr.Mode.FIT_TO_WIDTH, 250);

		// thumb_ 붙여 썸네일을 저장
		String thumbName = saveFolder + dateFolder + File.separator + "thumb_" + refileName;
		File thumbFile = new File(thumbName);
		ImageIO.write(destImg, fileExt.toUpperCase(), thumbFile);

		return dateFolder + "/" + "thumb_" + refileName;
	}

 

 

mybatis

		       

		
	        SELECT request_seq.CURRVAL FROM DUAL
	    

	INSERT INTO REQUEST			
		(REQUEST_NO, EXPERT_ID, WRITER, WRITER_TYPE, BUILDING_TYPE, BUILDING_TEXT, REPAIR_TYPE, REPAIR_TEXT, SIMPLE_REQ_TEXT, REQUEST_DATE)	
	VALUES(request_seq.NEXTVAL, #{expert_id}, #{writer}, #{writer_type}, #{building_type}, #{building_text}, #{repair_type}, #{repair_text}, #{simple_req_text}, SYSDATE)
	


		       
	INSERT INTO REQUEST_FILE	
			(FILE_NO, REQUEST_NO, FILE_NAME, FILE_ORIGINAL, FILE_THUMB_NAME, REQUEST_FILE_DATE)	
	VALUES (request_file_seq.NEXTVAL, #{request_no}, #{file_name}, #{file_original}, #{file_thumb_name}, SYSDATE)	
	

 

 

멀티파일 업로드 후에 특정 파일 만  제거처리가 제대로 동작하지 않는다.  특정 파일을 제거를 한후 전송을 해도

 멀티파일 업로드 한 것 전체가 업로드 전송처리 되어 진다.  따라서

멀티파일 업로드 후 자바스크립트에서 삭제 처리가 어려워서 다음과 같이

미리보기에서 삭제 된  것들의 대상으로 업로드 파일명 따로 추출후  서버단으로 보내는 작업을 거쳤으며

//삭제 처리시  실질 적으로 업로드할 이미지명 과 비교할 데이터
	 $(".upload_image").each(function(){
		   console.log($(this).attr("data-file"));
		   formData.append('realFiles',$(this).attr("data-file")); 
	});	

 

서버단에서 다음과 같이 실질 적으로  비교 처리 하는 과정을 거쳤다.

for(String realImage : realFiles) {           
						
						for (MultipartFile mf : fileList) {
															
								String originalFilename = mf.getOriginalFilename();
								if(realImage.equals(originalFilename)) {
									

 

 

 

 

 

spring

 

about author

PHRASE

Level 60  라이트

한 가랑이에 두 다리 넣는다 , 몹시 서둘러 댐을 비유하는 말.

댓글 ( 5)

댓글 남기기

작성