I am sending to backend a file, this is the upload code:
export class FileUploadComponent {
#Input() multiple: boolean = false;
#ViewChild('fileInput') inputEl: ElementRef;
constructor(private http: Http) {}
upload() {
let inputEl: HTMLInputElement = this.inputEl.nativeElement;
let fileCount: number = inputEl.files.length;
let formData = new FormData();
if (fileCount > 0) { // a file was selected
for (let i = 0; i < fileCount; i++) {
formData.append('file[]', inputEl.files.item(i));
}
this.http
.post('http://localhost:8080/upload', formData).toPromise().then(() => console.log('success')).catch(() => console.log('error'));
}
}
}
Now on the backendside I'd like to receive it via controller, but I don't know how to map the file property, following gives null's:
public #ResponseBody String handleFileUpload(#RequestBody MultipartFile file)
Your method signature is incorrect.
#RequestBody annotation parameters maps to the HTTP request body.
#RequestParam annotation parameters maps to the specific Servlet request parameters.
Use the following:
public #ResponseBody String handleFileUpload(#RequestParam MultipartFile file)
If you are sending multiple, then use array:
public #ResponseBody String handleFileUpload(#RequestParam MultipartFile[[] file)
Related
Image
I want to write a client code to consume an API. The API is expecting a text file. When I select the binary file option in the postman tool and select any text file from my local it worked. how to implement this in spring ?. I have tried MULTIPART_FORM_DATA but no luck.
If You mean file
#RestController
public class FileContentController {
#RequestMapping(value="/up", method = RequestMethod.POST)
public ResponseEntity<?> upload(#RequestParam("file") MultipartFile file)
throws IOException {
String contentType=file.getContentType());
InputStream i=file.getInputStream();
return new ResponseEntity<>(HttpStatus.OK);
}
return null;
}
also spring boot has multi part confs, you should enable it and set size and tempdir
,In Earlier version spring boot need to add:
spring.servlet.multipart.max-file-size=128KB
spring.servlet.multipart.max-request-size=128KB
spring.servlet.multipart.enabled=true
spring.servlet.multipart.location=${java.io.tmpdir}
However in your client code you should not set content-type application/json in your header post request
simple fetch should be such
const input = document.getElementById('uploadInput');
const data = new FormData();
data.append('file', input.files[0]);
var resp = await fetch('upload/', {
method: 'POST',
body: data
});
if (!resp.ok) {
throw new Error(`HTTP error! status: ${resp.status}`);
}
if (resp.ok) {
await this.images();
}
i am trying to call the api through feign client and upload the file along with some string parameter through MultipartFile.
This is my client code:
package com.abc;
import feign.codec.Encoder;
#FeignClient(url = "https://xys.com", name = "uploadfile", configuration = UploadFileFeign.MultipartSupportConfig.class)
public interface UploadFileFeign {
#PostMapping(value = "leaveApplication", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ObjectRestResponse<?> handleFileUpload(#RequestParam(value = "request") String request,
#RequestPart(value = "file") MultipartFile srcFile);
class MultipartSupportConfig {
#Bean
public Encoder feignFormEncoder() {
return new FeignSpringFormEncoder();
}
#Bean
public feign.Logger.Level multipartLoggerLevel() {
return feign.Logger.Level.FULL;
}
}
}
Below is the API code which my client is calling.
#RequestMapping(value="/services/leaveApplication", method=Request.POST, produces = MediaType.MULTIPART_FORM_DATA_VALUE, headers="Accept=application/json")
public ResponseOutput leaveApplication(#RequestParam("request") String request, #RequestParam(value = "file", required=false) MultipartFile srcFile) throws Exception {
}
But i am getting error in response:
403 - Forbidden error.
You do not have permission to access the /services/leaveApplication
Other api's which do not involve file upload are working fine.
Typo here :
Request mapping URL is : /services/leaveApplication
But you are accessing : /service/leaveApplication
Change service to services
I wanted to upload image and some more stuff with form from angular. This is VM object :
public class UserPictureVM {
private MultipartFile file;
private String type;
private String coverPosition;
And this is rest method :
#PostMapping("/user/upload-picture")
#Timed
public ResponseEntity<Void> uploadUserPicture(#RequestBody UserPictureVM userPicture){
This is Angular method that submit form :
saveCoverImage() {
const formData: FormData = new FormData();
formData.append('coverPosition', '0, 0');
formData.append('file', this.coverForm.file);
formData.append('type', 'cover');
this.profileService.uploadImages(formData)
.subscribe(res=> {
console.log(res);
})
}
But i get error :
Resolved exception caused by Handler execution: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'multipart/form-data;charset=UTF-8' not supported
You are submitting form with 3 request parameters. Because of that, you should change your controller method signature to this:
public ResponseEntity<Void> uploadUserPicture(
#RequestParam("coverPosition") String coverPosition,
#RequestParam("file") MultipartFile file,
#RequestParam("type") String type)
I have the following controller method for uploading multiple files at once, inspired by this blog post and answers to this question as well:
#RequestMapping(value = "/{user}/attachment", method = RequestMethod.POST)
#PreAuthorize(...)
public void upload(#PathVariable User user,
#RequestParam("file") List<MultipartFile> files) {
// handle files
}
However, the list of the files is always empty although request contains them.
If I add the third MultipartRequest parameter to the method:
public void upload(#PathVariable User user,
#RequestParam("file") List<MultipartFile> files,
MultipartRequest request)
I can see it contains my uploaded files correctly:
What might be the reason of empty List<MultipartFile>?
I'm using ng-file-upload to submit the files, but I don't think it is connected with the issue. Spring 4.2.4.
The problem was that ng-file-upload by default submits array of files using names file[0], file[1] etc. It is configurable with the arrayKey value when using Upload Service. Setting it to empty string forces the files to be sent under the same file key, which is correctly resolved with Spring and the #RequestParam("file") List<MultipartFile> contains all files that has been submitted.
Upload.upload({url: url, data: {file: arrayOfFiles}, arrayKey: ''})
Try to use #ModelAttribute like this:
#RequestMapping(value = "/{user}/attachment", method = RequestMethod.POST)
#PreAuthorize(...)
public void upload(#PathVariable User user,#ModelAttribute("uploadFile") FileUpload uploadFile) throws IllegalStateException, IOException {
List<MultipartFile> files = uploadFile.getFiles();
...
And create a class like:
public class FileUpload {
private List<MultipartFile> files;
public List<MultipartFile> getFiles() {
return files;
}
public void setFiles(List<MultipartFile> files) {
this.files= files;
}
}
That works for me, sending big 'email' object with multiple file attachments from UI to back-end:
Angular
sendEmailWithAttachments(taskId: string, template: string, email: any, modelConfig: any, files: any[]) {
let formData = new FormData();
formData.append('form', new Blob([JSON.stringify(email)], {type: 'application/json'}));
files.forEach(file => {
formData.append('files', file);
});
return this.$http({
method: 'POST',
data: formData,
url: this.baseUrl + '/' + taskId + '/email-with-attachment?template=' + template,
headers: {
'Content-Type': undefined
},
responseType: 'arraybuffer'
});
}
Java Spring
#RequestMapping(value = "{taskId}/email-with-attachment", method = RequestMethod.POST, consumes = MULTIPART_FORM_DATA_VALUE)
public void sendEmailWithAttachment(
#PathVariable String taskId,
#RequestParam String template,
#RequestParam("form") MultipartFile form,
#RequestParam("files") List<MultipartFile> files) throws IOException {
Map<String, String> parameters = new ObjectMapper().readValue(form.getInputStream(), HashMap.class);
System.out.println("taskId"+ taskId);
System.out.println("template"+ template);
System.out.println("files"+ files);
System.out.println("parameters"+ parameters);
}
for multiple files. do this in your javascript
//first add files to form data
var formData = new FormData();
for (let i = 0; i < files.length; i++) {
formData.append("images", files[i]);
}
//post files to backend e.g using angular
$http.post('upload', formData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.then(function(response){
console.log("UPLOAD COMPLETE::=> ", response);
}, function (error) {
console.log(error);
});
Do this in your java
//your java method signature
#PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE )
public Response uploadImage(#RequestParam(value = "images") MultipartFile[] images){
}
I think that in the way you sent data from front, it can not bound with java.util.List. If you create a JSON data as request and you annotated your List with #RequestBody like:
#RequestMapping(value = "/{user}/attachment", method = RequestMethod.POST)
#PreAuthorize(...)
public void upload(#PathVariable User user,
#RequestBody List<MultipartFile> files) {
// handle files
}
this should work. Some info here.
I am building a Spring rest service for uploading a file. There is a form that consists of various field and one field for uploading a file. On submitting that form, I am sending a multipart form request i.e. Content-Type as multipart/form-data.
So I tried with below
#RequestMapping(value = "/companies", method = RequestMethod.POST)
public void createCompany(#RequestBody CompanyDTO companyDTO, #RequestParam(value = "image", required = false) MultipartFile image){
.................
But, the above didn't work. So for time being,i sent JSON data as String and forming Company Object from that String in rest service like
#RequestMapping(value = "/companies", method = RequestMethod.POST)
public void createCompany(#RequestParam("companyJson") String companyJson, #RequestParam(value = "image",required = false) MultipartFile image) throws JsonParseException, JsonMappingException, IOException{
CompanyDTO companyDTO = new ObjectMapper().readValue(companyJson, CompanyDTO.class);
.............................
Can't I send JSON data with #RequestBody without passing JSON as String?
Appending the values to the URL what u have been doing now using #RequestParam.
#RequestParam annotation will not work for complex JSON Objects , it is specifi for Integer or String .
If it is a Http POST method , use of #RequestBody will make the Spring to map the incoming request to the POJO what u have created (condition: if the POJO maps the incoming JSON)
create FormData() and append your json and file
if (form.validate()) {
var file = $scope.file;
var fd = new FormData();
fd.append('jsondata', $scope.jsonData);
fd.append('file', file);
MyService.submitFormWithFile('doc/store.html', fd, '', (response){
console.log(response)
});
}
//Service called in above
MyService.submitFormWithFile = function(url, data, config, callback) {
$http({
method : 'POST',
url : url,
headers : {
'Content-Type' : undefined
},
data : data,
transformRequest : function(data, headersGetterFunction) {
return data;
}
}).success(function(response, status, header, config) {
if (status === 200) {
callback(response);
} else {
console.log("error")
}
}).error(function(response, status, header, config) {
console.log(response);
});
};
// in your java part using ObjectMapper
//it is like string
fd.append('jsondata', JSON.stringify($scope.jsonData));
#Autowired
private ObjectMapper mapper;
#RequestMapping(value = "/companies", method = RequestMethod.POST)
public void createCompany(#RequestParam String jsondata,
#RequestParam(required = true) MultipartFile file){
CompanyDto companyDto=mapper.readValue(jsondata, CompanyDTO.class);
......
}
Use below code snippet:
#RequestMapping(value= "/path", method=RequestMethod.POST, produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseObject methodName(MyData input, #RequestParam(required=false) MultipartFile file) {
// To Do
}