File Upload in Angular giving error when posting POST request - java

I have an HTML form like this to upload files from front-end to back-end and do some operations:
<button mat-raised-button color="primary" type="button" style='margin-right:20px' (click)="selectFile()">Select File To Upload</button>
<input #fileUploadInput type="file" id="fileUpload" hidden name="avatar" (change)="fileChangeEvent($event)">
<button mat-raised-button color="primary" type="button" style='margin-right:20px' enctype="multipart/form-data" (click)="uploadFile()">Submit</button>
<br><br>
<a class="generate-full-width" style="color: darkred;" *ngIf="fileName"><strong>{{fileName}}</strong></a>
The component.ts is:
export class uploadFileDialog {
constructor(
public dialogRef: MatDialogRef<AddProductDialog>,
private uploadService: UploadService,
private builder: FormBuilder, public dialog: MatDialog,
#Inject(MAT_DIALOG_DATA) public data) {
}
#ViewChild('fileUploadInput', {static: false})
fileUploadVariable: ElementRef;
fileName;
currentFile: File;
filesToUpload = [];
resetFile(){
this.fileUploadVariable.nativeElement.value = "";
}
selectFile(){
this.resetFile();
let el: HTMLElement = this.fileUploadVariable.nativeElement as HTMLElement;
el.click();
}
fileChangeEvent(fileInput: any) {
let file = fileInput.target.files[0]
console.log(file)
//console.log(file.data.toString());
this.filesToUpload = [];
this.filesToUpload.push(file);
this.fileName = file['name'];
}
uploadFile(){
this.currentFile = this.fileName;
console.log(this.currentFile);
this.uploadService.uploadFile(this.currentFile)
.subscribe((data) => {
console.log(data)
},
error => {
console.log(error)
});
}
}
Service.ts is:
uploadFile(file: File): Observable<any> {
let headers = new HttpHeaders({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
//'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization'
'Access-Control-Allow-Headers': 'Content-Type,Accept,X-Access-Token,X-Key,Authorization,X-Requested-With,Origin,Access-Control-Allow-Origin,Access-Control-Allow-Credentials,content-type=multipart/*'
})
let options = {headers:headers, observer: 'response'};
const formData: FormData = new FormData();
formData.append('file', file);
//return this.http.post(this.url+'/fileUpload/upload', formData,options)
const req = new HttpRequest('POST', this.url+'/fileUpload/upload', formData, {
reportProgress: true,
responseType: 'json'
});
return this.http.request(req);
}
The controller file at Java backend is:
#RestController
#CrossOrigin(origins = "*", allowedHeaders="*", exposedHeaders="Access-Control-Allow-Origin")
#RequestMapping("/fileUpload")
public class FileController {
private final FileService fileService;
#Autowired
public FileController(FileService fileService) {
this.fileService = fileService;
}
#PostMapping(value = "/upload")
public void handleFileUpload(#RequestParam("file") MultipartFile file) throws IOException {
fileService.storeFile(file);
}}
and the Service File at Java Backend is:
#Service
public class FileService {
private static final String FILE_DIRECTORY = "D:\\temp";
public void storeFile(MultipartFile file) throws IOException {
Path filePath = Paths.get(FILE_DIRECTORY + "\" + file.getOriginalFilename());
Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
}
}
I am able to see the file name when uploading in the console. Also, in the body of the request, the formData is showing the xml file as content in the Networks tab. I Java console, I am getting the error:
2020-12-15 12:26:53.144 WARN 9688 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present]
Error in front-end console:
HttpHeaderResponse {headers: HttpHeaders, status: 400, statusText: "OK", url: "http://localhost:8080/fileUpload/upload", ok: false, …}
headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}
ok: false
status: 400
statusText: "OK"
type: 2
url: "http://localhost:8080/fileUpload/upload"
__proto__: HttpResponseBase
What am I doing wrong?

