ajax 비동기 로 진행 막대 영상 을 업로드 하고 미리 보기 그림 을 추출 합 니 다.

최근 에는 미디어 기능 이 풍부 한 프로젝트 를 하고 있다.동 영상 올 려 야 돼.여기 서 저 는 비동기 업로드 가 되 고 진도 가 있 으 며 상태 코드,영상 연결,미리 보기 그림 에 응답 하고 싶 습 니 다.
서버 응답

 {
   "thumbnail": "/slsxpt//upload/thumbnail/fdceefc.jpg",
   "success": true,
   "link": "/slsxpt//upload/video/fdceefc.mp"
 }
그리고 내 input file 컨트롤 이 form 태그 에 싸 이지 않 았 으 면 좋 겠 습 니 다.이 유 는 form 에 form 을 삽입 할 수 없 기 때 문 입 니 다.또한 form 라벨 은 브 라 우 저 에 약간의 기본 스타일 이 있 기 때문에 css 를 쓸 수도 있 습 니 다.
이전에 ajax FileUpload 로 파일 비동기 업 로드 를 한 적 이 있 습 니 다.그러나 이 물건 은 오랫동안 업데이트 되 지 않 았 고 코드 와 bug 가 있 었 습 니 다.마지막 에 겨우 성공 적 으로 사 용 했 지만 좋 지 않 았 습 니 다.또한 ajax FileUpload 는 xhr 2 의 progress 이벤트 응답 을 직접 추가 하지 않 아 귀 찮 습 니 다.
인터넷 에서 찾 아 보 니 방법 이 매우 많다.
예 를 들 어 파일 을 업로드 한 후 업로드 진 도 를 session 에 넣 고 서버 session 에 문의 합 니 다.그러나 저 는 이 방법 에 문제 가 있다 고 생각 합 니 다.저 는 이런 방법 으로 본 진 도 는 제 서버 응용 프로그램 코드(제 것 은 action)가 서버 의 임시 디 렉 터 리 에서 파일 을 복사 하 는 진도 라 고 생각 합 니 다.모든 요청 은 서버 소프트웨어,즉 tomcat,tomcat 가 요청 에 대해 세 션,request 등 대상 을 봉인 해 야 하기 때 문 입 니 다.그리고 파일 도 실제로 받 아야 합 니 다.즉,내 action 코드 가 실행 되 기 전에 파일 이 실제로 업로드 되 었 다 는 것 이다.
나중에 jquery.form.js 플러그 인 을 사용 하 는 ajax Submit 방법 을 찾 았 습 니 다.이 방법 은 폼 으로 제출 합 니 다.즉,$.fn.ajaxsubmit.:$(form selector).ajaxsubmit({})입 니 다.이 api 의 장점 은 xhr 2 의 progress 시간 을 처리 한 것 입 니 다.호출 할 때 upload Progress 의 function 을 전달 하여 function 에서 진 도 를 얻 을 수 있 습 니 다.그리고 input file 이 form 에 싸 여 있 지 않 으 려 면 코드 에 createElement 가 있 을 수 있 습 니 다.그러나 이 방법 은 내 가 작은 실 수 를 했 기 때문에 결국 성공 하지 못 해서 애석 하 다.
ajax Submit 소스 코드
마지막 으로$.ajax 방법 으로 만 들 었 습 니 다.$..ajax 는 form 과 연결 할 필요 가 없습니다.약간 정적 인 방법 같 습 니 다.유일한 아 쉬 움 은$.ajax options 에서 progress 에 대한 응답 이 없습니다.그러나 이것 은 xhr 라 는 매개 변수 가 있 습 니 다.즉,xhr 를 맞 출 수 있 습 니 다.그러면 xhr 를 통 해 progress 의 이벤트 처리 프로그램 을 추가 할 수 있 습 니 다.ajax Submit 방법 에서 progress 사건 에 대한 처 리 를 결합 하여 보 니 갑자기 밝 아 졌 다.

