Ajax는 Spring과 협력하여 파일 업로드 기능을 구현합니다(그래픽 튜토리얼)

亚连
풀어 주다: 2018-05-22 15:41:34
원래의
1073명이 탐색했습니다.

최근에는 서버에 사진을 업로드할 수 있는 웹 표면 페이지를 개발 중입니다. 요구사항과 구현 아이디어를 공유하겠습니다. 필요한 친구들은 참고할 수 있습니다.

프로젝트의 필요로 인해 서버에 사진을 업로드할 수 있는 웹 양식 페이지입니다.

1. 요구 사항

웹 양식 페이지에서는 양식을 통해 사진 및 기타 텍스트 정보를 업로드할 수 있습니다.

2. 사진 업로드 과정

이런 페이지는 한번도 해본적이 없어서 정보를 문의하게 되네요. 일반적인 관행은 먼저 이미지를 서버측 파일 디렉터리에 업로드하고 서버가 이미지의 저장 경로를 프런트 데스크에 반환한 다음 프런트 데스크에서 이미지 저장 경로 및 기타 양식을 제출하는 것으로 나타났습니다. 정보는 서버로 전송되며 모든 양식 정보는 데이터베이스에 저장됩니다.

3. 방법

여기에서는 이미지를 업로드하는 두 가지 방법을 소개합니다. 첫 번째는 이미지를 직접 업로드하는 것입니다. 먼저 프런트 데스크에 파일을 업로드한 다음 ajax를 사용하여 이미지를 각각 서버에 업로드하면 서버가 파일 연결을 실현합니다. (대용량 파일을 업로드할 때는 방법 2가 적합합니다.) 아래에서는 두 가지 방법을 각각 소개하겠습니다.

방법 1:

1 html 페이지

<pre name="code" class="html"><!DOCTYPE html> 
<head></head> 
<body> 
<form id="uploadForm" action="/PicSubmit/form" method="post" enctype="multipart/form-data" onsubmit="return submit_check()" class="bootstrap-frm" >
<input id = "sid" type = "text" name="name" />
<pre name="code" class="html"><input id = "fileImage" type = "file" name="filename" />
<input id = "addressid" type = "hidden" name="address" />
<input id="ajaxsub" type="button" class="button" value="上传图片" onclick="fileUpload()<span style="font-family: Arial, Helvetica, sans-serif;">" /> </span>
<input type="submit" class="button" value="提交表单" /> 
<input type="reset" class="button" value="重置表单" /> 

 

 
这一部分需要注意的是,form表单的enctype属性必须设置为“multipart/form-data”,在Html5中,如果需要多张图片一起上传,可以在 标签中,增加multiple属性,例如:


2 js

(1)js使用ajax提供的ajaxfileupload.js库。这个库使用起来还是比较方便的,和普通的ajax函数使用方法几乎相同。首先,需要ajaxfileupload.js库文件。这里需要注意,我之前在网上下载了一个ajaxfileupload.js文件不能用,浪费了很长时间,我直接把js库文件粘贴到这里,方便分享。

