I'm building a java application with tomcat embedded and jersey REST.
What i need to do is to implement a VERY simple (and single) file upload inside this application but i can't find anywhere a guide for my context...i just found a file upload solution but NOT with embedded tomcat.
Any suggestions?
Thanks everyone in advice and sorry for my English
If you are using Spring Boot for Tomcat embedded, then below code example will help you..
#Controller
public class FileUploadController {
#RequestMapping(value="/upload", method=RequestMethod.GET)
public #ResponseBody String provideUploadInfo() {
return "You can upload a file by posting to this same URL.";
}
#RequestMapping(value="/upload", method=RequestMethod.POST)
public #ResponseBody String handleFileUpload(#RequestParam("name") String name,
#RequestParam("file") MultipartFile file){
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
BufferedOutputStream stream =
new BufferedOutputStream(new FileOutputStream(new File(name)));
stream.write(bytes);
stream.close();
return "You successfully uploaded " + name + "!";
} catch (Exception e) {
return "You failed to upload " + name + " => " + e.getMessage();
}
} else {
return "You failed to upload " + name + " because the file was empty.";
}
}
}
With ref. of
https://spring.io/guides/gs/uploading-files/
Related
I have an unusual task. I have to download the file and immediately force my browser to save it locally to disk?
Below, what I have written so far
#PostMapping("/uploadFile")
public String uploadFile(#RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes, Model model) {
if (file.isEmpty()) {
redirectAttributes.addFlashAttribute("errorMessage", "No file to upload.");
return "index";
}
if(getExtension(file.getOriginalFilename()).equals("XLS") || getExtension(file.getOriginalFilename()).equals("XLSX")) {
Path copyLocation = Paths
.get(UPLOAD_DIR + File.separator + StringUtils.cleanPath(file.getName()));
try {
Files.copy(file.getInputStream(), copyLocation, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
}
redirectAttributes.addFlashAttribute("successMessage", "File upload successfully, uploaded file name: " + file.getOriginalFilename());
}
return "response";
}
Well great, but you could show what you already have and write exactly what you have a problem with. Can't set the content disposition? Fine, but then you could show what you already have and write exactly what you have a problem with. Can't set the content disposition?
#PostMapping(value = "/", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<Resource> handleFileUpload(#RequestParam("file") MultipartFile file) {
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=dupa.xlsx").body(file.getResource());
}
Instead of returning String (view in this case I assume) you can change your endpoint to return byte array with the file content
public #ResponseBody byte[] uploadFile(
You should also provide configuration to the #PostMapping with the media type of the file if you know what kind it's going to be.
#PostMapping(value = "/uploadFile", produces = MediaType.IMAGE_JPEG_VALUE)
Another solution is to return ResponseEntity. The documentation has two examples for it (https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html)
I have problem with upload file to local WebDav. So far i have:
public interface IStorageService {
URI SaveFile(String filename, InputStream inputStream);
}
#Component
public class LocalStorageService implements IStorageService {
#Value( "C:\temp" )
private String filestorePath;
public URI SaveFile(String filename, InputStream inputStream) {
var rootLocation = Paths.get(filestorePath);
var filePath = rootLocation.resolve(filename);
try {
Files.copy(inputStream, filePath);
} catch (IOException e) {
throw new RuntimeException("Failure save file to " + filename + " in " + filestorePath + "." + e.getMessage(), e);
}
return filePath.toUri();
}
}
and controller
private final DocumentService documentService;
public DocumentController(DocumentService documentService) {
this.documentService = documentService;
}
#RequestMapping(method = RequestMethod.POST)
public DocumentModel handleFileUpload(#RequestParam("file") MultipartFile file) throws IOException {
return documentService.handleFileUpload(file.getOriginalFilename(), file.getInputStream());
}
And it is works correctly, the file is uploaded to C:/temp...
Now I would like to do the same but upload file to local WebDav. When i change in #Value "C:\temp to "http://localhost" (this is ma webdav location) i have:
invalidpathexception: illegal char <:> at index 4: http://localhost
or when I declare http//localhost without <:>
nosuchfileexception: http\localhost
How can I write my code to upload file directly to WebDav.
Parameters of SaveFile method cannot be changed, I need do it with Name as String and InputStream.
I tried with Sardine but to no avail. Could someone help me, give any tips or maybe suggestion of code ?
Greetings !
You can get the path where your web app/ war/ servlet / controllers are deployed :
ServletContext context = getContext();
String fullPath = context.getRealPath("/WEB-INF/test/foo.txt");
For a Spring project, in controller
'#Autowired
'ServletContext context;
And in controller method :
'String uploadPath = context.getRealPath("") + File.separator + UPLOAD_DIRECTORY;
And the real file name, but what if a user uploads same file twice or 2 users upload file with same name?
Better to put in sub directory with user id/ user name and maybe date time or some other identifier like TXN id + some fixed text like
' String fileName = context.getRealPath("") + File.separator + userId + readlName + "xyz."
extnFromMimeType;
And store the path in data base for this transaction/ user as per your busibess use case.
if mime type is image/PMG then extnFromMimeType will be "png"; if jpeg or jpg then "jpg"
See
File path to resource in our war/WEB-INF folder?
how to get getServletContext() in spring mvc Controller
In Spring MVC, how can I set the mime type header when using #ResponseBody
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
If can be many images per user/ transaction can also use createTemp File to get a unique file name
using a UUID also possible ... https://stackoverflow.com/a/1293712/1643558 or a large random number
I have a small problem which I've been unable to solve for a few hours. I am basically trying to stream an excel file from the resources folder withing a jar. The file has around 9KB in my file manager, however, when I download it by visiting the REST endpoint I receive a 13/14KB file which can no longer be opened by excel. The metadata is set correctly, as is the filename. I suspect the streaming/copying process is somehow corrupting the file. Here you may see the code snippet:
public void getTemplateByDataType(HttpServletResponse response, DataType dataType) {
String fileName = "excel_template.xlsx";
String templateDirectory = "templates";
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"");
InputStream data = this.getClass().getClassLoader().getResourceAsStream(templateDirectory + "/" + fileName); // loading file from resources folder
try {
IOUtils.copy(data, response.getOutputStream()); // copying to httpservletresponse output stream
} catch (IOException e) {
//...
}
}
I've already tried reading from a simple text file in the same location in order to verify whether the getResourceAsStream call works and this is the case. So I am somehow breaking something with the IOUtils.copy I guess? Does anybody have any suggestions why this simple code snippet breaks my xlsx files?
Just to get the full picture, the controller is relatively simple:
#GetMapping(value = "/templates", produces = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
public #ResponseBody
void getFileTemplate(HttpServletResponse response,
#ApiParam(value = "Type of data import", required = true) #RequestParam String dataType) {
importService.getTemplateByDataType(response, DataType.fromValue(dataType));
}
Try Streaming Output. Maybe this would help you Example of using StreamingOutput as Response entity in Jersey
If you want to download as an attachment, then return the Response like below:
Response.status(Response.Status.OK)
.header(HttpHeaders.CONTENT_DISPOSITION,
String.format("attachment; filename=\"download.gz\""))
.entity(streamingOutput)
.build();
StreamingOutput streams the content of the file and at the client end, it will be downloaded as an attachment.
try to copy this file directly to your output stream.
#GetMapping(value = "/templates", produces = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
public #ResponseBody
void getFileTemplate(HttpServletResponse response,
#ApiParam(value = "Type of data import", required = true) #RequestParam String dataType) {
String fileName = "excel_template.xlsx";
String templateDirectory = "templates";
Path templateFilePath = Paths.get(getClass().getClassLoader().getResource(templateDirectory + "/" + fileName).toURI());
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"");
try {
FileCopyUtils.copy(new BufferedInputStream(new FileInputStream(templateFilePath.toFile())), response.getOutputStream());
response.getOutputStream().flush();
response.getOutputStream().close();
} catch (IOException e) {
//...
}
}
```
I'm trying to upload an image with spring MVC in src/main/webapp/resources to display it in an img tag (<img src="<c:url value="/resources/images/image.jpg" />" alt="image" />) in my jsp. I have this controller :
#Controller
public class FileUploadController implements ServletContextAware {
private ServletContext servletContext;
private String rootPath;
#RequestMapping(value = "/uploadSingleFile", method = RequestMethod.GET)
public ModelAndView uploadSingleFileFormDisplay() {
return new ModelAndView("uploadSingleFile");
}
#RequestMapping(value = "/uploadSingleFile", method = RequestMethod.POST)
public #ResponseBody String uploadSingleFileHandler(#RequestParam("file") MultipartFile file) {
String filename = file.getOriginalFilename();
rootPath = servletContext.getRealPath("/") + "resources/uploads";
if (!file.isEmpty()) {
try {
Document document = new Document();
Image image = new Image();
byte[] bytes = file.getBytes();
BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(new File(
rootPath + "/" + filename
)));
stream.write(bytes);
stream.close();
return "You successfully uploaded " + filename + "!";
} catch (Exception e) {
return "You failed to upload " + filename + " => " + e.getMessage();
}
} else {
return "You failed to upload " + filename + " because the file was empty.";
}
}
(...)
}
How do I build the rootPath to have an absolute path of my system like this : C:/absolute/path/to/webapp/resources or /absolute/path/to/webapp/resources ?
I would say it is not good idea. In fact src folder does not exist. The resources are moved on compile.
Moreover it's not good to place uploaded under web root. First because on restart the web root could be replaced with a new structure from WAR and because of security reasons. You get a potential hole letting something to be uploaded in the place where it could be run.
Instead define an upload path property and use it to store uploaded files and download them if necessary.
UPDATE:
#Value("${myUploadPath}")
private String upload;
and specify property in e.g. application.properties or as JVM argument on start
-DmyUploadPath="C:/absolute/path/to"
I am writing the code for multipart file upload using the vertx.io .
In Spring boot my code is as follows. I want to write similar in vertex.io
#RequestMapping(value = "/upload", headers=("content-type=multipart/*") ,method = RequestMethod.POST)
public ImportExportResponse upload(#RequestParam("file") MultipartFile inputFile){
log.info(" upload service method starts ");
ImportExportResponse response = new ImportExportResponse();
FileOutputStream fileOutputStream=null;
try{
File outputFile = new File(FILE_LOCATION+inputFile.getOriginalFilename());
fileOutputStream = new FileOutputStream(outputFile);
fileOutputStream.write(inputFile.getBytes());
fileOutputStream.close();
response.setStatus(ImportExportConstants.ResponseStatus.SUCCESS.name());
response.setErrorMessage(EMPTY);
}catch (Exception e) {
log.error("Exception while upload the file . "+e.getMessage());
response.setStatus(ImportExportConstants.ResponseStatus.ERROR.name());
response.setErrorMessage(errorMap.get(SYSTEM_ERROR_CODE));
}
log.info(" upload service method ends. file is copied to a temp folder ");
return response;
}
Here is the same but in vert.x:
Router router = Router.router(vertx);
// Enable multipart form data parsing
router.post("/upload").handler(BodyHandler.create()
.setUploadsDirectory(FILE_LOCATION));
// handle the form
router.post("/upload").handler(ctx -> {
// in your example you only handle 1 file upload, here you can handle
// any number of uploads
for (FileUpload f : ctx.fileUploads()) {
// do whatever you need to do with the file (it is already saved
// on the directory you wanted...
System.out.println("Filename: " + f.fileName());
System.out.println("Size: " + f.size());
}
ctx.response().end();
});
For more examples you can always see the vertx-examples repo.