그럼 저도$.ajax 방법 에 progress 이벤트 처리 함 수 를 추가 할 수 있 습 니 다.dom 에 대한 작업 을 업로드 업무 에서 추출 하기 위해 플러그 인 형식 으로 쓰기 로 했 습 니 다.다음은 플러그 인 코드 입 니 다.

 ;(function ($) {
   var defaults = {
       uploadProgress    :  null,
       beforeSend      :  null,
       success        :  null,
     },
     setting = {
     };
   var upload = function($this){
     $this.parent().on('change',$this,function(event){
       //var $this = $(event.target),
       var  formData = new FormData(),
         target = event.target || event.srcElement;
       //$.each(target.files, function(key, value)
       //{
       //  console.log(key);
       //  formData.append(key, value);
       //});
       formData.append('file',target.files[]);
       settings.fileType && formData.append('fileType',settings.fileType);
       $.ajax({
         url        :  $this.data('url'),
         type      :  "POST",
         data      :  formData,
         dataType    :  'json',
         processData    :  false,
         contentType    :  false,
         cache      :  false,
         beforeSend    :  function(){
           //console.log('start');
           if(settings.beforeSend){
             settings.beforeSend();
           }
         },
         xhr        :   function() {
           var xhr = $.ajaxSettings.xhr();
           if(xhr.upload){
             xhr.upload.addEventListener('progress',function(event){
               var total = event.total,
                 position = event.loaded || event.position,
                 percent = ;
               if(event.lengthComputable){
                 percent = Math.ceil(position / total * );
               }
               if(settings.uploadProgress){
                 settings.uploadProgress(event, position, total, percent);
               }
             }, false);
           }
           return xhr;
         },
         success      :  function(data,status,jXhr){
           if(settings.success){
             settings.success(data);
           }
         },
         error      :  function(jXhr,status,error){
           if(settings.error){
             settings.error(jXhr,status,error);
           }
         }
       });
     });
   };
   $.fn.uploadFile = function (options) {
     settings = $.extend({}, defaults, options);
     //     
     return this.each(function(){
       upload($(this));
     });
   }
 })($ || jQuery);
다음은 제 jsp 페이지 에서 이 api 를 사용 할 수 있 습 니 다.

<div class="col-sm-">
   <input type="text" name="resource_url" id="resource_url" hidden="hidden"/>
   <div class="progress" style='display: none;'>
     <div class="progress-bar progress-bar-success uploadVideoProgress" role="progressbar"
        aria-valuenow="" aria-valuemin="" aria-valuemax="" style="width: %">
     </div>
   </div>
   <input type="file" class="form-control file inline btn btn-primary uploadInput uploadVideo"
      accept="video/mp"
      data-url="${baseUrl}/upload-video.action"
      data-label="<i class='glyphicon glyphicon-circle-arrow-up'></i> &nbsp;    " />
   <script>
     (function($){
       $(document).ready(function(){
         var $progress  = $('.uploadVideoProgress'),
             start = false;
         $('input.uploadInput.uploadVideo').uploadFile({
           beforeSend   : function(){
             $progress.parent().show();
           },
           uploadProgress : function(event, position, total, percent){
             $progress.attr('aria-valuenow',percent);
             $progress.width(percent+'%');
             if(percent >= ){
               $progress.parent().hide();
               $progress.attr('aria-valuenow',);
               $progress.width(+'%');
             }
           },
           success     : function(data){
             if(data.success){
               setTimeout(function(){
                 $('#thumbnail').attr('src',data.thumbnail);
               },);
             }
           }
         });
       });
     })(jQuery);
   </script>
 </div>
succes 에 응답 할 때 800 밀리초 초과 설정 을 한 후에 그림 을 가 져 옵 니 다.추출 축 량 도 는 다른 프로 세 스 가 응답 이 완 료 될 때 미리 보기 그림 이 추출 되 지 않 았 기 때 문 입 니 다.
효 과 를 보다

축 량 도 추출
아래 부분 은 서버 에서 업 로드 를 처리 하고 동 영상 추출 축 량 도 아래 는 action 의 처리 코드 입 니 다.

package org.lyh.app.actions;
 import org.apache.commons.io.FileUtils;
 import org.apache.struts.ServletActionContext;
 import org.lyh.app.base.BaseAction;
 import org.lyh.library.SiteHelpers;
 import org.lyh.library.VideoUtils;
 import java.io.File;
 import java.io.IOException;
 import java.security.KeyStore;
 import java.util.HashMap;
 import java.util.Map;
 /**
 * Created by admin on //.
 */
 public class UploadAction extends BaseAction{
   private String saveBasePath;
   private String imagePath;
   private String videoPath;
   private String audioPath;
   private String thumbnailPath;
   private File file;
   private String fileFileName;
   private String fileContentType;
   //   setter getter  
   public String video() {
     Map<String, Object> dataJson = new HashMap<String, Object>();
     System.out.println(file);
     System.out.println(fileFileName);
     System.out.println(fileContentType);
     String fileExtend = fileFileName.substring(fileFileName.lastIndexOf("."));
     String newFileName = SiteHelpers.md(fileFileName + file.getTotalSpace());
     String typeDir = "normal";
     String thumbnailName = null,thumbnailFile = null;
     boolean needThumb = false,extractOk = false;
     if (fileContentType.contains("video")) {
       typeDir = videoPath;
       //      
       needThumb = true;
       thumbnailName = newFileName + ".jpg";
       thumbnailFile
           = app.getRealPath(saveBasePath + thumbnailPath) + "/" + thumbnailName;
     }
     String realPath = app.getRealPath(saveBasePath + typeDir);
     File saveFile = new File(realPath, newFileName + fileExtend);
     //       ,  
     if (!saveFile.exists()) {
       if (!saveFile.getParentFile().exists()) {
         saveFile.getParentFile().mkdirs();
       }
       try {
         FileUtils.copyFile(file, saveFile);
         if(needThumb){
           extractOk = VideoUtils.extractThumbnail(saveFile, thumbnailFile);
           System.out.println("       :"+extractOk);
         }
         dataJson.put("success", true);
       } catch (IOException e) {
         System.out.println(e.getMessage());
         dataJson.put("success", false);
       }
     }else{
       dataJson.put("success", true);
     }
     if((Boolean)dataJson.get("success")){
       dataJson.put("link",
           app.getContextPath() + "/" + saveBasePath + typeDir + "/" + newFileName + fileExtend);
       if(needThumb){
         dataJson.put("thumbnail",
             app.getContextPath() + "/" + saveBasePath + thumbnailPath + "/" + thumbnailName);
       }
     }
     this.responceJson(dataJson);
     return NONE;
   }
 }