You are sending only file name but not actual file blob.
Try to do below changes,
component.ts :
uploadFile() {
this.currentFile = this.fileName;
console.log(this.currentFile, this.filesToUpload[0]);
this.uploadService.uploadFile(this.currentFile, this.filesToUpload[0])
.subscribe((data) => {
console.log(data)
},
error => {
console.log(error)
});
}
service.ts
uploadFile(fileName: string, file: File): Observable<any> {
let headers = new HttpHeaders({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type,Accept,X-Access-Token,X-Key,Authorization,X-Requested-With,Origin,Access-Control-Allow-Origin,Access-Control-Allow-Credentials,content-type=multipart/*'
})
let options = {headers:headers, observer: 'response'};
const formData: FormData = new FormData();
formData.append('fileName', fileName);
formData.append('file', file);
const req = new HttpRequest('POST', this.url+'/fileUpload/upload', formData, {
reportProgress: true,
responseType: 'json'
});
return this.http.request(req);
}
Please refer this link to know more about formData

Related

405 Error : multipart/form-data with Spring

I am trying to send a Json string along with multiple files into my Spring Controller, however it would always give me a 405 Method Not Allowed Error, what am I doing wrong?
Javascript Code:
var formdata = new FormData();
formdata.append('user', JSON.stringify(userData));
files.forEach(file=> {
formdata.append('files', file);
});
jQuery.ajax({
url: "user/submitForm",
type: "POST",
data: formdata,
enctype: 'multipart/form-data',
processData: false,
contentType: false,
success: function (data)
{
console.log("SUCCESS");
},
error: function (request, status, error) {
alert(status + " : " + JSON.stringify(request));
}
});
Controller in Spring:
#PostMapping(value= "/submitForm", consumes = {
MediaType.APPLICATION_JSON_VALUE,
MediaType.MULTIPART_FORM_DATA_VALUE })
public ResponseEntity<?> userRegistration( #RequestPart("user") String user,
#RequestPart("files") List<MultipartFile> files, BindingResult bindingResult) {
ObjectMapper obj = new ObjectMapper();
User newUser = new User();
newUser = obj.readValue(user, User.class);
System.out.println("User : \n"+ newUser.toString());
System.out.println("Files : \n"+ files.toString());
return null;
}
This was the solution that I found from Antonio112009's answer
SOLUTION
#PostMapping(value = "/submitForm")
public ResponseEntity<?> userRegistration(
#RequestParam("user") String user,
#RequestParam(value = "files", required = false) List<MultipartFile> files) {
ObjectMapper obj = new ObjectMapper();
User userObj = new User();
.
.
.
}
I use another solution, who works as expected and are a bit more flexible from my point of view.
Front-end part is in Typescript.
Front-end
var formData = new FormData();
options.files.forEach(function (file) {
formData.append(file.name, file);
});
formData.append("myParam", "coucou");
var xhr = new XMLHttpRequest();
xhr.open("POST", "/rest/upload");
xhr.onload = function () {
var data = JSON.parse(xhr.responseText);
options.callback("success", options.files.map(function (file) {
return {
file: file,
content: data[file.name]
};
}));
};
xhr.send(formData);
Back-end (Java Spring)
#RestController
#RequestMapping(value = "/rest")
public class UploadController {
#PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Boolean> upload(MultipartHttpServletRequest request) {
// Get param
Object myParam = request.getParameter("myParam");
// Get iteretaor on all files
Iterator<String> iterator = request.getFileNames();
MultipartFile multipartFile = null;
while (iterator.hasNext()) {
multipartFile = request.getFile(iterator.next());
final String fileName = multipartFile.getOriginalFilename();
final String fileSize = String.valueOf(multipartFile.getSize());
// Add logic ....
}
}
return new ResponseEntity(true);
}

Send JSON data as multipart/form-data using axios POST Request

Below API works using postman:
Spring boot, backend code:
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
#CrossOrigin(origins = "*", maxAge = 3600)
#RestController
#Slf4j
public class UploadFile {
#Autowired
private FTPClient con;
#PostMapping("/api/auth/uploadfiles")
public String handleFileUpload(#RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {
try {
boolean result = con.storeFile(file.getOriginalFilename(), file.getInputStream());
redirectAttributes.addFlashAttribute("message",
"You successfully uploaded " + file.getOriginalFilename() + "!");
} catch (Exception e) {
log.error(e.getMessage(), e);
redirectAttributes.addFlashAttribute("message",
"Could not upload " + file.getOriginalFilename() + "!");
}
return "redirect:/";
}
}
ReactJS, frontend code: I have array of objects in the this.state.ipData.
exportFTP = async () => {
const fromdata = this.state.ipData;
alert("Data Send to FTP server");
axios({
method: 'post',
url: 'http://localhost:8080/api/auth/uploadfiles',
data: fromdata,
header: {
'Accept': 'application/json ,text/plain, */*',
'Content-Type': 'multipart/form-data',
//'Authorization': 'Bearer '+JWTToken,
},
})
}
Button to trigger the function:
<button
style={{ marginRight: "2%", marginTop: "0.25%" }}
type="button"
className="btn btn-info"
onClick={() => this.exportFTP()}
>
Export to FTP
</button>
I need to change my frontend (ReactJS) code to as I did POST request using postman. The current JS code causes below error response:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Current request is not a multipart request] with root cause
Note that API works when using Postman. How to fix JS code?
You are sending JSON data as Blob in a multipart request. So, you need to use Blob API.
Create a function to create a blob from JSON data:
function jsonBlob(obj) {
return new Blob([JSON.stringify(obj)], {
type: "application/json",
});
}
And use this function in the request:
exportFTP = async () => {
const formData = new FormData();
formData.append("file", jsonBlob(this.state.ipData))
axios({
method: "post",
url: "http://localhost:8080/api/auth/uploadfiles",
data: formData,
/* You had a Typo: it is "headers" not "header".
And, multipart/form-data header should get set automatically
as we used FormData. You might not need to add that manually. */
// You may also not need Accept header; (should be set automatically).
headers: {
Accept: "application/json ,text/plain, */*",
"Content-Type": "multipart/form-data",
// 'Authorization': 'Bearer '+ JWTToken,
},
});
};
Try to remove the header and send the request
exportFTP = async () => {
const fromdata = this.state.ipData;
alert("Data Send to FTP server");
axios({
method: 'post',
url: 'http://localhost:8080/api/auth/uploadfiles',
data: fromdata
}).then(function (res) {
if (res.ok) {
alert("Perfect! ");
} else if (res.status == 401) {
alert("Oops! ");
}
}, function (e) {
alert("Error submitting form!");
});
}

