I have the following #Service class in my Spring application:
#Service
public class FileService {
//#Autowired
//CustomerDetailsRepository customerDetailsRepository;
//private static final String FILE_DIRECTORY = "D:\\temp\\xmlFromAdmin";
private static final String FILE_DIRECTORY = "//opt//xmlFromAdmin";
static String fileName = "";
#Autowired
CustomerDetailsRepository customerDetailsRepository;
//private static CustomerDetails customerDetails;
//private static final String TRANSFORMED_FILE_DIRECTORY = "D:\\temp\\valuesToFrontend";
private static final String TRANSFORMED_FILE_DIRECTORY = "//opt//valuesToFrontend";
public void storeFile(MultipartFile file) throws Exception {
fileName = file.getOriginalFilename();
Path filePath = Paths.get(FILE_DIRECTORY + "/" + fileName);
File fullFilePath = new File(FILE_DIRECTORY + "/" + fileName);
String transformedFileName = TRANSFORMED_FILE_DIRECTORY+"/"+fileName;
Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
Thread.sleep(1000);
FileDecryption fileDecryption = new FileDecryption();
fileDecryption.transformDocument(fullFilePath,transformedFileName);
From the front-end, I am taking an XML file from the user, transforming it, and feeding values to the front-end. This code is running fine when I run this on my local Windows machine, with the commented out path. However, when I put the code into Linux, file upload is failing. The path in Linux is also specified. I am getting Error 500 when uploading, even though the URL is correct. What is the error here? This is the POST request in the service file in angular:
uploadLicenseFile(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': '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('fileName', fileName);
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 problem was permission. The files being uploaded were by tomcat user whereas the directories I created were by root. Bypassed directory creation as of now.
Related
My api is not detecting any of the RequestParams. However it works fine with Postman, just not when being called from React. I've also verified that the formData is being loaded correctly via console.log statements:
formData = file,[object File],uploadId,173,uploadTypeId,1,dateEntered,1625025600000,description,Fourth Addendum testing,enteredBy,769
Does the formData object need to be stringified or something?
Can someone tell me what I'm doing wrong? I'm getting the following error:
Required request parameter 'uploadId' for method parameter type Long is not present
Here is my React snippet:
let formData = new FormData();
formData.append("file", file);
formData.append("uploadId",uploadId);
formData.append("uploadTypeId",uploadTypeId);
formData.append("dateEntered",dateEntered);
formData.append("description",description);
formData.append("enteredBy",enteredBy);
let myHeaders = new Headers();
myHeaders.append("Content-Type", "multipart/form-data; boundary=XXX");
myHeaders.append("type", "formData");
const serverName = "http://localhost:8080/MyApp/api/uploads/update/;
myHeaders.append("Access-Control-Allow-Credentials", 'true');
myHeaders.append("Access-Control-Allow-Origin", '*');
const jwt = sessionStorage.getItem("jwt");
//console.log("fetch jwt = ", jwt) ;
let headerJwt = "Bearer " + jwt;
if (jwt != null) {
myHeaders.append("Authorization", headerJwt);
}
//console.log("headers = ", Object.fromEntries(myHeaders));
let myInit = {method: "PUT"
,headers: myHeaders
};
let url = serverName + endpoint;
//console.log("data = " + data);
if (data)
myInit.body = data;
let returnFetch = fetch(url, myInit);
Here is my Java api snippet:
#PutMapping(value = "/update", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Upload> update(
#RequestParam("uploadId") Long uploadId,
#RequestParam("uploadTypeId") Long uploadTypeId,
#RequestParam("dateEntered") Date dateEntered,
#RequestParam("description") String description,
#RequestParam("enteredBy") Long enteredBy,
#RequestPart(value = "file") MultipartFile file)
throws JsonParseException, JsonMappingException, IOException
,SerialException, SQLException, DataAccessException
{
Upload upload = new Upload();
upload.setUploadId(uploadId);
upload.setUploadTypeId(uploadTypeId);
upload.setDateEntered(dateEntered);
upload.setDescription(description);
upload.setEnteredBy(enteredBy);
MultipartFile multipartFile = file;
byte[] bytes = multipartFile.getBytes();
SerialBlob blob = new SerialBlob(bytes);
upload.setFileBlob(blob);
String filename = multipartFile.getOriginalFilename();
upload.setFilename(filename);
long recordsUpdated = this.myService.updateUpload(upload);
return new ResponseEntity<Upload>(upload, HttpStatus.OK);
}
I found the problem!
I had to do 2 things:
Omit the content-type header.
Stringify all the additional parameters.
It works now!
Good afternoon.
I can't get the browser to download the file from the server. I took the code from a previous project and it doesn't work. Please explain why.
On the server, files are collected in a zip archive. It is necessary to download the archive. I am using this:
My controller
#SneakyThrows
#GetMapping("/report/UploadDocuments")
#ResponseBody
public ResponseEntity<InputStreamResource> uploadDocuments(HttpServletResponse response,
#RequestParam("check") String check){
deleteAllFilesFolder(Directories.DYRECTORY_EXPORT);
ArrayList<Long> idDocuments = Converter.arrayStringInLong(check);
List<PaymentOrderArchive> documents = paymentOrderArchiveService.findAllById(idDocuments);
for (PaymentOrderArchive p : documents){
UploadingFiles.dowloadFileInDirectory(p);
}
//"method" create zip-file and return path
String s = method(documents);
//Problem here
UploadingFiles up = new UploadingFiles();
return up.downloadFile1(servletContext);
}
My method for dowload
public ResponseEntity<InputStreamResource> downloadFile1(ServletContext servletContext) throws IOException {
MediaType mediaType = MediaTypeUtils.getMediaTypeForFileName(servletContext, Directories.NAME_ZIP);
File file = new File(Directories.DYRECTORY_EXPORT + Directories.NAME_ZIP);
InputStreamResource resource = new InputStreamResource(new FileInputStream(file));
return ResponseEntity.ok()
// Content-Disposition
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + Directories.NAME_ZIP)
// Content-Type
.contentType(mediaType)
// Contet-Length
.body(resource);
}
public class MediaTypeUtils {
public static MediaType getMediaTypeForFileName(ServletContext servletContext, String
fileName) {
String mineType = servletContext.getMimeType(fileName);
try {
MediaType mediaType = MediaType.parseMediaType(mineType);
return mediaType;
} catch (Exception e) {
return MediaType.APPLICATION_OCTET_STREAM;
}
}
Everything is working. The program does not give errors. But the file is not downloading. And I can't understand why.
Hello everyone i am using angularjs java and rest to implement one report. Based on UI field selected there is a call to Java Layer and from java there is some database call and the returned input stream i am downloading in a csv file.
There is one problem happening if i do the same with hitting the the same url by browser which i m passing through angularjs than i m able to download the file but if by using UI i m making the request than there is no download option and data is returned as a stream in http response to angular.
java code:
enter code here
#Path("/files")
public class DownloadCsvFile {
#GET
#Path("/csv")
#Produces({MediaType.APPLICATION_OCTET_STREAM})
public Response getFile() {
StreamingOutput outp = new StreamingOutput() {
#Override
public void write(OutputStream out) throws IOException,
WebApplicationException {
String url ="http://someurl?
indent=on&q=RCE_POST:2016&sort=id%20asc
&rows=100000&start=0&wt=csv";
final InputStreamReader is = new InputStreamReader(
((HttpURLConnection) (new URL(url)).openConnection())
.getInputStream(),
Charset.forName("UTF-8"));
IOUtils.copy(is, out);
}
};
ResponseBuilder response = Response.ok(outp);
response.header("Content-Disposition", "attachment;
filename=\"testFile_file.csv\"");
return response.build();
} }
AngularJs controller code :
enter code here
var app = angular.module('myApp', ['ngProgress']);
app.controller('myCtrl', function($scope,$http,ngProgressFactory) {
// on submit the fun is called
$scope.LMALLPeriodReport =function()
{
return $http.get("http://localhost:8080/IsaveIdeas/rest/files/csv?
parameters="+parameter)
//parameter contain the selected field in UI
.then(function (response) {
var result = response.data;
alert("printing data");
});
};
The same request from the browser http://localhost:8080/IsaveIdeas/rest/files/csv? parameters={parameter} enable me to download the file.
You can use Blob in your angularjs code like this:
....
.then(function (response) {
var fileName = "yourFileName.csv";
var a = document.createElement("a");
document.body.appendChild(a);
response.data = "\ufeff" + response.data;
var file = new Blob([response.data], {encoding:"UTF-8",type:'application/csv;charset=UTF-8'});
var fileURL = URL.createObjectURL(file);
a.href = fileURL;
a.download = fileName;
a.click();
}
I am using Jhipster.
I am using docx4j to create a .docx file.
I want to download this .docx file from server to client.
But The file I download is corrupted.
On server side:
I generate my file and put it in a byte[]
WordprocessingMLPackage p = null;
...
File f = new File(filePath);
p.save(f);
byte[] stream = Files.readAllBytes(f.toPath());
I have tried to send it to the client in different format:
byte[]
byte[] encoded Base64
String
String encoded Base64
An example of what's look like my method:
// send back as String encoded in Base64
public ResponseEntity<FileDTO> getFile(#PathVariable Long id) throws URISyntaxException, IOException {
FileDTO result = fillRepository.findOne(id);
byte[] stream = FileUtil.getFile(id) // retrieve file as byte[]
byte[] encoded = Base64.encodeBase64(stream);
String encodedString = new String(encoded, "UTF-8");
result.setFile(encodedString);
return ResponseUtil.wrapOrNotFound(Optional.ofNullable(result));
}
On client side:
I retrieve my file as byte[] or String and I put it in a blob to be downloaded.
FileService.get({id: id}, function(result) {
var res = result.file;
// var res = Base64.decode(result.file);
vm.blob = new Blob([res], {type: 'data:attachment;charset=utf-8;application/vnd.openxmlformats-officedocument.wordprocessingml.document'});
vm.url = (window.URL || window.webkitURL).createObjectURL(vm.blob);
});
My service is declared like this:
(function() {
'use strict';
angular
.module('myApp')
.factory('FileService', FileService);
FileService.$inject = ['$resource', 'DateUtils'];
function FileService($resource, DateUtils) {
var resourceUrl = 'api/file/:id/generate';
return $resource(resourceUrl, {}, {
'get': {
method: 'GET',
responseType:'arraybuffer'
}});}})();
When I download the file word say:
"We're sorry. We can't open file.docx because we found a problem with its content."
And when I compare my original file and the one downloaded in notepad++ for example I see that binary content is not exactly the same like there was encode/decode issues...
Also the size are not the same:
Original file 13Ko
Downloaded file 18Ko
Could you help me on knowing how and why the file downloaded is corrupted.
I finally found a solution:
I directly send back the binary without convertion in the response.
And access it with a window.location
I a new Rest Controller without annotation:#RequestMapping("/api")
#RestController
public class FileGenerationResource {
...
#GetMapping("/file/{id}")
#Timed
public void getFile(#PathVariable Long id, HttpServletResponse response) throws URISyntaxException, IOException {
FileInputStream stream = fileService.getFile(id);
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
response.setHeader("Content-disposition", "attachment; filename=test.docx");
IOUtils.copy(stream,response.getOutputStream());
stream.close();
}
}
The controller content:
(function() {
'use strict';
angular
.module('myApp')
.controller('MyController', MyController);
MyController.$inject = ['$timeout', '$scope', '$stateParams', '$uibModalInstance'];
function MyController ($timeout, $scope, $stateParams, $uibModalInstance) {
var vm = this;
vm.clear = clear;
vm.dwl = dwl;
function dwl (id) {
window.location = "http://localhost:8080/file/"+id;
vm.clear();
}
function clear () {
$uibModalInstance.dismiss('cancel');
}
}
})();
So far (up to Play 2.3) to create a mock request I used Helpers.fakeRequest().withAnyContent(). E.g.
private Request getMultiPartFormDataRequestForFileUpload(File file,
String filePartKey, String contentType) {
FilePart<TemporaryFile> part = new MultipartFormData.FilePart<>(
filePartKey, file.getName(), Scala.Option(contentType),
new TemporaryFile(file));
List<FilePart<TemporaryFile>> fileParts = new ArrayList<>();
fileParts.add(part);
scala.collection.immutable.List<FilePart<TemporaryFile>> files = scala.collection.JavaConversions
.asScalaBuffer(fileParts).toList();
MultipartFormData<TemporaryFile> formData = new MultipartFormData<TemporaryFile>(
null, files, null, null);
return Helpers.fakeRequest().withAnyContent(formData);
}
In Play 2.4 this isn't possible any more. If I look at the source of RequestBuilder (which is implemented by FakeRequest) a similar function exist, but it's protected and I can't use it.
protected Http.RequestBuilder body(play.api.mvc.AnyContent anyContent)
Set a AnyContent to this request.
Does anyone know how I can write a test case to check a file upload with MultipartFormData in 2.4?
As Helpers.fakeRequest is a very, very simple method (taken from github)
/**
* Build a new GET / fake request.
*/
public static RequestBuilder fakeRequest() {
return fakeRequest("GET", "/");
}
/**
* Build a new fake request.
*/
public static RequestBuilder fakeRequest(String method, String uri) {
return new RequestBuilder().method(method).uri(uri);
}
you can extend Http.RequestBuilder thus getting access to protected method:
public class FakeRequestBuilder extends HttpRequestBuilder() {
public RequestBuilder setAnyBody(RequestBody body, String contentType) {
header("Content-Type", contentType);
body(body);
}
}
And use that in your test:
//OLD return Helpers.fakeRequest().withAnyContent(formData);
//NEW
return new FakeRequestBuilder().setAnyBody(formData, "multipart/form-data").build();
//or is it application/x-www-form-urlencoded for you?
In Play2.4, body() does not accept a RequestBody, and you have to create an AnyContent from multipart first. Example:
private class FakeRequestBuilder extends Http.RequestBuilder {
public FakeRequestBuilder(String method, String uri) {
method(method).uri(uri);
}
protected RequestBuilder setAnyBody(MultipartFormData<TemporaryFile> formData, String contentType) {
header("Content-Type", contentType);
AnyContent anyContent = new AnyContentAsMultipartFormData(formData);
body(anyContent);
return this;
}
}
A MultiPartFormData thingie can be created by this for example:
private MultipartFormData<TemporaryFile> createFormData(String contentType, String filePartKey, File file) {
FilePart<TemporaryFile> part = new MultipartFormData.FilePart<>(filePartKey, file.getName(), Scala.Option(contentType), new TemporaryFile(file));
List<FilePart<TemporaryFile>> fileParts = new ArrayList<>();
fileParts.add(part);
scala.collection.immutable.List<FilePart<TemporaryFile>> files = scala.collection.JavaConversions.asScalaBuffer(fileParts).toList();
MultipartFormData<TemporaryFile> formData = new MultipartFormData<TemporaryFile>(null, files, null, null);
return formData;
}