// JavaScript Document
// ajax file uplaod 
jQuery.extend({ 
  createUploadIframe: function(id, uri) 
  { 
    //create frame 
    var frameId = &#39;jUploadFrame&#39; + id; 
    if(window.ActiveXObject) { 
      var io = document.createElement(&#39;<iframe id="&#39; + frameId + &#39;" name="&#39; + frameId + &#39;" />&#39;); 
      if(typeof uri== &#39;boolean&#39;){ 
        io.src = &#39;javascript:false&#39;; 
      } 
      else if(typeof uri== &#39;string&#39;){ 
        io.src = uri; 
      } 
    } 
    else { 
      var io = document.createElement(&#39;iframe&#39;); 
      io.id = frameId; 
      io.name = frameId; 
    } 
    io.style.position = &#39;absolute&#39;; 
    io.style.top = &#39;-1000px&#39;; 
    io.style.left = &#39;-1000px&#39;; 
    document.body.appendChild(io); 
    return io; 
  }, 
  createUploadForm: function(id, fileElementId) 
  { 
    //create form 
    var formId = &#39;jUploadForm&#39; + id; 
    var fileId = &#39;jUploadFile&#39; + id; 
    var form = jQuery(&#39;<form action="" method="POST" name="&#39; + formId + &#39;" id="&#39; + formId + &#39;" enctype="multipart/form-data"></form>&#39;); 
    var oldElement = jQuery(&#39;#&#39; + fileElementId); 
    var newElement = jQuery(oldElement).clone(); 
    jQuery(oldElement).attr(&#39;id&#39;, fileId); 
    jQuery(oldElement).before(newElement); 
    jQuery(oldElement).appendTo(form); 
    //set attributes 
    jQuery(form).css(&#39;position&#39;, &#39;absolute&#39;); 
    jQuery(form).css(&#39;top&#39;, &#39;-1200px&#39;); 
    jQuery(form).css(&#39;left&#39;, &#39;-1200px&#39;); 
    jQuery(form).appendTo(&#39;body&#39;); 
    return form; 
  }, 
  ajaxFileUpload: function(s) { 
    // TODO introduce global settings, allowing the client to modify them for all requests, not only timeout  
    s = jQuery.extend({}, jQuery.ajaxSettings, s); 
    var id = s.fileElementId; 
    var form = jQuery.createUploadForm(id, s.fileElementId); 
    var io = jQuery.createUploadIframe(id, s.secureuri); 
    var frameId = &#39;jUploadFrame&#39; + id; 
    var formId = &#39;jUploadForm&#39; + id; 
    if( s.global && ! jQuery.active++ ) 
    { 
      // Watch for a new set of requests 
      jQuery.event.trigger( "ajaxStart" ); 
    } 
    var requestDone = false; 
    // Create the request object 
    var xml = {}; 
    if( s.global ) 
    { 
      jQuery.event.trigger("ajaxSend", [xml, s]); 
    } 
    var uploadCallback = function(isTimeout) 
    { 
      // Wait for a response to come back 
      var io = document.getElementById(frameId); 
      try 
      { 
        if(io.contentWindow) 
        { 
          xml.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null; 
          xml.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document; 
        }else if(io.contentDocument) 
        { 
          xml.responseText = io.contentDocument.document.body?io.contentDocument.document.body.innerHTML:null; 
          xml.responseXML = io.contentDocument.document.XMLDocument?io.contentDocument.document.XMLDocument:io.contentDocument.document; 
        } 
      }catch(e) 
      { 
        jQuery.handleError(s, xml, null, e); 
      } 
      if( xml || isTimeout == "timeout") 
      { 
        requestDone = true; 
        var status; 
        try { 
          status = isTimeout != "timeout" ? "success" : "error"; 
          // Make sure that the request was successful or notmodified 
          if( status != "error" ) 
          { 
            // process the data (runs the xml through httpData regardless of callback) 
            var data = jQuery.uploadHttpData( xml, s.dataType ); 
            if( s.success ) 
            { 
              // ifa local callback was specified, fire it and pass it the data 
              s.success( data, status ); 
            }; 
            if( s.global ) 
            { 
              // Fire the global callback 
              jQuery.event.trigger( "ajaxSuccess", [xml, s] ); 
            }; 
          } else 
          { 
            jQuery.handleError(s, xml, status); 
          } 
        } catch(e) 
        { 
          status = "error"; 
          jQuery.handleError(s, xml, status, e); 
        }; 
        if( s.global ) 
        { 
          // The request was completed 
          jQuery.event.trigger( "ajaxComplete", [xml, s] ); 
        }; 
        // Handle the global AJAX counter 
        if(s.global && ! --jQuery.active) 
        { 
          jQuery.event.trigger("ajaxStop"); 
        }; 
        if(s.complete) 
        { 
          s.complete(xml, status); 
        } ; 
        jQuery(io).unbind(); 
        setTimeout(function() 
        { try 
        { 
          jQuery(io).remove(); 
          jQuery(form).remove(); 
        } catch(e) 
        { 
          jQuery.handleError(s, xml, null, e); 
        } 
        }, 100); 
        xml = null; 
      }; 
    } 
    // Timeout checker 
    if( s.timeout > 0 ) 
    { 
      setTimeout(function(){ 
        if( !requestDone ) 
        { 
          // Check to see ifthe request is still happening 
          uploadCallback( "timeout" ); 
        } 
      }, s.timeout); 
    } 
    try 
    { 
      var form = jQuery(&#39;#&#39; + formId); 
      jQuery(form).attr(&#39;action&#39;, s.url); 
      jQuery(form).attr(&#39;method&#39;, &#39;POST&#39;); 
      jQuery(form).attr(&#39;target&#39;, frameId); 
      if(form.encoding) 
      { 
        form.encoding = &#39;multipart/form-data&#39;; 
      } 
      else 
      { 
        form.enctype = &#39;multipart/form-data&#39;; 
      } 
      jQuery(form).submit(); 
    } catch(e) 
    { 
      jQuery.handleError(s, xml, null, e); 
    } 
    if(window.attachEvent){ 
      document.getElementById(frameId).attachEvent(&#39;onload&#39;, uploadCallback); 
    } 
    else{ 
      document.getElementById(frameId).addEventListener(&#39;load&#39;, uploadCallback, false); 
    } 
    return {abort: function () {}}; 
  }, 
  uploadHttpData: function( r, type ) { 
    var data = !type; 
    data = type == "xml" || data ? r.responseXML : r.responseText; 
    // ifthe type is "script", eval it in global context 
    if( type == "script" ) 
    { 
      jQuery.globalEval( data ); 
    } 
    // Get the JavaScript object, ifJSON is used. 
    if( type == "json" ) 
    { 
      eval( "data = " + data ); 
    } 
    // evaluate scripts within html 
    if( type == "html" ) 
    { 
      jQuery("<p>").html(data).evalScripts(); 
    } 
    return data; 
  }, 
  handleError: function( s, xhr, status, e )   { 
    // If a local callback was specified, fire it  
    if ( s.error ) { 
      s.error.call( s.context || s, xhr, status, e ); 
    } 
    // Fire the global callback 
    if ( s.global ) { 
      (s.context ? jQuery(s.context) : jQuery.event).trigger( "ajaxError", [xhr, s, e] ); 
    } 
  } 
});


로그인 후 복사

(2)를 직접 업로드합니다. 그런 다음 ajaxfileupload.js 라이브러리를 호출하고 여기에 ajaxfileuplaod_implement.js라는 이름의 이미지 업로드 스크립트를 작성합니다.

<p></p><pre name="code" class="javascript">function fileUpload() {  
  var inputObject = $("#fileImage").get(0); 
  if(inputObject.value == "") 
  { 
    alert("清先选择需要上传的图片"); 
    return false; 
  } 
  $.ajaxFileUpload({  
    url: &#39;/PicSubmit/pic&#39;, //服务器端请求地址  
    secureuri: false, //是否需要安全协议,一般设置为false  
    type: &#39;post&#39;, 
    fileElementId: &#39;fileImage&#39;, //文件上传域的ID  
    dataType: &#39;text&#39;, //返回值类型 一般设置为json  
    enctype:&#39;multipart/form-data&#39;,//注意一定要有该参数  
    success: function (data, status) //服务器成功响应处理函数  
    {  
      data=decodeURI(data);//服务器端使用urlencode将中文字符编码,所以这里需要解码。这样做的目的是防止中文乱码 
      var address = JSON.parse(data); 
      for(var i=0;i<address.length;i++){ 
        ajaxfile_onSuccess(address[i]); //这里的success回调函数可以自己定义,但是有一点需要注意,就是需要把服务器返回来的图片存储路径写入
<span style="white-space:pre">              </span>//hiden标签的value值中,方法见下面的writeHide函数 
      } 
    },  
    complete: function(xmlHttpRequest)  
    {<span style="white-space:pre"> </span>//这里将html中的文件上传标签替换为新的标签,是应为我在开发过程中发现,当ajax执行一次上传操作之后,再使用file标签选择文件时,标签没有反应,
<span style="white-space:pre">   </span>//所以暂时使用了这种方法。 
      inputObject.replaceWith(&#39;<input type="file" id="fileImage" name="fileImage" />&#39;); 
    }, 
    error: function (data, status, e)//服务器响应失败处理函数 
    {  
      //alert("无法连接到服务器"); 
    }  
  })  
}
function writeHide(data){ 
<span style="white-space:pre"> </span>if($("#addressid").get(0).value == "") 
<span style="white-space:pre"> </span>{ 
<span style="white-space:pre">   </span>$("#addressid").get(0).value = data.newName; 
<span style="white-space:pre"> </span>} 
<span style="white-space:pre"> </span>else 
<span style="white-space:pre"> </span>{ 
<span style="white-space:pre">   </span>$("#addressid").get(0).value = $("#addressid").get(0).value+","+data.newName; 
<span style="white-space:pre"> </span>} 
} 

3 spring.

完成上面两个部分之后,前台的主要工作基本就结束了。我后台使用了spring框架。

首先是springMVC的配置文件:viewspace-servlet.xml

<?xml version="1.0" encoding="UTF-8" ?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:mvc="http://www.springframework.org/schema/mvc" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
    http://www.springframework.org/schema/mvc  
    http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd 
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context-3.1.xsd"> 
  <!-- 静态资源 --> 
  <mvc:resources mapping="/js/**" location="/js/" /> 
  <mvc:resources mapping="/css/**" location="/css/" /> 
  <mvc:resources mapping="/image/**" location="/image/" /> 
  <!-- 扫描web包,应用Spring的注解 --> 
  <context:component-scan base-package="web"/> 
  <bean id="defaultAnnotationHandlerMapping" 
     class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" /> 
  <bean id="annotationMethodHandlerAdapter" 
     class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> 
  <!-- 配置视图解析器,将ModelAndView及字符串解析为具体的页面 --> 
  <bean 
      class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
      p:viewClass="org.springframework.web.servlet.view.JstlView" 
      p:prefix="/WEB-INF/jsp/" 
      p:suffix=".jsp"/>  
  <!-- 使springMVC支持图片上传 -->  
  <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
      <!-- 最大上传尺寸1MB --> 
      <property name="maxUploadSize" value="10485760"/> 
      <!-- 默认编码 --> 
      <property name="defaultEncoding" value="UTF-8" /> 
      <!-- 上传文件的解析 --> 
      <property name="resolveLazily" value="true" /> 
  </bean> 
  <!-- SpringMVC在超出上传文件限制时,会抛出org.springframework.web.multipart.MaxUploadSizeExceededException --> 
   <!-- 该异常是SpringMVC在检查上传的文件信息时抛出来的,而且此时还没有进入到Controller方法中 --> 
   <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" > 
     <property name="exceptionMappings"> 
       <props> 
         <!-- 遇到MaxUploadSizeExceededException异常时,自动跳转到/WEB-INF/jsp/error_toobig.jsp页面 --> 
         <prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">error_fileupload</prop> 
      </props> 
    </property> 
   </bean> 
</beans>
其中,类“org.springframework.web.multipart.commons.CommonsMultipartResolver”的配置是必须的,否则后台无法收到前台传来的文件。


为了防止文件名中的中文字符传输出现问题,在web.xml中做如下配置:

<?xml version="1.0" encoding="UTF-8"?> 
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> 
 <context-param> 
  <param-name>contextConfigLocation</param-name> 
  <param-value>classpath:applicationContext.xml</param-value> 
 </context-param> 
 <listener> 
  <listener-class> 
      org.springframework.web.context.ContextLoaderListener 
    </listener-class> 
 </listener> 
 <servlet> 
  <servlet-name>viewspace</servlet-name> 
  <servlet-class> 
      org.springframework.web.servlet.DispatcherServlet 
    </servlet-class> 
 </servlet> 
 <servlet-mapping> 
  <servlet-name>viewspace</servlet-name> 
  <url-pattern>/</url-pattern> 
 </servlet-mapping> 
 <!-- 支持传输中文字符 --> 
 <filter>  
    <filter-name>characterEncodingFilter</filter-name>  
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
    <init-param>  
      <param-name>encoding</param-name>  
      <param-value>UTF-8</param-value>  
    </init-param>  
    <init-param>  
      <param-name>forceEncoding</param-name>  
      <param-value>true</param-value>  
    </init-param>  
  </filter>  
  <filter-mapping>  
    <filter-name>characterEncodingFilter</filter-name>  
    <url-pattern>/*</url-pattern>  
  </filter-mapping>  
</web-app>


로그인 후 복사

다음으로 중요한 점은 Controller에서 아래와 같은 방법으로 프론트에서 반환된 파일을 받아준다는 것입니다.

<pre name="code" class="java"> @RequestMapping(value="/pic") 
  @ResponseBody 
  public String submitPic(@RequestParam(value = "filename",required = false) MultipartFile[] fileImage,  
      HttpServletRequest request){ 
    if(fileImage == null){ 
      return "[]"; 
    } 
    return picSaveService.savePic(fileImage); 
  }

로그인 후 복사

프런트 엔드 HTML의 입력 태그에 multiple 속성이 사용되는 경우 태그가 여러 이미지 업로드를 지원한다는 의미이며 컨트롤러의 경우 파일 형식은 MultipartFile []을 사용하고, 반대로 multiple 속성을 사용하지 않으면 사진이 업로드되고 컨트롤러는 MultipartFile 형식을 사용하여 이를 수신한다는 의미입니다.

<p><br> 
</p><p>文件接收完成后,就可以对文件进行存储了,方法有很多,我这里举一个例子如下:</p> 
<p></p><pre name="code" class="java">  public String savePic(MultipartFile[] fileImage){ 
    //为图片改名 
    String oldName = ""; 
    String newName = ""; 
    String extension = ""; 
    //图片按照上传时间命名 
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); 
    //存储每张图片的信息 
    List<PicConfirmData> resultList = new ArrayList<PicConfirmData>(); 
    //获取配置文件中图片的存储路径 
    String path = Parameters.getInstance().getDatabaseProps().getProperty("pic_save_dir"); 
    //依次将图片存储到path路径下 
    for(int i=0;i<fileImage.length;i++){ 
      System.out.println(fileImage[i].getOriginalFilename()); 
      oldName = fileImage[i].getOriginalFilename();     
      extension = oldName.substring(oldName.lastIndexOf(".")); 
      newName = sdf.format(new Date())+extension; 
      File target = new File(path,newName); 
      if(!target.exists()){ 
        target.mkdirs(); 
      } 
      try { 
          fileImage[i].transferTo(target); 
        } catch (IllegalStateException e) { 
          e.printStackTrace(); 
        } catch (IOException e) { 
          e.printStackTrace(); 
        } 
      //记录图片存储信息 
      PicConfirmData pic = null; 
      try { 
        //只存名称,路径已知,从而节省数据库空间 
        //pic = new PicConfirmData(URLEncoder.encode(oldName, "utf-8"), path+newName); 
        pic = new PicConfirmData(1,URLEncoder.encode(oldName, "utf-8"), newName); 
        resultList.add(pic); 
      } catch (UnsupportedEncodingException e) { 
        e.printStackTrace(); 
      } 
    } 
    return ToolJson.getJsonFromPicConfirmData(resultList); 
  }
这里将接收到的图片的原始名称以及修改后存储使用的名称返回给前台,原始名称用于在前台页面输出“存储成功”的提示信息,修改后的名称用于给hiden标签复制,hiden标签的内容会在之后随表单中其他信息一起提交到服务端,通过hiden标签,我们就可以知道与表单关联的图片被存储在什么地方。

最后,图片上传完成后还需要提交表单,这里使用SpringMVC实现一个表单接收功能。这里名为address的参数,存储的就是图片的存储路径。

  @RequestMapping(value="/form") 
  public String submitForm(HttpServletRequest request){ 
    String sid = request.getParameter("name"); 
    String address = request.getParameter("address"); 
     
    if(sid != null && submiter != null && faultTime != null && message != null && address != null){ 
      if(formDataSaveService.saveForm(sid, submiter, message, address, faultTime)){ 
        return "ac"; 
      } 
    } 
    return "error"; 
  }

로그인 후 복사

방법 2 프런트에서 잘라서 업로드 (나중에 남겨주세요)

관련 기사: aAJAX 요청 바이너리 스트림 처리(

ajax

비동기 다운로드 파일)

Webapi Ajax 도메인 간 요청 솔루션 게시 방법을 구현하기 위한 CORS 기반(그림 및 텍스트 튜토리얼)


위 내용은 Ajax는 Spring과 협력하여 파일 업로드 기능을 구현합니다(그래픽 튜토리얼)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!