액 션 설정

 <action name="upload-*" class="uploadAction" method="{}">
     <param name="saveBasePath">/upload</param>
     <param name="imagePath">/images</param>
     <param name="videoPath">/video</param>
     <param name="audioPath">/audio</param>
     <param name="thumbnailPath">/thumbnail</param>
 </action>
여기 서 개인 적 으로 파일 의 이름 이 크기 와 같다 면 파일 일 확률 이 매우 높다 고 생각 합 니 다.그래서 저 는 파일 이름과 파일 크기 를 md5 로 연산 하면 같은 파일 을 중복 업로드 하 는 것 을 조금 피 할 수 있 을 것 입 니 다.
코드 를 바 꿀 때 FFmpeg 을 사용 합 니 다.필요 한 건 여기 서 다운로드 할 수 있어 요.

package org.lyh.library;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 /**
 * Created by admin on //.
 */
 public class VideoUtils {
   public static final String FFMPEG_EXECUTOR = "C:/Software/ffmpeg.exe";
   public static final int THUMBNAIL_WIDTH = ;
   public static final int THUMBNAIL_HEIGHT = ;
   public static boolean extractThumbnail(File inputFile,String thumbnailOutput){
     List<String> command = new ArrayList<String>();
     File ffmpegExe = new File(FFMPEG_EXECUTOR);
     if(!ffmpegExe.exists()){
       System.out.println("       ");
       return false;
     }
     System.out.println(ffmpegExe.getAbsolutePath());
     System.out.println(inputFile.getAbsolutePath());
     command.add(ffmpegExe.getAbsolutePath());
     command.add("-i");
     command.add(inputFile.getAbsolutePath());
     command.add("-y");
     command.add("-f");
     command.add("image");
     command.add("-ss");
     command.add("");
     command.add("-t");
     command.add(".");
     command.add("-s");
     command.add(THUMBNAIL_WIDTH+"*"+THUMBNAIL_HEIGHT);
     command.add(thumbnailOutput);
     ProcessBuilder builder = new ProcessBuilder();
     builder.command(command);
     builder.redirectErrorStream(true);
     try {
       long startTime = System.currentTimeMillis();
       Process process = builder.start();
       System.out.println("    "+(System.currentTimeMillis()-startTime));
       return true;
     } catch (IOException e) {
       e.printStackTrace();
       return false;
     }
   }
 }
또한 자바 에서 다른 프로 세 스 를 시 작 했 습 니 다.제 가 보기 에는 서로 상 관 없 는 것 같 습 니 다.자바 가 ffmpeg.exe 를 시작 한 후에 다음 코드 를 계속 실행 해 야 하기 때문에 따로 스 레 드 를 만들어 축 량 도 를 추출 할 필요 가 없습니다.테스트 해 보 니 시간 이 많이 걸 리 지 않 았 다.매번 긴 전송 시간 도 차이 가 크 지 않 습 니 다.다음은 같은 파일 을 두 번 업로드 하 는 데 걸 리 는 시간 입 니 다.
처음

두 번 째


사용자 체험 에 있어 서 큰 차이 가 없다.
그리고 여기 큰 파일 을 업로드 하려 면 tomcat 와 struct 를 설정 해 야 합 니 다.
tomcat 아래 conf 디 렉 터 리 에 있 는 server.xml 파일 을 수정 하고 커 넥 터 노드 에 속성 maxPostSize="0"을 추가 하면 업로드 크기 를 표시 하지 않 습 니 다.
또한 struts.xml 추가 설정 을 수정 합 니 다.여기 value 단 위 는 바이트 입 니 다.여 기 는 약 300 여 mb 입 니 다.

좋은 웹페이지 즐겨찾기