Angularjs pass null value in file multipart FormData to Spring MVC

I am attempting to send form data with Multipart data (Image) to Spring MVC controller. From my form. image field is non mandatory. so when i call spring controller without input image field, i get below error in browser console.
Failed to load resource: the server responded with a status of 400
(Bad Request)
Html Code:
<input file="file" type="file" id ="file2"/>
AngularjS Code:
$scope.saveData = function (formObj) {
$http({
url: CONTEXT_PATH+'saveFile',
method: "POST",
headers: { 'Content-Type': undefined },
transformRequest: function (data) {
alert(data.files);
var formData = new FormData();
formData.append("model", angular.toJson(data.model));
formData.append("file", data.files);
return formData;
},
data: { model: formObj, files: $scope.file }
}).then(function (response) {
//alert(response);
});
};
app.directive('file', function () {
return {
scope: {
file: '='
},
link: function (scope, el, attrs) {
el.bind('change', function (event) {
var file = event.target.files[0];
scope.file = file ? file : undefined;
scope.$apply();
});
}
};
});
Spring Controller Code:
#RequestMapping(value = "/saveFile")
public #ResponseBody String storeAd(#RequestParam ("model") String adString, #RequestParam ("file") MultipartFile file) throws IOException {
System.out.println("adString > "+adString);
return "OK";
}
When the image is not uploaded, the request is bad because Spring MVC assumes all parameters required unless otherwise defined.
In your case, you should add required = false.
#RequestParam(value = "file", required = false)
Your server code is expecting a request parameter with name "file" but you are not defining it properly.
Change
<input file="file"
To
<input type="file" name="file"

The request was rejected because no multipart boundary was found angular+spring

