您好,我是使用Spring Boot和AngularJs编写Web应用程序的,需要简单的文件上传,目前无法正常工作。
我已经读过,当存在mvc依赖项时,spring boot应该会自动配置分段上传。来自:https : //spring.io/guides/gs/uploading- files/
作为自动配置Spring MVC的一部分,Spring Boot将创建一个MultipartConfigElement Bean,并准备好进行文件上传。
发送请求的Javascript函数:
var postFormData = function (file, url, successCallback, errorCallback, progressCallback) { var xhr = new XMLHttpRequest(), formData = new FormData(); formData.append("file", file); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { successCallback(xhr.status); //File is Uploaded } else { errorCallback(xhr.status); } } }; function progress(evt) { if (evt.lengthComputable) { var percentComplete = evt.loaded / evt.total; progressCallback(percentComplete); } else { progressCallback(evt.loaded); } } xhr.open("POST", url, true); //xhr.setRequestHeader("Content-Type", "multipart/form-data"); xhr.addEventListener("progress", progress, false); xhr.send(formData); }
我的主应用程序类中的多部分配置Bean:
@Bean MultipartConfigElement multipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); factory.setMaxFileSize(MAXIMUM_FILE_SIZE); factory.setMaxRequestSize(MAXIMUM_FILE_SIZE); return factory.createMultipartConfig(); }
上传控制器:
@Controller @RequestMapping("/api") public class FileUploadController { @Autowired UserRepository userRepository; @Autowired VolumeMetaRepository volumeMetaRepository; /** * Handles File upload of volumedata * * @param file Must not be null **/ @RequestMapping(value = "/volumedata/meta/test", consumes= "multipart/form-data", method=RequestMethod.POST) @ResponseBody public void handleFileUpload( @RequestParam("file") MultipartFile file) { if (!file.isEmpty()) { /* try { InputStream fileStream = file.getInputStream(); OutputStream out = new FileOutputStream(file.getOriginalFilename()); IOUtils.copy(fileStream, out); } catch (IOException e) { throw new IllegalStateException("Error uploading file.", e); }*/ /* String filePath = request.getServletContext().getRealPath("/"); try { file.transferTo(new File(filePath+ "/" + file.getOriginalFilename())); } catch (IOException e) { e.printStackTrace(); }*/ } }
而且由于还有其他Stackoverflow线程是新的Spring引导版本,使用‘1.2.2.BUILD- SNAPSHOT’解决了Im问题,因此我的gradle依赖项:
version = '1.2.2.BUILD-SNAPSHOT' dependencies { compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version:version compile group: 'org.springframework.boot', name: 'spring-boot-starter-aop', version:version compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version:version compile group: 'org.springframework.hateoas', name: 'spring-hateoas', version:'0.16.0.RELEASE' compile group: 'org.springframework.data', name: 'spring-data-rest-webmvc', version:'2.1.4.RELEASE' compile group: 'org.springframework.boot', name: 'spring-boot-starter-security', version:version compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-rest', version:version compile group: 'commons-io', name: 'commons-io', version:'2.1' compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version:'2.3.4' compile group: 'org.springframework.boot', name: 'spring-boot-starter-integration', version:version compile group: 'org.springframework.boot', name: 'spring-boot-starter-websocket', version:version compile group: 'org.springframework.session', name: 'spring-session', version:'1.0.0.BUILD-SNAPSHOT' compile group: 'org.springframework.data', name: 'spring-data-redis', version:'1.4.1.RELEASE' compile group: 'redis.clients', name: 'jedis', version:'2.4.2' compile group: 'org.springframework.boot', name: 'spring-boot-starter-remote-shell', version:version compile group:'com.google.guava', name:'guava', version:'18.0' compile files ('lib/vendor/niftijio.jar'); compile("com.h2database:h2") testCompile(group: 'org.springframework.boot', name: 'spring-boot-starter-test', version:'1.1.6.RELEASE') { exclude(module: 'commons-logging') } testCompile group: 'com.jayway.jsonpath', name: 'json-path', version:'0.9.1' testCompile 'org.springframework:spring-test:3.2.3.RELEASE' testCompile 'junit:junit:4.+' testCompile "org.mockito:mockito-all:1.9.5" }
引发的错误是:
{ "timestamp" : "2015-01-19T10:22:53.710Z", "status" : 400, "error" : "Bad Request", "exception" : "org.springframework.web.bind.MissingServletRequestParameterException", "message" : "Required MultipartFile parameter 'file' is not present", "path" : "/api/volumedata/meta/test" }
它告诉我“ file”参数不存在,但是我的请求有效负载显示该参数在那里。
Request Payload: ------WebKitFormBoundary40qPAhpvA20pd8V1 Content-Disposition: form-data; name="file" C:\fakepath\test.gz ------WebKitFormBoundary40qPAhpvA20pd8V1--
有人知道我的配置中缺少什么,或者什么会导致错误?
提前致谢
我找到了错误的原因。它不是来自我的Spring控制器,而是来自我的angularJS html代码。
这是我的上载输入字段:
<div class="form-group" ng-class="{ 'has-error': volume_upload_form.file_field.$invalid && volume_upload_form.file_field.$dirty}"> <label name=file-field-label>Volume Dataset</label> <input value=file name=file ng-model=upload.file required id=file file_ext_validation type="file" extensions="nii,NII,gz,jpeg,JPG"/> <div class="error" ng-show="volume_upload_form.volume.$invalid"> <small class="error" ng-show="volume_upload_form.volume.$error.fileExtValidation"> File must be of type ".nii" </small> </div> </div>
如您所见,也是使用默认的ng-model与我的角度控制器通信(“ upload”是我的Controller别名)。
ng-model=upload.file
但是Angular默认不支持文件输入html字段。因此,仅包含文件路径的字符串存储在upload.file中,而不是实际的文件对象。我必须编写一个自定义指令:
var fileModel = function ($parse) { return { restrict: 'A', link: function(scope, element, attrs) { var model = $parse(attrs.fileModel); var modelSetter = model.assign; element.bind('change', function () { scope.$apply(function () { modelSetter(scope, element[0].files[0]); }); }); } }; } module.exports = fileModel;
返回实际的File对象。我新上传的html代码如下:
<div class="form-group" ng-class="{ 'has-error': volume_upload_form.file_field.$invalid && volume_upload_form.file_field.$dirty}"> <label name=file-field-label>Volume Dataset</label> <input name=file file-model="upload.fileModel" ng-model="file" required file_ext_validation type="file" extensions="nii,NII,gz,jpeg,JPG"/> <div class="error" ng-show="volume_upload_form.volume.$invalid"> <small class="error" ng-show="volume_upload_form.volume.$error.fileExtValidation"> File must be of type ".nii" </small> </div> </div>
你可以看到
file-model="upload.fileModel"
将文件对象从文件输入字段链接到角度控制器。这是正确的请求有效负载。
------WebKitFormBoundaryR1AXAwLepSUKJB3i Content-Disposition: form-data; name="file"; filename="test.nii.gz" Content-Type: application/x-gzip ------WebKitFormBoundaryR1AXAwLepSUKJB3i--