I am trying to download a large file in a Spring Boot microservices application. Can anyone suggest a way of doing that?
Here is my front-end code
<a href={path + curDoc.id} download></a>
AJAX controller code
#GetMapping("/download-collector-file/{collectorFileId}")
public ResponseEntity<Resource> downloadCollectorFile(#PathVariable String collectorFileId) {
System.out.println("kjwenfjkewew beforr");
ResponseEntity<Resource> r= fileServiceAPI.downloadCollectorFile("token",collectorFileId, false);
System.out.println("after api");
return r;
}
Feign client code
#GetMapping("/order-files/read/{id}")
ResponseEntity<Resource> downloadCollectorFile(#RequestHeader("Authorization") String auth,
#PathVariable String id,
#RequestParam("isDownload") Boolean isDownload);
And my service back-end API code
#RequestMapping(value="/{id}" , method = RequestMethod.GET )
public ResponseEntity<InputStreamResource> downloadCollectorFile(#RequestHeader("Authorization") String auth, #PathVariable String id, #RequestParam(required = false, value = "isDownload") boolean isDownload) throws TgxValidationException, IOException {
System.out.println("new file id------===>"+id);
Optional<TgxFilesEntity> optionalTgxFilesEntity = tgxFilesRepository.findByIdAndDeletedFalse(id);
if (optionalTgxFilesEntity.isPresent()) {
TgxFilesEntity tgxFilesEntity = optionalTgxFilesEntity.get();
logger.info(">> UPLOAD_FOLDER=" + UPLOAD_FOLDER_PATH);
String absolutePath = UPLOAD_FOLDER_PATH + "/collector/" + tgxFilesEntity.getRelationalId() + "/";
final File parent = new File(absolutePath + tgxFilesEntity.getFilename());
InputStreamResource resource = new InputStreamResource(new FileInputStream(parent));
String mimeType = URLConnection.guessContentTypeFromName(tgxFilesEntity.getFilename());
logger.info("mimeType" + mimeType);
HttpHeaders headers = new HttpHeaders();
if (!isDownload) {
headers.add("Content-disposition", "inline; filename=" + tgxFilesEntity.getFilename());
if (mimeType == null) {
int lastIndexOf = tgxFilesEntity.getFilename().lastIndexOf(".");
if (tgxFilesEntity.getFilename().substring(lastIndexOf).contains(".json")) {
mimeType = "application/json";
} else if (tgxFilesEntity.getFilename().substring(lastIndexOf).contains(".xlsx")) {
mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
} else if (tgxFilesEntity.getFilename().substring(lastIndexOf).contains(".doc")) {
mimeType = "application/msword";
}
else if (tgxFilesEntity.getFilename().substring(lastIndexOf).contains(".zip")) {
mimeType = "application/zip";
}
else {
mimeType = "text/plain";
}
}
} else {
logger.info("hello else");
headers.add("Content-disposition", "attachment; filename=" + tgxFilesEntity.getFilename());
mimeType = "multipart/form-data";
}
System.out.println("brefore return===>"+resource.getFilename());
return ResponseEntity.ok().headers(headers).contentType(MediaType.parseMediaType(mimeType)).body(resource);
} else throw new FileNotFoundException(environment.getProperty("tgx.validation.file_not_found"));
}
Basically, it is not working for larger files like (300mb,400mb).
Is there any better approach of doing this?
Related
I am trying to extract Word document from JDBC resultset using Spring Boot . Everything is working fine , just that when there is some error , I am getting 500 Error along with an empty file . How do I prevent empty file from being generated.
#GetMapping(produces = "application/vnd.openxmlformats-officedocument.wordprocessingml.document", value = "export/word")
#ApiOperation(value = "Export table as word")
public void generateword(HttpServletResponse response, #RequestParam(required = true) String tableName,
#RequestParam(required = false) String search, #RequestParam(required = false) String searchColumn,
#RequestHeader(required = false, value = "x-remote-user") String username)
throws DataAccessException, IOException {
DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
String currentDateTime = dateFormatter.format(new Date());
String headerKey = "Content-Disposition";
String headerValue = "attachment; filename=" + tableName + "_" + currentDateTime + ".docx";
response.setHeader(headerKey, headerValue);
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
if (StringUtils.hasLength(search)) {
describeDatabaseRepository.generateWord(tableName, username, search, searchColumn, response);
} else {
describeDatabaseRepository.generateWord(tableName, username, response);
}
}
I fixed the issue by putting in try catch block.
try {
DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
String currentDateTime = dateFormatter.format(new Date());
String headerKey = "Content-Disposition";
String headerValue = "attachment; filename=" + tableName + "_" + currentDateTime + ".docx";
response.setHeader(headerKey, headerValue);
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
if (StringUtils.hasLength(search)) {
describeDatabaseRepository.generateWord(tableName, username, search, searchColumn, response);
} else {
describeDatabaseRepository.generateWord(tableName, username, response);
}
} catch (Exception e) {
response.reset();
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
ABCError err = new ABCError();
err.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
err.setDevMessage(e.getMessage());
err.setMessage("Something went wrong.Could not generate the file.");
response.getWriter().write(objectMapper.writeValueAsString(err));
}
I write code for download
#GetMapping(value= "/download/{fileName}")
public ResponseEntity<ByteArrayResource> downloadFile(#PathVariable String fileName) {
final byte[] data = amazonClient.downloadFile(fileName);
final ByteArrayResource resource = new ByteArrayResource(data);
return ResponseEntity
.ok()
.contentLength(data.length)
.header("Content-type", "application/octet-stream")
.header("Content-disposition", "attachment; filename=\"" + fileName + "\"")
.body(resource);
}
and the service method for that : -
public byte[] downloadFile(final String fileName) {
byte[] content = null;
logger.info("Downloading an object with key= " + fileName);
final S3Object s3Object = s3client.getObject(bucketName, fileName);
final S3ObjectInputStream stream = s3Object.getObjectContent();
try {
content = IOUtils.toByteArray(stream);
logger.info("File downloaded successfully.");
s3Object.close();
} catch(final IOException ex) {
logger.info("IO Error Message= " + ex.getMessage());
}
return content;
}
but I want to code for the only view not for download.
You can try this way...
AmazonS3 s3Client = new AmazonS3Client(new ProfileCredentialsProvider());
S3Object object = s3Client.getObject(new GetObjectRequest(bucketName, key));
InputStream objectData = object.getObjectContent();
BufferedImage bf = ImageIO.read(objectData);
using javax.imageio
I am using spring boot 2. My new task is file uploading. I already did it. But I am asked to do it without adding a additional parameter to controller method like #RequestParam("files") MultipartFile files[]. I want to get this from request instead of adding this parameter.
How can I solve this?
I am adding my current code following.
#RequestMapping(value="/uploadMultipleFiles", method=RequestMethod.POST)
public #ResponseBody String handleFileUpload( #RequestParam("files") MultipartFile files[]){
try {
String filePath="c:/temp/kk/";
StringBuffer result=new StringBuffer();
byte[] bytes=null;
result.append("Uploading of File(s) ");
for (int i=0;i<files.length;i++) {
if (!files[i].isEmpty()) {
bytes = files[i].getBytes();
BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(new File(filePath+files[i].getOriginalFilename())));
stream.write(bytes);
stream.close();
result.append(files[i].getOriginalFilename() + " Ok. ") ;
}
else
result.append( files[i].getOriginalFilename() + " Failed. ");
}
return result.toString();
} catch (Exception e) {
return "Error Occured while uploading files." + " => " + e.getMessage();
}
}
You can get files from HttpRequest:
#RequestMapping(value="/uploadMultipleFiles", method=RequestMethod.POST)
public String handleFileUpload(HttpRequest request){
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
Map<String, MultipartFile> yourFiles = multipartRequest.getFileMap();
return "All is Ok!";
}
My sample code.
#RequestMapping(value = "/multiple/upload", method = RequestMethod.POST)
public #ResponseBody String test(#RequestParam(value = "files[]") List<MultipartFile> files,
HttpServletRequest req) {
MultipartFileWriter writer = new MultipartFileWriter();
String folderPath = "/file/";
for (MultipartFile file : files) {
writer.writeFile(file, folderPath, req);
}
return "success";
}
I would like to ask information regarding Multipart/Form-data, if these are compatible with RequestMethod.GET?
In my case I have to return a file + JSON in one response. (Note: File should not be inside the JSON). Sample response:
FILE
{
"id":"1234",
"name":"question Man"
}
I think this might be helpful, please modify it as of your needs.
#RequestMapping(value = URIConstansts.GET_FILE, produces = { "application/json" }, method = RequestMethod.GET)
public #ResponseBody ResponseEntity getFile(#RequestParam(value="fileName", required=false) String fileName,HttpServletRequest request) throws IOException{
ResponseEntity respEntity = null;
byte[] reportBytes = null;
File result=new File("/filepath/"+fileName);
if(result.exists()){
InputStream inputStream = new FileInputStream("/filepath/"+fileName);
String type=result.toURL().openConnection().guessContentTypeFromName(fileName);
byte[]out=org.apache.commons.io.IOUtils.toByteArray(inputStream);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("content-disposition", "attachment; filename=" + fileName);
responseHeaders.add("Content-Type",type);
respEntity = new ResponseEntity(out, responseHeaders,HttpStatus.OK);
}else{
respEntity = new ResponseEntity ("File Not Found", HttpStatus.OK);
}
return respEntity;
}
I want to upload a file( any type of file ) into a forlder using web services and spring mvc so I have a sever side and a client side.
On my client side this is the code
#RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST , produces="application/json")
public #ResponseBody
Boolean uploadMultipleFileHandler(
#RequestParam("name") MultipartFile[] files) {
MailService ms= new MailService();
Map<String, List<ByteArrayResource>>rval = new HashMap<String, List<ByteArrayResource>>();
String message = "";
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
List<Object> files1 = new ArrayList<>();
List<Object> files2 = new ArrayList<>();
for (int i = 0; i < files.length; i++) {
MultipartFile file = files[i];
System.out.println(file.getOriginalFilename());
try {
byte[] bytes = file.getBytes();
files1.add(new ByteArrayResource(bytes));
files2.add(file.getOriginalFilename());
//System.out.println(map.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
map.put("files", files1);
map.put("names", files2);
System.out.println(map.get("files").toString());
RestTemplate restTemplate = new RestTemplate();
String SERVER_URI="http://localhost:8080/BackEndFinalVersion";
Boolean p=restTemplate.postForObject(SERVER_URI+"/uploadMultipleFile", map, Boolean.class);
System.out.println(p.toString());
//message = message + ms.encodeFileToBase64Binary( bytes);
//rval.put("success",message);
return true;
}
and the server side code is
#RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST, produces = "application/json")
public #ResponseBody Boolean uploadMultipleFileHandler(#RequestParam("files") List<Object> files , #RequestParam("names") List<Object> names) {
//MailService ms= new MailService();
//Map<String, Object> rval = new HashMap<String, Object>();
String message = "";
System.out.println("looool");
System.out.println(files);
System.out.println(names);
//System.out.println(files.get(0).toString());
for (int i = 0; i < files.size(); i++) {
System.out.println(files.get(i).getClass());
String file = (String)files.get(i);
try {
byte[] bytes = file.getBytes();
//FileUtils.writeStringToFile(new File("log.txt"), file, Charset.defaultCharset());
// Creating the directory to store file
String rootPath = "C:/Users/Wassim/Desktop/uploads";
File dir = new File(rootPath);
if (!dir.exists())
dir.mkdirs();
File serverFile = new File(dir.getAbsolutePath() + File.separator + ( names.get(i)));
BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(serverFile));
stream.write(bytes);
stream.close();
//message = message + "You successfully uploaded file=" + ( (MultipartFile) files.get(i)).getOriginalFilename() + "<br />";
//FileUtils.writeByteArrayToFile(new File(dir.getAbsolutePath() + File.separator + files.get(i).getOriginalFilename()), ms.decodeFileToBase64Binary(ms.encodeFileToBase64Binary( bytes)));
//rval.put("success"+i, message);
System.out.println("noooo");
} catch (Exception e) {
message += "You failed to upload " + " => " + e.getMessage();
//rval.put("error", message);
return false;
}
}
return true;
My problem is that this code doesn't work only with .txt files
can any one support me ??