I'm trying to upload a file recently downloaded with Angular2 to Spring API Rest.
The problem is (display on spring app)...
The request was rejected because no multipart boundary was found
at
org.apache.tomcat.util.http.fileupload.FileUploadBase$FileItemIteratorImpl.(FileUploadBase.java:831)
~[tomcat-embed-core-8.5.28.jar:8.5.28] at
org.apache.tomcat.util.http.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:256)
~[tomcat-embed-core-8.5.28.jar:8.5.28] at
org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:280)
~[tomcat-embed-core-8.5.28.jar:8.5.28] at
org.apache.catalina.connector.Request.parseParts(Request.java:2869)
~[tomcat-embed-core-8.5.28.jar:8.5.28] at
org.apache.catalina.connector.Request.parseParameters(Request.java:3216)
~[tomcat-embed-core-8.5.28.jar:8.5.28] at
org.apache.catalina.connector.Request.getParameter(Request.java:1137)
~[tomcat-embed-core-8.5.28.jar:8.5.28]
On the client side, the request is sent with "multipart/form-data" as content-type.
How can I fix it ?
fileDownloaderService
upload(file) {
const formData = new FormData();
formData.append('file', file);
const req = new HttpRequest('POST', this.urlUpload, file, {
headers: new HttpHeaders({'Content-Type':'multipart/form-data'}),
reportProgress: true
});
return this.http.request(req);
}
app.component
upload() {
let file = this.generate_dummy_file(50000000);
this.downloader.upload(file).subscribe( event => {
if (event.type === HttpEventType.UploadProgress) {
} else if (event instanceof HttpResponse) {
console.log('File is completly uploaded!');
}
});
}
generate_dummy_file(size) {
return new Blob([new ArrayBuffer(size)], {type: 'multipart/form-data'});
};
And spring side
#PostMapping("/uploadFile")
public UploadFileResponse uploadFile(#RequestParam("file") MultipartFile file) {
return ...;
}
Thanks for helping
Try this ,
const formData = new FormData();
formData.append("file", file);
formData.append("reportProgress", true);
use httpclient,
return this.httpclient.post(this.urlUpload, formData);
Have you set Content-Type? If so, please remove it.
headers:{
"Content-Type":"multipart/form-data", // remove it
},
Front End:
const formData = new FormData();
formData.append("file", file);
formData.append("reportProgress", "true");
return this.http.post<void>(this.API_URL + '/upload', formData);
backend end :
#Operation(description = "Upload File")
#ApiResponses(value = {
#ApiResponse(responseCode = "201", description = "File Uploaded successfully"),
#ApiResponse(responseCode = "400", description = "Problem during file upload ")
})
#PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
#ResponseStatus(value = HttpStatus.CREATED)
public void upload(#RequestPart("file") final MultipartFile file) {
//action;
}
Are you actually sending FormData to your server?
Try wrapping the file in a FormData object for the HttpClient to automatically add the multipart boundaries.
upload(file) {
const formData = new FormData();
formData.append('file', file);
const req = new HttpRequest('POST', this.urlUpload, formData, {
headers: new HttpHeaders({'Content-Type':'multipart/form-data'}),
reportProgress: true
});
return this.http.request(req);
}

jsp upload .vcf file to read mobile numbers

How to read .vcf file in jsp or how to pass .vcf file from html to controller.
I am using spring mvc.I want to read contacts from .vcf.
My jsp code:
<span><input type="file" id="vcfFile" name="vcfFile" /> </span>
jquery code :
$("#vcfUpload").click(function (){
var reader = new FileReader();
reader.onloadend = function(){
$
.ajax({
url : "../acquaintance/readingContactsFromVcfFile?vcfFileData="+reader,
type : "post",
contentType : "application/json; charset=utf-8",
cache : false,
dataType : "json",
success : function(data) {
alert(data.message);
}
});
};
reader.readAsText(document.getElementById('vcfFile').files[0]);
});
controller code:
#RequestMapping(value = { "/readingContactsFromVcfFile" }, method = RequestMethod.POST)
public #ResponseBody
ModelMap readContactsFromVcfFile(#RequestParam(value = "vcfFileData")Object vcfData) throws UserServiceException {
log.info("vcf file reading"+ vcfData);
ModelMap modelMap = new ModelMap();
try {
List<VCard> Vcards = Ezvcard.parseHtml((String) vcfData).all();
for (VCard vcard : Vcards) {
log.info("name"+vcard.getFormattedName().getValue());
}
modelMap.addAttribute("message","success");
} catch (Exception IoExp) {
log.info("exception while reading contacts from vcf file",IoExp);
modelMap.addAttribute("message","failed");
}
return modelMap;
}
And i am using Vcard for external :https://code.google.com/p/ez-vcard/wiki/Examples#Example_1.1:_Reading_from_a_plain-text_vCard

Categories